From 3aa8e78f77afe4d77dfb3fd290d7bd434d732b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Th=C3=A9venet?= Date: Thu, 30 Jan 2020 18:58:39 +0100 Subject: [PATCH 01/30] Moved js-client to ES6 module. These changes should not break anything when importing the bundle as before, see 'src/lnn.js' for the compatibility. Not all functions were converted to ES6 classes, but the individual files (modules) should be individually importable. Moving js-client to ES6 allows the JS code to be used for other libraries, in particular for Lightnion's WebSocket, and pave the way for unit-testing. --- .gitmodules | 12 +- js-client/.gitignore | 2 + js-client/Makefile | 89 +- js-client/README.md | 13 +- js-client/config.mk | 11 - js-client/package-lock.json | 1433 ++++++++++++++++++++++++++++++ js-client/package.json | 27 + js-client/rollup.config.js | 21 + js-client/sjcl | 1 - js-client/sjcl.patch | 8 - js-client/src/BigInteger.min.js | 1 - js-client/src/api.js | 239 +++-- js-client/src/consensusParser.js | 562 ++++++------ js-client/src/endpoint.js | 30 +- js-client/src/get.js | 110 +-- js-client/src/header.js | 109 +-- js-client/src/io.js | 123 ++- js-client/src/lnn.js | 119 +++ js-client/src/ntor.js | 196 ++-- js-client/src/onion.js | 148 ++- js-client/src/parser.js | 518 +++++------ js-client/src/path.js | 207 ++--- js-client/src/post.js | 184 ++-- js-client/src/relay.js | 84 +- js-client/src/signature.js | 33 +- js-client/src/stream.js | 742 ++++++++-------- js-client/src/util.js | 65 +- js-client/tweetnacl-js | 1 - js-client/tweetnacl-util-js | 1 - js-client/vendor/sjcl | 1 + 30 files changed, 3347 insertions(+), 1743 deletions(-) delete mode 100644 js-client/config.mk create mode 100644 js-client/package-lock.json create mode 100644 js-client/package.json create mode 100644 js-client/rollup.config.js delete mode 160000 js-client/sjcl delete mode 100644 js-client/sjcl.patch delete mode 100644 js-client/src/BigInteger.min.js create mode 100644 js-client/src/lnn.js delete mode 160000 js-client/tweetnacl-js delete mode 160000 js-client/tweetnacl-util-js create mode 160000 js-client/vendor/sjcl diff --git a/.gitmodules b/.gitmodules index 2ba2658..36fc970 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,6 @@ [submodule "stem"] path = stem-client url = https://git.torproject.org/stem.git -[submodule "js-client/sjcl"] - path = js-client/sjcl - url = https://github.com/bitwiseshiftleft/sjcl -[submodule "js-client/tweetnacl-js"] - path = js-client/tweetnacl-js - url = https://github.com/dchest/tweetnacl-js -[submodule "js-client/tweetnacl-util-js"] - path = js-client/tweetnacl-util-js - url = https://github.com/dchest/tweetnacl-util-js +[submodule "js-client/vendor/sjcl"] + path = js-client/vendor/sjcl + url = https://github.com/bitwiseshiftleft/sjcl.git diff --git a/js-client/.gitignore b/js-client/.gitignore index 7933508..0b7cfb0 100644 --- a/js-client/.gitignore +++ b/js-client/.gitignore @@ -3,3 +3,5 @@ lightnion.bundle.js lightnion.min.js lightnion.js sjcl.js + +node_modules/ diff --git a/js-client/Makefile b/js-client/Makefile index 3a53273..8b321d8 100644 --- a/js-client/Makefile +++ b/js-client/Makefile @@ -1,53 +1,64 @@ -include config.mk +.PHONY: all install build lint clean help submodules -all: lightnion.min.js lightnion.bundle.js +CP = cp +CD = cd +NPM = npm +GIT = git +JSDOC = ./node_modules/jsdoc/jsdoc.js -lightnion.js: $(SOURCES) - cat $(SOURCES) > $@ +VENDOR = ./vendor +SJCL = $(VENDOR)/sjcl +SJCL-GIT = $(SJCL)/.git +SJCL-BUILD = $(VENDOR)/sjcl.js -lightnion.min.js: lightnion.js - cd sjcl && sed -i 's/ADVANCED/SIMPLE/g' compress/compress_with_closure.sh - $(COMPRESSOR) $< > $@ +DIST = ./dist +LIGHTNION-BUNDLE = lightnion.bundle.js +LIGHTNION-BUNDLE-DIST = $(DIST)/lightnion.bundle.js +JSDOC-DIST = jsdoc/ -lightnion.bundle.js: lightnion.min.js $(BUNDLES) +all: $(LIGHTNION-BUNDLE) -sjcl.js: - cp sjcl.patch sjcl - cd sjcl && git apply sjcl.patch && make - cd sjcl && cp sjcl.js .. - cd sjcl && git reset --hard && rm sjcl.patch +install: + npm install -cleanup-bundle: - rm -f ./lightnion.bundle.js +# build project +build: LIGHTNION-BUNDLE-DIST LIGHTNION-BUNDLE -lightnion-bundle: - cat lightnion.min.js >> ./lightnion.bundle.js +# build javascript documentation +doc: jsdoc/index.html -lightnion-bundle-license: - echo -e '\n\n--\n\nLICENSE lightnion\n\n--\n\n' >> $(BUNDLELICENSE) - cat ../LICENSE >> $(BUNDLELICENSE) +# # run javascript linter +# lint: +# ./node_modules/.bin/eslint src -sjcl-bundle: sjcl.js - cat sjcl.js >> ./lightnion.bundle.js +# clean built files +clean: + $(RM) $(LIGHTNION-BUNDLE) + $(RM) $(DIST)/* + $(RM) -r $(JSDOC-DIST) -sjcl-bundle-license: - echo -e '\n\n--\n\nLICENSE sjcl\n\n--\n\n' >> $(BUNDLELICENSE) - cat sjcl/LICENSE.txt >> $(BUNDLELICENSE) +# clean built files and dependencies +mr_proper: clean + $(RM) $(SJCL-BUILD) -tweetnacl-bundle: - cat tweetnacl-js/nacl-fast.min.js >> ./lightnion.bundle.js - cat tweetnacl-util-js/nacl-util.min.js >> ./lightnion.bundle.js +# show this help +help: + @awk '/^#/{c=substr($$0,3);next}c&&/^[[:alpha:]][[:alnum:]_-]+:/{print substr($$1,1,index($$1,":")),c}1{c=0}' $(MAKEFILE_LIST) | column -s: -t -tweetnacl-bundle-license: - echo -e '\n\n--\n\nLICENSE tweetnacl-js\n\n--\n\n' >> $(BUNDLELICENSE) - cat tweetnacl-js/LICENSE >> $(BUNDLELICENSE) - echo -e '\n\n--\n\nLICENSE tweetnacl-util-js\n\n--\n\n' >> $(BUNDLELICENSE) - cat tweetnacl-util-js/LICENSE >> ./LICENSE.bundle.txt +$(LIGHTNION-BUNDLE): $(LIGHTNION-BUNDLE-DIST) + $(CP) $(LIGHTNION-BUNDLE-DIST) $@ -clean: - rm -f sjcl.js +$(LIGHTNION-BUNDLE-DIST): $(SJCL-BUILD) + npm run build -mr_proper: clean - rm -f $(BUNDLELICENSE) - rm -f lightnion.js lightnion.min.js - rm -f lightnion.bundle.js lightnion.bundle.min.js +$(SJCL-GIT): + git submodule update --init --recursive + +$(SJCL-BUILD): $(SJCL-GIT) + cd $(SJCL) && ./configure --with-codecBytes --with-sha1 + cd $(SJCL) && make && cp sjcl.js ../ + # modify sjcl to export + echo "export { sjcl };" >> $(SJCL-BUILD) + +jsdoc/index.html: + $(JSDOC) -r -d $(JSDOC-DIST) src/ \ No newline at end of file diff --git a/js-client/README.md b/js-client/README.md index e55d456..4594733 100644 --- a/js-client/README.md +++ b/js-client/README.md @@ -14,6 +14,7 @@ You will have to clone the repository as follows: git clone --recurse-submodules https://github.com/spring-epfl/lighttor lightnion cd lightnion cd js-client +make install make ``` @@ -50,14 +51,4 @@ See `./demo/` for more examples. ## Requirements -The bundle works on `firefox 61.0.2` and includes `sjcl+tweetnacl-js`. - -If you wish to provide dependencies by yourself, include only: -``` -nacl-fast.min.js -nacl-util.min.js -sjcl.js -lightnion.min.js -``` -Note that you have to build few things with `sjcl.patch` to enable some -codecs. +The bundle works on `firefox 61.0.2` and includes `sjcl+tweetnacl-js`. \ No newline at end of file diff --git a/js-client/config.mk b/js-client/config.mk deleted file mode 100644 index 0077a91..0000000 --- a/js-client/config.mk +++ /dev/null @@ -1,11 +0,0 @@ -SOURCES=\ -src/BigInteger.min.js src/header.js src/endpoint.js src/get.js src/ntor.js src/relay.js src/onion.js\ -src/io.js src/post.js src/stream.js src/util.js src/api.js\ -src/signature.js src/consensusParser.js src/parser.js src/path.js src/export.js - -BUNDLELICENSE=LICENSE.bundle.txt -BUNDLES=\ -cleanup-bundle tweetnacl-bundle sjcl-bundle lightnion-bundle\ -lightnion-bundle-license tweetnacl-bundle-license sjcl-bundle-license - -COMPRESSOR=./sjcl/compress/compress_with_closure.sh diff --git a/js-client/package-lock.json b/js-client/package-lock.json new file mode 100644 index 0000000..3b76f2e --- /dev/null +++ b/js-client/package-lock.json @@ -0,0 +1,1433 @@ +{ + "name": "lightnion-js", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@types/estree": { + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.42.tgz", + "integrity": "sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ==", + "dev": true + }, + "@types/node": { + "version": "13.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.5.2.tgz", + "integrity": "sha512-Fr6a47c84PRLfd7M7u3/hEknyUdQrrBA6VoPmkze0tcflhU5UnpWEX2kn12ktA/lb+MNHSqFlSiPHIHsaErTPA==", + "dev": true + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, + "ajv": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", + "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "big-integer": { + "version": "1.6.48", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", + "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-or-node": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", + "integrity": "sha512-sVIA0cysIED0nbmNOm7sZzKfgN1rpFmrqvLZaFWspaBAftfQcezlC81G6j6U2RJf4Lh66zFxrCeOsvkUXIcPWg==" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "catharsis": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", + "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "inquirer": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", + "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-reference": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", + "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + } + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "js2xmlparser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.0.tgz", + "integrity": "sha512-WuNgdZOXVmBk5kUPMcTcVUpbGRzLfNkv7+7APq7WiDihpXVKrgxo6wwRpRl9OQeEBgKCVk9mR7RbzrnNWC8oBw==", + "dev": true, + "requires": { + "xmlcreate": "^2.0.0" + } + }, + "jsdoc": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.3.tgz", + "integrity": "sha512-Yf1ZKA3r9nvtMWHO1kEuMZTlHOF8uoQ0vyo5eH7SQy5YeIiHM+B0DgKnn+X6y6KDYZcF7G2SPkKF+JORCXWE/A==", + "dev": true, + "requires": { + "@babel/parser": "^7.4.4", + "bluebird": "^3.5.4", + "catharsis": "^0.8.11", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.0", + "klaw": "^3.0.0", + "markdown-it": "^8.4.2", + "markdown-it-anchor": "^5.0.2", + "marked": "^0.7.0", + "mkdirp": "^0.5.1", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.0.1", + "taffydb": "2.6.2", + "underscore": "~1.9.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "magic-string": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.6.tgz", + "integrity": "sha512-3a5LOMSGoCTH5rbqobC2HuDNRtE2glHZ8J7pK+QZYppyWA36yuNpsX994rIY2nCuyP7CZYy7lQq/X2jygiZ89g==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "markdown-it-anchor": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.5.tgz", + "integrity": "sha512-xLIjLQmtym3QpoY9llBgApknl7pxAcN3WDRc2d3rwpl+/YvDZHPmKscGs+L6E05xf2KrCXPBvosWt7MZukwSpQ==", + "dev": true + }, + "marked": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", + "dev": true + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "requizzle": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", + "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.30.1.tgz", + "integrity": "sha512-Uus8mwQXwaO+ZVoNwBcXKhT0AvycFCBW/W8VZtkpVGsotRllWk9oldfCjqWmTnFRI0y7x6BnEqSqc65N+/YdBw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "rollup-plugin-commonjs": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", + "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-legacy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-legacy/-/rollup-plugin-legacy-1.0.0.tgz", + "integrity": "sha1-0IvfxEEL0Tgn9CeMUYcNPY29HqM=", + "dev": true, + "requires": { + "rollup-pluginutils": "^1.5.2" + }, + "dependencies": { + "estree-walker": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz", + "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=", + "dev": true + }, + "rollup-pluginutils": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz", + "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=", + "dev": true, + "requires": { + "estree-walker": "^0.2.1", + "minimatch": "^3.0.2" + } + } + } + }, + "rollup-plugin-node-resolve": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", + "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", + "dev": true, + "requires": { + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.11.1", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-terser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.2.0.tgz", + "integrity": "sha512-jQI+nYhtDBc9HFRBz8iGttQg7li9klmzR62RG2W2nN6hJ/FI2K2ItYQ7kJ7/zn+vs+BP1AEccmVRjRN989I+Nw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "jest-worker": "^24.9.0", + "rollup-pluginutils": "^2.8.2", + "serialize-javascript": "^2.1.2", + "terser": "^4.6.2" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", + "dev": true + }, + "terser": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz", + "integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tweetnacl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.2.tgz", + "integrity": "sha512-+8aPRjmXgf1VqvyxSlBUzKzeYqVS9Ai8vZ28g+mL7dNQl1jlUTCMDZnvNQdAS1xTywMkIXwJsfipsR/6s2+syw==" + }, + "tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "underscore": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.2.tgz", + "integrity": "sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "xmlcreate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.1.tgz", + "integrity": "sha512-MjGsXhKG8YjTKrDCXseFo3ClbMGvUD4en29H2Cev1dv4P/chlpw6KdYmlCWDkhosBVKRDjM836+3e3pm1cBNJA==", + "dev": true + } + } +} diff --git a/js-client/package.json b/js-client/package.json new file mode 100644 index 0000000..005a595 --- /dev/null +++ b/js-client/package.json @@ -0,0 +1,27 @@ +{ + "name": "lightnion-js", + "version": "1.0.0", + "description": "The Lightnion Javascript client.", + "main": "src/lnn.js", + "dependencies": { + "big-integer": "^1.6.48", + "browser-or-node": "^1.2.1", + "tweetnacl": "^1.0.2", + "tweetnacl-util": "^0.15.1" + }, + "devDependencies": { + "eslint": "^6.8.0", + "jsdoc": "^3.6.3", + "rollup": "^1.30.1", + "rollup-plugin-commonjs": "^10.1.0", + "rollup-plugin-legacy": "^1.0.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-terser": "^5.2.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "rollup -c" + }, + "author": "SPRING Lab, EPFL", + "license": "BSD-3-Clause" +} diff --git a/js-client/rollup.config.js b/js-client/rollup.config.js new file mode 100644 index 0000000..2088671 --- /dev/null +++ b/js-client/rollup.config.js @@ -0,0 +1,21 @@ +import resolve from 'rollup-plugin-node-resolve'; +import commonjs from 'rollup-plugin-commonjs'; + +export default [ + { + input: 'src/lnn.js', + output: { + name: "lightnion.bundle", + file: 'dist/lightnion.bundle.js', + format: 'iife', + sourcemap: true + }, + plugins: [ + resolve({ + browser: true, + preferBuiltins: false + }), + commonjs() + ], + } +]; \ No newline at end of file diff --git a/js-client/sjcl b/js-client/sjcl deleted file mode 160000 index cc887b5..0000000 --- a/js-client/sjcl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cc887b518c026407e4ad11ecef37ad9e40d4bd40 diff --git a/js-client/sjcl.patch b/js-client/sjcl.patch deleted file mode 100644 index 21a38fd..0000000 --- a/js-client/sjcl.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff --git a/config.mk b/config.mk -index 1a6a361..e3dbe84 100644 ---- a/config.mk -+++ b/config.mk -@@ -1,2 +1,2 @@ --SOURCES= core/sjcl.js core/aes.js core/bitArray.js core/codecString.js core/codecHex.js core/codecBase32.js core/codecBase64.js core/sha256.js core/ccm.js core/ocb2.js core/gcm.js core/hmac.js core/pbkdf2.js core/random.js core/convenience.js core/exports.js -+SOURCES= core/sjcl.js core/aes.js core/bitArray.js core/codecBytes.js core/codecString.js core/codecHex.js core/codecBase32.js core/codecBase64.js core/sha1.js core/sha256.js core/ccm.js core/ocb2.js core/gcm.js core/hmac.js core/pbkdf2.js core/random.js core/convenience.js core/exports.js - COMPRESS= core_closure.js diff --git a/js-client/src/BigInteger.min.js b/js-client/src/BigInteger.min.js deleted file mode 100644 index c7ca345..0000000 --- a/js-client/src/BigInteger.min.js +++ /dev/null @@ -1 +0,0 @@ -var bigInt=function(undefined){"use strict";var BASE=1e7,LOG_BASE=7,MAX_INT=9007199254740992,MAX_INT_ARR=smallToArray(MAX_INT),DEFAULT_ALPHABET="0123456789abcdefghijklmnopqrstuvwxyz";var supportsNativeBigInt=typeof BigInt==="function";function Integer(v,radix,alphabet,caseSensitive){if(typeof v==="undefined")return Integer[0];if(typeof radix!=="undefined")return+radix===10&&!alphabet?parseValue(v):parseBase(v,radix,alphabet,caseSensitive);return parseValue(v)}function BigInteger(value,sign){this.value=value;this.sign=sign;this.isSmall=false}BigInteger.prototype=Object.create(Integer.prototype);function SmallInteger(value){this.value=value;this.sign=value<0;this.isSmall=true}SmallInteger.prototype=Object.create(Integer.prototype);function NativeBigInt(value){this.value=value}NativeBigInt.prototype=Object.create(Integer.prototype);function isPrecise(n){return-MAX_INT0)return Math.floor(n);return Math.ceil(n)}function add(a,b){var l_a=a.length,l_b=b.length,r=new Array(l_a),carry=0,base=BASE,sum,i;for(i=0;i=base?1:0;r[i]=sum-carry*base}while(i0)r.push(carry);return r}function addAny(a,b){if(a.length>=b.length)return add(a,b);return add(b,a)}function addSmall(a,carry){var l=a.length,r=new Array(l),base=BASE,sum,i;for(i=0;i0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}BigInteger.prototype.add=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.subtract(n.negate())}var a=this.value,b=n.value;if(n.isSmall){return new BigInteger(addSmall(a,Math.abs(b)),this.sign)}return new BigInteger(addAny(a,b),this.sign)};BigInteger.prototype.plus=BigInteger.prototype.add;SmallInteger.prototype.add=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.subtract(n.negate())}var b=n.value;if(n.isSmall){if(isPrecise(a+b))return new SmallInteger(a+b);b=smallToArray(Math.abs(b))}return new BigInteger(addSmall(b,Math.abs(a)),a<0)};SmallInteger.prototype.plus=SmallInteger.prototype.add;NativeBigInt.prototype.add=function(v){return new NativeBigInt(this.value+parseValue(v).value)};NativeBigInt.prototype.plus=NativeBigInt.prototype.add;function subtract(a,b){var a_l=a.length,b_l=b.length,r=new Array(a_l),borrow=0,base=BASE,i,difference;for(i=0;i=0){value=subtract(a,b)}else{value=subtract(b,a);sign=!sign}value=arrayToSmall(value);if(typeof value==="number"){if(sign)value=-value;return new SmallInteger(value)}return new BigInteger(value,sign)}function subtractSmall(a,b,sign){var l=a.length,r=new Array(l),carry=-b,base=BASE,i,difference;for(i=0;i=0)};SmallInteger.prototype.minus=SmallInteger.prototype.subtract;NativeBigInt.prototype.subtract=function(v){return new NativeBigInt(this.value-parseValue(v).value)};NativeBigInt.prototype.minus=NativeBigInt.prototype.subtract;BigInteger.prototype.negate=function(){return new BigInteger(this.value,!this.sign)};SmallInteger.prototype.negate=function(){var sign=this.sign;var small=new SmallInteger(-this.value);small.sign=!sign;return small};NativeBigInt.prototype.negate=function(){return new NativeBigInt(-this.value)};BigInteger.prototype.abs=function(){return new BigInteger(this.value,false)};SmallInteger.prototype.abs=function(){return new SmallInteger(Math.abs(this.value))};NativeBigInt.prototype.abs=function(){return new NativeBigInt(this.value>=0?this.value:-this.value)};function multiplyLong(a,b){var a_l=a.length,b_l=b.length,l=a_l+b_l,r=createArray(l),base=BASE,product,carry,i,a_i,b_j;for(i=0;i0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}function shiftLeft(x,n){var r=[];while(n-- >0)r.push(0);return r.concat(x)}function multiplyKaratsuba(x,y){var n=Math.max(x.length,y.length);if(n<=30)return multiplyLong(x,y);n=Math.ceil(n/2);var b=x.slice(n),a=x.slice(0,n),d=y.slice(n),c=y.slice(0,n);var ac=multiplyKaratsuba(a,c),bd=multiplyKaratsuba(b,d),abcd=multiplyKaratsuba(addAny(a,b),addAny(c,d));var product=addAny(addAny(ac,shiftLeft(subtract(subtract(abcd,ac),bd),n)),shiftLeft(bd,2*n));trim(product);return product}function useKaratsuba(l1,l2){return-.012*l1-.012*l2+15e-6*l1*l2>0}BigInteger.prototype.multiply=function(v){var n=parseValue(v),a=this.value,b=n.value,sign=this.sign!==n.sign,abs;if(n.isSmall){if(b===0)return Integer[0];if(b===1)return this;if(b===-1)return this.negate();abs=Math.abs(b);if(abs=0;shift--){quotientDigit=base-1;if(remainder[shift+b_l]!==divisorMostSignificantDigit){quotientDigit=Math.floor((remainder[shift+b_l]*base+remainder[shift+b_l-1])/divisorMostSignificantDigit)}carry=0;borrow=0;l=divisor.length;for(i=0;ib_l){highx=(highx+1)*base}guess=Math.ceil(highx/highy);do{check=multiplySmall(b,guess);if(compareAbs(check,part)<=0)break;guess--}while(guess);result.push(guess);part=subtract(part,check)}result.reverse();return[arrayToSmall(result),arrayToSmall(part)]}function divModSmall(value,lambda){var length=value.length,quotient=createArray(length),base=BASE,i,q,remainder,divisor;remainder=0;for(i=length-1;i>=0;--i){divisor=remainder*base+value[i];q=truncate(divisor/lambda);remainder=divisor-q*lambda;quotient[i]=q|0}return[quotient,remainder|0]}function divModAny(self,v){var value,n=parseValue(v);if(supportsNativeBigInt){return[new NativeBigInt(self.value/n.value),new NativeBigInt(self.value%n.value)]}var a=self.value,b=n.value;var quotient;if(b===0)throw new Error("Cannot divide by zero");if(self.isSmall){if(n.isSmall){return[new SmallInteger(truncate(a/b)),new SmallInteger(a%b)]}return[Integer[0],self]}if(n.isSmall){if(b===1)return[self,Integer[0]];if(b==-1)return[self.negate(),Integer[0]];var abs=Math.abs(b);if(absb.length?1:-1}for(var i=a.length-1;i>=0;i--){if(a[i]!==b[i])return a[i]>b[i]?1:-1}return 0}BigInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall)return 1;return compareAbs(a,b)};SmallInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=Math.abs(this.value),b=n.value;if(n.isSmall){b=Math.abs(b);return a===b?0:a>b?1:-1}return-1};NativeBigInt.prototype.compareAbs=function(v){var a=this.value;var b=parseValue(v).value;a=a>=0?a:-a;b=b>=0?b:-b;return a===b?0:a>b?1:-1};BigInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(this.sign!==n.sign){return n.sign?1:-1}if(n.isSmall){return this.sign?-1:1}return compareAbs(a,b)*(this.sign?-1:1)};BigInteger.prototype.compareTo=BigInteger.prototype.compare;SmallInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall){return a==b?0:a>b?1:-1}if(a<0!==n.sign){return a<0?-1:1}return a<0?1:-1};SmallInteger.prototype.compareTo=SmallInteger.prototype.compare;NativeBigInt.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var a=this.value;var b=parseValue(v).value;return a===b?0:a>b?1:-1};NativeBigInt.prototype.compareTo=NativeBigInt.prototype.compare;BigInteger.prototype.equals=function(v){return this.compare(v)===0};NativeBigInt.prototype.eq=NativeBigInt.prototype.equals=SmallInteger.prototype.eq=SmallInteger.prototype.equals=BigInteger.prototype.eq=BigInteger.prototype.equals;BigInteger.prototype.notEquals=function(v){return this.compare(v)!==0};NativeBigInt.prototype.neq=NativeBigInt.prototype.notEquals=SmallInteger.prototype.neq=SmallInteger.prototype.notEquals=BigInteger.prototype.neq=BigInteger.prototype.notEquals;BigInteger.prototype.greater=function(v){return this.compare(v)>0};NativeBigInt.prototype.gt=NativeBigInt.prototype.greater=SmallInteger.prototype.gt=SmallInteger.prototype.greater=BigInteger.prototype.gt=BigInteger.prototype.greater;BigInteger.prototype.lesser=function(v){return this.compare(v)<0};NativeBigInt.prototype.lt=NativeBigInt.prototype.lesser=SmallInteger.prototype.lt=SmallInteger.prototype.lesser=BigInteger.prototype.lt=BigInteger.prototype.lesser;BigInteger.prototype.greaterOrEquals=function(v){return this.compare(v)>=0};NativeBigInt.prototype.geq=NativeBigInt.prototype.greaterOrEquals=SmallInteger.prototype.geq=SmallInteger.prototype.greaterOrEquals=BigInteger.prototype.geq=BigInteger.prototype.greaterOrEquals;BigInteger.prototype.lesserOrEquals=function(v){return this.compare(v)<=0};NativeBigInt.prototype.leq=NativeBigInt.prototype.lesserOrEquals=SmallInteger.prototype.leq=SmallInteger.prototype.lesserOrEquals=BigInteger.prototype.leq=BigInteger.prototype.lesserOrEquals;BigInteger.prototype.isEven=function(){return(this.value[0]&1)===0};SmallInteger.prototype.isEven=function(){return(this.value&1)===0};NativeBigInt.prototype.isEven=function(){return(this.value&BigInt(1))===BigInt(0)};BigInteger.prototype.isOdd=function(){return(this.value[0]&1)===1};SmallInteger.prototype.isOdd=function(){return(this.value&1)===1};NativeBigInt.prototype.isOdd=function(){return(this.value&BigInt(1))===BigInt(1)};BigInteger.prototype.isPositive=function(){return!this.sign};SmallInteger.prototype.isPositive=function(){return this.value>0};NativeBigInt.prototype.isPositive=SmallInteger.prototype.isPositive;BigInteger.prototype.isNegative=function(){return this.sign};SmallInteger.prototype.isNegative=function(){return this.value<0};NativeBigInt.prototype.isNegative=SmallInteger.prototype.isNegative;BigInteger.prototype.isUnit=function(){return false};SmallInteger.prototype.isUnit=function(){return Math.abs(this.value)===1};NativeBigInt.prototype.isUnit=function(){return this.abs().value===BigInt(1)};BigInteger.prototype.isZero=function(){return false};SmallInteger.prototype.isZero=function(){return this.value===0};NativeBigInt.prototype.isZero=function(){return this.value===BigInt(0)};BigInteger.prototype.isDivisibleBy=function(v){var n=parseValue(v);if(n.isZero())return false;if(n.isUnit())return true;if(n.compareAbs(2)===0)return this.isEven();return this.mod(n).isZero()};NativeBigInt.prototype.isDivisibleBy=SmallInteger.prototype.isDivisibleBy=BigInteger.prototype.isDivisibleBy;function isBasicPrime(v){var n=v.abs();if(n.isUnit())return false;if(n.equals(2)||n.equals(3)||n.equals(5))return true;if(n.isEven()||n.isDivisibleBy(3)||n.isDivisibleBy(5))return false;if(n.lesser(49))return true}function millerRabinTest(n,a){var nPrev=n.prev(),b=nPrev,r=0,d,t,i,x;while(b.isEven())b=b.divide(2),r++;next:for(i=0;i-MAX_INT)return new SmallInteger(value-1);return new BigInteger(MAX_INT_ARR,true)};NativeBigInt.prototype.prev=function(){return new NativeBigInt(this.value-BigInt(1))};var powersOfTwo=[1];while(2*powersOfTwo[powersOfTwo.length-1]<=BASE)powersOfTwo.push(2*powersOfTwo[powersOfTwo.length-1]);var powers2Length=powersOfTwo.length,highestPower2=powersOfTwo[powers2Length-1];function shift_isSmall(n){return Math.abs(n)<=BASE}BigInteger.prototype.shiftLeft=function(v){var n=parseValue(v).toJSNumber();if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}if(n<0)return this.shiftRight(-n);var result=this;if(result.isZero())return result;while(n>=powers2Length){result=result.multiply(highestPower2);n-=powers2Length-1}return result.multiply(powersOfTwo[n])};NativeBigInt.prototype.shiftLeft=SmallInteger.prototype.shiftLeft=BigInteger.prototype.shiftLeft;BigInteger.prototype.shiftRight=function(v){var remQuo;var n=parseValue(v).toJSNumber();if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}if(n<0)return this.shiftLeft(-n);var result=this;while(n>=powers2Length){if(result.isZero()||result.isNegative()&&result.isUnit())return result;remQuo=divModAny(result,highestPower2);result=remQuo[1].isNegative()?remQuo[0].prev():remQuo[0];n-=powers2Length-1}remQuo=divModAny(result,powersOfTwo[n]);return remQuo[1].isNegative()?remQuo[0].prev():remQuo[0]};NativeBigInt.prototype.shiftRight=SmallInteger.prototype.shiftRight=BigInteger.prototype.shiftRight;function bitwise(x,y,fn){y=parseValue(y);var xSign=x.isNegative(),ySign=y.isNegative();var xRem=xSign?x.not():x,yRem=ySign?y.not():y;var xDigit=0,yDigit=0;var xDivMod=null,yDivMod=null;var result=[];while(!xRem.isZero()||!yRem.isZero()){xDivMod=divModAny(xRem,highestPower2);xDigit=xDivMod[1].toJSNumber();if(xSign){xDigit=highestPower2-1-xDigit}yDivMod=divModAny(yRem,highestPower2);yDigit=yDivMod[1].toJSNumber();if(ySign){yDigit=highestPower2-1-yDigit}xRem=xDivMod[0];yRem=yDivMod[0];result.push(fn(xDigit,yDigit))}var sum=fn(xSign?1:0,ySign?1:0)!==0?bigInt(-1):bigInt(0);for(var i=result.length-1;i>=0;i-=1){sum=sum.multiply(highestPower2).add(bigInt(result[i]))}return sum}BigInteger.prototype.not=function(){return this.negate().prev()};NativeBigInt.prototype.not=SmallInteger.prototype.not=BigInteger.prototype.not;BigInteger.prototype.and=function(n){return bitwise(this,n,function(a,b){return a&b})};NativeBigInt.prototype.and=SmallInteger.prototype.and=BigInteger.prototype.and;BigInteger.prototype.or=function(n){return bitwise(this,n,function(a,b){return a|b})};NativeBigInt.prototype.or=SmallInteger.prototype.or=BigInteger.prototype.or;BigInteger.prototype.xor=function(n){return bitwise(this,n,function(a,b){return a^b})};NativeBigInt.prototype.xor=SmallInteger.prototype.xor=BigInteger.prototype.xor;var LOBMASK_I=1<<30,LOBMASK_BI=(BASE&-BASE)*(BASE&-BASE)|LOBMASK_I;function roughLOB(n){var v=n.value,x=typeof v==="number"?v|LOBMASK_I:typeof v==="bigint"?v|BigInt(LOBMASK_I):v[0]+v[1]*BASE|LOBMASK_BI;return x&-x}function integerLogarithm(value,base){if(base.compareTo(value)<=0){var tmp=integerLogarithm(value,base.square(base));var p=tmp.p;var e=tmp.e;var t=p.multiply(base);return t.compareTo(value)<=0?{p:t,e:e*2+1}:{p:p,e:e*2}}return{p:bigInt(1),e:0}}BigInteger.prototype.bitLength=function(){var n=this;if(n.compareTo(bigInt(0))<0){n=n.negate().subtract(bigInt(1))}if(n.compareTo(bigInt(0))===0){return bigInt(0)}return bigInt(integerLogarithm(n,bigInt(2)).e).add(bigInt(1))};NativeBigInt.prototype.bitLength=SmallInteger.prototype.bitLength=BigInteger.prototype.bitLength;function max(a,b){a=parseValue(a);b=parseValue(b);return a.greater(b)?a:b}function min(a,b){a=parseValue(a);b=parseValue(b);return a.lesser(b)?a:b}function gcd(a,b){a=parseValue(a).abs();b=parseValue(b).abs();if(a.equals(b))return a;if(a.isZero())return b;if(b.isZero())return a;var c=Integer[1],d,t;while(a.isEven()&&b.isEven()){d=min(roughLOB(a),roughLOB(b));a=a.divide(d);b=b.divide(d);c=c.multiply(d)}while(a.isEven()){a=a.divide(roughLOB(a))}do{while(b.isEven()){b=b.divide(roughLOB(b))}if(a.greater(b)){t=b;b=a;a=t}b=b.subtract(a)}while(!b.isZero());return c.isUnit()?a:a.multiply(c)}function lcm(a,b){a=parseValue(a).abs();b=parseValue(b).abs();return a.divide(gcd(a,b)).multiply(b)}function randBetween(a,b){a=parseValue(a);b=parseValue(b);var low=min(a,b),high=max(a,b);var range=high.subtract(low).add(1);if(range.isSmall)return low.add(Math.floor(Math.random()*range));var digits=toBase(range,BASE).value;var result=[],restricted=true;for(var i=0;i=absBase){if(c==="1"&&absBase===1)continue;throw new Error(c+" is not a valid digit in base "+base+".")}}}base=parseValue(base);var digits=[];var isNegative=text[0]==="-";for(i=isNegative?1:0;i"&&i=0;i--){val=val.add(digits[i].times(pow));pow=pow.times(base)}return isNegative?val.negate():val}function stringify(digit,alphabet){alphabet=alphabet||DEFAULT_ALPHABET;if(digit"}function toBase(n,base){base=bigInt(base);if(base.isZero()){if(n.isZero())return{value:[0],isNegative:false};throw new Error("Cannot convert nonzero numbers to base 0.")}if(base.equals(-1)){if(n.isZero())return{value:[0],isNegative:false};if(n.isNegative())return{value:[].concat.apply([],Array.apply(null,Array(-n.toJSNumber())).map(Array.prototype.valueOf,[1,0])),isNegative:false};var arr=Array.apply(null,Array(n.toJSNumber()-1)).map(Array.prototype.valueOf,[0,1]);arr.unshift([1]);return{value:[].concat.apply([],arr),isNegative:false}}var neg=false;if(n.isNegative()&&base.isPositive()){neg=true;n=n.abs()}if(base.isUnit()){if(n.isZero())return{value:[0],isNegative:false};return{value:Array.apply(null,Array(n.toJSNumber())).map(Number.prototype.valueOf,1),isNegative:neg}}var out=[];var left=n,divmod;while(left.isNegative()||left.compareAbs(base)>=0){divmod=left.divmod(base);left=divmod.quotient;var digit=divmod.remainder;if(digit.isNegative()){digit=base.minus(digit).abs();left=left.next()}out.push(digit.toJSNumber())}out.push(left.toJSNumber());return{value:out.reverse(),isNegative:neg}}function toBaseString(n,base,alphabet){var arr=toBase(n,base);return(arr.isNegative?"-":"")+arr.value.map(function(x){return stringify(x,alphabet)}).join("")}BigInteger.prototype.toArray=function(radix){return toBase(this,radix)};SmallInteger.prototype.toArray=function(radix){return toBase(this,radix)};NativeBigInt.prototype.toArray=function(radix){return toBase(this,radix)};BigInteger.prototype.toString=function(radix,alphabet){if(radix===undefined)radix=10;if(radix!==10)return toBaseString(this,radix,alphabet);var v=this.value,l=v.length,str=String(v[--l]),zeros="0000000",digit;while(--l>=0){digit=String(v[l]);str+=zeros.slice(digit.length)+digit}var sign=this.sign?"-":"";return sign+str};SmallInteger.prototype.toString=function(radix,alphabet){if(radix===undefined)radix=10;if(radix!=10)return toBaseString(this,radix,alphabet);return String(this.value)};NativeBigInt.prototype.toString=SmallInteger.prototype.toString;NativeBigInt.prototype.toJSON=BigInteger.prototype.toJSON=SmallInteger.prototype.toJSON=function(){return this.toString()};BigInteger.prototype.valueOf=function(){return parseInt(this.toString(),10)};BigInteger.prototype.toJSNumber=BigInteger.prototype.valueOf;SmallInteger.prototype.valueOf=function(){return this.value};SmallInteger.prototype.toJSNumber=SmallInteger.prototype.valueOf;NativeBigInt.prototype.valueOf=NativeBigInt.prototype.toJSNumber=function(){return parseInt(this.toString(),10)};function parseStringValue(v){if(isPrecise(+v)){var x=+v;if(x===truncate(x))return supportsNativeBigInt?new NativeBigInt(BigInt(x)):new SmallInteger(x);throw new Error("Invalid integer: "+v)}var sign=v[0]==="-";if(sign)v=v.slice(1);var split=v.split(/e/i);if(split.length>2)throw new Error("Invalid integer: "+split.join("e"));if(split.length===2){var exp=split[1];if(exp[0]==="+")exp=exp.slice(1);exp=+exp;if(exp!==truncate(exp)||!isPrecise(exp))throw new Error("Invalid integer: "+exp+" is not a valid exponent.");var text=split[0];var decimalPlace=text.indexOf(".");if(decimalPlace>=0){exp-=text.length-decimalPlace-1;text=text.slice(0,decimalPlace)+text.slice(decimalPlace+1)}if(exp<0)throw new Error("Cannot include negative exponent part for integers");text+=new Array(exp+1).join("0");v=text}var isValid=/^([0-9][0-9]*)$/.test(v);if(!isValid)throw new Error("Invalid integer: "+v);if(supportsNativeBigInt){return new NativeBigInt(BigInt(sign?"-"+v:v))}var r=[],max=v.length,l=LOG_BASE,min=max-l;while(max>0){r.push(+v.slice(min,max));min-=l;if(min<0)min=0;max-=l}trim(r);return new BigInteger(r,sign)}function parseNumberValue(v){if(supportsNativeBigInt){return new NativeBigInt(BigInt(v))}if(isPrecise(v)){if(v!==truncate(v))throw new Error(v+" is not an integer.");return new SmallInteger(v)}return parseStringValue(v.toString())}function parseValue(v){if(typeof v==="number"){return parseNumberValue(v)}if(typeof v==="string"){return parseStringValue(v)}if(typeof v==="bigint"){return new NativeBigInt(v)}return v}for(var i=0;i<1e3;i++){Integer[i]=parseValue(i);if(i>0)Integer[-i]=parseValue(-i)}Integer.one=Integer[1];Integer.zero=Integer[0];Integer.minusOne=Integer[-1];Integer.max=max;Integer.min=min;Integer.gcd=gcd;Integer.lcm=lcm;Integer.isInstance=function(x){return x instanceof BigInteger||x instanceof SmallInteger||x instanceof NativeBigInt};Integer.randBetween=randBetween;Integer.fromArray=function(digits,base,isNegative){return parseBaseFromArray(digits.map(parseValue),parseValue(base||10),isNegative)};return Integer}();if(typeof module!=="undefined"&&module.hasOwnProperty("exports")){module.exports=bigInt}if(typeof define==="function"&&define.amd){define("big-integer",[],function(){return bigInt})} \ No newline at end of file diff --git a/js-client/src/api.js b/js-client/src/api.js index a357da9..335db66 100644 --- a/js-client/src/api.js +++ b/js-client/src/api.js @@ -1,140 +1,136 @@ -lnn.fast = function(host, port, success, error, io, select_path) -{ - if(select_path === undefined) +/** + * @module api + */ + +import * as utils from "./util.js"; +import * as lnnEndpoint from "./endpoint.js"; +import * as lnnIO from "./io.js"; +import * as post from "./post.js"; +import * as get from "./get.js"; +import * as signature from "./signature.js"; +import { stream } from "./stream.js"; + +export function fast(host, port, success, error, io, select_path) { + if (select_path === undefined) select_path = true - return lnn.open(host, port, success, error, io, true, null, select_path) + return open(host, port, success, error, io, true, null, select_path) } -lnn.auth = function(host, port, suffix, success, error, io, select_path) -{ - if(select_path === undefined) +export function auth(host, port, suffix, success, error, io, select_path) { + if (select_path === undefined) select_path = true - if (typeof(suffix) == "string") - { + if (typeof (suffix) == "string") { suffix = suffix.replace(/-/g, "+").replace(/_/g, "/") - suffix = lnn.dec.base64(suffix) + suffix = utils.dec.base64(suffix) } - if (lnn.enc.utf8(suffix.slice(0, 5)) != "auth ") + if (utils.enc.utf8(suffix.slice(0, 5)) != "auth ") throw "Invalid prefix in auth. suffix!" suffix = suffix.slice(5) if (suffix.length != 20 + 32) throw "Invalid auth. suffix length!" - return lnn.open(host, port, success, error, io, true, { + return open(host, port, success, error, io, true, { identity: suffix.slice(0, 20), onionkey: suffix.slice(20), - ntor: nacl.box.keyPair()}, select_path) + ntor: nacl.box.keyPair() + }, select_path) } -lnn.open = function(host, port, success, error, io, fast, auth, select_path, tcp_ports) -{ - var endpoint = lnn.endpoint(host, port) +export function open(host, port, success, error, io, fast, auth, select_path, tcp_ports) { + let endpoint = lnnEndpoint.endpoint(host, port) if (io === undefined) - io = lnn.io.socket + io = lnnIO.socket if (fast === undefined) fast = false if (error === undefined) - error = function() { } + error = function () { } if (success === undefined) - success = function() { } - if(select_path === undefined) + success = function () { } + if (select_path === undefined) select_path = true - if(tcp_ports === undefined ) - tcp_ports = [80,443] + if (tcp_ports === undefined) + tcp_ports = [80, 443] endpoint.fast = fast endpoint.auth = auth endpoint.select_path = select_path var cb = { - guard: function(endpoint) - { + guard: function (endpoint) { endpoint.state = lnn.state.guarded - - lnn.post.circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports) + + post.circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports) }, - startWebSocket: function(endpoint, info) { - console.log('called startWebSocket cb') - endpoint.stream = lnn.stream.backend(error) - io(endpoint, lnn.stream.handler, function(endpoint) - { + startWebSocket: function (endpoint, info) { + console.log('called startWebSocket cb') + endpoint.stream = stream.backend(error) + io(endpoint, stream.handler, function (endpoint) { var state = endpoint.state endpoint.state = lnn.state.pending - + endpoint.state = state }, error) endpoint.io.start() - lnn.post.handshake(endpoint, info, cb.create, error) - }, - create: function(endpoint) - { - console.log('called create cb') + post.handshake(endpoint, info, cb.create, error) + }, + create: function (endpoint) { + console.log('called create cb') endpoint.state = lnn.state.created - - lnn.post.extend(endpoint, endpoint.path[0], cb.extend, error) + + post.extend(endpoint, endpoint.path[0], cb.extend, error) }, - extend: function(endpoint) - { - console.log('called extend cb') + extend: function (endpoint) { + console.log('called extend cb') endpoint.state = lnn.state.extpath - - lnn.post.extend(endpoint, endpoint.path[1], cb.success, error) + + post.extend(endpoint, endpoint.path[1], cb.success, error) }, - success: function(endpoint) - { - console.log('called success cb') + success: function (endpoint) { + console.log('called success cb') endpoint.state = lnn.state.success success(endpoint) - endpoint.io.success = function() { } + endpoint.io.success = function () { } } } endpoint.state = lnn.state.started - - - if(select_path) { - lnn.get.consensus_raw(endpoint,function() - { - lnn.get.signing_keys(endpoint,function() - { - if(!lnn.signature.verify(endpoint.consensus_raw,endpoint.signing_keys,0.5)) - { + + + if (select_path) { + get.consensus_raw(endpoint, function () { + get.signing_keys(endpoint, function () { + if (!signature.verify(endpoint.consensus_raw, endpoint.signing_keys, 0.5)) { throw "signature verification failed." } console.log("signature verification success") - lnn.get.descriptors_raw(endpoint,function() - { + get.descriptors_raw(endpoint, function () { if (endpoint.fast) - lnn.post.circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports) + post.circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports) else - lnn.get.guard(endpoint, cb.guard, error) + get.guard(endpoint, cb.guard, error) - },function() - { + }, function () { throw "Failed to fetch raw descriptors" }) - },function() - { + }, function () { throw "Failed to fetch signing keys" - }) - },function() - { + }) + }, function () { throw "Failed to fetch raw consensus!" }) - } - else - { + } + else { // fast channel: one-request channel creation (no guard pinning) if (endpoint.fast) - lnn.post.circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports) + post.circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports) else - lnn.get.guard(endpoint, cb.guard, error) + get.guard(endpoint, cb.guard, error) } return endpoint @@ -143,7 +139,7 @@ lnn.open = function(host, port, success, error, io, fast, auth, select_path, tcp /***** high level apis ****/ -lnn.agents = [ +export let agents = [ "curl/7.61.0", "curl/7.60.0", "curl/7.59.0", @@ -182,16 +178,15 @@ lnn.agents = [ "curl/7.38.0" ] -lnn.send_req = function(endpoint,url, method, data, data_type, success,error) { - var agent = lnn.agents[Math.floor(Math.random() * lnn.agents.length)] +export function send_req(endpoint, url, method, data, data_type, success, error) { + var agent = agents[Math.floor(Math.random() * agents.length)] var data_recv = '' var length = null var rawlen = 0 var headers = null - var handler = function(request) - { - if(request.state == lnn.state.success) { + var handler = function (request) { + if (request.state == lnn.state.success) { error('Connection closed') return } @@ -201,35 +196,34 @@ lnn.send_req = function(endpoint,url, method, data, data_type, success,error) { var payload = request.recv() rawlen += payload.length - data_recv += lnn.enc.utf8(payload) - - - if (length == null) - { - if (data_recv.match('\r\n\r\n')) - { + data_recv += utils.enc.utf8(payload) + + + if (length == null) { + if (data_recv.match('\r\n\r\n')) { headers = data_recv.split('\r\n\r\n')[0] var len = headers.match('Content-Length: ([^\r]*)') length = parseInt(len[1]) } } - + if (headers == null || length == null || rawlen < headers.length + length) return request.close() console.log("Stream closed") - success({headers: headers, - data: data_recv.slice(headers.length + 4)}) - success = function(request) { } + success({ + headers: headers, + data: data_recv.slice(headers.length + 4) + }) + success = function (request) { } } if (url.slice(0, 7) == "http://") url = url.slice(7) - else - { - error ('Urls must start with http://') + else { + error('Urls must start with http://') return } @@ -244,27 +238,27 @@ lnn.send_req = function(endpoint,url, method, data, data_type, success,error) { if (host.match(":") != null) port = host.split(":", 2)[1] - if(method != "GET" && method != "POST") { - error ('Unsupported method') + if (method != "GET" && method != "POST") { + error('Unsupported method') return } - if(data_type != "json" && data_type != "form") { + if (data_type != "json" && data_type != "form") { error('Unsupported content type') return } - if(data_type == "json") + if (data_type == "json") data_type = "application/json" else data_type = "application/x-www-form-urlencoded" - - if(method == "GET" && data.length > 0) { + + if (method == "GET" && data.length > 0) { data = "?" + data path += data path = encodeURI(path) } - else if(data_type == "application/x-www-form-urlencoded"){ + else if (data_type == "application/x-www-form-urlencoded") { data = encodeURI(data) } @@ -274,12 +268,12 @@ lnn.send_req = function(endpoint,url, method, data, data_type, success,error) { ["User-Agent:", agent].join(" "), ["Accept:", "*/*"].join(" ")] - if(method == "POST") { - payload.push(["Content-Length:",data.length].join(" ")) - payload.push(["Content-Type:",data_type].join(" ")) + if (method == "POST") { + payload.push(["Content-Length:", data.length].join(" ")) + payload.push(["Content-Type:", data_type].join(" ")) payload = payload.join("\r\n") + "\r\n\r\n" + data + "\r\n" - } - else{ + } + else { payload = payload.join("\r\n") + "\r\n\r\n" } @@ -287,48 +281,45 @@ lnn.send_req = function(endpoint,url, method, data, data_type, success,error) { console.log(payload) host = host.split(':')[0] - lnn.stream.tcp(endpoint, host, port, handler).send(payload) + stream.tcp(endpoint, host, port, handler).send(payload) } -lnn.http_request = function(url, method, data, data_type, success, error,tor_host,tor_port) -{ - if(tor_host === undefined) +export function http_request(url, method, data, data_type, success, error, tor_host, tor_port) { + if (tor_host === undefined) tor_host = 'localhost' - if(tor_port === undefined) + if (tor_port === undefined) tor_port = 4990 if (error === undefined) - error = function() { } + error = function () { } if (success === undefined) - success = function() { } + success = function () { } var closed = false - var channel = lnn.open( - tor_host,tor_port,function(endpoint) - { + var channel = open( + tor_host, tor_port, function (endpoint) { if (endpoint.state != lnn.state.success) { return } - - lnn.send_req(endpoint,url, method, data, data_type,function(request) { + + send_req(endpoint, url, method, data, data_type, function (request) { //close circuit here. - if(!closed) { - endpoint.close(function(success_msg) {console.log(success_msg)}) + if (!closed) { + endpoint.close(function (success_msg) { console.log(success_msg) }) closed = true } success(request) - },function(message) { + }, function (message) { //close circuit here - if(!closed) { - endpoint.close(function(success_msg) {console.log(success_msg)}) + if (!closed) { + endpoint.close(function (success_msg) { console.log(success_msg) }) closed = true } error(message) }) } - ,function() - { + , function () { error("Connection establishment failed") } ) diff --git a/js-client/src/consensusParser.js b/js-client/src/consensusParser.js index a777c53..cdef807 100644 --- a/js-client/src/consensusParser.js +++ b/js-client/src/consensusParser.js @@ -1,24 +1,29 @@ -lnn.consensusParser = {} -lnn.consensusParser.parse = function(rawText,flavor = 'microdesc') { +/** + * @module consensusParser + */ + +let consensusParser = {}; + +consensusParser.parse = function (rawText, flavor = 'microdesc') { if (typeof rawText !== 'string') throw `Error: the consensus must be given as a string` - lnn.consensusParser.lines = rawText.split('\n') - lnn.consensusParser.words = lnn.consensusParser.lines[0].split(' ') - lnn.consensusParser.consensus = {} - lnn.consensusParser.validFlags = ['Authority', 'BadExit', 'Exit', 'Fast', 'Guard', 'HSDir', 'NoEdConsensus', 'Stable', 'StaleDesc', 'Running', 'Valid', 'V2Dir'] - lnn.consensusParser.index = 0 - lnn.consensusParser.totalLines = lnn.consensusParser.lines.length - - if(flavor != 'unflavored' && flavor != 'microdesc') { + consensusParser.lines = rawText.split('\n') + consensusParser.words = consensusParser.lines[0].split(' ') + consensusParser.consensus = {} + consensusParser.validFlags = ['Authority', 'BadExit', 'Exit', 'Fast', 'Guard', 'HSDir', 'NoEdConsensus', 'Stable', 'StaleDesc', 'Running', 'Valid', 'V2Dir'] + consensusParser.index = 0 + consensusParser.totalLines = consensusParser.lines.length + + if (flavor != 'unflavored' && flavor != 'microdesc') { throw 'Error: Unexpected flavor' } - lnn.consensusParser.consensus['flavor'] = flavor + consensusParser.consensus['flavor'] = flavor - lnn.consensusParser.consumeHeaders() - lnn.consensusParser.consumeAuthority() - lnn.consensusParser.consumeRouters() - lnn.consensusParser.consumeFooter() + consensusParser.consumeHeaders() + consensusParser.consumeAuthority() + consensusParser.consumeRouters() + consensusParser.consumeFooter() - return lnn.consensusParser.consensus + return consensusParser.consensus } //----------------------------------HEADERS PARSER-------------------------------- @@ -26,129 +31,129 @@ lnn.consensusParser.parse = function(rawText,flavor = 'microdesc') { /** * Function that parses the headers */ -lnn.consensusParser.consumeHeaders = function() { - lnn.consensusParser.consumeNetworkStatusVersion() - lnn.consensusParser.consumeVoteStatus() - lnn.consensusParser.consumeConsensusMethod() - lnn.consensusParser.consumeDate('valid-after') - lnn.consensusParser.consumeDate('fresh-until') - lnn.consensusParser.consumeDate('valid-until') - lnn.consensusParser.consumeVotingDelay() - lnn.consensusParser.tryConsumeVersions('client-versions') - lnn.consensusParser.tryConsumeVersions('server-versions') - - while (lnn.consensusParser.words[0] === 'package') { - lnn.consensusParser.consumePackage() +consensusParser.consumeHeaders = function () { + consensusParser.consumeNetworkStatusVersion() + consensusParser.consumeVoteStatus() + consensusParser.consumeConsensusMethod() + consensusParser.consumeDate('valid-after') + consensusParser.consumeDate('fresh-until') + consensusParser.consumeDate('valid-until') + consensusParser.consumeVotingDelay() + consensusParser.tryConsumeVersions('client-versions') + consensusParser.tryConsumeVersions('server-versions') + + while (consensusParser.words[0] === 'package') { + consensusParser.consumePackage() } - lnn.consensusParser.consumeKnownFlags() - lnn.consensusParser.tryConsumeProtocols('recommended-client-protocols') - lnn.consensusParser.tryConsumeProtocols('recommended-relay-protocols') - lnn.consensusParser.tryConsumeProtocols('required-client-protocols') - lnn.consensusParser.tryConsumeProtocols('required-relay-protocols') - lnn.consensusParser.tryConsumeParams() - lnn.consensusParser.tryConsumeShareRand('shared-rand-previous-value') - lnn.consensusParser.tryConsumeShareRand('shared-rand-current-value') + consensusParser.consumeKnownFlags() + consensusParser.tryConsumeProtocols('recommended-client-protocols') + consensusParser.tryConsumeProtocols('recommended-relay-protocols') + consensusParser.tryConsumeProtocols('required-client-protocols') + consensusParser.tryConsumeProtocols('required-relay-protocols') + consensusParser.tryConsumeParams() + consensusParser.tryConsumeShareRand('shared-rand-previous-value') + consensusParser.tryConsumeShareRand('shared-rand-current-value') } /** * Parse the field network-status-version */ -lnn.consensusParser.consumeNetworkStatusVersion = function() { +consensusParser.consumeNetworkStatusVersion = function () { let expectedLength = 2 - if(lnn.consensusParser.consensus.flavor == 'microdesc') { + if (consensusParser.consensus.flavor == 'microdesc') { expectedLength = 3 - if(lnn.consensusParser.words[2] != 'microdesc') + if (consensusParser.words[2] != 'microdesc') throw 'Error: Flavor mismatch in header.' } - let version = lnn.consensusParser.tryParseKeyValueInteger('network-status-version',expectedLength) - lnn.consensusParser.consensus['headers'] = { + let version = consensusParser.tryParseKeyValueInteger('network-status-version', expectedLength) + consensusParser.consensus['headers'] = { 'network-status-version': { 'version': version, - 'flavor': lnn.consensusParser.consensus.flavor + 'flavor': consensusParser.consensus.flavor } } - lnn.consensusParser.nextLine() + consensusParser.nextLine() } /** * Parse the field vote-status * @throws WrongParameterException if status is not consensus */ -lnn.consensusParser.consumeVoteStatus = function() { - let status = lnn.consensusParser.tryParseKeyValueString('vote-status') +consensusParser.consumeVoteStatus = function () { + let status = consensusParser.tryParseKeyValueString('vote-status') if (status !== 'consensus') throw `WrongParameterException: vote-status must be consensus` - lnn.consensusParser.consensus['headers']['vote-status'] = status - lnn.consensusParser.nextLine() + consensusParser.consensus['headers']['vote-status'] = status + consensusParser.nextLine() } /** * Parse the field consensus-method */ -lnn.consensusParser.consumeConsensusMethod = function() { - lnn.consensusParser.consensus['headers']['consensus-method'] = lnn.consensusParser.tryParseKeyValueInteger('consensus-method') - lnn.consensusParser.nextLine() +consensusParser.consumeConsensusMethod = function () { + consensusParser.consensus['headers']['consensus-method'] = consensusParser.tryParseKeyValueInteger('consensus-method') + consensusParser.nextLine() } /** * Parse the fields valid-after, fresh-until and valid-until * @param {strin} word */ -lnn.consensusParser.consumeDate = function(word) { - lnn.consensusParser.consensus['headers'][word] = lnn.consensusParser.tryParseDate(word) - lnn.consensusParser.nextLine() +consensusParser.consumeDate = function (word) { + consensusParser.consensus['headers'][word] = consensusParser.tryParseDate(word) + consensusParser.nextLine() } /** * Parse the field voting-delay - * @throws NotEqualException if lnn.consensusParser.words[0] != word - * @throws WrongParameterException if lnn.consensusParser.words[1] or lnn.consensusParser.words[2] is not a number - * @throws WrongFormatException if lnn.consensusParser.words.length is not 3 - */ -lnn.consensusParser.consumeVotingDelay = function() { - lnn.consensusParser.checkFormat(3, 'voting-delay') - if (isNaN(lnn.consensusParser.words[1])) throw `WrongParameterException: ${words[1]} is not a number` - if (isNaN(lnn.consensusParser.words[2])) throw `WrongParameterException: ${words[2]} is not a number` - - lnn.consensusParser.consensus['headers']['voting-delay'] = { - 'vote': Number(lnn.consensusParser.words[1]), - 'dist': Number(lnn.consensusParser.words[2]) + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongParameterException if consensusParser.words[1] or consensusParser.words[2] is not a number + * @throws WrongFormatException if consensusParser.words.length is not 3 + */ +consensusParser.consumeVotingDelay = function () { + consensusParser.checkFormat(3, 'voting-delay') + if (isNaN(consensusParser.words[1])) throw `WrongParameterException: ${words[1]} is not a number` + if (isNaN(consensusParser.words[2])) throw `WrongParameterException: ${words[2]} is not a number` + + consensusParser.consensus['headers']['voting-delay'] = { + 'vote': Number(consensusParser.words[1]), + 'dist': Number(consensusParser.words[2]) } - lnn.consensusParser.nextLine() + consensusParser.nextLine() } /** * Try to parse the fields client-versions or server-versions if they are present * @param {string} word either client-versions or server-versions */ -lnn.consensusParser.tryConsumeVersions = function(word) { +consensusParser.tryConsumeVersions = function (word) { - if (lnn.consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` - if (lnn.consensusParser.words[0] === word) { - lnn.consensusParser.consensus['headers'][word] = lnn.consensusParser.tryParseCommaSeparatedList(word) - lnn.consensusParser.nextLine() + if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` + if (consensusParser.words[0] === word) { + consensusParser.consensus['headers'][word] = consensusParser.tryParseCommaSeparatedList(word) + consensusParser.nextLine() } } /** * Parses the field package - * @throws WrongFormatException if lnn.consensusParser.words.length is smaller than 5 + * @throws WrongFormatException if consensusParser.words.length is smaller than 5 */ -lnn.consensusParser.consumePackage = function() { +consensusParser.consumePackage = function () { - if (lnn.consensusParser.words.length < 5) throw `WrongFormatException: at least 5 fields are expected` - if (lnn.consensusParser.consensus['headers']['package'] === undefined) lnn.consensusParser.consensus['headers']['package'] = [] + if (consensusParser.words.length < 5) throw `WrongFormatException: at least 5 fields are expected` + if (consensusParser.consensus['headers']['package'] === undefined) consensusParser.consensus['headers']['package'] = [] let pack = { - 'name': lnn.consensusParser.words[1], - 'version': lnn.consensusParser.words[2], - 'url': lnn.consensusParser.words[3] + 'name': consensusParser.words[1], + 'version': consensusParser.words[2], + 'url': consensusParser.words[3] } - let remaining = lnn.consensusParser.words.splice(4, lnn.consensusParser.words.length) + let remaining = consensusParser.words.splice(4, consensusParser.words.length) let digests = {} for (let digest of remaining) { @@ -157,38 +162,38 @@ lnn.consensusParser.consumePackage = function() { } pack['digests'] = digests - lnn.consensusParser.consensus['headers']['package'].push(pack) - lnn.consensusParser.nextLine() + consensusParser.consensus['headers']['package'].push(pack) + consensusParser.nextLine() } /** * Parses the field package * @throws NotValidFlagException if one of the flags is not in the valid flag list */ -lnn.consensusParser.consumeKnownFlags = function() { - lnn.consensusParser.consensus['headers']['flags'] = lnn.consensusParser.tryParseFlags() - lnn.consensusParser.nextLine() +consensusParser.consumeKnownFlags = function () { + consensusParser.consensus['headers']['flags'] = consensusParser.tryParseFlags() + consensusParser.nextLine() } /** * Try to parse the fields recommended-client-protocols, recommended-relay-protocols, required-client-protocols and required-client-protocols if they are present * @param {string} word either client-versions or server-versions */ -lnn.consensusParser.tryConsumeProtocols = function(word) { - if (lnn.consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` - if (lnn.consensusParser.words[0] === word) { - lnn.consensusParser.consensus['headers'][word] = lnn.consensusParser.tryParseRanges(lnn.consensusParser.words.splice(1, lnn.consensusParser.words.length)) - lnn.consensusParser.nextLine() +consensusParser.tryConsumeProtocols = function (word) { + if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` + if (consensusParser.words[0] === word) { + consensusParser.consensus['headers'][word] = consensusParser.tryParseRanges(consensusParser.words.splice(1, consensusParser.words.length)) + consensusParser.nextLine() } } /** * Try to parse the field params if it is present */ -lnn.consensusParser.tryConsumeParams = function() { - if (lnn.consensusParser.words[0] === 'params') { - lnn.consensusParser.consensus['headers']['params'] = lnn.consensusParser.tryParseParams() - lnn.consensusParser.nextLine() +consensusParser.tryConsumeParams = function () { + if (consensusParser.words[0] === 'params') { + consensusParser.consensus['headers']['params'] = consensusParser.tryParseParams() + consensusParser.nextLine() } } @@ -196,20 +201,20 @@ lnn.consensusParser.tryConsumeParams = function() { * Try to parse the fields shared-rand-previous-value and shared-rand-current-value if they are present * @param {string} word specify the field */ -lnn.consensusParser.tryConsumeShareRand = function(word) { - if (lnn.consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` - if (lnn.consensusParser.words[0] === word) { - let reveals = Number(lnn.consensusParser.words[1]) - let value = lnn.consensusParser.words[2] +consensusParser.tryConsumeShareRand = function (word) { + if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` + if (consensusParser.words[0] === word) { + let reveals = Number(consensusParser.words[1]) + let value = consensusParser.words[2] - if (!lnn.consensusParser.isBase64(value)) throw `InvalidParameterException: value ${value} must be in hexadecimal` + if (!consensusParser.isBase64(value)) throw `InvalidParameterException: value ${value} must be in hexadecimal` - lnn.consensusParser.consensus['headers'][word] = { + consensusParser.consensus['headers'][word] = { 'NumReveals': reveals, 'Value': value } - lnn.consensusParser.nextLine() + consensusParser.nextLine() } } @@ -219,12 +224,12 @@ lnn.consensusParser.tryConsumeShareRand = function(word) { * @throws InvalidIPException if address or IP are not valid IP addresses * @throws InvalidPortException if dirport or orport are not valid ports */ -lnn.consensusParser.consumeAuthority = function() { - if (lnn.consensusParser.words[0] !== 'dir-source') throw `WrongFieldException: there must be at least one dir-source` - lnn.consensusParser.consensus['dir-sources'] = [] +consensusParser.consumeAuthority = function () { + if (consensusParser.words[0] !== 'dir-source') throw `WrongFieldException: there must be at least one dir-source` + consensusParser.consensus['dir-sources'] = [] - while (lnn.consensusParser.words[0] === 'dir-source') { - lnn.consensusParser.consumeDirSource() + while (consensusParser.words[0] === 'dir-source') { + consensusParser.consumeDirSource() } } @@ -234,36 +239,36 @@ lnn.consensusParser.consumeAuthority = function() { * @throws InvalidPortException if dirport or orport are not valid * @throws InvalidParameterException if the vote-digest is not in hexadecimal */ -lnn.consensusParser.consumeDirSource = function() { +consensusParser.consumeDirSource = function () { let dirSource = {} - lnn.consensusParser.checkFormat(7, 'dir-source') + consensusParser.checkFormat(7, 'dir-source') - dirSource['nickname'] = lnn.consensusParser.words[1] + dirSource['nickname'] = consensusParser.words[1] - if (!lnn.consensusParser.isHex(lnn.consensusParser.words[2])) throw `InvalidParameterException: vote-digest ${lnn.consensusParser.words[2]} must be in hexadecimal` - dirSource['identity'] = lnn.consensusParser.words[2].toUpperCase() + if (!consensusParser.isHex(consensusParser.words[2])) throw `InvalidParameterException: vote-digest ${consensusParser.words[2]} must be in hexadecimal` + dirSource['identity'] = consensusParser.words[2].toUpperCase() - dirSource['hostname'] = lnn.consensusParser.words[3] + dirSource['hostname'] = consensusParser.words[3] - if (!lnn.consensusParser.isValidIP(lnn.consensusParser.words[4])) throw `InvalidIPException: ${lnn.consensusParser.words[4]} is not a valid IP` + if (!consensusParser.isValidIP(consensusParser.words[4])) throw `InvalidIPException: ${consensusParser.words[4]} is not a valid IP` - dirSource['address'] = lnn.consensusParser.words[4] + dirSource['address'] = consensusParser.words[4] - if (!lnn.consensusParser.isValidPort(Number(lnn.consensusParser.words[5])) || !lnn.consensusParser.isValidPort(Number(lnn.consensusParser.words[6]))) throw `InvalidPortException` + if (!consensusParser.isValidPort(Number(consensusParser.words[5])) || !consensusParser.isValidPort(Number(consensusParser.words[6]))) throw `InvalidPortException` - dirSource['dirport'] = Number(lnn.consensusParser.words[5]) - dirSource['orport'] = Number(lnn.consensusParser.words[6]) + dirSource['dirport'] = Number(consensusParser.words[5]) + dirSource['orport'] = Number(consensusParser.words[6]) - lnn.consensusParser.nextLine() - dirSource['contact'] = lnn.consensusParser.words.splice(1, lnn.consensusParser.words.length).join(' ') - lnn.consensusParser.nextLine() - let digest = lnn.consensusParser.tryParseKeyValueString('vote-digest').toUpperCase() + consensusParser.nextLine() + dirSource['contact'] = consensusParser.words.splice(1, consensusParser.words.length).join(' ') + consensusParser.nextLine() + let digest = consensusParser.tryParseKeyValueString('vote-digest').toUpperCase() - if (!lnn.consensusParser.isHex(digest)) throw `InvalidParameterException: vote-digest ${digest} must be in hexadecimal` + if (!consensusParser.isHex(digest)) throw `InvalidParameterException: vote-digest ${digest} must be in hexadecimal` dirSource['vote-digest'] = digest - lnn.consensusParser.consensus['dir-sources'].push(dirSource) - lnn.consensusParser.nextLine() + consensusParser.consensus['dir-sources'].push(dirSource) + consensusParser.nextLine() } @@ -273,30 +278,30 @@ lnn.consensusParser.consumeDirSource = function() { * Consume each router status entry * @throws WrongFieldException if there is no router entry */ -lnn.consensusParser.consumeRouters = function() { - if (lnn.consensusParser.words[0] !== 'r') throw `WrongFieldException: there must be at least one router` - lnn.consensusParser.consensus['routers'] = [] +consensusParser.consumeRouters = function () { + if (consensusParser.words[0] !== 'r') throw `WrongFieldException: there must be at least one router` + consensusParser.consensus['routers'] = [] - while (lnn.consensusParser.words[0] === 'r') { + while (consensusParser.words[0] === 'r') { let router = {} - lnn.consensusParser.consumeRfield(router) + consensusParser.consumeRfield(router) - if (lnn.consensusParser.words[0] === 'a') router['a'] = [] - while (lnn.consensusParser.words[0] === 'a') { - lnn.consensusParser.consumeAfield(router) + if (consensusParser.words[0] === 'a') router['a'] = [] + while (consensusParser.words[0] === 'a') { + consensusParser.consumeAfield(router) } - if(lnn.consensusParser.consensus.flavor == 'microdesc') { - lnn.consensusParser.consumeMfield(router) + if (consensusParser.consensus.flavor == 'microdesc') { + consensusParser.consumeMfield(router) } - lnn.consensusParser.consumeSfield(router) - lnn.consensusParser.tryConsumeVfield(router) - lnn.consensusParser.tryConsumePrField(router) - lnn.consensusParser.tryConsumeWfield(router) - lnn.consensusParser.tryConsumePfield(router) + consensusParser.consumeSfield(router) + consensusParser.tryConsumeVfield(router) + consensusParser.tryConsumePrField(router) + consensusParser.tryConsumeWfield(router) + consensusParser.tryConsumePfield(router) - lnn.consensusParser.consensus['routers'].push(router) + consensusParser.consensus['routers'].push(router) } } @@ -306,39 +311,39 @@ lnn.consensusParser.consumeRouters = function() { * @param {} router * @throws InvalidParameterException if the fields are not valid */ -lnn.consensusParser.consumeRfield = function(router) { +consensusParser.consumeRfield = function (router) { let len = 9 - if(lnn.consensusParser.consensus.flavor == 'microdesc') len = 8 - lnn.consensusParser.checkFormat(len, 'r') + if (consensusParser.consensus.flavor == 'microdesc') len = 8 + consensusParser.checkFormat(len, 'r') - router['nickname'] = lnn.consensusParser.words[1] + router['nickname'] = consensusParser.words[1] + + if (!consensusParser.isBase64(consensusParser.words[2] + "=")) throw `InvalidParameterException: identity ${consensusParser.words[2]} must be in base64` + router['identity'] = consensusParser.words[2] - if (!lnn.consensusParser.isBase64(lnn.consensusParser.words[2] + "=")) throw `InvalidParameterException: identity ${lnn.consensusParser.words[2]} must be in base64` - router['identity'] = lnn.consensusParser.words[2] - let nxt = 3 - if(lnn.consensusParser.consensus.flavor == 'unflavored') { - if (!lnn.consensusParser.isBase64(lnn.consensusParser.words[3] + "=")) throw `InvalidParameterException: digest ${lnn.consensusParser.words[3]} must be in base64` - router['digest'] = lnn.consensusParser.words[3] + if (consensusParser.consensus.flavor == 'unflavored') { + if (!consensusParser.isBase64(consensusParser.words[3] + "=")) throw `InvalidParameterException: digest ${consensusParser.words[3]} must be in base64` + router['digest'] = consensusParser.words[3] nxt += 1 } - if (!lnn.consensusParser.isValidDate(lnn.consensusParser.words[nxt])) throw `InvalidParameterException: date ${lnn.consensusParser.words[nxt]} must have the format YYYY-MM-DD` - router['date'] = lnn.consensusParser.words[nxt] + if (!consensusParser.isValidDate(consensusParser.words[nxt])) throw `InvalidParameterException: date ${consensusParser.words[nxt]} must have the format YYYY-MM-DD` + router['date'] = consensusParser.words[nxt] - if (!lnn.consensusParser.isValidTime(lnn.consensusParser.words[nxt + 1])) throw `InvalidParameterException: time ${lnn.consensusParser.words[nxt + 1]} must have the format HH:MM:SS` - router['time'] = lnn.consensusParser.words[nxt + 1] + if (!consensusParser.isValidTime(consensusParser.words[nxt + 1])) throw `InvalidParameterException: time ${consensusParser.words[nxt + 1]} must have the format HH:MM:SS` + router['time'] = consensusParser.words[nxt + 1] - if (!lnn.consensusParser.isValidIP(lnn.consensusParser.words[nxt + 2])) throw `InvalidParameterException: IP ${lnn.consensusParser.words[nxt + 2]} must be a valid IP address` - router['address'] = lnn.consensusParser.words[nxt + 2] + if (!consensusParser.isValidIP(consensusParser.words[nxt + 2])) throw `InvalidParameterException: IP ${consensusParser.words[nxt + 2]} must be a valid IP address` + router['address'] = consensusParser.words[nxt + 2] - if (!lnn.consensusParser.isValidPort(Number(lnn.consensusParser.words[nxt + 3]))) throw `InvalidParameterException: ORPort ${lnn.consensusParser.words[nxt + 3]} must be a valid port` - router['orport'] = Number(lnn.consensusParser.words[nxt + 3]) + if (!consensusParser.isValidPort(Number(consensusParser.words[nxt + 3]))) throw `InvalidParameterException: ORPort ${consensusParser.words[nxt + 3]} must be a valid port` + router['orport'] = Number(consensusParser.words[nxt + 3]) - if (!lnn.consensusParser.isValidPort(Number(lnn.consensusParser.words[nxt + 4]))) throw `InvalidParameterException: DirPort ${lnn.consensusParser.words[nxt + 4]} must be a valid port` - router['dirport'] = Number(lnn.consensusParser.words[nxt + 4]) + if (!consensusParser.isValidPort(Number(consensusParser.words[nxt + 4]))) throw `InvalidParameterException: DirPort ${consensusParser.words[nxt + 4]} must be a valid port` + router['dirport'] = Number(consensusParser.words[nxt + 4]) - lnn.consensusParser.nextLine() + consensusParser.nextLine() } /** @@ -346,19 +351,19 @@ lnn.consensusParser.consumeRfield = function(router) { * @param {} router * @throws InvalidParameterException if the fields are not valid */ -lnn.consensusParser.consumeAfield = function(router) { - let i = lnn.consensusParser.words[1].indexOf("]") - let address = lnn.consensusParser.words[1].slice(1, i) - if (!lnn.consensusParser.isValidIP(address)) throw `InvalidParameterException: IP ${address} must be a valid IP address` +consensusParser.consumeAfield = function (router) { + let i = consensusParser.words[1].indexOf("]") + let address = consensusParser.words[1].slice(1, i) + if (!consensusParser.isValidIP(address)) throw `InvalidParameterException: IP ${address} must be a valid IP address` let guessedType = 'IPv6' - if (lnn.consensusParser.isIPv4(address)) { + if (consensusParser.isIPv4(address)) { guessedType = 'IPv4' } - let port = Number(lnn.consensusParser.words[1].slice(address.length + 3, lnn.consensusParser.words[1].length)) + let port = Number(consensusParser.words[1].slice(address.length + 3, consensusParser.words[1].length)) - if (!lnn.consensusParser.isValidPort(port)) throw `InvalidParameterException: port ${port} must be a valid port` + if (!consensusParser.isValidPort(port)) throw `InvalidParameterException: port ${port} must be a valid port` router['a'].push({ 'ip': address, @@ -366,7 +371,7 @@ lnn.consensusParser.consumeAfield = function(router) { 'type': guessedType }) - lnn.consensusParser.nextLine() + consensusParser.nextLine() } @@ -374,59 +379,59 @@ lnn.consensusParser.consumeAfield = function(router) { * Parses the field 's' of the router status entry * @param {} router */ -lnn.consensusParser.consumeSfield = function(router) { - router['flags'] = lnn.consensusParser.tryParseFlags() - lnn.consensusParser.nextLine() +consensusParser.consumeSfield = function (router) { + router['flags'] = consensusParser.tryParseFlags() + consensusParser.nextLine() } /** * Tries to parse the field 'v' of the router status entry * @param {} router */ -lnn.consensusParser.tryConsumeVfield = function(router) { - if (lnn.consensusParser.words[0] === 'v') { - lnn.consensusParser.checkFormat(3, 'v') - router['version'] = lnn.consensusParser.words.splice(1, lnn.consensusParser.words.length).join(' ') - lnn.consensusParser.nextLine() +consensusParser.tryConsumeVfield = function (router) { + if (consensusParser.words[0] === 'v') { + consensusParser.checkFormat(3, 'v') + router['version'] = consensusParser.words.splice(1, consensusParser.words.length).join(' ') + consensusParser.nextLine() } } /** * Tries to parse the field 'v' of the router status entry * @param {} router */ -lnn.consensusParser.tryConsumePrField = function(router) { - if (lnn.consensusParser.words[0] === 'pr') { - router['protocols'] = lnn.consensusParser.tryParseRanges(lnn.consensusParser.words.splice(1, lnn.consensusParser.words.length)) - lnn.consensusParser.nextLine() +consensusParser.tryConsumePrField = function (router) { + if (consensusParser.words[0] === 'pr') { + router['protocols'] = consensusParser.tryParseRanges(consensusParser.words.splice(1, consensusParser.words.length)) + consensusParser.nextLine() } } /** * Tries to parse the field 'w' of the router status entry * @param {} router */ -lnn.consensusParser.tryConsumeWfield = function(router) { - if (lnn.consensusParser.words[0] === 'w') { - router['w'] = lnn.consensusParser.tryParseParams() - lnn.consensusParser.nextLine() +consensusParser.tryConsumeWfield = function (router) { + if (consensusParser.words[0] === 'w') { + router['w'] = consensusParser.tryParseParams() + consensusParser.nextLine() } } /** * Tries to parse the field 'p' of the router status entry * @param {} router */ -lnn.consensusParser.tryConsumePfield = function(router) { - if (lnn.consensusParser.words[0] === 'p') { - lnn.consensusParser.checkFormat(3, 'p') - if (lnn.consensusParser.words[1] !== 'accept' && lnn.consensusParser.words[1] !== 'reject') throw `WrongParameterException: ${lnn.consensusParser.words[1]} must be either accept or reject` +consensusParser.tryConsumePfield = function (router) { + if (consensusParser.words[0] === 'p') { + consensusParser.checkFormat(3, 'p') + if (consensusParser.words[1] !== 'accept' && consensusParser.words[1] !== 'reject') throw `WrongParameterException: ${consensusParser.words[1]} must be either accept or reject` - let portList = lnn.consensusParser.parse_range_once(lnn.consensusParser.words[2]) + let portList = consensusParser.parse_range_once(consensusParser.words[2]) router['exit-policy'] = { - 'type': lnn.consensusParser.words[1], + 'type': consensusParser.words[1], 'PortList': portList } - lnn.consensusParser.nextLine() + consensusParser.nextLine() } } @@ -434,13 +439,13 @@ lnn.consensusParser.tryConsumePfield = function(router) { * Parses the field 'm' of the router status entry (for microdesc flavor) * @param {} router */ -lnn.consensusParser.consumeMfield = function(router) { - lnn.consensusParser.checkFormat(2, 'm') - - if (!lnn.consensusParser.isBase64(lnn.consensusParser.words[1] + "=")) throw `InvalidParameterException: digest ${lnn.consensusParser.words[1]} must be in base64` - router['micro-digest'] = lnn.consensusParser.words[1] - - lnn.consensusParser.nextLine() +consensusParser.consumeMfield = function (router) { + consensusParser.checkFormat(2, 'm') + + if (!consensusParser.isBase64(consensusParser.words[1] + "=")) throw `InvalidParameterException: digest ${consensusParser.words[1]} must be in base64` + router['micro-digest'] = consensusParser.words[1] + + consensusParser.nextLine() } @@ -450,17 +455,17 @@ lnn.consensusParser.consumeMfield = function(router) { * Consume the footer * @throws WrongFieldException if there is no footer or no signature */ -lnn.consensusParser.consumeFooter = function() { - if (lnn.consensusParser.words[0] !== 'directory-footer') throw `WrongFieldException: there must be a footer` - lnn.consensusParser.nextLine() - lnn.consensusParser.consensus['footer'] = {} - lnn.consensusParser.tryConsumeBandwidthWeights() +consensusParser.consumeFooter = function () { + if (consensusParser.words[0] !== 'directory-footer') throw `WrongFieldException: there must be a footer` + consensusParser.nextLine() + consensusParser.consensus['footer'] = {} + consensusParser.tryConsumeBandwidthWeights() - if (lnn.consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: there must be at least one signature` - lnn.consensusParser.consensus['footer']['directory-signatures'] = [] + if (consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: there must be at least one signature` + consensusParser.consensus['footer']['directory-signatures'] = [] - while (lnn.consensusParser.words[0] === 'directory-signature') { - lnn.consensusParser.consensus['footer']['directory-signatures'].push(lnn.consensusParser.consumeSignature()); + while (consensusParser.words[0] === 'directory-signature') { + consensusParser.consensus['footer']['directory-signatures'].push(consensusParser.consumeSignature()); } } @@ -468,10 +473,10 @@ lnn.consensusParser.consumeFooter = function() { /** * Tries to consume the bandwidth weights */ -lnn.consensusParser.tryConsumeBandwidthWeights = function() { - if (lnn.consensusParser.words[0] === 'bandwidth-weights') { - lnn.consensusParser.consensus['footer']['bandwidth-weights'] = lnn.consensusParser.tryParseParams() - lnn.consensusParser.nextLine() +consensusParser.tryConsumeBandwidthWeights = function () { + if (consensusParser.words[0] === 'bandwidth-weights') { + consensusParser.consensus['footer']['bandwidth-weights'] = consensusParser.tryParseParams() + consensusParser.nextLine() } } @@ -480,31 +485,31 @@ lnn.consensusParser.tryConsumeBandwidthWeights = function() { * @throws WrongFieldException if the first field is not directory-signature * @throws InvalidParameterException if either the identity or the signing-key-digest are not in hexadecimal */ -lnn.consensusParser.consumeSignature = function() { - if (lnn.consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: next field must be directory-signature` - let length = lnn.consensusParser.words.length +consensusParser.consumeSignature = function () { + if (consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: next field must be directory-signature` + let length = consensusParser.words.length let algo let remaining if (length === 4) { - algo = lnn.consensusParser.words[1] - remaining = lnn.consensusParser.words.splice(2, length) + algo = consensusParser.words[1] + remaining = consensusParser.words.splice(2, length) } else if (length === 3) { algo = 'sha1' - remaining = lnn.consensusParser.words.splice(1, length) + remaining = consensusParser.words.splice(1, length) } else throw `WrongParameterException: directory-signature has 3 or 4 arguments` let identity = remaining[0] - if (!lnn.consensusParser.isHex(identity)) throw `InvalidParameterException: the identity ${identity} must be in hexadecimal` + if (!consensusParser.isHex(identity)) throw `InvalidParameterException: the identity ${identity} must be in hexadecimal` let digest = remaining[1] - if (!lnn.consensusParser.isHex(digest)) throw `InvalidParameterException: the signing-key-digest ${digest} must be in hexadecimal` + if (!consensusParser.isHex(digest)) throw `InvalidParameterException: the signing-key-digest ${digest} must be in hexadecimal` - lnn.consensusParser.nextLine() + consensusParser.nextLine() - let signature = lnn.consensusParser.parseSignature() - if (lnn.consensusParser.index < lnn.consensusParser.totalLines - 1) lnn.consensusParser.nextLine() + let signature = consensusParser.parseSignature() + if (consensusParser.index < consensusParser.totalLines - 1) consensusParser.nextLine() return { 'Algorithm': algo, @@ -518,69 +523,69 @@ lnn.consensusParser.consumeSignature = function() { /** * Parses lines with the format "field value" where value is an integer and field must be equal to word and return value. * @param {string} word indicates to which field we are adding the newly parsed line -* @throws NotEqualException if lnn.consensusParser.words[0] != word -* @throws WrongParameterException if lnn.consensusParser.words[1] is not a number -* @throws WrongFormatException if lnn.consensusParser.words.length is not 2 +* @throws NotEqualException if consensusParser.words[0] != word +* @throws WrongParameterException if consensusParser.words[1] is not a number +* @throws WrongFormatException if consensusParser.words.length is not 2 */ -lnn.consensusParser.tryParseKeyValueInteger = function(word,expectedLength = 2) { - lnn.consensusParser.checkFormat(expectedLength, word) - if (isNaN(lnn.consensusParser.words[1])) throw `WrongParameterException: ${lnn.consensusParser.words[1]} is not a number` +consensusParser.tryParseKeyValueInteger = function (word, expectedLength = 2) { + consensusParser.checkFormat(expectedLength, word) + if (isNaN(consensusParser.words[1])) throw `WrongParameterException: ${consensusParser.words[1]} is not a number` - return Math.floor(lnn.consensusParser.words[1]) + return Math.floor(consensusParser.words[1]) } /** * Parses lines with the format "field value" where value is a string and field must be equal to word and return value. * @param {string} word indicates to which field we are adding the newly parsed line - * @throws NotEqualException if lnn.consensusParser.words[0] != word - * @throws WrongFormatException if lnn.consensusParser.words.length is not 2 + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongFormatException if consensusParser.words.length is not 2 */ -lnn.consensusParser.tryParseKeyValueString = function(word) { - lnn.consensusParser.checkFormat(2, word) - return lnn.consensusParser.words[1] +consensusParser.tryParseKeyValueString = function (word) { + consensusParser.checkFormat(2, word) + return consensusParser.words[1] } /** * Parses lines with the format "field YYYY-MM-DD HH:MM:SS" where field must be equal to word and return a date object * @param {string} word indicates to which field we are adding the newly parsed line - * @throws NotEqualException if lnn.consensusParser.words[0] != word - * @throws WrongFormatException if lnn.consensusParser.words.length is not 2 + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongFormatException if consensusParser.words.length is not 2 * @throws NonValidDateException if the date is not valid * @throws NonValidTimeException if the time is not valid */ -lnn.consensusParser.tryParseDate = function(word) { - lnn.consensusParser.checkFormat(3, word) - if (!lnn.consensusParser.isValidDate(lnn.consensusParser.words[1])) throw `NonValidDateException: ${lnn.consensusParser.words[1]} is not a valid date` - if (!lnn.consensusParser.isValidTime(lnn.consensusParser.words[2])) throw `NonValidTimeException: ${lnn.consensusParser.words[2]} is not a valid time` +consensusParser.tryParseDate = function (word) { + consensusParser.checkFormat(3, word) + if (!consensusParser.isValidDate(consensusParser.words[1])) throw `NonValidDateException: ${consensusParser.words[1]} is not a valid date` + if (!consensusParser.isValidTime(consensusParser.words[2])) throw `NonValidTimeException: ${consensusParser.words[2]} is not a valid time` return { - "date": lnn.consensusParser.words[1], - "time": lnn.consensusParser.words[2] + "date": consensusParser.words[1], + "time": consensusParser.words[2] } } /** * Parses lines with the format "field list" where list is a comma separated list, returns the list as an array * @param {string} word indicates to which field we are adding the newly parsed line - * @throws NotEqualException if lnn.consensusParser.words[0] != word - * @throws WrongFormatException if lnn.consensusParser.words.length is not 2 + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongFormatException if consensusParser.words.length is not 2 */ -lnn.consensusParser.tryParseCommaSeparatedList = function(word) { - lnn.consensusParser.checkFormat(2, word) - return lnn.consensusParser.words[1].split(",") +consensusParser.tryParseCommaSeparatedList = function (word) { + consensusParser.checkFormat(2, word) + return consensusParser.words[1].split(",") } /** * Parse the ranges of the protocols * @param pairs Array of entries => Keyword=Values where values is the range */ -lnn.consensusParser.tryParseRanges = function(pairs) { +consensusParser.tryParseRanges = function (pairs) { let content = {} for (let pair of pairs) { if (pair.includes("=")) { let tmp = pair.split("=") - content[tmp[0]] = lnn.consensusParser.parse_range_once(tmp[1]) + content[tmp[0]] = consensusParser.parse_range_once(tmp[1]) } } @@ -591,7 +596,7 @@ lnn.consensusParser.tryParseRanges = function(pairs) { * Helper function to parse the ranges of the protocols * @param value the range we want to parse */ -lnn.consensusParser.parse_range_once = function(value) { +consensusParser.parse_range_once = function (value) { value = value.split(',') let subvalues = [] @@ -616,11 +621,11 @@ lnn.consensusParser.parse_range_once = function(value) { * Parse the flags * @throws NotValidFlagException if one of the flags is not valid */ -lnn.consensusParser.tryParseFlags = function() { - let flags = lnn.consensusParser.words.splice(1, lnn.consensusParser.words.length) - +consensusParser.tryParseFlags = function () { + let flags = consensusParser.words.splice(1, consensusParser.words.length) + for (let f of flags) { - if (!lnn.consensusParser.validFlags.includes(f)) throw `NotValidFlagException: ${f} is not a valid flag` + if (!consensusParser.validFlags.includes(f)) throw `NotValidFlagException: ${f} is not a valid flag` } return flags @@ -630,13 +635,13 @@ lnn.consensusParser.tryParseFlags = function() { * Parse signature * @throws WrongFormatException if the line does not start with ----BEGIN */ -lnn.consensusParser.parseSignature = function() { - if (lnn.consensusParser.words[0] !== '-----BEGIN') throw `WrongFormatException` - lnn.consensusParser.nextLine() +consensusParser.parseSignature = function () { + if (consensusParser.words[0] !== '-----BEGIN') throw `WrongFormatException` + consensusParser.nextLine() let signature = '' - while (lnn.consensusParser.lines[lnn.consensusParser.index] !== "-----END SIGNATURE-----") { - signature += lnn.consensusParser.lines[lnn.consensusParser.index] - lnn.consensusParser.nextLine() + while (consensusParser.lines[consensusParser.index] !== "-----END SIGNATURE-----") { + signature += consensusParser.lines[consensusParser.index] + consensusParser.nextLine() } return signature } @@ -645,9 +650,9 @@ lnn.consensusParser.parseSignature = function() { /** * parase parameters */ -lnn.consensusParser.tryParseParams = function() { +consensusParser.tryParseParams = function () { let content = {} - for (let param of lnn.consensusParser.words.splice(1, lnn.consensusParser.words.length)) { + for (let param of consensusParser.words.splice(1, consensusParser.words.length)) { let tmp = param.split('=') content[tmp[0]] = Number(tmp[1]) } @@ -658,7 +663,7 @@ lnn.consensusParser.tryParseParams = function() { * Check if the string in date has the format YYYY-MM-DD * @param {string} time String representing the date */ -lnn.consensusParser.isValidDate = function(date) { +consensusParser.isValidDate = function (date) { if (typeof date !== 'string') return false let regex = /^\d{4}[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$/ return regex.test(date) @@ -667,7 +672,7 @@ lnn.consensusParser.isValidDate = function(date) { /**Check if the string time has the format HH:MM:SS * @param {string} time String representing the time */ -lnn.consensusParser.isValidTime = function(time) { +consensusParser.isValidTime = function (time) { if (typeof time !== 'string') return false let regex = /^(0[0-9]|1[0-9]|2[0-3])[:][0-5][0-9][:][0-5][0-9]$/ return regex.test(time) @@ -677,7 +682,7 @@ lnn.consensusParser.isValidTime = function(time) { * Check if the IP address is valid (either IPv4 or IPv6) * @param {string} IP the address we want to check */ -lnn.consensusParser.isValidIP = function(IP) { +consensusParser.isValidIP = function (IP) { let regex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/ return regex.test(IP) } @@ -686,7 +691,7 @@ lnn.consensusParser.isValidIP = function(IP) { * Check if the IP is an IPv4 address * @param {string} IP */ -lnn.consensusParser.isIPv4 = function(IP) { +consensusParser.isIPv4 = function (IP) { let regex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ return regex.test(IP) } @@ -695,7 +700,7 @@ lnn.consensusParser.isIPv4 = function(IP) { * Check if the given port is valid * @param {number} port */ -lnn.consensusParser.isValidPort = function(port) { +consensusParser.isValidPort = function (port) { if (isNaN(port)) return false //TODO: < or <= ? return port >= 0 && port <= 65535 @@ -705,7 +710,7 @@ lnn.consensusParser.isValidPort = function(port) { * Check if the given string is in hexadecimal * @param {string} str */ -lnn.consensusParser.isHex = function(str) { +consensusParser.isHex = function (str) { let regex = /^[a-fA-F0-9]+$/ return regex.test(str) } @@ -714,18 +719,18 @@ lnn.consensusParser.isHex = function(str) { * Check if the given string is in base 64 * @param {string} str */ -lnn.consensusParser.isBase64 = function(str) { +consensusParser.isBase64 = function (str) { let regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/ return regex.test(str) } /** - * Updates lnn.consensusParser.index and lnn.consensusParser.words + * Updates consensusParser.index and consensusParser.words * @throws EndOfFileException if the end of the file has already been reached */ -lnn.consensusParser.nextLine = function() { - if (lnn.consensusParser.index >= lnn.consensusParser.totalLines) throw `EndOfFileException: there are no lines to parse` - lnn.consensusParser.words = lnn.consensusParser.lines[++lnn.consensusParser.index].split(" ") +consensusParser.nextLine = function () { + if (consensusParser.index >= consensusParser.totalLines) throw `EndOfFileException: there are no lines to parse` + consensusParser.words = consensusParser.lines[++consensusParser.index].split(" ") } /** @@ -733,8 +738,9 @@ lnn.consensusParser.nextLine = function() { * @param {number} expectedLength the expected length of words * @param {string} expectedWord the expected word[0] */ -lnn.consensusParser.checkFormat = function(expectedLength, expectedWord) { - if (lnn.consensusParser.words.length != expectedLength) throw `WrongFormatException: ${expectedLength} fields are expected` - if (lnn.consensusParser.words[0] != expectedWord) throw `NotEqualException:b ${expectedWord} is not equal to ${lnn.consensusParser.words[0]}` +consensusParser.checkFormat = function (expectedLength, expectedWord) { + if (consensusParser.words.length != expectedLength) throw `WrongFormatException: ${expectedLength} fields are expected` + if (consensusParser.words[0] != expectedWord) throw `NotEqualException:b ${expectedWord} is not equal to ${consensusParser.words[0]}` } +export { consensusParser }; \ No newline at end of file diff --git a/js-client/src/endpoint.js b/js-client/src/endpoint.js index 8b33316..0c6ded0 100644 --- a/js-client/src/endpoint.js +++ b/js-client/src/endpoint.js @@ -1,3 +1,12 @@ +/** + * @module endpoint + */ + +import { lnn } from "./header.js"; +import * as api from "./api.js"; +import * as post from "./post.js"; + + /** * Create an empty endpoint object, consider using {@link lnn.open} first. * @@ -8,8 +17,7 @@ * @param {string} port (ex: 4990, 8080, 5000, 443…) * @return {endpoint_t} */ -lnn.endpoint = function(host, port) -{ +export function endpoint(host, port) { var http = "http://" + host + ":" + port.toString() http += lnn.api.url @@ -153,7 +161,7 @@ lnn.endpoint = function(host, port) * @default null */ consensus: null, - + /** * Consensus obtained by {@link lnn.get.descriptors} upon request * @name endpoint_t#descriptors @@ -168,21 +176,19 @@ lnn.endpoint = function(host, port) select_path: false, /*perform http get/post request*/ - - http_request: function(url, method, data, data_type, success, error) - { + + http_request: function (url, method, data, data_type, success, error) { if (error === undefined) - error = function() { } + error = function () { } if (success === undefined) - success = function() { } + success = function () { } - lnn.send_req(endpoint,url, method, data, data_type, success,error) + api.send_req(endpoint, url, method, data, data_type, success, error) }, /*destroy the circuit*/ - close: function(success,error) - { - lnn.post.close(endpoint,success,error) + close: function (success, error) { + post.close(endpoint, success, error) } } diff --git a/js-client/src/get.js b/js-client/src/get.js index aae7b66..cf6a3bf 100644 --- a/js-client/src/get.js +++ b/js-client/src/get.js @@ -1,39 +1,35 @@ /** * GET operations. + * @module get * @namespace * @see lnn.get.guard */ -lnn.get = {} /** - * Perform GET /guard and update endpoint accordingly, - * see {@link endpoint_t#guard}. - * - * @param {endpoint_t} endpoint endpoint in use, stores answer - * @param {callback} success optional, called on success - * @param {callback} error optional, called on error - * @example - * // Note: lnn.open perform these steps for you whenever needed. - * endpoint = lnn.endpoint('localhost', 4990) - * lnn.get.guard(endpoint, function (endpoint) - * { - * console.log('Guard identity:', endpoint.guard.router.identity) - * }) - * // (can also have error callback: function (endpoint, xhttp_status) { }) - */ -lnn.get.guard = function(endpoint, success, error) -{ +* Perform GET /guard and update endpoint accordingly, +* see {@link endpoint_t#guard}. +* +* @param {endpoint_t} endpoint endpoint in use, stores answer +* @param {callback} success optional, called on success +* @param {callback} error optional, called on error +* @example +* // Note: lnn.open perform these steps for you whenever needed. +* endpoint = lnn.endpoint('localhost', 4990) +* lnn.get.guard(endpoint, function (endpoint) +* { +* console.log('Guard identity:', endpoint.guard.router.identity) +* }) +* // (can also have error callback: function (endpoint, xhttp_status) { }) +*/ +export function guard(endpoint, success, error) { var rq = new XMLHttpRequest() - rq.onreadystatechange = function() - { - if (rq.readyState == 4 && rq.status == 200) - { + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { endpoint.guard = JSON.parse(rq.responseText) if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4 && error !== undefined) - { + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } @@ -58,19 +54,15 @@ lnn.get.guard = function(endpoint, success, error) * * @see lnn.get.guard */ -lnn.get.consensus = function(endpoint, success, error) -{ +export function consensus(endpoint, success, error) { var rq = new XMLHttpRequest() - rq.onreadystatechange = function() - { - if (rq.readyState == 4 && rq.status == 200) - { + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { endpoint.consensus = JSON.parse(rq.responseText) if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4 && error !== undefined) - { + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } @@ -81,15 +73,15 @@ lnn.get.consensus = function(endpoint, success, error) /** * Perform GET /descriptors */ -lnn.get.descriptors = function(endpoint, success, error){ +export function descriptors(endpoint, success, error) { var rq = new XMLHttpRequest() - rq.onreadystatechange = function(){ - if(rq.readyState == 4 && rq.status == 200){ + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { endpoint.descriptors = JSON.parse(rq.responseText) - - if(success !== undefined) success(endpoint) + + if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4 && error !== undefined){ + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } @@ -98,55 +90,51 @@ lnn.get.descriptors = function(endpoint, success, error){ rq.send() } -lnn.get.consensus_raw = function(endpoint, success, error,flavor = 'microdesc') -{ +export function consensus_raw(endpoint, success, error, flavor = 'microdesc') { var rq = new XMLHttpRequest() - rq.onreadystatechange = function() - { - if (rq.readyState == 4 && rq.status == 200) - { - endpoint.consensus_raw = rq.responseText + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { + endpoint.consensus_raw = rq.responseText if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4 && error !== undefined) - { + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } - rq.open("GET", endpoint.urls.consensus+ "-raw/" + flavor, true) + rq.open("GET", endpoint.urls.consensus + "-raw/" + flavor, true) rq.send() } /** * Perform GET /descriptors */ -lnn.get.descriptors_raw = function(endpoint, success, error,flavor = 'microdesc'){ +export function descriptors_raw(endpoint, success, error, flavor = 'microdesc') { var rq = new XMLHttpRequest() - rq.onreadystatechange = function(){ - if(rq.readyState == 4 && rq.status == 200){ + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { endpoint.descriptors_raw = rq.responseText - - if(success !== undefined) success(endpoint) + + if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4 && error !== undefined){ + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } - rq.open("GET", endpoint.urls.descriptors+ "-raw/" + flavor, true) + rq.open("GET", endpoint.urls.descriptors + "-raw/" + flavor, true) rq.send() } -lnn.get.signing_keys = function(endpoint, success, error){ +export function signing_keys(endpoint, success, error) { var rq = new XMLHttpRequest() - rq.onreadystatechange = function(){ - if(rq.readyState == 4 && rq.status == 200){ + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { endpoint.signing_keys = JSON.parse(rq.responseText) - - if(success !== undefined) success(endpoint) + + if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4 && error !== undefined){ + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } diff --git a/js-client/src/header.js b/js-client/src/header.js index d797a49..2cf79af 100644 --- a/js-client/src/header.js +++ b/js-client/src/header.js @@ -1,3 +1,8 @@ +/** + * @module header + * The Lightnion Javascript client, top-level namespace. + */ + "use strict" /** @@ -31,7 +36,7 @@ * } * */ -var lnn = {} +let lnn = {} /** * Common API constants. @@ -64,53 +69,55 @@ lnn.api.ws_port = "8765" * @readonly **/ lnn.state = { - /** - * operation started - * @type channel - */ - started: 1, - /** - * /guard get success (channel only) - * @type channel - */ - guarded: 2, - /** - * circuit created - * @type channel - */ - created: 3, - /** - * circuit negotiation - * @type channel - */ - pending: 4, - /** circuit extended (channel only) - * @type channel - */ - extpath: 5, - /** - * ready to use - * @type channel - */ - success: 6, - /** - * operation started - * @type stream - */ - started: 1, - /** - * ready to use - * @type stream - */ - created: 3, - /** - * incoming data - * @type stream - */ - pending: 4, - /** - * completed or closed - * @type stream - */ - success: 6 - } + /** + * operation started + * @type channel + */ + started: 1, + /** + * /guard get success (channel only) + * @type channel + */ + guarded: 2, + /** + * circuit created + * @type channel + */ + created: 3, + /** + * circuit negotiation + * @type channel + */ + pending: 4, + /** circuit extended (channel only) + * @type channel + */ + extpath: 5, + /** + * ready to use + * @type channel + */ + success: 6, + /** + * operation started + * @type stream + */ + started: 1, + /** + * ready to use + * @type stream + */ + created: 3, + /** + * incoming data + * @type stream + */ + pending: 4, + /** + * completed or closed + * @type stream + */ + success: 6 +} + +export { lnn } \ No newline at end of file diff --git a/js-client/src/io.js b/js-client/src/io.js index 861fb43..da82ade 100644 --- a/js-client/src/io.js +++ b/js-client/src/io.js @@ -1,50 +1,56 @@ -lnn.io = {} -lnn.io.polling = function(endpoint, handler, success, error) -{ - var io = { - incoming: [], - outcoming: [], - pending: 0, - handler: handler, - success: success, - error: error, - cell: null, - poll: function() - { - setTimeout(function() - { - lnn.post.channel(endpoint, io.poll) - }, 100) - }, - send: function(cell) - { - io.outcoming.push(lnn.enc.base64(cell)) - }, - recv: function() - { - if (io.incoming.length < 1) - return undefined +/** + * @module io + */ - io.cell = io.incoming.shift() - return lnn.dec.base64(io.cell) - }, - start: function() - { - lnn.post.channel(endpoint, io.poll) - } +import * as post from "./post.js"; +import { enc, dec } from "./util.js"; + +export const polling = (endpoint, handler, success, error) => new Polling(endpoint, handler, success, error); + +class Polling { + constructor(endpoint, handler, success, error) { + this.incoming = []; + this.outcoming = []; + this.pending = 0; + this.handler = handler; + this.success = success; + this.error = error; + this.cell = null; + + this.endpoint = endpoint; + + endpoint.io = this; + } + + poll() { + setTimeout(function () { + post.channel(this.endpoint, this.poll); + }, 100); + } + + send(cell) { + this.outcoming.push(enc.base64(cell)); + } + + recv() { + if (this.incoming.length < 1) { return undefined; } + + this.cell = this.incoming.shift(); + return dec.base64(this.cell); + } + + start() { + post.channel(this.endpoint, this.poll); } - endpoint.io = io - return io } -lnn.io.socket = function(endpoint, handler, success, error) -{ +export function socket(endpoint, handler, success, error) { if (handler === undefined) - handler = function(endpoint) { } + handler = function (endpoint) { } if (success === undefined) - success = function(endpoint) { } + success = function (endpoint) { } if (error === undefined) - error = function(endpoint) { } + error = function (endpoint) { } var io = { event: null, @@ -56,44 +62,40 @@ lnn.io.socket = function(endpoint, handler, success, error) success: success, error: error, cell: null, - cell_recv: 0, - //cell_sent: 0, - send: function(cell) - { + cell_recv: 0, + //cell_sent: 0, + send: function (cell) { io.outcoming.push(cell) //io.cell_sent += 1 //var cell_repr = Array.from(cell.slice(0,20)).map(function(x) {return x.toString(16).padStart(2, '0')}).join('') //console.log("cell ", io.cell_sent.toString(), " sent to wbskt ", cell_repr) }, - recv: function() - { + recv: function () { if (io.incoming.length < 1) return undefined io.cell = io.incoming.shift() io.cell_recv += 1 - var cell_repr = Array.from(io.cell.slice(0,20)).map(function(x) {return x.toString(16).padStart(2, '0')}).join('') + var cell_repr = Array.from(io.cell.slice(0, 20)).map(function (x) { return x.toString(16).padStart(2, '0') }).join('') console.log("cell recv by wbskt ", cell_repr) return io.cell }, - start: function() { } + start: function () { } } var socket = new WebSocket(endpoint.urls.socket + "/" + endpoint.id) socket.binaryType = "arraybuffer" - socket.onopen = function(event) - { + socket.onopen = function (event) { io.event = event io.success(endpoint) while (io.outcoming.length > 0) io.socket.send(io.outcoming.shift()) - io.send = function(cell) - { + io.send = function (cell) { if (io.closed) throw "Unable to send, connection closed." io.socket.send(cell.buffer) @@ -103,26 +105,23 @@ lnn.io.socket = function(endpoint, handler, success, error) //console.log("cell ", io.cell_sent.toString(), " sent to wbskt ", cell_repr) } } - socket.onerror = function(event) - { + socket.onerror = function (event) { io.event = event io.error(endpoint) } - socket.onmessage = function(event) - { + socket.onmessage = function (event) { io.event = event - var data = new Uint8Array(event.data) + var data = new Uint8Array(event.data) - var cell_repr = Array.from(data.slice(0,20)).map(function(x) {return x.toString(16).padStart(2, '0')}).join('') - console.log("cell recv by wbskt ", cell_repr) + var cell_repr = Array.from(data.slice(0, 20)).map(function (x) { return x.toString(16).padStart(2, '0') }).join('') + console.log("cell recv by wbskt ", cell_repr) // io.incoming.push(data) - io.cell = data + io.cell = data io.handler(endpoint, data) } - socket.onclose = function(event) - { + socket.onclose = function (event) { io.event = event io.closed = true io.error(endpoint) diff --git a/js-client/src/lnn.js b/js-client/src/lnn.js new file mode 100644 index 0000000..4f4711b --- /dev/null +++ b/js-client/src/lnn.js @@ -0,0 +1,119 @@ +/** + * @module lnn + */ + +import { isNode } from 'browser-or-node'; + +if (!isNode) { + // saving WebSocket default + // when using lightnion with redirected WebSockets, + // the client must still create a WebSocket to the lightnion proxy + // hence we save the standard WebSocket as _WebSocket + window._WebSocket = WebSocket; +} + +import * as header from "./header.js"; +import * as endpoint from "./endpoint.js"; +import * as api from "./api.js"; +import * as consensusParser from "./consensusParser.js"; +import * as get from "./get.js"; +import * as io from "./io.js"; +import * as ntor from "./ntor.js"; +import * as onion from "./onion.js"; +import * as parser from "./parser.js"; +import * as path from "./path.js"; +import * as post from "./post.js"; +import * as relay from "./relay.js"; +import * as signature from "./signature"; +import * as stream from "./stream.js"; +import * as utils from "./util.js"; + +// header +let lnn = header.lnn; + +// api +lnn.fast = api.fast +lnn.auth = api.auth +lnn.open = api.open +lnn.agents = api.agents +lnn.send_req = api.send_req +lnn.http_request = api.http_request + +// consensus parser +lnn.consensusParser = consensusParser.consensusParser; + +// endpoint +lnn.endpoint = endpoint.endpoint; + +// get +lnn.get = {}; +lnn.get.guard = get.guard; +lnn.get.consensus = get.consensus; +lnn.get.descriptors = get.descriptors; +lnn.get.consensus_raw = get.consensus_raw; +lnn.get.descriptors_raw = get.descriptors_raw; +lnn.get.signing_keys = get.signing_keys; + +// io +lnn.io = {}; +lnn.io.polling = io.polling; +lnn.io.socket = io.socket; + +// ntor +lnn.ntor = ntor.ntor; + +// onion +lnn.onion = {}; +lnn.onion.ctr = onion.ctr; +lnn.onion.sha = onion.sha; +lnn.onion.forward = onion.forward; +lnn.onion.backward = onion.backward; +lnn.onion.build = onion.build; +lnn.onion.peel = onion.peel; + +// parser +lnn.parser = parser.parser; + +// path +lnn.path = path.path; + +// post +lnn.post = {}; +lnn.post.create = post.create; +lnn.post.circuit_info = post.circuit_info; +lnn.post.handshake = post.handshake; +lnn.post.channel = post.channel; +lnn.post.extend = post.extend; +lnn.post.close = post.close; + +// relay +lnn.relay = relay.relay; + +// signature +lnn.signature = {}; +lnn.signature.verify = signature.verify; +lnn.signature.get_hash = signature.get_hash; +lnn.signature.verify_key = signature.verify_key; +lnn.signature.get_sig_and_keys_digests = signature.get_sig_and_keys_digests; +lnn.signature.get_signature_big_int = signature.get_signature_big_int; +lnn.signature.get_hash_from_rsa_cipher = signature.get_hash_from_rsa_cipher; + +// stream +lnn.stream = stream.stream; + +// utils +lnn.enc = {}; +lnn.enc.bits = utils.enc.bits; +lnn.enc.utf8 = utils.enc.utf8; +lnn.enc.base64 = utils.enc.base64; +lnn.enc.bin = utils.enc.bin; + +lnn.dec = {}; +lnn.dec.bits = utils.dec.bits; +lnn.dec.utf8 = utils.dec.utf8; +lnn.dec.base64 = utils.dec.base64; +lnn.dec.bin = utils.dec.bin; + +window.lnn = lnn; + +export { lnn }; \ No newline at end of file diff --git a/js-client/src/ntor.js b/js-client/src/ntor.js index c217247..4b3fc10 100644 --- a/js-client/src/ntor.js +++ b/js-client/src/ntor.js @@ -1,80 +1,87 @@ + /** * Cryptographic operations related to ntor handshakes. + * @module ntor * @namespace - * @see lnn.ntor.hand - * @see lnn.ntor.shake + * @see ntor.hand + * @see ntor.shake */ -lnn.ntor = {} + +import { enc, dec } from "./util.js"; +import { sjcl } from "../vendor/sjcl.js"; +import nacl from "tweetnacl"; + +let ntor = {} /** * Number of bytes to derive from successful ntor handshakes. * @readonly * @default */ -lnn.ntor.keybytes = 92 +ntor.keybytes = 92 /** * Protocol identifier, prefix tweaks used in ntor handshakes various hashes. * @readonly * @default * - * @see lnn.ntor.tweaks + * @see ntor.tweaks */ -lnn.ntor.protoid = "ntor-curve25519-sha256-1" +ntor.protoid = "ntor-curve25519-sha256-1" /** * Tweaks used in ntor handshakes for various hashes and key derivation. * @enum * @readonly * - * @see lnn.ntor.hash + * @see ntor.hash */ -lnn.ntor.tweaks = { +ntor.tweaks = { /** * rfc5869 Expand {info} * @type kdf */ - expand: lnn.ntor.protoid + ":key_expand", + expand: ntor.protoid + ":key_expand", /** * rfc5869 Extract {salt} * @type kdf */ - key: lnn.ntor.protoid + ":key_extract", + key: ntor.protoid + ":key_extract", /** * H({secret_input}, t_verify) * @type ntor */ - verify: lnn.ntor.protoid + ":verify", + verify: ntor.protoid + ":verify", /** * suffix of {auth_input} * @type ntor */ - server: lnn.ntor.protoid + "Server", + server: ntor.protoid + "Server", /** * H({auth_input}, t_mac) * @type ntor */ - mac: lnn.ntor.protoid + ":mac"} + mac: ntor.protoid + ":mac" +} /** - * Tweaked pseudo-random function factory, see {@link lnn.ntor.hash}. + * Tweaked pseudo-random function factory, see {@link ntor.hash}. * - * @param {lnn.ntor.tweaks} tweak tweak to use + * @param {ntor.tweaks} tweak tweak to use * @return {hash_t} * - * @see lnn.ntor.hash + * @see ntor.hash */ -lnn.ntor.hash_factory = function(tweak) -{ - tweak = lnn.ntor.tweaks[tweak] +ntor.hash_factory = function (tweak) { + tweak = ntor.tweaks[tweak] tweak = sjcl.codec.utf8String.toBits(tweak) /** - * Tweaked pseudo-random function used by {@link lnn.ntor}, returned - * by {@link lnn.ntor.hash_factory}. + * Tweaked pseudo-random function used by {@link ntor}, returned + * by {@link ntor.hash_factory}. * * @interface hash_t - * @see lnn.ntor.hash + * @see ntor.hash * * @property {Object} hmac underlying hmac provider */ @@ -87,12 +94,12 @@ lnn.ntor.hash_factory = function(tweak) * @name hash_t#encrypt * @param {Uint8Array} data input data */ - encrypt: function(data) - { - data = lnn.enc.bits(data) + encrypt: function (data) { + data = enc.bits(data) data = hash.hmac.encrypt(data) - return lnn.dec.bits(data) - }} + return dec.bits(data) + } + } return hash } @@ -101,22 +108,22 @@ lnn.ntor.hash_factory = function(tweak) * @enum * @type hash_t * - * @see lnn.ntor.tweaks + * @see ntor.tweaks */ -lnn.ntor.hash = { - /** - * used for H({secret_input}, t_verify) during ntor handshakes - */ - verify: lnn.ntor.hash_factory("verify"), - /** - * used for H({auth_input}, t_mac) during ntor handshakes - */ - mac: lnn.ntor.hash_factory("mac"), - /** - * used for extraction during ntor handshakes key derivation - */ - prk: lnn.ntor.hash_factory("key") - } +ntor.hash = { + /** + * used for H({secret_input}, t_verify) during ntor handshakes + */ + verify: ntor.hash_factory("verify"), + /** + * used for H({auth_input}, t_mac) during ntor handshakes + */ + mac: ntor.hash_factory("mac"), + /** + * used for extraction during ntor handshakes key derivation + */ + prk: ntor.hash_factory("key") +} /** * Compute ntor key derivation from given material to n bytes. @@ -125,20 +132,18 @@ lnn.ntor.hash = { * @param {int} n number of bytes to output * @return {Uint8Array} */ -lnn.ntor.kdf = function(material, n) -{ - material = lnn.ntor.hash.prk.encrypt(material) - var hash = new sjcl.misc.hmac(lnn.enc.bits(material)) +ntor.kdf = function (material, n) { + material = ntor.hash.prk.encrypt(material) + var hash = new sjcl.misc.hmac(enc.bits(material)) - var tweak = lnn.ntor.tweaks["expand"] + var tweak = ntor.tweaks["expand"] tweak = sjcl.codec.utf8String.toBits(tweak) var idx = 1 - var out = lnn.enc.bits([]) - var last = lnn.enc.bits([]) - while (sjcl.bitArray.bitLength(out) < n * 8) - { - var idxbits = lnn.enc.bits([idx]) + var out = enc.bits([]) + var last = enc.bits([]) + while (sjcl.bitArray.bitLength(out) < n * 8) { + var idxbits = enc.bits([idx]) var current = sjcl.bitArray.concat(tweak, idxbits) last = hash.encrypt(sjcl.bitArray.concat(last, current)) @@ -146,7 +151,7 @@ lnn.ntor.kdf = function(material, n) idx = idx + 1 } - return lnn.dec.bits(sjcl.bitArray.clamp(out, n * 8)) + return dec.bits(sjcl.bitArray.clamp(out, n * 8)) } @@ -159,24 +164,23 @@ lnn.ntor.kdf = function(material, n) * @param {Boolean} encode if true, returns base64 (default: true) * @return {Uint8Array|string} * - * @see lnn.ntor.shake + * @see ntor.shake */ -lnn.ntor.hand = function(endpoint, descriptor, encode) -{ +ntor.hand = function (endpoint, descriptor, encode) { if (encode === undefined) encode = true if (descriptor === undefined) descriptor = endpoint.guard - var identity = lnn.dec.base64(descriptor.router.identity + "=") - var onionkey = lnn.dec.base64(descriptor["ntor-onion-key"]) + var identity = dec.base64(descriptor.router.identity + "=") + var onionkey = dec.base64(descriptor["ntor-onion-key"]) /** * Internal object, half-finished ntor handshake state in {@link * endpoint_t#material}, created by: *
    - *
  • {@link lnn.ntor.hand} - *
  • {@link lnn.ntor.fast} + *
  • {@link ntor.hand} + *
  • {@link ntor.fast} *
  • {@link lnn.auth} *
* Captures cryptographic state required to finish the handshake. @@ -188,10 +192,10 @@ lnn.ntor.hand = function(endpoint, descriptor, encode) * @property {Uint8Array} onionkey node public key */ endpoint.material = { - ntor: nacl.box.keyPair(), - identity: identity, - onionkey: onionkey - } + ntor: nacl.box.keyPair(), + identity: identity, + onionkey: onionkey + } var pubkey = endpoint.material.ntor.publicKey var length = identity.length + onionkey.length + pubkey.length @@ -199,15 +203,15 @@ lnn.ntor.hand = function(endpoint, descriptor, encode) var payload = new Uint8Array(length) payload.set(identity, 0) payload.set(onionkey, identity.length) - payload.set(pubkey, identity.length+onionkey.length) + payload.set(pubkey, identity.length + onionkey.length) if (encode) - return lnn.enc.base64(payload) + return enc.base64(payload) return payload } /** - * Just as {@link lnn.ntor.hand} but without node identity and onion key – used + * Just as {@link ntor.hand} but without node identity and onion key – used * by {@link lnn.fast}, writes a {@link half_t} in {@link endpoint_t#material}. * *
Note: always returns base64-encoded handshake.
@@ -217,19 +221,18 @@ lnn.ntor.hand = function(endpoint, descriptor, encode) * * @see lnn.fast */ -lnn.ntor.fast = function(endpoint) -{ +ntor.fast = function (endpoint) { endpoint.material = {} endpoint.material.ntor = nacl.box.keyPair() endpoint.material.identity = null endpoint.material.onionkey = null - return lnn.enc.base64(endpoint.material.ntor.publicKey) + return enc.base64(endpoint.material.ntor.publicKey) } /** * Compute the second part of a ntor handshake read * from {@link endpoint_t#material}, returns derived bytes suitable as - * {@link lnn.ntor.slice} input. + * {@link ntor.slice} input. * *
Note: returns null if handshake is invalid.
* @@ -239,14 +242,13 @@ lnn.ntor.fast = function(endpoint) * (default: true) * @return {Uint8Array|null} * - * @see lnn.ntor.hand + * @see ntor.hand */ -lnn.ntor.shake = function(endpoint, data, encoded) -{ +ntor.shake = function (endpoint, data, encoded) { if (encoded === undefined) encoded = true if (encoded) - data = lnn.dec.base64(data) + data = dec.base64(data) var client_pubkey = endpoint.material.ntor.publicKey var client_secret = endpoint.material.ntor.secretKey @@ -259,7 +261,7 @@ lnn.ntor.shake = function(endpoint, data, encoded) var exp_share = nacl.scalarMult(client_secret, server_pubkey) var exp_onion = nacl.scalarMult(client_secret, onionkey) - var protoid = lnn.dec.utf8(lnn.ntor.protoid) + var protoid = dec.utf8(ntor.protoid) var length = exp_share.length * 2 + identity.length + onionkey.length * 3 var off = 0 @@ -271,9 +273,9 @@ lnn.ntor.shake = function(endpoint, data, encoded) secret_input.set(client_pubkey, off); off += client_pubkey.length secret_input.set(server_pubkey, off); off += server_pubkey.length secret_input.set(protoid, off) - var verify = lnn.ntor.hash.verify.encrypt(secret_input) + var verify = ntor.hash.verify.encrypt(secret_input) - var server = lnn.dec.utf8(lnn.ntor.tweaks["server"]) + var server = dec.utf8(ntor.tweaks["server"]) var length = verify.length + identity.length + onionkey.length * 3 var off = 0 @@ -284,12 +286,11 @@ lnn.ntor.shake = function(endpoint, data, encoded) auth_input.set(server_pubkey, off); off += server_pubkey.length auth_input.set(client_pubkey, off); off += client_pubkey.length auth_input.set(server, off) - var client_auth = lnn.ntor.hash.mac.encrypt(auth_input) + var client_auth = ntor.hash.mac.encrypt(auth_input) var valid = true length = client_auth.length - for (var i = 0; i < length; i++) - { + for (var i = 0; i < length; i++) { if (client_auth[i] != server_auth[i]) valid = false } @@ -297,8 +298,7 @@ lnn.ntor.shake = function(endpoint, data, encoded) var zero_onion = 0 var zero_share = 0 length = exp_onion.length - for (var i = 0; i < length; i++) - { + for (var i = 0; i < length; i++) { if (exp_onion[i] == 0) zero_onion = zero_onion + 1 if (exp_share[i] == 0) @@ -308,36 +308,34 @@ lnn.ntor.shake = function(endpoint, data, encoded) if (zero_onion == exp_onion.length || zero_share == exp_share.length) valid = false - if (valid) - { - return lnn.ntor.kdf(secret_input, lnn.ntor.keybytes) + if (valid) { + return ntor.kdf(secret_input, ntor.keybytes) } return null } /** * Build a shared cryptographic {@link material_t} for - * {@link endpoint_t#material} from the output of {@link lnn.ntor.shake}. + * {@link endpoint_t#material} from the output of {@link ntor.shake}. * *
  * Note: assume KEY_LEN == 16 (aes256) and HASH_LEN == 20 (sha1) internally.
  * 
* - * @param {Uint8Array} material exactly {@link lnn.ntor.keybytes} + * @param {Uint8Array} material exactly {@link ntor.keybytes} * bytes * @return {material_t} */ -lnn.ntor.slice = function(material) -{ +ntor.slice = function (material) { var k = 16 // KEY_LEN var h = 20 // HASH_LEN /** * Internal object, stores shared cryptographic material - * as {@link endpoint_t#material}, returned by {@link lnn.ntor.slice}. + * as {@link endpoint_t#material}, returned by {@link ntor.slice}. * * @interface material_t - * @see lnn.ntor.slice + * @see ntor.slice * * @property {Uint8Array} key_hash unused * @property {Uint8Array} forward_key used in {@link forward_t} @@ -369,19 +367,21 @@ lnn.ntor.slice = function(material) * if and only if the authentication succeeded. * */ -lnn.ntor.auth = function(endpoint, client, data) -{ +ntor.auth = function (endpoint, client, data) { var pending_material = endpoint.material endpoint.material = endpoint.auth - var data = lnn.dec.base64(data) - var material = lnn.ntor.shake(endpoint, client) + var data = dec.base64(data) + var material = ntor.shake(endpoint, client) if (material == null) throw "Invalid auth." endpoint.material = pending_material var key = material.slice(0, 32) - var nonce = material.slice(32, 32+24) + var nonce = material.slice(32, 32 + 24) data = nacl.secretbox.open(data, nonce, key) - return JSON.parse(lnn.enc.utf8(data)) + return JSON.parse(enc.utf8(data)) } + + +export { ntor } \ No newline at end of file diff --git a/js-client/src/onion.js b/js-client/src/onion.js index 24fcb38..d82a8c2 100644 --- a/js-client/src/onion.js +++ b/js-client/src/onion.js @@ -1,40 +1,42 @@ -lnn.onion = {} -lnn.onion.ctr = function(key) -{ - var key = lnn.enc.bits(key) +/** + * @module onion + */ + +import { enc, dec } from "./util.js"; +import { relay } from "./relay.js"; +import { sjcl } from "../vendor/sjcl.js"; + +export function ctr(key) { + var key = enc.bits(key) var aes = new sjcl.cipher.aes(key) var ctr = { prf: aes, nonce: 0, buffer: new Uint8Array(0), - extend: function(n) - { + extend: function (n) { var length = (Math.floor(n / 16) + 1) * 16 var remains = ctr.buffer - ctr.buffer = new Uint8Array(length+remains.length) + ctr.buffer = new Uint8Array(length + remains.length) ctr.buffer.set(remains, 0) - for (var idx = remains.length; idx < ctr.buffer.length; idx += 16) - { + for (var idx = remains.length; idx < ctr.buffer.length; idx += 16) { var nonce = new Uint8Array(16) new DataView(nonce.buffer).setUint32(12, ctr.nonce, false) - nonce = lnn.enc.bits(nonce) - var pad = lnn.dec.bits(ctr.prf.encrypt(nonce)) + nonce = enc.bits(nonce) + var pad = dec.bits(ctr.prf.encrypt(nonce)) ctr.buffer.set(pad, idx) ctr.nonce = ctr.nonce + 1 } }, - process: function(data) - { + process: function (data) { if (data.length > ctr.buffer.length) ctr.extend(data.length) var data = data.slice(0) - for (var idx = 0; idx < data.length; idx++) - { + for (var idx = 0; idx < data.length; idx++) { data[idx] ^= ctr.buffer[idx] } ctr.buffer = ctr.buffer.slice(data.length) @@ -45,17 +47,15 @@ lnn.onion.ctr = function(key) return ctr } -lnn.onion.sha = function(digest) -{ - var digest = lnn.enc.bits(digest) +export function sha(digest) { + var digest = enc.bits(digest) var sha = { hash: new sjcl.hash.sha1(), - digest: function(data) - { - sha.hash.update(lnn.enc.bits(data)) + digest: function (data) { + sha.hash.update(enc.bits(data)) data = new sjcl.hash.sha1(sha.hash).finalize() - return lnn.dec.bits(data) + return dec.bits(data) } } @@ -63,12 +63,10 @@ lnn.onion.sha = function(digest) return sha } -lnn.onion.forward = function(endpoint) -{ +export function forward(endpoint) { var early = 8 var layers = [] - if (endpoint.forward != null) - { + if (endpoint.forward != null) { layers = endpoint.forward.layers layers.push(endpoint.forward) early = endpoint.forward.early @@ -76,32 +74,28 @@ lnn.onion.forward = function(endpoint) var forward = { iv: 0, - ctr: lnn.onion.ctr(endpoint.material.forward_key), - sha: lnn.onion.sha(endpoint.material.forward_digest), + ctr: ctr(endpoint.material.forward_key), + sha: sha(endpoint.material.forward_digest), early: early, // (first 8 relay cells will be replaced by relay_early) layers: layers, - encrypt: function(cell) - { - if ((cell.length) != lnn.relay.full_len) + encrypt: function (cell) { + if ((cell.length) != relay.full_len) throw "Invalid size for cell, fatal." var body = cell.slice(5) - for (var idx = 0; idx < forward.layers.length; idx++) - { + for (var idx = 0; idx < forward.layers.length; idx++) { body.set(forward.layers[idx].ctr.process(body), 0) } cell.set(forward.ctr.process(body), 5) - if (forward.early > 0 && cell[4] == 3 /* relay */) - { + if (forward.early > 0 && cell[4] == 3 /* relay */) { forward.early = forward.early - 1 cell[4] = 9 /* relay_early */ } return cell }, - digest: function(cell) - { - if ((cell.length) != lnn.relay.full_len) + digest: function (cell) { + if ((cell.length) != relay.full_len) throw "Invalid size for cell, fatal." var body = cell.slice(5) @@ -112,62 +106,55 @@ lnn.onion.forward = function(endpoint) return forward } -lnn.onion.backward = function(endpoint) -{ +export function backward(endpoint) { var layers = [] - if (endpoint.backward != null) - { + if (endpoint.backward != null) { layers = endpoint.backward.layers layers.push(endpoint.backward) } var backward = { iv: 0, - ctr: lnn.onion.ctr(endpoint.material.backward_key), - sha: lnn.onion.sha(endpoint.material.backward_digest), + ctr: ctr(endpoint.material.backward_key), + sha: sha(endpoint.material.backward_digest), layers: layers, - decrypt: function(cell) - { - if ((cell.length) != lnn.relay.full_len) + decrypt: function (cell) { + if ((cell.length) != relay.full_len) throw "Invalid size for cell, fatal." var body = cell.slice(5) - - for (var idx = 0; idx < backward.layers.length; idx++) - { + + for (var idx = 0; idx < backward.layers.length; idx++) { body.set(backward.layers[idx].ctr.process(body), 0) - + cell.set(body, 5) - + var recognized = cell.slice(6, 8) - if (recognized[0] == recognized[1] && recognized[0] == 0) - { + if (recognized[0] == recognized[1] && recognized[0] == 0) { var digest = cell.slice(10, 14) var expect = backward.layers[idx].digest(cell) var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false) - if(expect[0] == digest[0] && + if (expect[0] == digest[0] && expect[1] == digest[1] && expect[2] == digest[2] && - expect[3] == digest[3] ) { - if (length <= lnn.relay.data_len) - { + expect[3] == digest[3]) { + if (length <= relay.data_len) { console.log("Warning: Cell sent by intermediate \ - tor node, after " + (idx+1) + " hop(s)") + tor node, after " + (idx + 1) + " hop(s)") return cell - } + } } } } - + cell.set(backward.ctr.process(body), 5) var digest = cell.slice(10, 14) cell.set(new Uint8Array(4), 10) var recognized = cell.slice(6, 8) - if (!(recognized[0] == recognized[1] && recognized[0] == 0)) - { + if (!(recognized[0] == recognized[1] && recognized[0] == 0)) { throw "Invalid cell recognized field." } @@ -176,24 +163,21 @@ lnn.onion.backward = function(endpoint) && digest[0] == expect[0] && digest[1] == expect[1] && digest[2] == expect[2] - && digest[3] == expect[3])) - { + && digest[3] == expect[3])) { throw "Invalid cell digest." } - + var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false) - if (length > lnn.relay.data_len) - { + if (length > relay.data_len) { throw "Invalid cell data length." } return cell - + }, - digest: function(cell) - { - if ((cell.length) != lnn.relay.full_len) + digest: function (cell) { + if ((cell.length) != relay.full_len) throw "Invalid size for cell, fatal." var body = cell.slice(5) @@ -204,25 +188,23 @@ lnn.onion.backward = function(endpoint) return backward } -lnn.onion.build = function(endpoint, cmd, stream_id, data) -{ - var cell = lnn.relay.pack(cmd, stream_id, data) +export function build(endpoint, cmd, stream_id, data) { + var cell = relay.pack(cmd, stream_id, data) cell.set(endpoint.forward.digest(cell), 10) return endpoint.forward.encrypt(cell) } -lnn.onion.peel = function(endpoint, cell) -{ +export function peel(endpoint, cell) { var cell = endpoint.backward.decrypt(cell) - - + + var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false) var id = new DataView(cell.slice(8, 10).buffer).getUint16(0, false) - var cmd = lnn.relay.cmd[cell.slice(5, 6)[0]] + var cmd = relay.cmd[cell.slice(5, 6)[0]] var data = cell.slice(16, 16 + length) - var relay = {cmd: cmd, stream_id: id, data: data} - - return relay + var relay_ = { cmd: cmd, stream_id: id, data: data } + + return relay_ } diff --git a/js-client/src/parser.js b/js-client/src/parser.js index fe38a9a..1edebd6 100644 --- a/js-client/src/parser.js +++ b/js-client/src/parser.js @@ -1,63 +1,70 @@ -lnn.parser = {} +/** + * @module parser + */ + +import { enc, dec } from "./util.js"; +import { sjcl } from "../vendor/sjcl.js"; -lnn.parser.descriptors = { +let parser = {} + +parser.descriptors = { line_count: 0, total_lines: -1, lines: undefined, valid_bridge_distribution: ["none", "any", "https", "email", "moat", "hyphae"], - + exactly_once: ["router", "bandwidth", "published", "onion-key", "signing-key", "router-signatures"], - exactly_once_mic: ["onion-key","policy","ipv6-policy"], + exactly_once_mic: ["onion-key", "policy", "ipv6-policy"], parse: function (raw_descriptors, flavor = 'microdesc') { - if(flavor != 'unflavored' && flavor != 'microdesc') { + if (flavor != 'unflavored' && flavor != 'microdesc') { throw 'Error: Unexpected flavor' } let descriptors = [] - lnn.parser.descriptors.lines = raw_descriptors.split('\n') - lnn.parser.descriptors.line_count = 0 - lnn.parser.descriptors.total_lines = lnn.parser.descriptors.lines.length - lnn.parser.descriptors.flavor = flavor - - while (lnn.parser.descriptors.line_count < lnn.parser.descriptors.total_lines) { - if(lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count] === ""){ - lnn.parser.descriptors.line_count++ + parser.descriptors.lines = raw_descriptors.split('\n') + parser.descriptors.line_count = 0 + parser.descriptors.total_lines = parser.descriptors.lines.length + parser.descriptors.flavor = flavor + + while (parser.descriptors.line_count < parser.descriptors.total_lines) { + if (parser.descriptors.lines[parser.descriptors.line_count] === "") { + parser.descriptors.line_count++ continue } - - let descriptor = lnn.parser.descriptors.consume_one_node() + + let descriptor = parser.descriptors.consume_one_node() descriptor['flavor'] = flavor descriptors.push(descriptor) } return descriptors }, - validate: function(descriptors,consensus,flavor = 'microdesc',fail_on_missing = false) { + validate: function (descriptors, consensus, flavor = 'microdesc', fail_on_missing = false) { let digest_name = (flavor == 'unflavored') ? 'digest' : 'micro-digest' let digests = [] - for (idx = 0; idx < consensus['routers'].length; idx++){ - let router = consensus['routers'][idx] + for (let idx = 0; idx < consensus['routers'].length; idx++) { + let router = consensus['routers'][idx] digests.push(router[digest_name]) } let obtained = [] - for (idx = 0; idx < descriptors.length; idx++){ - obtained.push(descriptors[idx][digest_name]) + for (let idx = 0; idx < descriptors.length; idx++) { + obtained.push(descriptors[idx][digest_name]) } let invalid = [] console.log(obtained.length) - for (idx = 0; idx < digests.length; idx++){ + for (let idx = 0; idx < digests.length; idx++) { let digest = digests[idx] - if (obtained.includes(digest)){ - obtained.splice( obtained.indexOf(digest), 1 ); + if (obtained.includes(digest)) { + obtained.splice(obtained.indexOf(digest), 1); } else invalid.push(digest) } console.log(obtained.length) - - if (obtained.length){ + + if (obtained.length) { throw `Invalid descriptors found` } @@ -70,33 +77,33 @@ lnn.parser.descriptors = { * Parse one node in the raw data file * @returns {object} the descriptor of the parsed node */ - let tot =0 -lnn.parser.descriptors.consume_one_node = function () { +let tot = 0 +parser.descriptors.consume_one_node = function () { - if (lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].startsWith('@type')) lnn.parser.descriptors.line_count++ - if (lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count] === ""){ - lnn.parser.descriptors.line_count++ + if (parser.descriptors.lines[parser.descriptors.line_count].startsWith('@type')) parser.descriptors.line_count++ + if (parser.descriptors.lines[parser.descriptors.line_count] === "") { + parser.descriptors.line_count++ } let descriptor = {} - let startLine = lnn.parser.descriptors.line_count + let startLine = parser.descriptors.line_count - if(lnn.parser.descriptors.flavor == 'unflavored') { - descriptor = lnn.parser.descriptors.consume_router(descriptor) - descriptor = lnn.parser.descriptors.try_consume_identity_ed25519(descriptor) + if (parser.descriptors.flavor == 'unflavored') { + descriptor = parser.descriptors.consume_router(descriptor) + descriptor = parser.descriptors.try_consume_identity_ed25519(descriptor) } else { - descriptor = lnn.parser.descriptors.consume_onion_key(descriptor) + descriptor = parser.descriptors.consume_onion_key(descriptor) } - let line = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count] - + let line = parser.descriptors.lines[parser.descriptors.line_count] + while (true) { - if(lnn.parser.descriptors.flavor == 'unflavored') { - if(line.startsWith("router-signature")) + if (parser.descriptors.flavor == 'unflavored') { + if (line.startsWith("router-signature")) break - } else{ - if(lnn.parser.descriptors.line_count == lnn.parser.descriptors.total_lines + } else { + if (parser.descriptors.line_count == parser.descriptors.total_lines || line.startsWith('@type') || line.startsWith('onion-key')) break } @@ -106,168 +113,168 @@ lnn.parser.descriptors.consume_one_node = function () { let first_word = (index_sp === -1) ? line : line.substring(0, index_sp) switch (first_word) { case "master-key-ed25519": - descriptor = lnn.parser.descriptors.consume_master_key_ed25519(descriptor) + descriptor = parser.descriptors.consume_master_key_ed25519(descriptor) break case "platform": - descriptor = lnn.parser.descriptors.consume_platform(descriptor) + descriptor = parser.descriptors.consume_platform(descriptor) break case "published": - descriptor = lnn.parser.descriptors.consume_published(descriptor) + descriptor = parser.descriptors.consume_published(descriptor) break case "bandwidth": - descriptor = lnn.parser.descriptors.consume_bandwidth(descriptor) + descriptor = parser.descriptors.consume_bandwidth(descriptor) break case "fingerprint": - descriptor = lnn.parser.descriptors.consume_fingerprint(descriptor) + descriptor = parser.descriptors.consume_fingerprint(descriptor) break case "hibernating": - descriptor = lnn.parser.descriptors.consume_hibernating(descriptor) + descriptor = parser.descriptors.consume_hibernating(descriptor) break case "uptime": - descriptor = lnn.parser.descriptors.consume_uptime(descriptor) + descriptor = parser.descriptors.consume_uptime(descriptor) break case "extra-info-digest": - descriptor = lnn.parser.descriptors.consume_extra_info_digest(descriptor) + descriptor = parser.descriptors.consume_extra_info_digest(descriptor) break case "caches-extra-info": - descriptor = lnn.parser.descriptors.consume_single_word_line("caches-extra-info", descriptor) + descriptor = parser.descriptors.consume_single_word_line("caches-extra-info", descriptor) break case "onion-key": - descriptor = lnn.parser.descriptors.consume_onion_key(descriptor) + descriptor = parser.descriptors.consume_onion_key(descriptor) break case "onion-key-crosscert": - descriptor = lnn.parser.descriptors.consume_onion_key_crosscert(descriptor) + descriptor = parser.descriptors.consume_onion_key_crosscert(descriptor) break case "ntor-onion-key": - descriptor = lnn.parser.descriptors.consume_base64_digest('ntor-onion-key', descriptor) + descriptor = parser.descriptors.consume_base64_digest('ntor-onion-key', descriptor) break case "ntor-onion-key-crosscert": - descriptor = lnn.parser.descriptors.consume_ntor_onion_key_crosscert(descriptor) + descriptor = parser.descriptors.consume_ntor_onion_key_crosscert(descriptor) break case "accept": - descriptor = lnn.parser.descriptors.consume_exit_policy("accept", descriptor) + descriptor = parser.descriptors.consume_exit_policy("accept", descriptor) break case "reject": - descriptor = lnn.parser.descriptors.consume_exit_policy("reject", descriptor) + descriptor = parser.descriptors.consume_exit_policy("reject", descriptor) break case "signing-key": - descriptor = lnn.parser.descriptors.consume_signing_key(descriptor) + descriptor = parser.descriptors.consume_signing_key(descriptor) break case "ipv6-policy": - descriptor = lnn.parser.consume_exit_policy('ipv6-policy', lnn.parser.descriptors.lines, lnn.parser.descriptors.line_count++, descriptor) + descriptor = parser.consume_exit_policy('ipv6-policy', parser.descriptors.lines, parser.descriptors.line_count++, descriptor) break case "router-sig-ed25519": - descriptor = lnn.parser.descriptors.consume_router_sig_ed25519(descriptor) + descriptor = parser.descriptors.consume_router_sig_ed25519(descriptor) break case "contact": - descriptor = lnn.parser.consume_contact(lnn.parser.descriptors.lines, lnn.parser.descriptors.line_count++, descriptor) + descriptor = parser.consume_contact(parser.descriptors.lines, parser.descriptors.line_count++, descriptor) break case "bridge-distribution": - descriptor = lnn.parser.descriptors.consume_bridge_distribution(descriptor) + descriptor = parser.descriptors.consume_bridge_distribution(descriptor) break case "family": - descriptor = lnn.parser.descriptors.consume_family(descriptor) + descriptor = parser.descriptors.consume_family(descriptor) break case "read-history": - descriptor = lnn.parser.descriptors.consume_history("read", descriptor) + descriptor = parser.descriptors.consume_history("read", descriptor) break case "write-history": - descriptor = lnn.parser.descriptors.consume_history("write", descriptor) + descriptor = parser.descriptors.consume_history("write", descriptor) break case "eventdns": - descriptor = lnn.parser.descriptors.consume_eventdns(descriptor) + descriptor = parser.descriptors.consume_eventdns(descriptor) break case "hidden-service-dir": - descriptor = lnn.parser.descriptors.consume_single_word_line("hidden-service-dir", descriptor) + descriptor = parser.descriptors.consume_single_word_line("hidden-service-dir", descriptor) break case "allow-single-hop-exits": - descriptor = lnn.parser.descriptors.consume_single_word_line("allow-single-hop-exits", descriptor) + descriptor = parser.descriptors.consume_single_word_line("allow-single-hop-exits", descriptor) break case "tunnelled-dir-server": - descriptor = lnn.parser.descriptors.consume_single_word_line("tunnelled-dir-server", descriptor) + descriptor = parser.descriptors.consume_single_word_line("tunnelled-dir-server", descriptor) break case "proto": - descriptor = lnn.parser.consume_proto("proto", lnn.parser.descriptors.lines, lnn.parser.descriptors.line_count++, descriptor) + descriptor = parser.consume_proto("proto", parser.descriptors.lines, parser.descriptors.line_count++, descriptor) break case "p": - descriptor = lnn.parser.consume_exit_policy('p', lnn.parser.descriptors.lines, lnn.parser.descriptors.line_count++, descriptor) + descriptor = parser.consume_exit_policy('p', parser.descriptors.lines, parser.descriptors.line_count++, descriptor) break case "p6": - descriptor = lnn.parser.consume_exit_policy('p6', lnn.parser.descriptors.lines, lnn.parser.descriptors.line_count++, descriptor) + descriptor = parser.consume_exit_policy('p6', parser.descriptors.lines, parser.descriptors.line_count++, descriptor) break case "id": - descriptor = lnn.parser.descriptors.consume_id(descriptor) + descriptor = parser.descriptors.consume_id(descriptor) break default: - ++lnn.parser.descriptors.line_count + ++parser.descriptors.line_count break } - line = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count] + line = parser.descriptors.lines[parser.descriptors.line_count] } - if(descriptor['ipv6-policy'] === undefined) descriptor['ipv6-policy'] = { + if (descriptor['ipv6-policy'] === undefined) descriptor['ipv6-policy'] = { "type": "reject", - "PortList":[[1,65535]] + "PortList": [[1, 65535]] } - if(descriptor['policy'] === undefined) { + if (descriptor['policy'] === undefined) { descriptor['policy'] = { "type": "reject", - "PortList":[[1,65535]] + "PortList": [[1, 65535]] } } - let fields = lnn.parser.descriptors.exactly_once_mic - let endLine = lnn.parser.descriptors.line_count //include till router-signature + let fields = parser.descriptors.exactly_once_mic + let endLine = parser.descriptors.line_count //include till router-signature - if(lnn.parser.descriptors.flavor == 'unflavored') { - endLine+=1 //include till router-signature - descriptor = lnn.parser.descriptors.consume_router_signature(descriptor) - fields = lnn.parser.descriptors.exactly_once + if (parser.descriptors.flavor == 'unflavored') { + endLine += 1 //include till router-signature + descriptor = parser.descriptors.consume_router_signature(descriptor) + fields = parser.descriptors.exactly_once } - if (!lnn.parser.descriptors.check_exactly_once(descriptor,fields)) throw "Invalid descriptor: some mandatory fields are not present" + if (!parser.descriptors.check_exactly_once(descriptor, fields)) throw "Invalid descriptor: some mandatory fields are not present" let fullDesc = "" - for(i = startLine; i < endLine; i++) { - if(lnn.parser.descriptors.lines[i] == "") + for (let i = startLine; i < endLine; i++) { + if (parser.descriptors.lines[i] == "") continue - fullDesc += (lnn.parser.descriptors.lines[i] + '\n') + fullDesc += (parser.descriptors.lines[i] + '\n') } - if(lnn.parser.descriptors.flavor == 'unflavored') { + if (parser.descriptors.flavor == 'unflavored') { let digest = sjcl.hash.sha1.hash(fullDesc) - digest = lnn.enc.base64(lnn.dec.bits(digest)) + digest = enc.base64(dec.bits(digest)) - while(digest.length > 0 && digest[digest.length - 1] == '=') - digest = digest.slice(0,-1) + while (digest.length > 0 && digest[digest.length - 1] == '=') + digest = digest.slice(0, -1) descriptor['digest'] = digest } else { let mdigest = sjcl.hash.sha256.hash(fullDesc) - mdigest = lnn.dec.bits(mdigest) - mdigest = lnn.enc.base64(mdigest) - - while(mdigest.length > 0 && mdigest[mdigest.length - 1] == '=') - mdigest = mdigest.slice(0,-1) + mdigest = dec.bits(mdigest) + mdigest = enc.base64(mdigest) + + while (mdigest.length > 0 && mdigest[mdigest.length - 1] == '=') + mdigest = mdigest.slice(0, -1) descriptor['micro-digest'] = mdigest } return descriptor } - + /** * Checks that all mandatory fields of the descriptor were parsed */ -lnn.parser.descriptors.check_exactly_once = function (descriptor,fields) { - - if(descriptor['ipv6-policy'] === undefined) descriptor - +parser.descriptors.check_exactly_once = function (descriptor, fields) { + + if (descriptor['ipv6-policy'] === undefined) descriptor + let parsed = true - if(descriptor['identity-ed25519'] !== undefined){ + if (descriptor['identity-ed25519'] !== undefined) { parsed = descriptor["ntor-onion-key-crosscert"] !== undefined && descriptor["onion-key-crosscert"] !== undefined && descriptor["router-sig-ed25519"] !== undefined - }else{ + } else { parsed = descriptor["router-sig-ed25519"] === undefined } @@ -279,15 +286,15 @@ lnn.parser.descriptors.check_exactly_once = function (descriptor,fields) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_router = function (descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].split(' ') - lnn.parser.check_format(6, 'router', words) +parser.descriptors.consume_router = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' ') + parser.check_format(6, 'router', words) - if (!lnn.parser.is_valid_nickname(words[1])) throw `Invalid nickname: ${words[1]} contains non-alphanumeric characters` - if (!lnn.parser.is_valid_ipv4(words[2])) throw `Invalid address: ${words[2]} is not a valid iPv4 address` - if (!lnn.parser.is_valid_port(words[3])) throw `Invalid port: ${words[3]} is not a valid port (0 to 65535)` - if (!lnn.parser.is_valid_port(words[4])) throw `Invalid port: ${words[4]} is not a valid port (0 to 65535)` - if (!lnn.parser.is_valid_port(words[5])) throw `Invalid port: ${words[5]} is not a valid port (0 to 65535)` + if (!parser.is_valid_nickname(words[1])) throw `Invalid nickname: ${words[1]} contains non-alphanumeric characters` + if (!parser.is_valid_ipv4(words[2])) throw `Invalid address: ${words[2]} is not a valid iPv4 address` + if (!parser.is_valid_port(words[3])) throw `Invalid port: ${words[3]} is not a valid port (0 to 65535)` + if (!parser.is_valid_port(words[4])) throw `Invalid port: ${words[4]} is not a valid port (0 to 65535)` + if (!parser.is_valid_port(words[5])) throw `Invalid port: ${words[5]} is not a valid port (0 to 65535)` descriptor['router'] = { "nickname": words[1], @@ -297,7 +304,7 @@ lnn.parser.descriptors.consume_router = function (descriptor) { "dirport": Number(words[5]) } - ++lnn.parser.descriptors.line_count + ++parser.descriptors.line_count return descriptor } @@ -306,14 +313,14 @@ lnn.parser.descriptors.consume_router = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.try_consume_identity_ed25519 = function (descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].split(' ') +parser.descriptors.try_consume_identity_ed25519 = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' ') if (words[0] === 'identity-ed25519') { - lnn.parser.check_format(1, 'identity-ed25519', words) - ++lnn.parser.descriptors.line_count + parser.check_format(1, 'identity-ed25519', words) + ++parser.descriptors.line_count - let [offset, certificate] = lnn.parser.consume_pem(lnn.parser.descriptors.lines, lnn.parser.descriptors.line_count) - lnn.parser.descriptors.line_count += offset + 1 + let [offset, certificate] = parser.consume_pem(parser.descriptors.lines, parser.descriptors.line_count) + parser.descriptors.line_count += offset + 1 descriptor['identity'] = { "type": "ed25519", "cert": certificate @@ -325,17 +332,17 @@ lnn.parser.descriptors.try_consume_identity_ed25519 = function (descriptor) { return descriptor } -lnn.parser.descriptors.consume_id = function (descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].split(' ') +parser.descriptors.consume_id = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' ') - lnn.parser.check_format(3, 'id', words) + parser.check_format(3, 'id', words) let type = words[1] - if(type != 'rsa1024' && type != 'ed25519') + if (type != 'rsa1024' && type != 'ed25519') throw `Unexpected identity type ${type}` - lnn.parser.check_reused('identity', descriptor) - if (!lnn.parser.is_valid_base64(lnn.parser.add_ending(words[2]))) + parser.check_reused('identity', descriptor) + if (!parser.is_valid_base64(parser.add_ending(words[2]))) throw `Invalid master key: the master key ${words[2]} must be in base64` descriptor['identity'] = { @@ -343,7 +350,7 @@ lnn.parser.descriptors.consume_id = function (descriptor) { "master-key": words[2] } - ++lnn.parser.descriptors.line_count + ++parser.descriptors.line_count return descriptor } @@ -352,15 +359,15 @@ lnn.parser.descriptors.consume_id = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_master_key_ed25519 = function (descriptor) { +parser.descriptors.consume_master_key_ed25519 = function (descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].split(' ') - lnn.parser.check_format(2, 'master-key-ed25519', words) - lnn.parser.check_reused('master-key-ed25519', descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' ') + parser.check_format(2, 'master-key-ed25519', words) + parser.check_reused('master-key-ed25519', descriptor) let key = words[1] - if (!lnn.parser.is_valid_base64(lnn.parser.add_ending(key))) throw `Invalid master key: the master key ${words[1]} must be in base64` + if (!parser.is_valid_base64(parser.add_ending(key))) throw `Invalid master key: the master key ${words[1]} must be in base64` descriptor['identity']['master-key'] = key - lnn.parser.descriptors.line_count++ + parser.descriptors.line_count++ return descriptor } @@ -370,12 +377,12 @@ lnn.parser.descriptors.consume_master_key_ed25519 = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_platform = function (descriptor) { - lnn.parser.check_reused("platform", descriptor) - let line = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count] +parser.descriptors.consume_platform = function (descriptor) { + parser.check_reused("platform", descriptor) + let line = parser.descriptors.lines[parser.descriptors.line_count] let platform = line.substring("platform".length + 1) descriptor['platform'] = platform - lnn.parser.descriptors.line_count++ + parser.descriptors.line_count++ return descriptor } @@ -384,10 +391,10 @@ lnn.parser.descriptors.consume_platform = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_published = function (descriptor) { - lnn.parser.check_reused('published', descriptor) - descriptor['published'] = lnn.parser.consume_date('published', lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count]) - ++lnn.parser.descriptors.line_count +parser.descriptors.consume_published = function (descriptor) { + parser.check_reused('published', descriptor) + descriptor['published'] = parser.consume_date('published', parser.descriptors.lines[parser.descriptors.line_count]) + ++parser.descriptors.line_count return descriptor } @@ -396,10 +403,10 @@ lnn.parser.descriptors.consume_published = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_bandwidth = function (descriptor) { - lnn.parser.check_reused('bandwidth', descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(4, 'bandwidth', words) +parser.descriptors.consume_bandwidth = function (descriptor) { + parser.check_reused('bandwidth', descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(4, 'bandwidth', words) let avg = Number(words[1]) let burst = Number(words[2]) @@ -421,16 +428,16 @@ lnn.parser.descriptors.consume_bandwidth = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_fingerprint = function (descriptor) { - lnn.parser.check_reused('fingerprint', descriptor) - let line = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++] +parser.descriptors.consume_fingerprint = function (descriptor) { + parser.check_reused('fingerprint', descriptor) + let line = parser.descriptors.lines[parser.descriptors.line_count++] let index_sp = line.indexOf(" ") let fingerprint = line.substring(index_sp + 1) - + let bytes = fingerprint.split(" ") let join_bytes = bytes.join("") if (bytes.length != 10) throw `Invalid fingerprint: wrong size` - if (!lnn.parser.is_valid_hex(join_bytes)) throw `Invalid fingerprint: not a hex string` + if (!parser.is_valid_hex(join_bytes)) throw `Invalid fingerprint: not a hex string` let identity = sjcl.codec.hex.toBits(join_bytes) identity = sjcl.codec.base64.fromBits(identity).replace("=", "") @@ -446,10 +453,10 @@ lnn.parser.descriptors.consume_fingerprint = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_hibernating = function (descriptor) { - lnn.parser.check_reused('hibernating', descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(2, 'hibernating', words) +parser.descriptors.consume_hibernating = function (descriptor) { + parser.check_reused('hibernating', descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(2, 'hibernating', words) let b = Number(words[1]) if (b !== 0 && b !== 1) throw `Invalid boolean` @@ -462,10 +469,10 @@ lnn.parser.descriptors.consume_hibernating = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_uptime = function (descriptor) { - lnn.parser.check_reused('uptime', descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(2, 'uptime', words) +parser.descriptors.consume_uptime = function (descriptor) { + parser.check_reused('uptime', descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(2, 'uptime', words) let uptime = Number(words[1]) @@ -481,11 +488,11 @@ lnn.parser.descriptors.consume_uptime = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_onion_key = function (descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].split(" ") - lnn.parser.check_reused('onion-key', descriptor) - lnn.parser.check_format(1,'onion-key',words) - return lnn.parser.descriptors.consume_key('onion-key', descriptor) +parser.descriptors.consume_onion_key = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(" ") + parser.check_reused('onion-key', descriptor) + parser.check_format(1, 'onion-key', words) + return parser.descriptors.consume_key('onion-key', descriptor) } /** @@ -493,20 +500,20 @@ lnn.parser.descriptors.consume_onion_key = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_extra_info_digest = function (descriptor) { - lnn.parser.check_reused('extra-info-digest', descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") +parser.descriptors.consume_extra_info_digest = function (descriptor) { + parser.check_reused('extra-info-digest', descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") if (words.length != 2 && words.length != 3) throw `Invalid format: 1 or 2 fields are expected` let sha1 = words[1] - if (!lnn.parser.is_valid_hex(sha1)) throw `Invalid encoding: the sha1 digest must be in hexadecimal` + if (!parser.is_valid_hex(sha1)) throw `Invalid encoding: the sha1 digest must be in hexadecimal` descriptor["extra-info-digest"] = { "sha1": sha1 } if (words.length === 3) { let sha256 = words[2] - if (!lnn.parser.is_valid_base64(lnn.parser.add_ending(sha256))) throw `Invalid encoding: the sha256 digest must base 64` + if (!parser.is_valid_base64(parser.add_ending(sha256))) throw `Invalid encoding: the sha256 digest must base 64` descriptor['extra-info-digest']['sha256'] = sha256 } @@ -519,10 +526,10 @@ lnn.parser.descriptors.consume_extra_info_digest = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_single_word_line = function (type, descriptor) { - lnn.parser.check_reused(type, descriptor) +parser.descriptors.consume_single_word_line = function (type, descriptor) { + parser.check_reused(type, descriptor) descriptor[type] = 'true' - ++lnn.parser.descriptors.line_count + ++parser.descriptors.line_count return descriptor } @@ -532,9 +539,9 @@ lnn.parser.descriptors.consume_single_word_line = function (type, descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_onion_key_crosscert = function (descriptor) { - lnn.parser.check_reused('onion-key-crosscert', descriptor) - return lnn.parser.descriptors.consume_key('onion-key-crosscert', descriptor) +parser.descriptors.consume_onion_key_crosscert = function (descriptor) { + parser.check_reused('onion-key-crosscert', descriptor) + return parser.descriptors.consume_key('onion-key-crosscert', descriptor) } /** @@ -542,17 +549,17 @@ lnn.parser.descriptors.consume_onion_key_crosscert = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_ntor_onion_key_crosscert = function (descriptor) { +parser.descriptors.consume_ntor_onion_key_crosscert = function (descriptor) { - lnn.parser.check_reused('ntor-onion-key-crosscert', descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].split(" ") - lnn.parser.check_format(2, 'ntor-onion-key-crosscert', words) + parser.check_reused('ntor-onion-key-crosscert', descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count].split(" ") + parser.check_format(2, 'ntor-onion-key-crosscert', words) let bit = Number(words[1]) if (bit != 0 && bit != 1) throw "Invalid bit for ntor-onion-key-crosscert" - let [offset, cert] = lnn.parser.consume_pem(lnn.parser.descriptors.lines, ++lnn.parser.descriptors.line_count) - lnn.parser.descriptors.line_count += offset + 1 + let [offset, cert] = parser.consume_pem(parser.descriptors.lines, ++parser.descriptors.line_count) + parser.descriptors.line_count += offset + 1 descriptor['ntor-onion-key-crosscert'] = { "bit": bit, @@ -568,14 +575,14 @@ lnn.parser.descriptors.consume_ntor_onion_key_crosscert = function (descriptor) * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_router_sig_ed25519 = function (descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(2, "router-sig-ed25519", words) - lnn.parser.check_reused("router-signatures", descriptor) +parser.descriptors.consume_router_sig_ed25519 = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(2, "router-sig-ed25519", words) + parser.check_reused("router-signatures", descriptor) let signature = words[1] - if (!lnn.parser.is_valid_base64(lnn.parser.add_ending(signature))) throw "Invalid digest: must be a base 64 string" + if (!parser.is_valid_base64(parser.add_ending(signature))) throw "Invalid digest: must be a base 64 string" descriptor["router-signatures"] = { "ed25519": signature, @@ -589,14 +596,14 @@ lnn.parser.descriptors.consume_router_sig_ed25519 = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_router_signature = function (descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count].split(' ') +parser.descriptors.consume_router_signature = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' ') if (words[0] === 'router-signature') { - lnn.parser.check_format(1, 'router-signature', words) - ++lnn.parser.descriptors.line_count + parser.check_format(1, 'router-signature', words) + ++parser.descriptors.line_count - let [offset, signature] = lnn.parser.consume_pem(lnn.parser.descriptors.lines, lnn.parser.descriptors.line_count) - lnn.parser.descriptors.line_count += offset + 1 + let [offset, signature] = parser.consume_pem(parser.descriptors.lines, parser.descriptors.line_count) + parser.descriptors.line_count += offset + 1 if (descriptor["router-signatures"] === undefined) { descriptor["router-signatures"] = {} @@ -613,12 +620,12 @@ lnn.parser.descriptors.consume_router_signature = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_bridge_distribution = function (descriptor) { - lnn.parser.check_reused('bridge-distribution', descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(2, 'bridge-distribution', words) +parser.descriptors.consume_bridge_distribution = function (descriptor) { + parser.check_reused('bridge-distribution', descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(2, 'bridge-distribution', words) let dist = words[1] - if (!lnn.parser.descriptors.valid_bridge_distribution.includes(dist)) dist = "none" + if (!parser.descriptors.valid_bridge_distribution.includes(dist)) dist = "none" descriptor['bridge-distribution'] = dist @@ -631,10 +638,10 @@ lnn.parser.descriptors.consume_bridge_distribution = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_family = function (descriptor) { - lnn.parser.check_reused("family", descriptor) +parser.descriptors.consume_family = function (descriptor) { + parser.check_reused("family", descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") let family = words.splice(1) descriptor['family'] = family @@ -647,17 +654,17 @@ lnn.parser.descriptors.consume_family = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_history = function (type, descriptor) { +parser.descriptors.consume_history = function (type, descriptor) { let field = type + "-history" - lnn.parser.check_reused(field, descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(6, type + "-history", words) + parser.check_reused(field, descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(6, type + "-history", words) let date = words[1] - if (!lnn.parser.is_valid_date(date)) throw "Invalid date" + if (!parser.is_valid_date(date)) throw "Invalid date" let time = words[2] - if (!lnn.parser.is_valid_time(time)) throw "Invalid time" + if (!parser.is_valid_time(time)) throw "Invalid time" let interval = Number(words[3].substring(1)) let bytes = words[5].split(",").map(x => Number(x)) @@ -677,10 +684,10 @@ lnn.parser.descriptors.consume_history = function (type, descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_eventdns = function (descriptor) { - lnn.parser.check_reused("eventdns", descriptor) - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(2, "eventdns", words) +parser.descriptors.consume_eventdns = function (descriptor) { + parser.check_reused("eventdns", descriptor) + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(2, "eventdns", words) let bool = Number(words[1]) @@ -696,14 +703,14 @@ lnn.parser.descriptors.consume_eventdns = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_base64_digest = function (field, descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(2, field, words) - lnn.parser.check_reused(field, descriptor) +parser.descriptors.consume_base64_digest = function (field, descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(2, field, words) + parser.check_reused(field, descriptor) let key = words[1] - if (!lnn.parser.is_valid_base64(lnn.parser.add_ending(key))) throw "Invalid digest: must be a base 64 string" + if (!parser.is_valid_base64(parser.add_ending(key))) throw "Invalid digest: must be a base 64 string" descriptor[field] = key @@ -715,9 +722,9 @@ lnn.parser.descriptors.consume_base64_digest = function (field, descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_signing_key = function (descriptor) { - lnn.parser.check_reused('signing-key', descriptor) - return lnn.parser.descriptors.consume_key('signing-key', descriptor) +parser.descriptors.consume_signing_key = function (descriptor) { + parser.check_reused('signing-key', descriptor) + return parser.descriptors.consume_key('signing-key', descriptor) } /** @@ -726,9 +733,9 @@ lnn.parser.descriptors.consume_signing_key = function (descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_exit_policy = function (type, descriptor) { - let words = lnn.parser.descriptors.lines[lnn.parser.descriptors.line_count++].split(" ") - lnn.parser.check_format(2, type, words) +parser.descriptors.consume_exit_policy = function (type, descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" ") + parser.check_format(2, type, words) if (descriptor['policy'] === undefined) { descriptor['policy'] = { @@ -753,9 +760,9 @@ lnn.parser.descriptors.consume_exit_policy = function (type, descriptor) { * @param {object} descriptor the currently being built decriptors object * @returns {Object} the updated descriptor */ -lnn.parser.descriptors.consume_key = function (field, descriptor) { - [offset, key] = lnn.parser.consume_pem(lnn.parser.descriptors.lines, ++lnn.parser.descriptors.line_count) - lnn.parser.descriptors.line_count += offset + 1 +parser.descriptors.consume_key = function (field, descriptor) { + let [offset, key] = parser.consume_pem(parser.descriptors.lines, ++parser.descriptors.line_count) + parser.descriptors.line_count += offset + 1 descriptor[field] = key return descriptor } @@ -766,7 +773,7 @@ lnn.parser.descriptors.consume_key = function (field, descriptor) { * @param {string} expected_word the expected word * @param {Array} words the line splitted into words */ -lnn.parser.check_format = function (expected_length, expected_word, words) { +parser.check_format = function (expected_length, expected_word, words) { if (words.length != expected_length) { throw `wrong_format_exception: ${expected_length} fields are expected` } else if (words[0] !== expected_word) { @@ -778,7 +785,7 @@ lnn.parser.check_format = function (expected_length, expected_word, words) { * Check if the IP is an IPv4 address * @param {string} IP */ -lnn.parser.is_valid_ipv4 = function (IP) { +parser.is_valid_ipv4 = function (IP) { let regex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ return regex.test(IP) } @@ -787,7 +794,7 @@ lnn.parser.is_valid_ipv4 = function (IP) { * Check if the given port is valid * @param {number} port */ -lnn.parser.is_valid_port = function (port) { +parser.is_valid_port = function (port) { if (isNaN(port)) return false return port >= 0 && port <= 65535 } @@ -797,7 +804,7 @@ lnn.parser.is_valid_port = function (port) { * @param {string} nickname the nickname we want to verify * @returns {boolean} the validity of the nickname */ -lnn.parser.is_valid_nickname = function (nickname) { +parser.is_valid_nickname = function (nickname) { let regex = /^[a-z0-9]+$/i return regex.test(nickname) } @@ -806,7 +813,7 @@ lnn.parser.is_valid_nickname = function (nickname) { * Check if the given string is in base 64 * @param {string} str */ -lnn.parser.is_valid_base64 = function (str) { +parser.is_valid_base64 = function (str) { let regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/ return regex.test(str) } @@ -814,7 +821,7 @@ lnn.parser.is_valid_base64 = function (str) { * Check if the given string is in hexadecimal * @param {string} str */ -lnn.parser.is_valid_hex = function (str) { +parser.is_valid_hex = function (str) { let regex = /^[a-fA-F0-9]+$/ return regex.test(str) } @@ -826,7 +833,7 @@ lnn.parser.is_valid_hex = function (str) { * @param {function} base_function optional function to verifiy the base * @returns {Array} tuple containing the parsed pem and the offset */ -lnn.parser.consume_pem = function (lines, start) { +parser.consume_pem = function (lines, start) { let offset = 0; let content = '' if (!lines[start].startsWith('-----BEGIN')) throw `Invalid signature, certificate or key: must begin with "-----BEGIN"` @@ -836,7 +843,7 @@ lnn.parser.consume_pem = function (lines, start) { offset++ } - if (!lnn.parser.is_valid_base64(content)) throw "Invalid PEM: must be in base 64" + if (!parser.is_valid_base64(content)) throw "Invalid PEM: must be in base 64" return [offset, content] } @@ -846,12 +853,12 @@ lnn.parser.consume_pem = function (lines, start) { * @param {string} ranges format: Keyword=Values... * @returns {object} the parsed ranges */ -lnn.parser.parse_range = function (ranges) { +parser.parse_range = function (ranges) { let content = {} for (let pair of ranges) { if (pair.includes("=")) { let tmp = pair.split("=") - content[tmp[0]] = lnn.parser.parse_range_once(tmp[1]) + content[tmp[0]] = parser.parse_range_once(tmp[1]) } } return content @@ -862,7 +869,7 @@ lnn.parser.parse_range = function (ranges) { * @param {string} value the sting we want to parse * @returns {Array} a list containing the ranges */ -lnn.parser.parse_range_once = function (value) { +parser.parse_range_once = function (value) { value = value.split(',') let subvalues = [] @@ -888,18 +895,18 @@ lnn.parser.parse_range_once = function (value) { * @param {object} node the node we want to update * @returns the updated node */ -lnn.parser.consume_exit_policy = function (field, lines, index, node) { - lnn.parser.check_reused(field, node) +parser.consume_exit_policy = function (field, lines, index, node) { + parser.check_reused(field, node) let words = lines[index].split(" ") - lnn.parser.check_format(3, field, words) + parser.check_format(3, field, words) let policy = words[1] if (policy !== 'accept' && policy !== 'reject') throw "Invalid policy: policy must either be accept or reject" - let ranges = lnn.parser.parse_range_once(words[2]) - - if(field == 'p') field = 'policy' - if(field == 'p6') field = 'ipv6-policy' + let ranges = parser.parse_range_once(words[2]) + + if (field == 'p') field = 'policy' + if (field == 'p6') field = 'ipv6-policy' node[field] = { 'type': policy, @@ -917,8 +924,8 @@ lnn.parser.consume_exit_policy = function (field, lines, index, node) { * @param {object} node the node we want to update * @returns the updated node */ -lnn.parser.consume_contact = function (lines, index, node) { - lnn.parser.check_reused("contact", node) +parser.consume_contact = function (lines, index, node) { + parser.check_reused("contact", node) let contact = lines[index].substring("contact".length + 1) node["contact"] = contact @@ -930,7 +937,7 @@ lnn.parser.consume_contact = function (lines, index, node) { * Check if the string in date has the format YYYY-MM-DD * @param {string} time String representing the date */ -lnn.parser.is_valid_date = function (date) { +parser.is_valid_date = function (date) { if (typeof date !== 'string') return false let regex = /^\d{4}[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$/ return regex.test(date) @@ -939,7 +946,7 @@ lnn.parser.is_valid_date = function (date) { /**Check if the string time has the format HH:MM:SS * @param {string} time String representing the time */ -lnn.parser.is_valid_time = function (time) { +parser.is_valid_time = function (time) { if (typeof time !== 'string') return false let regex = /^(0[0-9]|1[0-9]|2[0-3])[:][0-5][0-9][:][0-5][0-9]$/ return regex.test(time) @@ -951,12 +958,12 @@ lnn.parser.is_valid_time = function (time) { * @param {string} line the line we are consuming * @returns {object} object containing both the date and the time */ -lnn.parser.consume_date = function (field, line) { +parser.consume_date = function (field, line) { let words = line.split(" ") - lnn.parser.check_format(3, field, words) + parser.check_format(3, field, words) - if (!lnn.parser.is_valid_date(words[1])) throw `Invalid date: ${words[1]} is not a valid date` - if (!lnn.parser.is_valid_time(words[2])) throw `Invalid time: ${words[2]} is not a valid time` + if (!parser.is_valid_date(words[1])) throw `Invalid date: ${words[1]} is not a valid date` + if (!parser.is_valid_time(words[2])) throw `Invalid time: ${words[2]} is not a valid time` return { "date": words[1], @@ -972,10 +979,10 @@ lnn.parser.consume_date = function (field, line) { * @param {object} node the node we want to update * @returns the updated node */ -lnn.parser.consume_proto = function (type, lines, index, node) { - lnn.parser.check_reused(type, node) +parser.consume_proto = function (type, lines, index, node) { + parser.check_reused(type, node) let ranges = lines[index].split(" ").splice(1) - node[type] = lnn.parser.parse_range(ranges) + node[type] = parser.parse_range(ranges) return node } @@ -984,7 +991,7 @@ lnn.parser.consume_proto = function (type, lines, index, node) { * @param {string} field the field we want to verify * @param {object} node the node for which we don't want a repetition of field */ -lnn.parser.check_reused = function (field, node) { +parser.check_reused = function (field, node) { if (node[field] !== undefined) throw `The field ${field} appears more than once` } @@ -993,7 +1000,7 @@ lnn.parser.check_reused = function (field, node) { * @param {string} str the string we want to modify * @returns {string} base 64 string with correct ending = */ -lnn.parser.add_ending = function (str) { +parser.add_ending = function (str) { if (str.length % 4 !== 0) { let rem = str.length % 4 for (let i = 0; i < 4 - rem; i++) str += '=' @@ -1001,7 +1008,4 @@ lnn.parser.add_ending = function (str) { return str } - - - - +export { parser } \ No newline at end of file diff --git a/js-client/src/path.js b/js-client/src/path.js index 429ad4c..37c6576 100644 --- a/js-client/src/path.js +++ b/js-client/src/path.js @@ -1,57 +1,60 @@ +/** + * @module path + */ -lnn.path = {} +let path = {} /** - * This function selects a lnn.path from the parsed consensus and parsed descriptors + * This function selects a path from the parsed consensus and parsed descriptors * Flavor is 'unflavored' * * @param {Object} consensus a parsed consensus * @param {Object} descriptors parsed descriptors of the routers in the consensus - * @param {Bool} isChutney boolean used to indicate if the lnn.path selection is done with routers from chutney + * @param {Bool} isChutney boolean used to indicate if the path selection is done with routers from chutney */ -lnn.path.select = function (consensus, descriptors, isChutney) { - if(isChutney === undefined){ - lnn.path["isChutney"] = false - }else{ - lnn.path["isChutney"] = isChutney +path.select = function (consensus, descriptors, isChutney) { + if (isChutney === undefined) { + path["isChutney"] = false + } else { + path["isChutney"] = isChutney } //build a hashmap of descriptor where the keys are the identity - lnn.path["descriptorsMap"] = {} + path["descriptorsMap"] = {} for (let descriptor of descriptors) { let identity = descriptor['router'].identity - lnn.path.descriptorsMap[identity] = descriptor + path.descriptorsMap[identity] = descriptor } //pre-process consensus by filering the routers that do not obey //the minimal constraints - lnn.path["consensus"] = consensus['routers'].filter(r => lnn.path.obeyMinimalConstraints(r)) - - //lnn.path selection - lnn.path["exit"] = lnn.path.chooseGoodExit(consensus) - lnn.path["guard"] = lnn.path.chooseGoodGuard(consensus) - lnn.path["middle"] = lnn.path.chooseGoodMiddle(consensus) - - //TODO: it should create/return a new lnn.path and not the descriptors - return [lnn.path.guard, lnn.path.middle, lnn.path.exit] + path["consensus"] = consensus['routers'].filter(r => path.obeyMinimalConstraints(r)) + + //path selection + path["exit"] = path.chooseGoodExit(consensus) + path["guard"] = path.chooseGoodGuard(consensus) + path["middle"] = path.chooseGoodMiddle(consensus) + + //TODO: it should create/return a new path and not the descriptors + return [path.guard, path.middle, path.exit] } //assumes microdesc flavor. -lnn.path.select_end_path = function (consensus, descriptors,guard, isChutney, tcp_ports) { - if(isChutney === undefined){ - lnn.path["isChutney"] = false - }else{ - lnn.path["isChutney"] = isChutney +path.select_end_path = function (consensus, descriptors, guard, isChutney, tcp_ports) { + if (isChutney === undefined) { + path["isChutney"] = false + } else { + path["isChutney"] = isChutney } //build a hashmap of descriptor where the keys are the identity let consMap = {} - for(let router of consensus['routers']) { + for (let router of consensus['routers']) { consMap[router['micro-digest']] = router } - lnn.path["descriptorsMap"] = {} + path["descriptorsMap"] = {} for (let descriptor of descriptors) { descriptor['router'] = consMap[descriptor['micro-digest']] @@ -59,23 +62,23 @@ lnn.path.select_end_path = function (consensus, descriptors,guard, isChutney, tc descriptor['bandwidth']['avg'] = descriptor['router']['w']['Bandwidth'] let identity = descriptor['router'].identity - lnn.path.descriptorsMap[identity] = descriptor + path.descriptorsMap[identity] = descriptor } //pre-process consensus by filering the routers that do not obey //the minimal constraints console.log(consensus['routers'].length) console.log(descriptors.length) - lnn.path["consensus"] = consensus['routers'].filter(r => lnn.path.obeyMinimalConstraints(r)) - console.log(lnn.path["consensus"].length) + path["consensus"] = consensus['routers'].filter(r => path.obeyMinimalConstraints(r)) + console.log(path["consensus"].length) - //lnn.path selection - lnn.path["guard"] = guard - lnn.path["exit"] = lnn.path.chooseGoodExitGivenGuard(tcp_ports) - lnn.path["middle"] = lnn.path.chooseGoodMiddle() + //path selection + path["guard"] = guard + path["exit"] = path.chooseGoodExitGivenGuard(tcp_ports) + path["middle"] = path.chooseGoodMiddle() - //TODO: it should create/return a new lnn.path and not the descriptors - return [lnn.path.middle, lnn.path.exit] + //TODO: it should create/return a new path and not the descriptors + return [path.middle, path.exit] } /** @@ -83,11 +86,11 @@ lnn.path.select_end_path = function (consensus, descriptors,guard, isChutney, tc * * @param {Object} router the router subpart of one of the nodes of the parsed consensus */ -lnn.path.obeyMinimalConstraints = function (router) { - let des = lnn.path.descriptorsMap[router['identity']] +path.obeyMinimalConstraints = function (router) { + let des = path.descriptorsMap[router['identity']] let flags = router['flags'] - - if(des === undefined) return false + + if (des === undefined) return false if (!flags.includes("Valid")) return false if (!flags.includes("Running")) return false if (!router['version'].startsWith("Tor 0.3.")) return false @@ -103,29 +106,29 @@ lnn.path.obeyMinimalConstraints = function (router) { * @param {Array} candidates the list of candidates */ -lnn.path.weightedRandomChoice = function (candidates) { +path.weightedRandomChoice = function (candidates) { let total = 0 - - for(let candidate of candidates){ - let des =lnn.path.descriptorsMap[candidate['identity']] - if(des !== undefined){ + + for (let candidate of candidates) { + let des = path.descriptorsMap[candidate['identity']] + if (des !== undefined) { total += des['bandwidth']['avg'] } } - + let r = Math.random() * total let upto = 0 for (let router of candidates) { - let des = lnn.path.descriptorsMap[router['identity']] + let des = path.descriptorsMap[router['identity']] - if(des !== undefined){ + if (des !== undefined) { let bandwidth = des['bandwidth']['avg'] if (upto + bandwidth >= r) return des else upto += bandwidth } - + } throw "No candidate has been chosen" @@ -138,9 +141,9 @@ lnn.path.weightedRandomChoice = function (candidates) { * @param {Object} des2 the descriptor of the second router * */ -lnn.path.inSame16Subnet = function (des1, des2) { +path.inSame16Subnet = function (des1, des2) { - if(lnn.path.isChutney){ + if (path.isChutney) { return false } @@ -156,7 +159,7 @@ lnn.path.inSame16Subnet = function (des1, des2) { * @param {Object} des1 the descriptor of the first router * @param {Object} des2 the descriptor of the second router */ -lnn.path.inSameFamily = function (des1, des2) { +path.inSameFamily = function (des1, des2) { if (des1['family'] != undefined && des2['family'] != undefined) { for (let fam of des1['family']) { if (des2['family'].includes(fam)) return true @@ -167,17 +170,17 @@ lnn.path.inSameFamily = function (des1, des2) { } /** - * This function choose a good exit given the TOR lnn.path selection rules + * This function choose a good exit given the TOR path selection rules */ -lnn.path.chooseGoodExit = function () { - let candidates = lnn.path.consensus.filter(lnn.path.isGoodExit) - return lnn.path.weightedRandomChoice(candidates) +path.chooseGoodExit = function () { + let candidates = path.consensus.filter(path.isGoodExit) + return path.weightedRandomChoice(candidates) } -lnn.path.chooseGoodExitGivenGuard = function (tcp_ports) { - let candidates = lnn.path.consensus.filter(r => lnn.path.isGoodExitGivenGuard(r,tcp_ports)) +path.chooseGoodExitGivenGuard = function (tcp_ports) { + let candidates = path.consensus.filter(r => path.isGoodExitGivenGuard(r, tcp_ports)) console.log("Exit candidates: " + candidates.length) - return lnn.path.weightedRandomChoice(candidates) + return path.weightedRandomChoice(candidates) } /** @@ -185,77 +188,77 @@ lnn.path.chooseGoodExitGivenGuard = function (tcp_ports) { * * @param {Object} router the router subpart of one of the nodes of the parsed consensus */ -lnn.path.isGoodExit = function (router) { +path.isGoodExit = function (router) { let flags = router['flags'] if (!flags.includes('Exit') || flags.includes('BadExit')) return false - if(router['exit-policy'] === undefined ) - router['exit-policy'] = lnn.path.descriptorsMap[router.identity]['policy'] + if (router['exit-policy'] === undefined) + router['exit-policy'] = path.descriptorsMap[router.identity]['policy'] if (router['exit-policy']['type'] !== 'accept') return false return true } -lnn.path.isGoodExitGivenGuard = function (router, tcp_ports) { +path.isGoodExitGivenGuard = function (router, tcp_ports) { let flags = router['flags'] if (!flags.includes('Exit') || flags.includes('BadExit')) return false - let des = lnn.path.descriptorsMap[router.identity] - + let des = path.descriptorsMap[router.identity] + - if(router['exit-policy'] === undefined ) + if (router['exit-policy'] === undefined) router['exit-policy'] = des['policy'] let port_arr = router['exit-policy']['PortList'] - for(i = 0; i < tcp_ports.length; i++) { + for (let i = 0; i < tcp_ports.length; i++) { let found = false let cur_port = tcp_ports[i] - for(j = 0; j < port_arr.length; j++) { - if(port_arr[j][0] == cur_port) { + for (let j = 0; j < port_arr.length; j++) { + if (port_arr[j][0] == cur_port) { found = true break } - else if(port_arr[j].length == 2){ - if(port_arr[j][0] <= cur_port && cur_port <= port_arr[j][1]) { + else if (port_arr[j].length == 2) { + if (port_arr[j][0] <= cur_port && cur_port <= port_arr[j][1]) { found = true break } } } - if(router['exit-policy']['type'] == 'accept') { - if(!found) return false - } + if (router['exit-policy']['type'] == 'accept') { + if (!found) return false + } else { - if(found) return false + if (found) return false } } - if(des === undefined){ + if (des === undefined) { return false } - if(des["router"]["identity"] === lnn.path.guard["router"]["identity"]){ + if (des["router"]["identity"] === path.guard["router"]["identity"]) { return false } - if (lnn.path.inSame16Subnet(des, lnn.path.guard)) return false - if (lnn.path.inSameFamily(des, lnn.path.guard)) return false + if (path.inSame16Subnet(des, path.guard)) return false + if (path.inSameFamily(des, path.guard)) return false return true } /** - * This function choose a good guard given the TOR lnn.path selection rules. + * This function choose a good guard given the TOR path selection rules. * - * Note: this implements a lightweight version of the TOR lnn.path selection, where the selection based on the different + * Note: this implements a lightweight version of the TOR path selection, where the selection based on the different * sets is put aside * */ -lnn.path.chooseGoodGuard = function () { - let candidates = lnn.path.consensus.filter(r => lnn.path.isGoodGuard(r)) - return lnn.path.weightedRandomChoice(candidates) +path.chooseGoodGuard = function () { + let candidates = path.consensus.filter(r => path.isGoodGuard(r)) + return path.weightedRandomChoice(candidates) } /** @@ -263,33 +266,33 @@ lnn.path.chooseGoodGuard = function () { * * @param {Object} router the router subpart of one of the nodes of the parsed consensus */ -lnn.path.isGoodGuard = function (router) { +path.isGoodGuard = function (router) { let flags = router['flags'] - let des = lnn.path.descriptorsMap[router.identity] + let des = path.descriptorsMap[router.identity] - if(des === undefined){ + if (des === undefined) { return false } - if(des["router"]["identity"] === lnn.path.exit["router"]["identity"]){ + if (des["router"]["identity"] === path.exit["router"]["identity"]) { return false } if (!flags.includes('Guard')) return false if (!flags.includes('Stable')) return false if (!flags.includes('V2Dir')) return false - if (lnn.path.inSame16Subnet(des, lnn.path.exit)) return false - if (lnn.path.inSameFamily(des, lnn.path.exit)) return false + if (path.inSame16Subnet(des, path.exit)) return false + if (path.inSameFamily(des, path.exit)) return false return true } /** - * This function choose a good middle given the TOR lnn.path selection rules + * This function choose a good middle given the TOR path selection rules */ -lnn.path.chooseGoodMiddle = function () { - let candidates = lnn.path.consensus.filter(r => lnn.path.isGoodMiddle(r)) - return lnn.path.weightedRandomChoice(candidates) +path.chooseGoodMiddle = function () { + let candidates = path.consensus.filter(r => path.isGoodMiddle(r)) + return path.weightedRandomChoice(candidates) } /** @@ -297,22 +300,24 @@ lnn.path.chooseGoodMiddle = function () { * * @param {Object} router the router subpart of one of the nodes of the parsed consensus */ -lnn.path.isGoodMiddle = function (router) { - let des = lnn.path.descriptorsMap[router.identity] +path.isGoodMiddle = function (router) { + let des = path.descriptorsMap[router.identity] - if(des === undefined){ + if (des === undefined) { return false } - if(des["router"]["identity"] === lnn.path.exit["router"]["identity"] ||des["router"]["identity"] === lnn.path.guard["router"]["identity"]){ + if (des["router"]["identity"] === path.exit["router"]["identity"] || des["router"]["identity"] === path.guard["router"]["identity"]) { return false } - if (lnn.path.inSame16Subnet(des, lnn.path.guard)) return false - if (lnn.path.inSame16Subnet(des, lnn.path.exit)) return false - if (lnn.path.inSameFamily(des, lnn.path.guard)) return false - if (lnn.path.inSameFamily(des, lnn.path.exit)) return false + if (path.inSame16Subnet(des, path.guard)) return false + if (path.inSame16Subnet(des, path.exit)) return false + if (path.inSameFamily(des, path.guard)) return false + if (path.inSameFamily(des, path.exit)) return false return true } + +export { path }; \ No newline at end of file diff --git a/js-client/src/post.js b/js-client/src/post.js index c0c3dde..d8385b6 100644 --- a/js-client/src/post.js +++ b/js-client/src/post.js @@ -1,57 +1,64 @@ -lnn.post = {} -lnn.post.create = function(endpoint, success, error) -{ +/** + * @module post + */ + + +import { ntor } from "./ntor.js"; +import { enc, dec } from "./util.js"; +import * as onion from "./onion.js"; +import { consensusParser } from "./consensusParser.js"; +import { parser } from "./parser.js"; +import { relay } from "./relay.js"; +import { path } from "./path.js" + + + +export function create(endpoint, success, error) { var rq = new XMLHttpRequest() - rq.onreadystatechange = function() - { - if (rq.readyState == 4 && rq.status == 201) - { + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 201) { var info = JSON.parse(rq.responseText) - if (endpoint.auth != null) - { - info = lnn.ntor.auth(endpoint, info["auth"], info["data"]) + if (endpoint.auth != null) { + info = ntor.auth(endpoint, info["auth"], info["data"]) } endpoint.id = info["id"] endpoint.url = endpoint.urls.channels + "/" + info["id"] endpoint.path = info["path"] - if (endpoint.fast) - { + if (endpoint.fast) { endpoint.guard = info["guard"] - endpoint.material.identity = lnn.dec.base64( + endpoint.material.identity = dec.base64( info["guard"].router.identity + "=") - endpoint.material.onionkey = lnn.dec.base64( + endpoint.material.onionkey = dec.base64( info["guard"]["ntor-onion-key"]) } - var material = lnn.ntor.shake(endpoint, info["ntor"]) + var material = ntor.shake(endpoint, info["ntor"]) if (material == null) throw "Invalid guard handshake." - material = lnn.ntor.slice(material) + material = ntor.slice(material) endpoint.material = material - endpoint.forward = lnn.onion.forward(endpoint) - endpoint.backward = lnn.onion.backward(endpoint) + endpoint.forward = onion.forward(endpoint) + endpoint.backward = onion.backward(endpoint) if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4 && error !== undefined) - { + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } var payload = null if (endpoint.fast) - payload = lnn.ntor.fast(endpoint) + payload = ntor.fast(endpoint) else - payload = lnn.ntor.hand(endpoint) + payload = ntor.hand(endpoint) - payload = {ntor: payload} - if (endpoint.auth != null) - { - payload["auth"] = lnn.enc.base64(endpoint.auth.ntor.publicKey) + payload = { ntor: payload } + if (endpoint.auth != null) { + payload["auth"] = enc.base64(endpoint.auth.ntor.publicKey) } payload = JSON.stringify(payload) @@ -61,41 +68,35 @@ lnn.post.create = function(endpoint, success, error) } -lnn.post.circuit_info = function(endpoint, success, error, select_path, tcp_ports) -{ - if(select_path === undefined) { +export function circuit_info(endpoint, success, error, select_path, tcp_ports) { + if (select_path === undefined) { select_path = false } var rq = new XMLHttpRequest() - rq.onreadystatechange = function() - { - if (rq.readyState == 4 && rq.status == 201) - { + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 201) { var info = JSON.parse(rq.responseText) - if (endpoint.auth != null) - { - info = lnn.ntor.auth(endpoint, info["auth"], info["data"]) + if (endpoint.auth != null) { + info = ntor.auth(endpoint, info["auth"], info["data"]) } endpoint.id = info["id"] endpoint.url = endpoint.urls.channels + "/" + info["id"] - - if (endpoint.fast) - { + + if (endpoint.fast) { endpoint.guard = info["guard"] } - if(!select_path) + if (!select_path) endpoint.path = info["path"] else { - endpoint.consensus = lnn.consensusParser.parse(endpoint.consensus_raw) - endpoint.descriptors = lnn.parser.descriptors.parse(endpoint.descriptors_raw) - lnn.parser.descriptors.validate(endpoint.descriptors,endpoint.consensus) + endpoint.consensus = consensusParser.parse(endpoint.consensus_raw) + endpoint.descriptors = parser.descriptors.parse(endpoint.descriptors_raw) + parser.descriptors.validate(endpoint.descriptors, endpoint.consensus) - - endpoint.path = lnn.path.select_end_path(endpoint.consensus, endpoint.descriptors, endpoint.guard, true, tcp_ports) + endpoint.path = path.select_end_path(endpoint.consensus, endpoint.descriptors, endpoint.guard, true, tcp_ports) console.log(endpoint.guard) console.log(endpoint.path) } @@ -103,8 +104,7 @@ lnn.post.circuit_info = function(endpoint, success, error, select_path, tcp_port if (success !== undefined) success(endpoint, info) } - else if (rq.readyState == 4 && error !== undefined) - { + else if (rq.readyState == 4 && error !== undefined) { error(endpoint, rq.status) } } @@ -112,14 +112,13 @@ lnn.post.circuit_info = function(endpoint, success, error, select_path, tcp_port var payload = {} /** if (endpoint.fast) - payload = lnn.ntor.fast(endpoint) + payload = ntor.fast(endpoint) else - payload = lnn.ntor.hand(endpoint) + payload = ntor.hand(endpoint) payload = {ntor: payload}*/ - if (endpoint.auth != null) - { - payload["auth"] = lnn.enc.base64(endpoint.auth.ntor.publicKey) + if (endpoint.auth != null) { + payload["auth"] = enc.base64(endpoint.auth.ntor.publicKey) } payload["select_path"] = select_path.toString() payload = JSON.stringify(payload) @@ -129,36 +128,34 @@ lnn.post.circuit_info = function(endpoint, success, error, select_path, tcp_port rq.send(payload) } -lnn.post.handshake = function(endpoint, info, success, error) -{ +export function handshake(endpoint, info, success, error) { //var handshake = info['handshake'] var normal_handler = endpoint.io.handler - var handler = function(endpoint, material) - { + var handler = function (endpoint, material) { endpoint.io.handler = normal_handler //var material = endpoint.io.recv() - material = lnn.ntor.shake(endpoint, material.slice(7, 7+64), false) + material = ntor.shake(endpoint, material.slice(7, 7 + 64), false) if (material == null) throw "Invalid guard handshake." - material = lnn.ntor.slice(material) + material = ntor.slice(material) endpoint.material = material - endpoint.forward = lnn.onion.forward(endpoint) - endpoint.backward = lnn.onion.backward(endpoint) + endpoint.forward = onion.forward(endpoint) + endpoint.backward = onion.backward(endpoint) if (success !== undefined) success(endpoint) } endpoint.io.handler = handler - - var handshake = new Uint8Array(lnn.relay.full_len) - var payload = lnn.ntor.hand(endpoint,endpoint.guard,false) + + var handshake = new Uint8Array(relay.full_len) + var payload = ntor.hand(endpoint, endpoint.guard, false) var view = new DataView(handshake.buffer) @@ -166,22 +163,18 @@ lnn.post.handshake = function(endpoint, info, success, error) view.setUint8(4, 10 /* CREATE2 CELL */, false) view.setUint16(5, 2 /* ntor handshake */, false) view.setUint16(7, payload.length, false) - handshake.set(payload,9) + handshake.set(payload, 9) endpoint.io.send(handshake) } -lnn.post.channel = function(endpoint, success, error) -{ +export function channel(endpoint, success, error) { var rq = new XMLHttpRequest() - rq.onreadystatechange = function() - { - if (rq.readyState == 4 && rq.status == 201) - { + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 201) { var cells = JSON.parse(rq.responseText)["cells"] - if (cells === undefined) - { + if (cells === undefined) { if (endpoint.io.error !== undefined) endpoint.io.error(endpoint) return @@ -191,8 +184,7 @@ lnn.post.channel = function(endpoint, success, error) if (pending > 0 && endpoint.io.success !== undefined) endpoint.io.success(endpoint) - if (cells.length > 0) - { + if (cells.length > 0) { endpoint.io.incoming = endpoint.io.incoming.concat(cells) if (endpoint.io.handler !== undefined) endpoint.io.handler(endpoint) @@ -204,8 +196,7 @@ lnn.post.channel = function(endpoint, success, error) if (success !== undefined) success(endpoint) } - else if (rq.readyState == 4) - { + else if (rq.readyState == 4) { if (endpoint.io.error !== undefined) endpoint.io.error(endpoint) @@ -218,32 +209,29 @@ lnn.post.channel = function(endpoint, success, error) rq.open("POST", endpoint.url, true) rq.setRequestHeader("Content-type", "application/json") - rq.send(JSON.stringify({cells: endpoint.io.outcoming})) + rq.send(JSON.stringify({ cells: endpoint.io.outcoming })) } -lnn.post.extend = function(endpoint, descriptor, success, error) -{ - var hand = lnn.ntor.hand(endpoint, descriptor, false) +export function extend(endpoint, descriptor, success, error) { + var hand = ntor.hand(endpoint, descriptor, false) var eidentity = descriptor["identity"]["master-key"] // (assuming ed25519) var identity = endpoint.material.identity var addr = descriptor["router"]["address"] var port = descriptor["router"]["orport"] - var data = lnn.relay.extend(hand, addr, port, identity, eidentity) - var cell = lnn.onion.build(endpoint, "extend2", 0, data) + var data = relay.extend(hand, addr, port, identity, eidentity) + var cell = onion.build(endpoint, "extend2", 0, data) var extend_error = error var extend_success = success var normal_handler = endpoint.io.handler - var handler = function(endpoint, data) - { + var handler = function (endpoint, data) { endpoint.io.handler = normal_handler - var cell = lnn.onion.peel(endpoint, data) - if (cell == null || cell.cmd != "extended2") - { + var cell = onion.peel(endpoint, data) + if (cell == null || cell.cmd != "extended2") { if (extend_error !== undefined) return extend_error(endpoint) throw "Invalid answer, expecting extended2 cell, fatal!" @@ -251,17 +239,17 @@ lnn.post.extend = function(endpoint, descriptor, success, error) var view = new DataView(cell.data.buffer) var length = view.getUint16(0, false) - var data = cell.data.slice(2, 2+length) + var data = cell.data.slice(2, 2 + length) - var material = lnn.ntor.shake(endpoint, data, false) - material = lnn.ntor.slice(material) + var material = ntor.shake(endpoint, data, false) + material = ntor.slice(material) endpoint.material = material if (material == null && extend_error !== undefined) return extend_error(endpoint) - endpoint.forward = lnn.onion.forward(endpoint) - endpoint.backward = lnn.onion.backward(endpoint) + endpoint.forward = onion.forward(endpoint) + endpoint.backward = onion.backward(endpoint) if (extend_success !== undefined) extend_success(endpoint) @@ -272,18 +260,14 @@ lnn.post.extend = function(endpoint, descriptor, success, error) } -lnn.post.close = function(endpoint, success, error) -{ +export function close(endpoint, success, error) { var rq = new XMLHttpRequest() - rq.onreadystatechange = function() - { - if (rq.readyState == 4 && rq.status == 202) - { + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 202) { if (success !== undefined) success("Circuit closed") } - else if (rq.readyState == 4 && error !== undefined) - { + else if (rq.readyState == 4 && error !== undefined) { error("Error in closing circuit") } } diff --git a/js-client/src/relay.js b/js-client/src/relay.js index 1e83c2e..dcaac65 100644 --- a/js-client/src/relay.js +++ b/js-client/src/relay.js @@ -1,41 +1,46 @@ -lnn.relay = {} -lnn.relay.payload_len = 509 -lnn.relay.data_len = lnn.relay.payload_len - 11 -lnn.relay.full_len = 5 + lnn.relay.payload_len -lnn.relay.cmd = { - "begin" : 1, 1: "begin", - "data" : 2, 2: "data", - "end" : 3, 3: "end", - "connected" : 4, 4: "connected", - "sendme" : 5, 5: "sendme", - "extend" : 6, 6: "extend", - "extended" : 7, 7: "extended", - "truncate" : 8, 8: "truncate", - "truncated" : 9, 9: "truncated", - "drop" : 10, 10: "drop", - "resolve" : 11, 11: "resolve", - "resolved" : 12, 12: "resolved", - "begin_dir" : 13, 13: "begin_dir", - "extend2" : 14, 14: "extend2", - "extended2" : 15, 15: "extended2" - } +/** + * @module relay + */ + +import { dec } from "./util.js"; + +let relay = {} +relay.payload_len = 509 +relay.data_len = relay.payload_len - 11 +relay.full_len = 5 + relay.payload_len +relay.cmd = { + "begin": 1, 1: "begin", + "data": 2, 2: "data", + "end": 3, 3: "end", + "connected": 4, 4: "connected", + "sendme": 5, 5: "sendme", + "extend": 6, 6: "extend", + "extended": 7, 7: "extended", + "truncate": 8, 8: "truncate", + "truncated": 9, 9: "truncated", + "drop": 10, 10: "drop", + "resolve": 11, 11: "resolve", + "resolved": 12, 12: "resolved", + "begin_dir": 13, 13: "begin_dir", + "extend2": 14, 14: "extend2", + "extended2": 15, 15: "extended2" +} -lnn.relay.pack = function(cmd, stream_id, data) -{ +relay.pack = function (cmd, stream_id, data) { if (data === undefined) data = new Uint8Array(0) if (stream_id === undefined) stream_id = 0 - if (typeof(data) == "string") - data = lnn.dec.utf8(data) + if (typeof (data) == "string") + data = dec.utf8(data) - var cell = new Uint8Array(lnn.relay.full_len) /* padded with \x00 */ + var cell = new Uint8Array(relay.full_len) /* padded with \x00 */ var view = new DataView(cell.buffer) view.setUint32(0, 2147483648 /* fake circuit_id */, false) view.setUint8(4, 3 /* RELAY CELL */, false) - view.setUint8(5, lnn.relay.cmd[cmd], false) + view.setUint8(5, relay.cmd[cmd], false) view.setUint16(6, 0 /* recognized */, false) view.setUint16(8, stream_id, false) // (implicit 4-bytes zeroed digest at offset 10) @@ -45,18 +50,17 @@ lnn.relay.pack = function(cmd, stream_id, data) return cell } -lnn.relay.extend = function(handshake, host, port, identity, eidentity) -{ +relay.extend = function (handshake, host, port, identity, eidentity) { // (assuming that host is an IPv4) var addr = new Uint8Array(host.split(".")) if (addr.join(".") != host) throw "Invalid extend IPv4 address, fatal." port = parseInt(port) - if (typeof(identity) == "string") - identity = lnn.dec.base64(identity) - if (typeof(eidentity) == "string") - eidentity = lnn.dec.base64(eidentity + "=") + if (typeof (identity) == "string") + identity = dec.base64(identity) + if (typeof (eidentity) == "string") + eidentity = dec.base64(eidentity + "=") var nspec = 2 if (eidentity !== undefined) @@ -86,8 +90,7 @@ lnn.relay.extend = function(handshake, host, port, identity, eidentity) view.setUint8(off, identity.length, false); off += 1 data.set(identity, off); off += identity.length - if (nspec == 3) - { + if (nspec == 3) { view.setUint8(off, 3 /* Ed25519 identity specifier */, false); off += 1 view.setUint8(off, eidentity.length, false); off += 1 data.set(eidentity, off); off += eidentity.length @@ -100,9 +103,8 @@ lnn.relay.extend = function(handshake, host, port, identity, eidentity) return data } -lnn.relay.begin = function(host, port) -{ - valid = false +relay.begin = function (host, port) { + let valid = false if (host.match("(\\d\+\\.){3}\\d\+")) valid = true if (host.match("^\\[[\\d:]*\\]$")) @@ -116,11 +118,13 @@ lnn.relay.begin = function(host, port) if (!valid) throw "Invalid host provided?" - var address = lnn.dec.utf8(host + ":" + port) + var address = dec.utf8(host + ":" + port) var data = new Uint8Array(address.length + 1 + 4) // (1o null, 4o flags) data.set(address, 0) - data[address.length+1+3] = 5 // flags IPv6 okay+preferred and IPv4 okay + data[address.length + 1 + 3] = 5 // flags IPv6 okay+preferred and IPv4 okay return data } + +export { relay } \ No newline at end of file diff --git a/js-client/src/signature.js b/js-client/src/signature.js index c246436..6ee2906 100644 --- a/js-client/src/signature.js +++ b/js-client/src/signature.js @@ -1,4 +1,10 @@ -lnn.signature = {} +/** + * @module signature + */ + +import bigInt from "big-integer"; +import { sjcl } from "../vendor/sjcl.js"; +import { lnn } from "./header.js"; /** * This function verifies the given raw consensus @@ -20,7 +26,7 @@ lnn.signature = {} * @param {Number} minimal the minimal percentage of the signatures that must be verified in order to verify the consensus * @returns {Boolean} the result of the verification */ -lnn.signature.verify = function (raw_cons, keys, minimal, flavor = 'microdesc') { +export function verify(raw_cons, keys, minimal, flavor = 'microdesc') { if (minimal === undefined) { minimal = 0.5 } else if (minimal <= 0 || minimal > 1) { @@ -38,22 +44,22 @@ lnn.signature.verify = function (raw_cons, keys, minimal, flavor = 'microdesc') hash = sjcl.codec.hex.fromBits(hash) // Get the signatures and the signing keys - let sig_and_keys_digests = lnn.signature.get_sig_and_keys_digests(split_cons.splice(1)) + let sig_and_keys_digests = get_sig_and_keys_digests(split_cons.splice(1)) for (let fingerprint in sig_and_keys_digests) { total++ - + let key = keys[fingerprint] let e = bigInt(key["exponent"]) let n = bigInt(key["modulus"]) let key_digest = sig_and_keys_digests[fingerprint]["signing-key-digest"] - if (key === undefined || !lnn.signature.verify_key(key["pem"], key_digest)) continue + if (key === undefined || !verify_key(key["pem"], key_digest)) continue let signature = sig_and_keys_digests[fingerprint]["signature"] - let sig_big_int = lnn.signature.get_signature_big_int(signature) - let padded_hash = lnn.signature.get_hash(sig_big_int, e, n) - let recovered_hash = lnn.signature.get_hash_from_rsa_cipher(padded_hash) + let sig_big_int = get_signature_big_int(signature) + let padded_hash = get_hash(sig_big_int, e, n) + let recovered_hash = get_hash_from_rsa_cipher(padded_hash) nbr_verified = (recovered_hash === undefined || recovered_hash !== hash) ? nbr_verified : nbr_verified + 1 } @@ -69,7 +75,7 @@ lnn.signature.verify = function (raw_cons, keys, minimal, flavor = 'microdesc') * @param {BigInteger} modulus the modulus of the key * @returns {String} the padded hash */ -lnn.signature.get_hash = function (signature, exponent, modulus) { +export function get_hash(signature, exponent, modulus) { let padded_hash = signature.modPow(exponent, modulus).toString(16) let size = modulus.toString(16).length let offset = size - padded_hash.length @@ -85,7 +91,7 @@ lnn.signature.get_hash = function (signature, exponent, modulus) { * @param {string} key the key with the format pem * @param {string} key_digest the hex digest extracted from the consensus */ -lnn.signature.verify_key = function (key, key_digest) { +export function verify_key(key, key_digest) { let raw_key = key.split('\n') let b_index = raw_key.indexOf("-----BEGIN RSA PUBLIC KEY-----") let e_index = raw_key.indexOf("-----END RSA PUBLIC KEY-----") @@ -108,7 +114,7 @@ lnn.signature.verify_key = function (key, key_digest) { * signature * } */ -lnn.signature.get_sig_and_keys_digests = function (remaining) { +export function get_sig_and_keys_digests(remaining) { let sign_and_digests = {} for (let r of remaining) { if (r !== '') { @@ -128,13 +134,14 @@ lnn.signature.get_sig_and_keys_digests = function (remaining) { } return sign_and_digests } + /** * * This function transforms a signature in base64 into a bigInteger * @param {string} signature the signature encoded in base64 * @returns {BigInteger} the integer corresponding to the signature */ -lnn.signature.get_signature_big_int = function (signature) { +export function get_signature_big_int(signature) { let sig_hex = sjcl.codec.hex.fromBits(sjcl.codec.base64.toBits(signature)) let sig = bigInt(sig_hex, 16) return sig @@ -146,7 +153,7 @@ lnn.signature.get_signature_big_int = function (signature) { * @param {string} cipher the padded hash of the consensus * @returns {string} the hash of the consensus */ -lnn.signature.get_hash_from_rsa_cipher = function (padded_hash) { +export function get_hash_from_rsa_cipher(padded_hash) { if (!padded_hash.startsWith("0001")) return undefined padded_hash = padded_hash.substring(4) diff --git a/js-client/src/stream.js b/js-client/src/stream.js index 966b6da..5ca088a 100644 --- a/js-client/src/stream.js +++ b/js-client/src/stream.js @@ -1,420 +1,446 @@ -lnn.stream = {} -lnn.stream.entrancy = 0 -lnn.stream.backend = function(error) -{ - var sendme = function(cell, endpoint) - { - if (cell.cmd == "sendme"){ - endpoint.stream.sendme += 1 - endpoint.stream.deliverywindow += 100 - //flush the send queue for the circuit - - while(endpoint.stream.deliverywindow > 0 && endpoint.stream.tosend.length > 0) { - var cell = endpoint.stream.tosend.shift() - endpoint.io.send(cell) - endpoint.stream.deliverywindow -= 1 +/** + * @module stream + */ + +import { lnn } from "./header.js"; +import * as onion from "./onion.js"; +import { enc, dec } from "./util.js"; +import { relay } from "./relay.js"; + +let stream = {}; +stream.entrancy = 0; + +class Backend { + constructor(error) { + const sendMe = function (cell, endpoint) { + if (cell.cmd == "sendme") { + endpoint.stream.sendme += 1; + endpoint.stream.deliverywindow += 100; + // flush the send queue for the circuit + + while (endpoint.stream.deliverywindow > 0 && endpoint.stream.tosend.length > 0) { + const ncell = endpoint.stream.tosend.shift(); + endpoint.io.send(ncell); + endpoint.stream.deliverywindow -= 1; + } + } else { + error(endpoint); + throw "Got unexpected control cell."; } + }; + + this.id = 0; + this.tosend = []; + this.sendme = 0; + this.handles = { 0: { callback: sendMe } }; + this.packagewindow = 1000; // circuit-level receiving window + this.deliverywindow = 1000; // circuit level sending window + } + + register(handle) { + this.id += 1; + handle.id = this.id; + handle.packagewindow = 500; // stream-level receiving window + handle.deliverywindow = 500; // stream level sending window + this.handles[this.id] = handle; + return this.id; + } + + send(cell, endpoint) { + if (this.deliverywindow > 0) { + // if we can send + endpoint.io.send(cell); + this.deliverywindow -= 1; + } else { + // add to the send queue, will be sent when "sendme" is received. + this.tosend.push(cell); + } + } + +} + +class Raw { + constructor(endpoint, handler) { + this.id = null; + this.data = []; + this.cell = null; + this.state = lnn.state.started; + this.packagewindow = null; + this.deliverywindow = null; + this.tosend = []; + this.endpoint = endpoint; + this.handler = handler; + + // let id = endpoint.stream.register(this); + this.handler(this); + } + + send(cmd, data) { + const cell = onion.build( + this.endpoint, cmd, this.id, data); + + if (cmd != "data") { + this.endpoint.io.send(cell); // non-data cells dont affect congestion control + return; } - else - { - error(endpoint) - throw "Got unexpected control cell." + + if (this.deliverywindow > 0) { // send if stream level window is non zero + this.endpoint.stream.send(cell, this.endpoint); // send thru circuit level window + this.deliverywindow -= 1; + } else { + this.tosend.push(cell); // add to queue of stream level window } } - var backend = { - id: 0, - tosend: [], - sendme: 0, - handles: {0: {callback: sendme}}, - packagewindow: 1000, // (circuit-level receiving window) - deliverywindow: 1000,// circuit level sending window - register: function(handle) - { - backend.id += 1 - handle.id = backend.id - handle.packagewindow = 500 // (stream-level receiving window) - handle.deliverywindow = 500// stream level sending window - backend.handles[backend.id] = handle - return backend.id - }, - send: function(cell, endpoint) - { - if(backend.deliverywindow > 0) { //if we can send - endpoint.io.send(cell) - backend.deliverywindow -= 1 - } - else { ///add to the send queue, will be sent when "sendme" is received. - backend.tosend.push(cell) + recv() { + const data = this.data; + this.data = []; + return data; + } + + callback(cell) { + if (cell.cmd == "connected") { + this.state = lnn.state.created; + } + if (cell.cmd == "end") { + this.state = lnn.state.success; + } + + if (cell.cmd == "sendme") { // receive stream level sendme + this.deliverywindow += 50; + while (this.deliverywindow > 0 && this.tosend.length > 0) { + const ncell = this.tosend.shift(); + this.endpoint.stream.send(ncell, this.endpoint); + this.deliverywindow -= 1; } } + + this.data.push(cell); + this.handler(this); + + if (cell.cmd == "connected") { + this.state = lnn.state.pending; + } } - return backend } -lnn.stream.handler = function(endpoint, cell) -{ - lnn.stream.entrancy += 1 - if(lnn.stream.entrancy > 1) { - console.log("ENTRANCY BUG") +class Dir { + constructor(endpoint, path, handler) { + this.id = null; + this.data = ""; + this.cell = null; + this.state = lnn.state.started; + this.packagewindow = null; + this.deliverywindow = null; + this.tosend = []; + this.endpoint = endpoint; + + this.handler = handler; + this.path = path; + + const id = endpoint.stream.register(this); + let cell = onion.build(endpoint, "begin_dir", id); + endpoint.io.send(cell); + + let data = "GET " + path + " HTTP/1.0\r\n"; + data += "Accept-Encoding: identity\r\n\r\n"; + data = dec.utf8(data); + + cell = onion.build(endpoint, "data", id, data); + this.deliverywindow -= 1; + endpoint.stream.send(cell, endpoint); + + this.handler(this); } - if (cell[4] != 3) // (relay cell only) - { - console.log("Got non-relay cell, dropped: ", cell[4]) - lnn.stream.entrancy -= 1 - return + send() { + throw "No send method on directory streams."; } - cell = lnn.onion.peel(endpoint, cell) - if (cell == null) - { - console.log("Got invalid cell, dropped.") - lnn.stream.entrancy -= 1 - return + recv() { + const data = this.data; + this.data = ""; + return data; } - if (!(cell.stream_id in endpoint.stream.handles)) - { - console.log("Got cell outside stream, dropped: ", cell.stream_id) - lnn.stream.entrancy -= 1 - return + callback(cell) { + if (cell.cmd == "connected") { + this.state = lnn.state.created; + this.handler(this); + this.state = lnn.state.pending; + } + if (cell.cmd == "end") { + this.state = lnn.state.success; + this.handler(this); + } + if (cell.cmd == "sendme") { + this.deliverywindow += 50; + while (this.deliverywindow > 0 && this.tosend.length > 0) { + const ncell = this.tosend.shift(); + this.endpoint.stream.send(ncell, this.endpoint); + this.deliverywindow -= 1; + } + } + + if (cell.cmd != "data") { return; } + + this.data += enc.utf8(cell.data); + this.handler(this); } +} - var handle = endpoint.stream.handles[cell.stream_id] - if (cell.cmd == "end") - delete endpoint.stream.handles[cell.stream_id] +class TCP { + constructor(endPoint, host, port, handler) { + this.id = null; + this.data = new Uint8Array(0); + this.cell = null; + this.cache = []; - handle.cell = cell - handle.callback(cell, endpoint) + this.state = lnn.state.started; + this.packagewindow = null; + this.deliverywindow = null; + this.tosend = []; + this.endpoint = endPoint; + this.retries = 0; - /* handle circuit-level sendme */ + this.host = host; + this.port = port; + this.handler = handler; + // WL: Get new identifier for stream? + const id = endPoint.stream.register(this); - if(cell.cmd == "data") { - endpoint.stream.packagewindow -= 1 - } - console.log('Update window: ', endpoint.stream.packagewindow) - if (endpoint.stream.packagewindow < 900) - { - //console.log("Circuit window is ", endpoint.stream.packagewindow) - //console.log("Sending circuit level sendme cell now ", endpoint.io.counter) - endpoint.io.send(lnn.onion.build(endpoint, 'sendme')) - endpoint.stream.packagewindow += 100 - } + // WL: Create a BEGIN package containing host and port of the server? + const data = relay.begin(host, port); + + // WL: Construct the cell around it? + const cell = onion.build(endPoint, "begin", id, data); + + // WL: Send that sell to start the process? + this.endpoint.io.send(cell); + + this.handler(this); + + this.send = this.send.bind(this); - /* handle stream-level sendme */ - if(cell.cmd == "data"){ - handle.packagewindow -= 1 - } - if (handle.packagewindow < 450) - { - //console.log("Stream window is ", handle.packagewindow) - //console.log("Sending stream level sendme cell now ", endpoint.io.counter) - cell = lnn.onion.build(endpoint, 'sendme', handle.id) - endpoint.io.send(cell) - handle.packagewindow += 50 } - lnn.stream.entrancy -= 1 -} + send(send_data) { + if (send_data !== undefined) { + this.cache.push(send_data); + } -lnn.stream.raw = function(endpoint, handler) -{ - var request = { - id: null, - data: [], - cell: null, - send: function(cmd, data) - { - - var cell = lnn.onion.build( - request.endpoint, cmd, request.id, data) - - if(cmd != "data") { - endpoint.io.send(cell) //non-data cells dont affect congestion control - return - } + if (this.state == lnn.state.started) { // not yet recvd reply for relay begin + return; + } - if(request.deliverywindow > 0) { //send if stream level window is non zero - endpoint.stream.send(cell,endpoint) //send thru circuit level window. - request.deliverywindow -= 1 - } - else { - request.tosend.push(cell) //add to queue of stream level window + while (this.cache.length) { + let data = this.cache.shift(); + + if (typeof (data) == "string") { + data = lnn.dec.utf8(data); } - }, - recv: function() - { - var data = request.data - request.data = [] - return data - }, - state: lnn.state.started, - packagewindow: null, - deliverywindow: null, - tosend: [], - endpoint: endpoint, - callback: function(cell) - { - if (cell.cmd == "connected") - request.state = lnn.state.created - if (cell.cmd == "end") - request.state = lnn.state.success - - if(cell.cmd == "sendme") { //receive stream level sendme - request.deliverywindow += 50 - while(request.deliverywindow > 0 && request.tosend.length > 0) { - var cell = request.tosend.shift() - endpoint.stream.send(cell,endpoint) - request.deliverywindow -= 1 + + const payload = new Uint8Array(lnn.relay.data_len); + + while (data.length > payload.length) { + payload.set(data.slice(0, payload.length), 0); + data = data.slice(payload.length); + + const cell = lnn.onion.build( + this.endpoint, "data", this.id, payload); + + if (this.deliverywindow > 0) { + this.endpoint.stream.send(cell, this.endpoint); + this.deliverywindow -= 1; + } else { + this.tosend.push(cell); } + } - request.data.push(cell) - handler(request) + const cell = lnn.onion.build( + this.endpoint, "data", this.id, data); - if (cell.cmd == "connected") - request.state = lnn.state.pending + if (this.deliverywindow > 0) { + this.endpoint.stream.send(cell, this.endpoint); + this.deliverywindow -= 1; + } else { + this.tosend.push(cell); + } } } - var id = endpoint.stream.register(request) - handler(request) - return request -} -lnn.stream.dir = function(endpoint, path, handler) -{ - var request = { - id: null, - data: "", - cell: null, - send: function() { throw "No send method on directory streams." }, - recv: function() - { - var data = request.data - request.data = "" - return data - }, - state: lnn.state.started, - packagewindow: null, - deliverywindow: null, - tosend: [], - endpoint: endpoint, - callback: function(cell) - { - if (cell.cmd == "connected") - { - request.state = lnn.state.created - handler(request) - request.state = lnn.state.pending - } - if (cell.cmd == "end") - { - request.state = lnn.state.success - handler(request) - } - if(cell.cmd == "sendme") { - request.deliverywindow += 50 - while(request.deliverywindow > 0 && request.tosend.length > 0) { - var cell = request.tosend.shift() - endpoint.stream.send(cell,endpoint) - request.deliverywindow -= 1 + + callback(cell) { + console.log(cell.cmd); + if (cell.cmd == "connected") { + this.state = lnn.state.created; + this.retries = 0; + this.send(); + } + if (cell.cmd == "end") { + if (cell.data[0] == 4) { // REASON EXIT_POLICY + if (this.retries == 3) { // threshold for retrying + console.log('Retries limit exceeded. Cant connect to host. '); + this.state = lnn.state.success; + this.retries = 0; + } else { + this.retries += 1; + console.log("Retrying to build circuit, retry#: " + this.retries); + + let ports = [80, 443]; + + if (!ports.includes(this.port)) { + ports.push(this.port); + } + + lnn.open( + this.endpoint.host, + this.endpoint.port, + this.success_on_open, + this.error_on_open, + undefined, + this.endpoint.fast, + this.endpoint.auth, + this.endpoint.select_path, + ports + ); } + } else { + this.state = lnn.state.success; } + } + if (cell.cmd == "data") { + const data = this.data; + this.data = new Uint8Array(data.length + cell.data.length); + this.data.set(data, 0); + this.data.set(cell.data, data.length); + } + if (cell.cmd == "sendme") { - if (cell.cmd != "data") - return + this.deliverywindow += 50; + while (this.deliverywindow > 0 && this.tosend.length > 0) { + const ncell = this.tosend.shift(); + this.endpoint.stream.send(ncell, this.endpoint); + this.deliverywindow -= 1; + } + } - request.data += lnn.enc.utf8(cell.data) - handler(request) + this.handler(this); + if (cell.cmd == "connected") { + this.state = lnn.state.pending; } } - var id = endpoint.stream.register(request) - var cell = lnn.onion.build(endpoint, "begin_dir", id) - endpoint.io.send(cell) + recv() { + const data = this.data; + this.data = new Uint8Array(0); + return data; + } + + close() { + let data = new Uint8Array(1); + data[0] = 6; // reason done + const cell = onion.build(this.endpoint, "end", this.id, data); + this.endpoint.io.send(cell); + } - var data = "GET " + path + " HTTP/1.0\r\n" - data += "Accept-Encoding: identity\r\n\r\n" - data = lnn.dec.utf8(data) + success_on_open(endp) { + if (endp.consensus === null) + endp.consensus = this.endpoint.consensus; + if (endp.descriptors === null) + endp.descriptors = this.endpoint.descriptors; + if (endp.consensus_raw === null) + endp.consensus_raw = this.endpoint.consensus_raw; + if (endp.descriptors_raw === null) + endp.descriptors_raw = this.endpoint.descriptors_raw; + if (endp.signing_keys === null) + endp.signing_keys = this.endpoint.signing_keys; + + this.endpoint = endp; + + const id = this.endpoint.stream.register(this); + const data = lnn.relay.begin(this.host, this.port); + const cell = lnn.onion.build(this.endpoint, "begin", id, data); + this.endpoint.io.send(cell); + + this.handler(this); + } - cell = lnn.onion.build(endpoint, "data", id, data) - request.deliverywindow -= 1 - endpoint.stream.send(cell,endpoint) - handler(request) - return request + error_on_open(error_msg) { + throw error_msg; + } } -lnn.stream.tcp = function(endPoint, host, port, handler) -{ - var request = { - id: null, - data: new Uint8Array(0), - cell: null, - cache: [], - send: function(send_data) - { - if(send_data !== undefined){ - request.cache.push(send_data) - } +stream.handler = function (endpoint, cell) { + stream.entrancy += 1; + if (stream.entrancy > 1) { + console.log("ENTRANCY BUG"); + } - if(request.state == lnn.state.started) { //not yet recvd reply for relay begin - return - } + if (cell[4] != 3) { // (relay cell only) + console.log("Got non-relay cell, dropped: ", cell[4]); + stream.entrancy -= 1; + return; + } - while(request.cache.length) { - var data = request.cache.shift() - - if (typeof(data) == "string") - data = lnn.dec.utf8(data) + cell = onion.peel(endpoint, cell) + if (cell === null) { + console.log("Got invalid cell, dropped."); + stream.entrancy -= 1; + return; + } - var payload = new Uint8Array(lnn.relay.data_len) - while (data.length > payload.length) - { - payload.set(data.slice(0, payload.length), 0) - data = data.slice(payload.length) + if (!(cell.stream_id in endpoint.stream.handles)) { + console.log("Got cell outside stream, dropped: ", cell.stream_id); + stream.entrancy -= 1; + return; + } - var cell = lnn.onion.build( - request.endpoint, "data", request.id, payload) + let handle = endpoint.stream.handles[cell.stream_id]; + if (cell.cmd == "end") + delete endpoint.stream.handles[cell.stream_id]; - if(request.deliverywindow > 0) { - request.endpoint.stream.send(cell,request.endpoint) - request.deliverywindow -= 1 - } - else { - request.tosend.push(cell) - } + handle.cell = cell; + handle.callback(cell, endpoint); - } - var cell = lnn.onion.build( - request.endpoint, "data", request.id, data) + /* handle circuit-level sendme */ - if(request.deliverywindow > 0) { - request.endpoint.stream.send(cell,request.endpoint) - request.deliverywindow -= 1 - } - else { - request.tosend.push(cell) - } - } - }, - recv: function() - { - var data = request.data - request.data = new Uint8Array(0) - return data - }, - close: function() - { - var data = new Uint8Array(1) - data[0] = 6 //reason done. - var cell = lnn.onion.build(request.endpoint,"end",request.id,data) - request.endpoint.io.send(cell) - }, - state: lnn.state.started, - packagewindow: null, - deliverywindow: null, - tosend: [], - endpoint: endPoint, - retries: 0, - callback: function(cell) - { - console.log(cell.cmd) - if (cell.cmd == "connected"){ - request.state = lnn.state.created - request.retries = 0 - request.send() - } - if (cell.cmd == "end"){ - if(cell.data[0] == 4) { //REASON EXIT_POLICY - if(request.retries == 3) { //threshold for retrying - console.log( 'Retries limit exceeded. Cant connect to host. ' ) - request.state = lnn.state.success - request.retries = 0 - } - else { - request.retries += 1 - console.log("Retrying to build circuit, retry#: " + request.retries) - - var ports = [80,443] - if(!ports.includes(port)) - ports.push(port) - - lnn.open( - request.endpoint.host, - request.endpoint.port, - request.success_on_open, - request.error_on_open, - undefined, - request.endpoint.fast, - request.endpoint.auth, - request.endpoint.select_path, - ports - ) - } - } - else { - request.state = lnn.state.success - } - } - if (cell.cmd == "data") - { - var data = request.data - request.data = new Uint8Array(data.length + cell.data.length) - request.data.set(data, 0) - request.data.set(cell.data, data.length) - } - if(cell.cmd == "sendme") { + if (cell.cmd == "data") { + endpoint.stream.packagewindow -= 1; + } + console.log('Update window: ', endpoint.stream.packagewindow); + if (endpoint.stream.packagewindow < 900) { + //console.log("Circuit window is ", endpoint.stream.packagewindow) + //console.log("Sending circuit level sendme cell now ", endpoint.io.counter) + endpoint.io.send(onion.build(endpoint, 'sendme')); + endpoint.stream.packagewindow += 100; + } - request.deliverywindow += 50 - while(request.deliverywindow > 0 && request.tosend.length > 0) { - var cell = request.tosend.shift() - request.endpoint.stream.send(cell,request.endpoint) - request.deliverywindow -= 1 - } - } + /* handle stream-level sendme */ + if (cell.cmd == "data") { + handle.packagewindow -= 1; + } + if (handle.packagewindow < 450) { + //console.log("Stream window is ", handle.packagewindow) + //console.log("Sending stream level sendme cell now ", endpoint.io.counter) + cell = onion.build(endpoint, 'sendme', handle.id); + endpoint.io.send(cell); + handle.packagewindow += 50; + } + stream.entrancy -= 1; +}; - handler(request) - if (cell.cmd == "connected") - request.state = lnn.state.pending - }, - success_on_open: function(endp) { - if(endp.consensus == null) - endp.consensus = request.endpoint.consensus - if(endp.descriptors == null) - endp.descriptors = request.endpoint.descriptors - if(endp.consensus_raw == null) - endp.consensus_raw = request.endpoint.consensus_raw - if(endp.descriptors_raw == null) - endp.descriptors_raw = request.endpoint.descriptors_raw - if(endp.signing_keys == null) - endp.signing_keys = request.endpoint.signing_keys - - request.endpoint = endp - - var id = request.endpoint.stream.register(request) - var data = lnn.relay.begin(host, port) - var cell = lnn.onion.build(request.endpoint, "begin", id, data) - request.endpoint.io.send(cell) - - handler(request) - }, - error_on_open: function(error_msg) { - throw error_msg - } - } +stream.backend = (error) => new Backend(error); +stream.raw = (endpoint, handler) => new Raw(endpoint, handler); +stream.dir = (endpoint, path, handler) => new Dir(endpoint, path, handler); +stream.tcp = (endPoint, host, port, handler) => new TCP(endPoint, host, port, handler); - var id = endPoint.stream.register(request) - var data = lnn.relay.begin(host, port) - var cell = lnn.onion.build(endPoint, "begin", id, data) - endPoint.io.send(cell) - handler(request) - return request -} +export { stream }; \ No newline at end of file diff --git a/js-client/src/util.js b/js-client/src/util.js index ec7c426..403b698 100644 --- a/js-client/src/util.js +++ b/js-client/src/util.js @@ -1,26 +1,45 @@ -lnn.enc = {} -lnn.enc.bits = sjcl.codec.bytes.toBits -lnn.enc.utf8 = nacl.util.encodeUTF8 -lnn.enc.base64 = nacl.util.encodeBase64 -lnn.enc.bin = function(data) -{ - var str = "" - for(var idx = 0; idx < data.length; idx++) - str += String.fromCharCode(data[idx]) - return str -} +/** + * @module utils + * Utility functions used in the lightnion js-client module. + */ + +import { sjcl } from "../vendor/sjcl.js"; +import naclutil from "tweetnacl-util"; -lnn.dec = {} -lnn.dec.bits = function(data) -{ - return new Uint8Array(sjcl.codec.bytes.fromBits(data)) +/** + * Encoding functions. + */ +export class enc { + static get bits() { return sjcl.codec.bytes.toBits; } + static get utf8() { return naclutil.encodeUTF8; } + static get base64() { return naclutil.encodeBase64; } + static get bin() { + return function (data) { + var str = "" + for (var idx = 0; idx < data.length; idx++) + str += String.fromCharCode(data[idx]) + return str + } + } } -lnn.dec.utf8 = nacl.util.decodeUTF8 -lnn.dec.base64 = nacl.util.decodeBase64 -lnn.dec.bin = function(str) -{ - var data = new Uint8Array(str.length) - for(var idx = 0; idx < str.length; idx++) - data[idx] = str.charCodeAt(idx) - return data + +/** + * Decoding functions. + */ +export class dec { + static get bits() { + return function (data) { + return new Uint8Array(sjcl.codec.bytes.fromBits(data)); + } + } + static get utf8() { return naclutil.decodeUTF8; } + static get base64() { return naclutil.decodeBase64; } + static get bin() { + return function (str) { + var data = new Uint8Array(str.length) + for (var idx = 0; idx < str.length; idx++) + data[idx] = str.charCodeAt(idx) + return data + } + } } diff --git a/js-client/tweetnacl-js b/js-client/tweetnacl-js deleted file mode 160000 index ae93137..0000000 --- a/js-client/tweetnacl-js +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ae93137a7244c4713a2f85878a41eff9a7d2146b diff --git a/js-client/tweetnacl-util-js b/js-client/tweetnacl-util-js deleted file mode 160000 index 7be17e4..0000000 --- a/js-client/tweetnacl-util-js +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7be17e460bfb96660c9d7b55f6a7ba1cc5f58dc9 diff --git a/js-client/vendor/sjcl b/js-client/vendor/sjcl new file mode 160000 index 0000000..85caa53 --- /dev/null +++ b/js-client/vendor/sjcl @@ -0,0 +1 @@ +Subproject commit 85caa53c281eeeb502310013312c775d35fe0867 From d53e4dbb7922b430e99265577998572bec48e8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Th=C3=A9venet?= Date: Fri, 31 Jan 2020 14:47:47 +0100 Subject: [PATCH 02/30] Added unit tests capabilities to js-client. Uses mocha and runs on node with `make test`. --- js-client/Makefile | 6 +- js-client/README.md | 6 +- js-client/package-lock.json | 1398 ++++++++++++++++++++++++++++++- js-client/package.json | 5 + js-client/src/test/util.test.js | 16 + js-client/src/util.js | 8 + 6 files changed, 1431 insertions(+), 8 deletions(-) create mode 100644 js-client/src/test/util.test.js diff --git a/js-client/Makefile b/js-client/Makefile index 8b321d8..2c45d88 100644 --- a/js-client/Makefile +++ b/js-client/Makefile @@ -1,4 +1,4 @@ -.PHONY: all install build lint clean help submodules +.PHONY: all install build test doc lint clean help submodules CP = cp CD = cd @@ -27,6 +27,10 @@ build: LIGHTNION-BUNDLE-DIST LIGHTNION-BUNDLE # build javascript documentation doc: jsdoc/index.html +# run unit tests +test: + @./node_modules/mocha/bin/mocha -r jsdom-global/register --require esm --recursive --exclude "src/export.js" src/ + # # run javascript linter # lint: # ./node_modules/.bin/eslint src diff --git a/js-client/README.md b/js-client/README.md index 4594733..9f1755e 100644 --- a/js-client/README.md +++ b/js-client/README.md @@ -51,4 +51,8 @@ See `./demo/` for more examples. ## Requirements -The bundle works on `firefox 61.0.2` and includes `sjcl+tweetnacl-js`. \ No newline at end of file +The bundle works on `firefox 61.0.2` and includes `sjcl+tweetnacl-js`. + +## Unit testing + +Run `make test`. \ No newline at end of file diff --git a/js-client/package-lock.json b/js-client/package-lock.json index 3b76f2e..135d9ad 100644 --- a/js-client/package-lock.json +++ b/js-client/package-lock.json @@ -51,18 +51,48 @@ "@types/node": "*" } }, + "abab": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", + "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", + "dev": true + }, "acorn": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", + "dev": true + } + } + }, "acorn-jsx": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, "ajv": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", @@ -75,6 +105,12 @@ "uri-js": "^4.2.2" } }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, "ansi-escapes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", @@ -99,6 +135,16 @@ "color-convert": "^1.9.0" } }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -108,23 +154,85 @@ "sprintf-js": "~1.0.2" } }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + } + } + }, "big-integer": { "version": "1.6.48", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==" }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -141,11 +249,32 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-or-node": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", "integrity": "sha512-sVIA0cysIED0nbmNOm7sZzKfgN1rpFmrqvLZaFWspaBAftfQcezlC81G6j6U2RJf4Lh66zFxrCeOsvkUXIcPWg==" }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -164,6 +293,18 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, "catharsis": { "version": "0.8.11", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", @@ -173,6 +314,20 @@ "lodash": "^4.17.14" } }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -190,6 +345,28 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -205,6 +382,42 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -220,6 +433,15 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -232,6 +454,12 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -253,6 +481,49 @@ } } }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz", + "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -262,12 +533,54 @@ "ms": "^2.1.1" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decimal.js": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", + "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -277,6 +590,25 @@ "esutils": "^2.0.2" } }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -289,12 +621,55 @@ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "escodegen": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.13.0.tgz", + "integrity": "sha512-eYk2dCkxR07DsHA/X2hRBj0CFAZeri/LyDMc0C8JT1Hqi6JnVpMhJ7XFITbb0+yZS3lVkaPL2oCkZ3AVmeVbMw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, "eslint": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", @@ -365,6 +740,12 @@ "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true + }, "espree": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", @@ -418,6 +799,12 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -429,6 +816,12 @@ "tmp": "^0.0.33" } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, "fast-deep-equal": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", @@ -465,6 +858,33 @@ "flat-cache": "^2.0.1" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -482,18 +902,69 @@ "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -532,12 +1003,75 @@ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.0.tgz", + "integrity": "sha512-Y9prnPKkM7FXxQevZ5UH8Z6aVTY0ede1tHquck5UxGmKWDshxXh95gSa2xXYjS8AsGO5iOvrCI5+GttRKnLdNA==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -606,14 +1140,47 @@ "through": "^2.3.6" } }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", "dev": true }, - "is-fullwidth-code-point": { - "version": "3.0.0", + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true @@ -633,6 +1200,12 @@ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", "dev": true }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -656,12 +1229,42 @@ } } }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, "jest-worker": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", @@ -708,6 +1311,12 @@ "xmlcreate": "^2.0.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, "jsdoc": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.3.tgz", @@ -738,6 +1347,51 @@ } } }, + "jsdom": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.0.1.tgz", + "integrity": "sha512-wKJe/APzq+ak9i+2ybWE20lDIhF9AkGKSZf8UsjPN39acatFB6oA7K397kQvHVikds0yQono2h6J7UjbPtPOWw==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "acorn": "^7.1.0", + "acorn-globals": "^4.3.2", + "cssom": "^0.4.4", + "cssstyle": "^2.0.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.0", + "domexception": "^2.0.1", + "escodegen": "^1.12.1", + "html-encoding-sniffer": "^2.0.0", + "nwsapi": "^2.2.0", + "parse5": "5.1.1", + "request": "^2.88.0", + "request-promise-native": "^1.0.8", + "saxes": "^4.0.2", + "symbol-tree": "^3.2.2", + "tough-cookie": "^3.0.1", + "w3c-hr-time": "^1.0.1", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^5.0.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0", + "ws": "^7.2.1", + "xml-name-validator": "^3.0.0" + } + }, + "jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -750,6 +1404,24 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", @@ -778,12 +1450,37 @@ "uc.micro": "^1.0.1" } }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, "magic-string": { "version": "0.25.6", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.6.tgz", @@ -830,6 +1527,21 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dev": true, + "requires": { + "mime-db": "1.43.0" + } + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -860,6 +1572,84 @@ "minimist": "0.0.8" } }, + "mocha": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -884,6 +1674,76 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -922,6 +1782,30 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -931,6 +1815,18 @@ "callsites": "^3.0.0" } }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -949,6 +1845,24 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -961,18 +1875,129 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "psl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", + "dev": true + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "requizzle": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", @@ -1120,12 +2145,27 @@ "tslib": "^1.9.0" } }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "saxes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-4.0.2.tgz", + "integrity": "sha512-EZOTeQ4bgkOaGCDaTKux+LaRNcLNbdbvMH7R3/yjEEULPEmqvkFbFub6DJhJTub2iGMT93CfpZ5LTdKZmAbVeQ==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -1138,6 +2178,12 @@ "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", "dev": true }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -1206,6 +2252,37 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + } + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, "string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", @@ -1228,6 +2305,26 @@ } } }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -1260,6 +2357,12 @@ "has-flag": "^3.0.0" } }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -1335,12 +2438,50 @@ "os-tmpdir": "~1.0.2" } }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "dev": true, + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.0.tgz", + "integrity": "sha512-LrErSqfhdUw73AC/eXV2fEmNkvgSYxfm5lvxnLvuVgoVDknvD28Pa5FeDGc8RuVouDxUD3GnHHFv7xnBp7As5w==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, "tweetnacl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.2.tgz", @@ -1360,6 +2501,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -1387,12 +2534,79 @@ "punycode": "^2.1.0" } }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, "v8-compile-cache": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", "dev": true }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.0.0.tgz", + "integrity": "sha512-41ou2Dugpij8/LPO5Pq64K5q++MnRCBpEHvQr26/mArEKTkCV5aoXIqyhuYtE0pkqScXwhf2JP57rkRTYM29lQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^2.0.0", + "webidl-conversions": "^5.0.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -1402,12 +2616,96 @@ "isexe": "^2.0.0" } }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1423,11 +2721,99 @@ "mkdirp": "^0.5.1" } }, + "ws": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", + "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "xmlcreate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.1.tgz", "integrity": "sha512-MjGsXhKG8YjTKrDCXseFo3ClbMGvUD4en29H2Cev1dv4P/chlpw6KdYmlCWDkhosBVKRDjM836+3e3pm1cBNJA==", "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + }, + "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } } } } diff --git a/js-client/package.json b/js-client/package.json index 005a595..12d0fe6 100644 --- a/js-client/package.json +++ b/js-client/package.json @@ -10,8 +10,13 @@ "tweetnacl-util": "^0.15.1" }, "devDependencies": { + "chai": "^4.2.0", "eslint": "^6.8.0", + "esm": "^3.2.25", "jsdoc": "^3.6.3", + "jsdom": "^16.0.1", + "jsdom-global": "^3.0.2", + "mocha": "^7.0.1", "rollup": "^1.30.1", "rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-legacy": "^1.0.0", diff --git a/js-client/src/test/util.test.js b/js-client/src/test/util.test.js new file mode 100644 index 0000000..0c751e2 --- /dev/null +++ b/js-client/src/test/util.test.js @@ -0,0 +1,16 @@ +// Tests for util functions. + +import { assert } from "chai"; +import { enc, dec } from "../util.js"; + +describe("string char codes encoding and decoding", function () { + it("should encode then decode to the same string", function () { + let tt = [ + "", "non empty", "unicode ☑️" + ] + + for (const tc in tt) { + assert.equal(enc.bin(dec.bin(tc)), tc); + } + }); +}); \ No newline at end of file diff --git a/js-client/src/util.js b/js-client/src/util.js index 403b698..1f399d4 100644 --- a/js-client/src/util.js +++ b/js-client/src/util.js @@ -13,6 +13,10 @@ export class enc { static get bits() { return sjcl.codec.bytes.toBits; } static get utf8() { return naclutil.encodeUTF8; } static get base64() { return naclutil.encodeBase64; } + + /** + * Return a function transforming an array of char codes to its string. + */ static get bin() { return function (data) { var str = "" @@ -34,6 +38,10 @@ export class dec { } static get utf8() { return naclutil.decodeUTF8; } static get base64() { return naclutil.decodeBase64; } + + /** + * Return a function transforming a string to its array of char codes. + */ static get bin() { return function (str) { var data = new Uint8Array(str.length) From 962ad4df4905d894760c7817e5ed93c5b3c96f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Th=C3=A9venet?= Date: Fri, 31 Jan 2020 16:08:23 +0100 Subject: [PATCH 03/30] Added WebSocket client implementation In preparation for the Lightnion WebSocket. Unit tests included. --- js-client/Makefile | 9 +- js-client/package-lock.json | 24 + js-client/package.json | 2 + js-client/src/header.js | 10 +- .../src/lightnion-websocket/http/http.js | 12 + .../src/lightnion-websocket/http/parsing.js | 108 ++++ .../http/test/parsing.test.js | 89 +++ .../lightnion-websocket.js | 0 .../src/lightnion-websocket/utils/utils.js | 106 ++++ .../lightnion-websocket/websocket-client.js | 7 + .../websocket-client/defragmenter.js | 186 ++++++ .../websocket-client/handlers.js | 187 ++++++ .../websocket-client/mocks.js | 24 + .../websocket-client/packets-utils.js | 23 + .../websocket-client/packets.js | 259 ++++++++ .../websocket-client/stream-handler.js | 165 +++++ .../websocket-client/test/handlers.test.js | 179 ++++++ .../websocket-client/test/mock-websocket.js | 64 ++ .../test/packets-utils.test.js | 22 + .../websocket-client/test/packets.test.js | 231 +++++++ .../test/stream-handler.test.js | 145 +++++ .../websocket-client/test/utils.test.js | 99 +++ .../test/websocket-client.test.js | 181 ++++++ .../websocket-client/utils.js | 93 +++ .../websocket-client/websocket-client.js | 579 ++++++++++++++++++ js-client/src/util.js | 3 +- 26 files changed, 2796 insertions(+), 11 deletions(-) create mode 100644 js-client/src/lightnion-websocket/http/http.js create mode 100644 js-client/src/lightnion-websocket/http/parsing.js create mode 100644 js-client/src/lightnion-websocket/http/test/parsing.test.js create mode 100644 js-client/src/lightnion-websocket/lightnion-websocket.js create mode 100644 js-client/src/lightnion-websocket/utils/utils.js create mode 100644 js-client/src/lightnion-websocket/websocket-client.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/defragmenter.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/handlers.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/mocks.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/packets-utils.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/packets.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/stream-handler.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/test/handlers.test.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/test/mock-websocket.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/test/packets-utils.test.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/test/packets.test.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/test/stream-handler.test.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/test/utils.test.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/test/websocket-client.test.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/utils.js create mode 100644 js-client/src/lightnion-websocket/websocket-client/websocket-client.js diff --git a/js-client/Makefile b/js-client/Makefile index 2c45d88..cdfb7b4 100644 --- a/js-client/Makefile +++ b/js-client/Makefile @@ -1,5 +1,8 @@ .PHONY: all install build test doc lint clean help submodules +# recursive wildcard +rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) + CP = cp CD = cd NPM = npm @@ -16,6 +19,8 @@ LIGHTNION-BUNDLE = lightnion.bundle.js LIGHTNION-BUNDLE-DIST = $(DIST)/lightnion.bundle.js JSDOC-DIST = jsdoc/ +SOURCES = $(call rwildcard,src/) + all: $(LIGHTNION-BUNDLE) install: @@ -52,7 +57,7 @@ help: $(LIGHTNION-BUNDLE): $(LIGHTNION-BUNDLE-DIST) $(CP) $(LIGHTNION-BUNDLE-DIST) $@ -$(LIGHTNION-BUNDLE-DIST): $(SJCL-BUILD) +$(LIGHTNION-BUNDLE-DIST): $(SJCL-BUILD) $(SOURCES) npm run build $(SJCL-GIT): @@ -64,5 +69,5 @@ $(SJCL-BUILD): $(SJCL-GIT) # modify sjcl to export echo "export { sjcl };" >> $(SJCL-BUILD) -jsdoc/index.html: +jsdoc/index.html: $(SOURCES) $(JSDOC) -r -d $(JSDOC-DIST) src/ \ No newline at end of file diff --git a/js-client/package-lock.json b/js-client/package-lock.json index 135d9ad..77f0a56 100644 --- a/js-client/package-lock.json +++ b/js-client/package-lock.json @@ -233,6 +233,11 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "blob-polyfill": { + "version": "4.0.20190430", + "resolved": "https://registry.npmjs.org/blob-polyfill/-/blob-polyfill-4.0.20190430.tgz", + "integrity": "sha512-REie9DM5XvHcqa9tuVT1QverzNpPbuRGffFGfwtHhZLHoToiAFP2YxHqVTQvET+UYnjRttGnlWag0+i3YgPKtw==" + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -460,6 +465,15 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cross-blob": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cross-blob/-/cross-blob-1.2.0.tgz", + "integrity": "sha512-34Hn7h8NhHJnKh5yztq2Xk3hdbwuyok7T/3kNUgpg4nkABaD8vjMgln8RtxSUbFpReJFvTIKQubU41gai3cEdg==", + "requires": { + "blob-polyfill": "^4.0.20190430", + "fetch-blob": "^1.0.5" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -840,6 +854,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fetch-blob": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-1.0.5.tgz", + "integrity": "sha512-BIggzO037jmCrZmtgntzCD2ymEaWgw9OMJsfX7FOS1jXGqKW9FEhETJN8QK4KxzIJknRl3RQdyzz34of+NNTMQ==" + }, "figures": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", @@ -1692,6 +1711,11 @@ } } }, + "node-forge": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", diff --git a/js-client/package.json b/js-client/package.json index 12d0fe6..f5ad92d 100644 --- a/js-client/package.json +++ b/js-client/package.json @@ -6,6 +6,8 @@ "dependencies": { "big-integer": "^1.6.48", "browser-or-node": "^1.2.1", + "cross-blob": "^1.2.0", + "node-forge": "^0.9.1", "tweetnacl": "^1.0.2", "tweetnacl-util": "^0.15.1" }, diff --git a/js-client/src/header.js b/js-client/src/header.js index 2cf79af..b248b59 100644 --- a/js-client/src/header.js +++ b/js-client/src/header.js @@ -1,13 +1,5 @@ /** * @module header - * The Lightnion Javascript client, top-level namespace. - */ - -"use strict" - -/** - * The Lightnion Javascript client, top-level namespace. - * * @namespace * @see lnn.open * @see lnn.stream.tcp @@ -36,6 +28,8 @@ * } * */ +"use strict" + let lnn = {} /** diff --git a/js-client/src/lightnion-websocket/http/http.js b/js-client/src/lightnion-websocket/http/http.js new file mode 100644 index 0000000..ad247bf --- /dev/null +++ b/js-client/src/lightnion-websocket/http/http.js @@ -0,0 +1,12 @@ +// HTTP constants and functions. + +export let methods = { + OPTIONS: "OPTIONS", + GET: "GET", + HEAD: "HEAD", + POST: "POST", + PUT: "PUT", + DELETE: "DELETE", + TRACE: "TRACE", + CONNECT: "CONNECT", +}; diff --git a/js-client/src/lightnion-websocket/http/parsing.js b/js-client/src/lightnion-websocket/http/parsing.js new file mode 100644 index 0000000..1173150 --- /dev/null +++ b/js-client/src/lightnion-websocket/http/parsing.js @@ -0,0 +1,108 @@ +/** + * HTTP packet parsing utilities. + */ + +// Parsing function helpers +import * as http from "./http.js"; + +/** + * Parse the request line of a HTTP request. + * No validation is made on the request-uri and version. + * + * @param {string} line the request line + * @throws error when `line` could not be parsed + * @return {Array{ [method, request-uri, version] the parsed header line fields + * @private + */ +export function parseRequestLine(line) { + // Request-Line = Method SP Request-URI SP HTTP-Version CRLF + if (!line) { + throw `could not parse request line from ${line}`; + } + + const elements = line.trim().split(" "); + + if (elements.length < 3) { + throw `could not parse request line from ${line}: should be of the form 'Method Request-URI HTTP-Version CRLF'`; + } + + const method = elements[0]; + if (!Object.values(http.methods).includes(method)) { + throw `could not parse request line from ${line}: method is not recognized'`; + } + + const requestURI = elements[1]; + const version = elements[2]; + + return [method, requestURI, version]; +} + +/** + * Parse the status line of a HTTP response. + * No validation is made on the fields. + * + * @param {string} line the status-line + * @return {Array} [version, statusCode {int}, reason] the parsed status line fields + * @private + */ +export function parseStatusLine(line) { + // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF + if (!line) { + throw `could not parse status line from ${line}`; + } + const elements = line.trim().split(" "); + + if (elements.length < 3) { + throw `could not parse status line from ${line}: should be of the form 'HTTP-Version Status-Code Reason CRLF'`; + } + + const version = elements[0]; + const statusCode = parseInt(elements[1]); + const reason = elements.slice(2).join(" "); + + if (isNaN(statusCode)) { + throw `could not parse status line from ${line}: status-code is not an integer`; + } + + return [version, statusCode, reason]; +} + +/** + * Parse the headers of a HTTP packet. + * No validation is performed on fields and keys. + * + * @param {string} headers HTTP headers + * @returns a dictionnary of key-values in the header, + * if multiple header key is present, values will be comma separated + * the header field names and values are set to lower-case, except for case-sensitive values + * @private + */ +export function parseHeaders(headers) { + let parsed = {}; + + if (!headers) { return parsed; } + + headers.split('\r\n') + .forEach(line => { + // split header line in key - value + let i = line.indexOf(':'); + let key = line.substr(0, i).trim().toLowerCase(); + let val; + // Header fields names should be case-insensitive (RFC2616 4.2) + // So we only use lower case versions, except for 'sec-websocket' headers. + // For some reason WebSocket servers do not understand lower case 'sec-websocket' headers. + if (key != "sec-websocket-accept" && key != "sec-websocket-key") { + val = line.substr(i + 1).trim().toLowerCase(); + } else { + val = line.substr(i + 1).trim(); + } + + if (key) { + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + } + }); + + return parsed; +} + + diff --git a/js-client/src/lightnion-websocket/http/test/parsing.test.js b/js-client/src/lightnion-websocket/http/test/parsing.test.js new file mode 100644 index 0000000..371a773 --- /dev/null +++ b/js-client/src/lightnion-websocket/http/test/parsing.test.js @@ -0,0 +1,89 @@ +// Tests for HTTP parsing functions. + +import { assert } from "chai"; +import { parseHeaders, parseStatusLine, parseRequestLine } from "../parsing.js"; + +describe("parseRequestLine", function () { + it("should throw error on incorrect request lines", function () { + let wrongStatus = [ + "MethodNotExisting / HTTP/1.1", + "NoVersion /", + ]; + + wrongStatus.forEach(s => { + assert.throws(() => parseStatusLine(s), ``, + `incorrect request line '${s}' should have raised an error while parsing`); + }); + + }); + + it("should parse correct request lines correctly", function () { + let tt = new Map([ + ["GET / HTTP/1.1", ["GET", "/", "HTTP/1.1"]], + ["POST /post.html HTTP/1.1", ["POST", "/post.html", "HTTP/1.1"]], + ["GET / HTTP/1.1", ["GET", "/", "HTTP/1.1"]], + ["PUT / HTTP/1.1", ["PUT", "/", "HTTP/1.1"]], + ["DELETE / HTTP/1.1", ["DELETE", "/", "HTTP/1.1"]], + ]); + + for (const [requestLine, expected] of tt.entries()) { + let got = parseRequestLine(requestLine); + assert.deepEqual(got, expected, "wrong parsed status line"); + } + }); +}); + +describe("parseStatusLine", function () { + it("sould throw error on incorrect status line", function () { + let wrongHeaders = [ + "HTTP/1.1 NOT-AN-INT REASOn", + "", + "HTTP/1.1", + "HTTP/1.1 404", + "404 NOT-FOUND", + ]; + + wrongHeaders.forEach(h => { + assert.throws(() => parseStatusLine(h), ``, + `incorrect status line '${h}' should have raised an error while parsing`); + }); + }); + + it("should parse correct status lines correctly", function () { + let tt = new Map([ + ["HTTP/1.1 100 MESSAGE", ["HTTP/1.1", 100, "MESSAGE"]], + ["HTTP/2 404 NOT-FOUND", ["HTTP/2", 404, "NOT-FOUND"]], + ["HTTP/1 404 NOT-FOUND something-more", ["HTTP/1", 404, "NOT-FOUND something-more"]], + ]); + + for (const [statusLine, expected] of tt.entries()) { + let got = parseStatusLine(statusLine); + assert.deepEqual(got, expected, "wrong parsed status line"); + } + }); + + + +}); + +describe("parseHeaders", function () { + it("should parse no headers", function () { + let httpHeaders = ""; + let parsed = parseHeaders(httpHeaders); + assert.isEmpty(parsed, "parsing no headers should output an empty object"); + }); + + it("should parse host", function () { + let httpHeaders = "Host: localhost:1234"; + let parsed = parseHeaders(httpHeaders); + assert.equal(parsed["host"], "localhost:1234"); + }); + + it("should parse multiple headers", function () { + let httpHeaders = `Host: localhost:1234\r\n + Content-Language: en\r\n + Content-Length: 3495`; + let parsed = parseHeaders(httpHeaders); + assert.deepEqual(parsed, { "host": "localhost:1234", "content-language": "en", "content-length": "3495" }); + }); +}); diff --git a/js-client/src/lightnion-websocket/lightnion-websocket.js b/js-client/src/lightnion-websocket/lightnion-websocket.js new file mode 100644 index 0000000..e69de29 diff --git a/js-client/src/lightnion-websocket/utils/utils.js b/js-client/src/lightnion-websocket/utils/utils.js new file mode 100644 index 0000000..2870203 --- /dev/null +++ b/js-client/src/lightnion-websocket/utils/utils.js @@ -0,0 +1,106 @@ +// Utilities + +/** + * A MessageEvent implementation for Node. + * + * @private + */ +export class MessageEvent { + constructor(type, init = undefined) { + this.type = type; + if (init) { + this.data = init.data; + this.origin = init.origin; + this.lastEventId = init.lastEventId; + this.channel = init.channel; + this.source = init.source; + this.port = init.port; + } + } +} + +/** + * A CloseEvent implementation for Node. + * + * @private + */ +export class CloseEvent extends MessageEvent { + constructor(type, init = undefined) { + super(type, init); + if (init) { + this.wasClean = init.wasClean; + this.code = init.code; + this.reason = init.reason; + } + } +} + +/** + * Simple implementation of EventTarget. + * See {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget}. + * + * Used for mocking browsers' DOM EventTarget. + * + * @private + */ +export class EventTarget { + constructor() { + this.listeners = {}; + } + + addEventListener(type, callback) { + if (!(type in this.listeners)) { + this.listeners[type] = []; + } + this.listeners[type].push(callback); + } + + removeEventListener(type, callback) { + if (!(type in this.listeners)) { + return; + } + const stack = this.listeners[type]; + for (let i = 0, l = stack.length; i < l; i++) { + if (stack[i] === callback) { + stack.splice(i, 1); + return; + } + } + } + + dispatchEvent(event) { + if (!(event.type in this.listeners)) { + return true; + } + const stack = this.listeners[event.type].slice(); + + for (let i = 0, l = stack.length; i < l; i++) { + stack[i].call(this, event); + } + return !event.defaultPrevented; + + } + +} + +/** + * Check for inclusion of an array in an array. + * + * @param haystack {Array} the array of arrays + * @param needle {Array} the array that may be included in the haystack + * @private + */ +export function containsArray(haystack, needle) { + return haystack.filter(arr => { + if (arr.length !== needle.length) { + return false; + } + + for (let i = 0; i < needle.length; i++) { + if (arr[i] !== needle[i]) { + return false; + } + } + return true; + }).length > 0; +} \ No newline at end of file diff --git a/js-client/src/lightnion-websocket/websocket-client.js b/js-client/src/lightnion-websocket/websocket-client.js new file mode 100644 index 0000000..fe59db6 --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client.js @@ -0,0 +1,7 @@ +/* + * Exports for WebSocketClient. + * To use as a library. + */ + +import { WebSocketClient } from "./websocket-client/websocket-client.js"; +export default WebSocketClient; diff --git a/js-client/src/lightnion-websocket/websocket-client/defragmenter.js b/js-client/src/lightnion-websocket/websocket-client/defragmenter.js new file mode 100644 index 0000000..1ffee6f --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/defragmenter.js @@ -0,0 +1,186 @@ +import { isControlFrame, Frame, opcodes } from "./packets.js"; +import { concatenate } from "./utils.js"; + +/** + * Defragments WebSocket frames + * Used when receiving websocket frames that may have been fragmented. + * + * @private + */ +export class FrameDefragmenter { + + constructor() { + this._outputQueue = []; + this._parsed = undefined; + } + + + /** + * Add a received frame, that may be fragmented. + * + * @param {frame} Uint8Array packet received, unmasked + * @throws error when fed out of order frames + * @return {undefined} control frame if given packet is a control frame, undefined otherwise + */ + add(frame) { + let parsed = FrameDefragmenter._fields(frame); + + if (parsed === undefined) { + console.warn("received websocket frame could not be parsed"); + return undefined; + } + + if (isControlFrame(parsed['opcode'])) { + this._outputQueue.push(new Frame( + parsed["rsv1"] === 1, + parsed["rsv2"] === 1, + parsed["rsv3"] === 1, + parsed["opcode"], + parsed["payload data"], + )); + return; + } + + const fin = parsed["fin"]; + const opcode = parsed["opcode"]; + + if (this._parsed === undefined) { + if (fin && opcode !== opcodes.continuation) { + // unfragmented + this._outputQueue.push(new Frame( + parsed["rsv1"] === 1, + parsed["rsv2"] === 1, + parsed["rsv3"] === 1, + parsed["opcode"], + parsed["payload data"], + )); + this._parsed = undefined; + return; + } else if (!fin && opcode !== opcodes.continuation) { + // first fragmented frame + this._parsed = parsed; + return; + } else { + throw `Error: FrameBuilder was given an out of order frame`; + } + } else { + if (!fin && opcode === opcodes.continuation) { + // continuation frame + // append the payload to the current fragments' payload + this._parsed["payload data"] = concatenate(this._parsed["payload data"], parsed["payload data"]); + return; + } else if (fin && opcode === opcodes.continuation) { + // last fragmented frame + // append the payload to the current fragments' payload + this._parsed["payload data"] = concatenate(this._parsed["payload data"], parsed["payload data"]); + + this._outputQueue.push(new Frame( + this._parsed["rsv1"] === 1, + this._parsed["rsv2"] === 1, + this._parsed["rsv3"] === 1, + this._parsed["opcode"], + this._parsed["payload data"], + )); + this._parsed = undefined; + return; + } else { + throw `Error: FrameBuilder was given an out of order frame`; + } + } + } + + /** + * Return the next websocket frame. + * @returns {Uint8Array | undefined} an unfragmented websocket frame + * or undefined if no frame is ready. + */ + get() { + return this._outputQueue.shift(); + } + + /** + * Parse a websocket frame into key-value fields. + * Do not decode payload if masked. + * + * @private + * @param {Uint8Array} frame an encapsulated websocket frame, or undefined if error + * @returns dictionnary of fields and fields values of the encapsulated packet, or undefined if packet is invalid + * keys are a subset of ['fin', 'rsv1', 'rsv2', 'rsv3', 'opcode', 'mask', 'Payload Len', 'masking-key', 'payload data'] + * or undefined if the frame is bogus + */ + static _fields(frame) { + let parsed = {}; + let restLen = frame.byteLength; + if (restLen < 2) { + // bogus frame + return undefined; + } + + let byteIterator = frame.entries(); + + // first byte + const bits0 = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split('').map(c => c === "1" ? 1 : 0); + parsed["fin"] = bits0[0]; + parsed["rsv1"] = bits0[1]; + parsed["rsv2"] = bits0[2]; + parsed["rsv3"] = bits0[3]; + parsed["opcode"] = parseInt(bits0.slice(4, 8).join(''), 2); + restLen--; + + // second byte + const bits1 = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split('').map(c => c === "1" ? 1 : 0); + parsed["mask"] = bits1[0]; + parsed["payload len"] = parseInt(bits1.slice(1, 8).join(''), 2); + restLen--; + + // rest + + if (parsed["payload len"] == 126) { + // if 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length + if (restLen < 2) { + console.warn("error: received websocket frame with incorrect 'payload len'"); + return undefined; + } + let pLen = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split(''); + pLen = pLen.concat((byteIterator.next().value[1]).toString(2).padStart(8, '0').split('')); + parsed["payload len"] = parseInt(pLen.join(""), 2); + restLen -= 2; + } else if (parsed["payload len"] == 127) { + // if 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length + if (restLen < 8) { + console.warn("error: received websocket frame with incorrect 'payload len'"); + return undefined; + } + let pLenBits = []; + for (let i = 0; i < 8; i++) { + pLenBits = pLenBits.concat((byteIterator.next().value[1]).toString(2).padStart(8, '0').split('')); + } + parsed["payload len"] = parseInt(pLenBits.join(""), 2); + restLen -= 8; + } + + if (parsed["mask"]) { + // next 4 bytes is the masking key + if (restLen < 4) { + console.warn("error: received websocket frame with masking"); + return undefined; + } + let maskingKeyBits = ""; + for (let i = 0; i < 4; i++) { + maskingKeyBits += (byteIterator.next().value[1]).toString(2).padStart(8, '0'); + } + parsed["masking-key"] = parseInt(maskingKeyBits, 2); + restLen -= 4; + } + + if (restLen <= 0) { + parsed["payload data"] = new Uint8Array(0); + } else { + // parsed["payload data"] = frame.slice(-restLen); + parsed["payload data"] = frame.slice(-parsed["payload len"]); + } + + return parsed; + } + +} diff --git a/js-client/src/lightnion-websocket/websocket-client/handlers.js b/js-client/src/lightnion-websocket/websocket-client/handlers.js new file mode 100644 index 0000000..cf68dfb --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/handlers.js @@ -0,0 +1,187 @@ +/** + * Packet handling for WebSockets. + */ + +import * as wspackets from "./packets.js"; +import { binaryTypes } from "./websocket-client.js"; +import { MessageEventClass } from "./mocks.js"; +import naclutil from "tweetnacl-util"; + +/** + * Return a handler for received websocket packets when in connecting state, for given WebSocket. + * @param {WebSocket} ws websocket handling the packets. + * @private + */ +export function onConnectingMessage() { + return (request) => { + console.warn(`received message while in connecting state: ${request}`); + }; +} + +/** + * Return a handler for recevied bwesocket packets when in closing state, for given WebSocket. + * @param {WebSocket} ws websocket handling the packets. + * @private + */ +export function onClosingMessage() { + return (request) => { + console.warn(`received message while in closing state: ${request}`); + }; +} + +/** + * Return a handler for recevied bwesocket packets when in closed state, for given WebSocket. + * @param {WebSocket} ws websocket handling the packets. + * @private + */ +export function onClosedMessage() { + return (request) => { + console.warn(`received message while in closed state: ${request}`); + }; +} + +/** + * Return a handler for received websocket packets when in open state, for given WebSocket. + * @param {WebSocket} ws websocket handling the packets. + * @param {Boolean} noMasking disable masking of frames sent, for testing purposes only + * @private + */ +export function onOpenMessage(ws, noMasking = false) { + return (pkt) => { + + // add the packet to the stream handler + ws._streamHandler.add(pkt); + + let frame; + // process all frames that are ready + while ((frame = ws._streamHandler.get()) !== undefined) { + ws._frameDefragmenter.add(frame); + } + + while ((frame = ws._frameDefragmenter.get()) !== undefined) { + if (wspackets.isControlFrame(frame.opcode)) { + handleControlFrame(ws, frame, noMasking); + } else { + handleDataFrame(ws, frame); + } + } + + }; +} + +/** + * Handle a data frame. + * + * @param {WebSocket} ws websocket handling the frame + * @param {Frame} dataFrame frame to handle + * @private + */ +function handleDataFrame(ws, dataFrame) { + if (dataFrame.payload === undefined) { + return; + } + + // wrap to event + let eventData; + try { + if (dataFrame.opcode === wspackets.opcodes.text) { + eventData = naclutil.encodeUTF8(dataFrame.payload); + } else if (dataFrame.opcode === wspackets.opcodes.binary) { + if (ws.binaryType === binaryTypes.blob) { + eventData = new Blob([dataFrame.payload]); + } else if (ws.binaryType === binaryTypes.arraybuffer) { + eventData = dataFrame.payload.buffer; + } + } else { + console.warn(`unknown opcode: ${dataFrame.opcode}, dropping frame`); + return; + } + } catch (err) { + console.warn(`error: tried to decode websocket data packet: ${err}`); + return; + } + let event = new MessageEventClass( + "message", + { + data: eventData, + origin: ws._url.href, + lastEventId: "", // TODO ? + source: null, // TODO ? + ports: [], // TODO ? + } + ); + + ws._received(event); + ws.__onmessage(event); // user defined handler +} + +/** + * Handle a control frame. + * + * @param {WebSocket} ws websocket handling the frame + * @param {Frame} controlFrame frame to handle + * @param {Boolean} noMasking disable masking of frames sent, for testing purposes only + * @private + */ +function handleControlFrame(ws, controlFrame, noMasking) { + const payload = controlFrame.payload; + switch (controlFrame.opcode) { + case wspackets.opcodes.close: { + // status and reason are parsed but not needed for now + // the whole payload is echoed back + let status = 1005; + let reason = ""; + if (payload.length >= 2) { + status = payload[0] << 8 + payload[1]; + let reasonBytes = payload.slice(2); + if (reasonBytes.length > 0) { + // read reason + reason = naclutil.encodeUTF8(reasonBytes); + } + } + + if (!ws._the_websocket_closing_handshake_is_started) { + // send back a close frame + ws._closing(); + + // if present, echo back status and reason + // otherwise use defaults + if (payload.length >= 2) { + // 2-byte unsigned integer + status = (payload[0] << 8) + payload[1]; + if (payload.length > 2) { + reason = naclutil.encodeUTF8(payload.slice(2)); + } + } + + if (noMasking) { + ws._socket.send(wspackets.closeFrame(status, reason, new Uint8Array(4))); + } else { + ws._socket.send(wspackets.closeFrame(status, reason)); + } + // end of the closing handshake + ws._close_the_websocket_connection(); + } else { + // end of the closing handshake + ws._close_the_websocket_connection(); + } + break; + } + case wspackets.opcodes.ping: { + // send back a pong frame, with received (decoded) payload if any + if (noMasking) { + ws._socket.send(wspackets.pongFrame(payload, new Uint8Array(4))); + } else { + ws._socket.send(wspackets.pongFrame(payload)); + } + break; + } + case wspackets.opcodes.pong: + break; + default: + // not implemented or invalid + break; + } + return; +} + diff --git a/js-client/src/lightnion-websocket/websocket-client/mocks.js b/js-client/src/lightnion-websocket/websocket-client/mocks.js new file mode 100644 index 0000000..2f36f9a --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/mocks.js @@ -0,0 +1,24 @@ +/* + * Mocks for use in node/broswer. + */ + +import * as utils from "../utils/utils.js"; +import { isNode } from 'browser-or-node'; + +export let EventTargetClass; +export let MessageEventClass; +export let BlobClass; +export let CloseEventClass; + +if (isNode) { + // running in node + EventTargetClass = utils.EventTarget; + MessageEventClass = utils.MessageEvent; + BlobClass = require("cross-blob"); + CloseEventClass = utils.CloseEvent; +} else { + EventTargetClass = EventTarget; + MessageEventClass = MessageEvent; + BlobClass = Blob; + CloseEventClass = CloseEvent; +} diff --git a/js-client/src/lightnion-websocket/websocket-client/packets-utils.js b/js-client/src/lightnion-websocket/websocket-client/packets-utils.js new file mode 100644 index 0000000..6a07d56 --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/packets-utils.js @@ -0,0 +1,23 @@ + +import forge from "node-forge"; +import naclutil from "tweetnacl-util"; +import { GUID } from "./packets.js"; + +/** + * Verify the Sec-WebSocket-Accept header field by computing its expected value. + * @param {Uint8Array} key 4-bytes sec-websocket-key used for client handshake + * @param {string} resp received header field value string + * @returns boolean true if the received value is the expected + * @private + */ +export function verifySecWebSocketAccept(key, resp) { + const fromHexString = hexString => + new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); + + const keyb64 = naclutil.encodeBase64(key); + let hashed = forge.md.sha1.create(); + hashed.update(keyb64 + GUID); + const hashedBytes = fromHexString(hashed.digest().toHex()); + const expected = naclutil.encodeBase64(hashedBytes); + return resp === expected; +} \ No newline at end of file diff --git a/js-client/src/lightnion-websocket/websocket-client/packets.js b/js-client/src/lightnion-websocket/websocket-client/packets.js new file mode 100644 index 0000000..fd025ec --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/packets.js @@ -0,0 +1,259 @@ +/** + * Packet crafting for the WebSocket protocol. + * + * WebSocket frame (RFC 6455): + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|M| Payload len | Extended payload length | + * |I|S|S|S| (4) |A| (7) | (16/64) | + * |N|V|V|V| |S| | (if payload len==126/127) | + * | |1|2|3| |K| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | |Masking-key, if MASK set to 1 | + * +-------------------------------+-------------------------------+ + * | Masking-key (continued) | Payload Data... | + * +---------------------------------------------------------------| + * + */ + +import nacl from "tweetnacl"; +import naclutil from "tweetnacl-util"; +import { maskWithKey, concatenate } from "./utils.js"; + +/** + * Construct the HTTP packet send by the client during the WebSocket handshake. + * @returns {Array} [pkt, nonce] the HTTP client handshake packet as a string, with the Uint8Array SecWebSocketKey nonce used in it + * @private + */ +export function clientHandshake(host, port, resourceName, protocols = []) { + // TODO: + // - Sec-WebSocket-Protocol + // - Sec-WebSocket-Extensions + + // create the nonce: base64 encoded 16 random bytes + const nonce = nacl.randomBytes(16); + const nonceB64 = naclutil.encodeBase64(nonce); + + // create the http packet + let fields = [ + ["GET", `${resourceName}`, "HTTP/1.1"], + ["Host:", `${host}:${port}`], + ["Connection:", "Upgrade"], + ["Upgrade:", "websocket"], + ["Sec-WebSocket-Key:", `${nonceB64}`], + ["Origin:", `${host}`], + ["Sec-WebSocket-Version:", "13"], + ]; + + if (Array.isArray(protocols) && protocols.length > 0) { + fields.push(["Sec-WebSocket-Protocol:", protocols.join(", ")]); + } + + const pkt = fields.map(s => s.join(" ")).join("\r\n") + "\r\n\r\n"; + + return [pkt, nonce]; +} + +/** + * The GUID used for the Sec-WebSocket verification. + * @private + */ +export const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + +/** + * Construct a pong frame. + * @param {Uint8Array} payload the pong payload, usually the application data of the received ping + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @private + */ +export function pongFrame(payload, maskingKey = undefined) { + return Frame._encapsulate(payload, "1000", opcodes.pong, maskingKey); +} + +/** + * Construct a ping frame. + * @param {Uint8Array} payload the ping application data + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @private + */ +export function pingFrame(payload, maskingKey = undefined) { + return Frame._encapsulate(payload, "1000", opcodes.ping, maskingKey); +} + +/** + * Construct a close frame + * @param {Number} code status code for closing the connection (2bytes) + * @param {reason} string reason for closing the connection + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @private + */ +export function closeFrame(code, reason = undefined, maskingKey = undefined) { + if (code < 0 || code >= 65536) { + throw `cannot encode int ${code} to 2 bytes`; + } + let payload = new Uint8Array([ + code >> 8, + code & 255 + ]); + if (reason) { + payload = concatenate(concatenate, naclutil.decodeUTF8(reason)); + } + + return Frame._encapsulate(payload, "1000", opcodes.close, maskingKey); +} + +/** + * Construct a text frame. + * @param {string} text the text to send + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @private + */ +export function textFrame(text, maskingKey = undefined) { + const payload = naclutil.decodeUTF8(text); + return Frame._encapsulate(payload, "1000", opcodes.text, maskingKey); +} + +export let opcodes = { + continuation: 0, + text: 1, + binary: 2, + // x3-7 reserved for further non-control frames + close: 8, + ping: 9, + pong: 10, + // xB-F reserved for further control frames +}; + +export let isControlFrame = (opcode) => (opcode & 8) === 8; + +/** + * Represent a WebSocket frame, not fragmented. + * + * See websocket framing protocol: + * {@link https://tools.ietf.org/html/rfc6455#section-5.2}. + * @private + */ +export class Frame { + + /** + * Construct a WebSocket Frame. + * + * @param {Boolean} rsv1 + * @param {Boolean} rsv2 + * @param {Boolean} rsv3 + * @param {Integer} opcode + * @param {Uint8Array} payload + */ + constructor(rsv1, rsv2, rsv3, opcode, payload) { + this.rsv1 = rsv1 ? "1" : "0"; + this.rsv2 = rsv2 ? "1" : "0"; + this.rsv3 = rsv3 ? "1" : "0"; + this.opcode = opcode; + this.payload = payload; + } + + // Return true if the frame represents a control frame + isControl() { + return isControlFrame(this.opcode); + } + + /** + * Encapsulate Frame into a WebSocket packet in byte array format. + * + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @returns {Uint8Array} packet + */ + encapsulate(maskingKey = undefined) { + const flags = "1".concat(this.rsv1, this.rsv2, this.rsv3); + return Frame._encapsulate(this.payload, flags, this.opcode, maskingKey); + } + + /** + * Fragment frame into several websocket packets. + * To be used in place of the `encapsulate` method when fragmentation is needed. + * + * @param {int} chunkSize the maximum length of a (websocket) payload, in bytes + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @returns {Array} an array of Uint8Array, that contains in-order websocket-encapsulated packets + */ + fragment(chunkSize, maskingKey = undefined) { + // chunk payload into smaller payloads + let payloads = []; + for (let i = 0; i < this.payload.length; i += chunkSize) { + payloads.push(this.payload.slice(i, i + chunkSize)); + } + + // create packets + let packets = []; + for (let i = 0; i < payloads.length; i++) { + // only the last fragment has the FIN flag set + const finFlag = (i !== (payloads.length - 1)) ? "0" : "1"; + const flags = finFlag.concat(this.rsv1, this.rsv2, this.rsv3); + // only the first fragment has the opcode set + const code = (i === 0) ? this.opcode : opcodes.continuation; + + packets.push(Frame._encapsulate(payloads[i], flags, code, maskingKey)); + } + + return packets; + } + + /** + * Encapsulate given data into a WebSocket packet in byte array format. + * + * @param {Uint8Array} payload the packet payload + * @param {string} flags the first 4 bits of the packet, FIN/RSV1/RSV2/RSV3 in bitstring format + * @param {int} opcode the integer opcode + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @returns {Uint8Array} packet + */ + static _encapsulate(payload, flags = "1000", opcode = 1, maskingKey = undefined) { + const opcodeBits = opcode.toString(2).padStart(4, '0'); + + let payloadLen; + if (payload.length >= 126) { + if (payload.length < 65536) { + // use next two bytes to encode the payload length + let code = 126; + payloadLen = code.toString(2).padStart(7, '0'); + payloadLen += payload.length.toString(2).padStart(16, '0'); + + } else { + if (payload.length > 2 ^ (8 * 8)) { + throw `Error: payload too large for the websocket protocol`; + } + // use next eight bytes to encode the payload length + let code = 127; + payloadLen = code.toString(2).padStart(7, '0'); + payloadLen += payload.length.toString(2).padStart(64, '0'); + } + } else { + payloadLen = payload.length.toString(2).padStart(7, '0'); + } + + let mask = '1'; + if (maskingKey === undefined) { + // create a nonce + maskingKey = new Uint8Array(nacl.randomBytes(4)); + } + const maskedPayload = maskWithKey(payload, maskingKey); + + function bitstringToUint8Array(bitstring) { + const len = Math.ceil(bitstring.length / 8); + let out = new Uint8Array(len); + for (let i = 0; i < len; i++) { + out[i] = parseInt(bitstring.slice(8 * i, 8 * i + 8), 2); + } + return out; + } + + let headerStart = bitstringToUint8Array(flags + opcodeBits + mask + payloadLen); + + return Uint8Array.from([...headerStart, ...maskingKey, ...maskedPayload]); + } +} + diff --git a/js-client/src/lightnion-websocket/websocket-client/stream-handler.js b/js-client/src/lightnion-websocket/websocket-client/stream-handler.js new file mode 100644 index 0000000..da91b34 --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/stream-handler.js @@ -0,0 +1,165 @@ +import { maskWithKey } from "./utils.js"; + +/** + * The interface between a stream-oriented socket to a WebSocket. + * Reconstruct websocket frames from stream messages. + * + * To be used when receiving data from the TCP stream, + * feed this data into the add() method, + * and use get() method to poll for ready frames. + * + * @private + */ +export class StreamHandler { + constructor() { + // the queue containing ready websocket frames + this._outputQueue = []; + // the buffer containing remaining bytes to be consumed + // invariant: the start of the buffer corresponds to the start of a websocket frame + this._buffer = []; + } + + /** + * Add a received packet. + * After this call, zero, one or more frames may be used by calling get() multiple times. + * @param {Uint8Array} data raw data taken from the streaming socket + */ + add(data) { + this._buffer.push(...data); + + // consume buffer to add new ready frames to the output queue + let frame; + while ((frame = this._consume()) !== undefined) { + this._outputQueue.push(frame); + } + } + + /** + * Return the next websocket frame. + * @returns {Uint8Array | undefined} a raw websocket frame + * or undefined if no frame is ready. + */ + get() { + return this._outputQueue.shift(); + } + + + /** + * Try to consume buffer into a websocket frame. + * @returns {Uint8Array} the websocket frame constructed, or undefined if not successful + */ + _consume() { + // check if we have a full frame header in the buffer + const headerLen = nextHeaderLength(this._buffer); + if (headerLen === 0) { + return undefined; + } + + // we have a full frame header available + // parse it to get the payload length + const payloadLen = headerPayloadLength(this._buffer.slice(0, headerLen)); + + // check if we have the payload ready in the buffer + if (this._buffer.length < (headerLen + payloadLen)) { + return undefined; + } + + // we can extract a frame from the buffer + let rawFrame = this._buffer.splice(0, headerLen + payloadLen); + + // unmask if needed + let frame = unmaskFrame(rawFrame, headerLen); + + return new Uint8Array(frame); + } +} + +/** + * Unmask websocket frame if needed. + * + * @param {Array} frame byte array + * @param {number} headerLen the length of the header in the frame + * @returns {Array} the unmasked frame + * @private + */ +function unmaskFrame(frame, headerLen) { + const pLen = frame[1] & 127; + + let maskIndex; + if (pLen < 126) { + maskIndex = 2; + } else if (pLen === 127) { + maskIndex = 4; + } else { + maskIndex = 10; + } + let maskingKey = frame.slice(maskIndex, maskIndex + 4); + + const payload = maskWithKey(frame.slice(headerLen), maskingKey); + + frame.slice(0, headerLen).push(...payload); + + return frame; +} + +/** + * Returns the payload length from a frame header. + * @param {Array} header the input header, assumed valid and no extra bytes, only contains bytes + * @returns {number} the length of the payload associated with the header + * @private + */ +function headerPayloadLength(header) { + const pLen = header[1] & 127; // 7 last bits of 2nd byte + + if (pLen < 126) { + return pLen; + } else if (pLen === 126) { + // if 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length + return (header[2] << 8) + header[3]; + } else if (pLen === 127) { + // if 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length + let len = 0; + + for (let i = 0; i < 8; i++) { + len += (header[2 + i] << (8 * (7 - i))); + } + return len; + } +} + +/** + * Try to read a header from the start of the input buffer. + * @param {Array} data input buffer, contaning only bytes + * @returns {boolean} the byte length of the header contained in the start of the input buffer if any, 0 otherwise + * @private + */ +function nextHeaderLength(data) { + // a frame header is between 2 and 12 bytes long + if (data.length < 2) { return 0; } + + const mask = (data[1] & 128) === 128; // mask is true if mask is set in header + const payloadLen = data[1] & 127; // 7 last bits of 2nd byte + + // now check all the cases... + + if (!mask && payloadLen < 126) { + // header length is 2B + return 2; + } else if (!mask && payloadLen === 126) { + // header length is (2 + 2) = 4B + if (data.length < 4) { return 0; } else { return 4; } + } else if (!mask && payloadLen === 127) { + // header length is (2 + 8) = 10B + if (data.length < 10) { return 0; } else { return 10; } + } else if (mask && payloadLen < 126) { + // header length is (2 + 4) = 6B + if (data.length < 6) { return 0; } else { return 6; } + } else if (mask && payloadLen === 126) { + // header length is (2 + 2 + 4) = 8B + if (data.length < 8) { return 0; } else { return 8; } + } else if (mask && payloadLen === 127) { + // header length is (2 + 8 + 4) = 14B + if (data.length < 14) { return 0; } else { return 14; } + } +} + diff --git a/js-client/src/lightnion-websocket/websocket-client/test/handlers.test.js b/js-client/src/lightnion-websocket/websocket-client/test/handlers.test.js new file mode 100644 index 0000000..fe7d27c --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/test/handlers.test.js @@ -0,0 +1,179 @@ +// Tests for websocket packet handlers + +import { assert } from "chai"; +import { MockWebSocket } from "./mock-websocket"; +import * as wspackets from "../packets.js"; +import { FrameDefragmenter } from "../defragmenter.js"; +import { onOpenMessage } from "../handlers.js"; +import naclutil from "tweetnacl-util"; + +describe("open message handler", function () { + + let socket; + let ws; + let url; + let nullKey = new Uint8Array(4); + + this.beforeEach(function () { + url = "ws://example.com/"; + ws = new MockWebSocket(url); + socket = ws._socket; + socket.onmessage = onOpenMessage(ws, true); + }); + + it('should send back a pong when a ping is received, with the same empty payload', function () { + let defrag = new FrameDefragmenter(); + + const payload = new Uint8Array(0); + socket.receive(wspackets.pingFrame(payload)); + + defrag.add(wspackets.pongFrame(payload)); + + const expectedResponse = defrag.get(); + assert.exists(expectedResponse); + + assert.equal(socket.sentMessages.length, 1); + + defrag.add(socket.sentMessages[0]); + const actualResponse = defrag.get(); + assert.exists(actualResponse); + + assert.equal(actualResponse.opcode, expectedResponse.opcode, `websocket should have sent a pong frame upon reception of a ping frame`); + assert.deepEqual(actualResponse.payload, expectedResponse.payload, `websocket should have sent a pong frame of same payload upon reception of a ping frame`); + }); + + it('should send back a pong when a ping is received, with the same non-empty payload', function () { + let defrag = new FrameDefragmenter(); + + const payload = Uint8Array.from([1, 2, 3, 4]); + socket.receive(wspackets.pingFrame(payload, nullKey)); + + defrag.add(wspackets.pongFrame(payload, nullKey)); + + const expectedResponse = defrag.get(); + assert.exists(expectedResponse); + assert.equal(socket.sentMessages.length, 1); + defrag.add(socket.sentMessages[0]); + const actualResponse = defrag.get(); + assert.exists(actualResponse); + + assert.equal(actualResponse.opcode, expectedResponse.opcode, `websocket should have sent a pong frame upon reception of a ping frame`); + assert.deepEqual(actualResponse.payload, expectedResponse.payload, `websocket should have sent a pong frame of same payload upon reception of a ping frame`); + }); + + it('should close the connection correctly when a close frame is received with no payload, while the closing handshake has not been started ', function () { + ws._the_websocket_closing_handshake_is_started = false; + let defrag = new FrameDefragmenter(); + const status = 1000; + + socket.receive(wspackets.closeFrame(status, undefined, nullKey)); + + assert.isTrue(socket.closed, "expected websocket to close underlying socket"); + assert.equal(ws.readyState, MockWebSocket.CLOSED, "expected websocket to enter CLOSING state"); + defrag.add(wspackets.closeFrame(status, undefined, nullKey)); + const expectedResponse = defrag.get(); + + assert.equal(socket.sentMessages.length, 1); + defrag.add(socket.sentMessages[0]); + const actualResponse = defrag.get(); + + assert.exists(actualResponse); + + assert.equal(actualResponse.opcode, expectedResponse.opcode, 'websocket should have sent the same close frame upong reception of a close frame'); + assert.deepEqual(actualResponse.payload, expectedResponse.payload, 'websocket should have sent the same close frame upong reception of a close frame'); + }); + + + it('should close the connection correctly when a close frame is received with no payload, while the closing handshake has been started', function () { + ws._the_websocket_closing_handshake_is_started = true; + + const status = 1000; + + socket.receive( + wspackets.closeFrame(status) + ); + + assert.isTrue(socket.closed, "expected websocket to close underlying socket"); + assert.equal(ws.readyState, MockWebSocket.CLOSED, "expected websocket to enter CLOSING state"); + + assert.isEmpty(socket.sentMessages, + `websocket should not send packets once the closing handshake has been started `); + }); + + + it('should handle non-fragmented data frames correctly', function () { + const text = "this is a text frame's payload"; + + let received = []; + ws.onmessage = (event) => { + received.push(event.data); + }; + + socket.onmessage = onOpenMessage(ws); + + socket.receive(wspackets.textFrame(text, nullKey)); + + assert.deepInclude(received, text); + assert.equal(received.length, 1, "websocket should not have received more messages than sent"); + }); + + it('should handle fragmented data frames correctly', function () { + const text = "this is a text frame's payload"; + const payload = naclutil.decodeUTF8(text); + const chunkSize = 4; + + let received = []; + ws.onmessage = (event) => { + received.push(event.data); + }; + + socket.onmessage = onOpenMessage(ws); + + // construct and send fragments in order + let frame = new wspackets.Frame(false, false, false, wspackets.opcodes.text, payload); + frame.fragment(chunkSize, nullKey).forEach((pkt) => { + socket.receive(pkt); + }); + + // expect to have received one packet containing the whole text + assert.deepInclude(received, text); + assert.equal(received.length, 1, "websocket should not have received more messages than sent"); + }); + + it('should handle fragmented data frames correctly with control frame received inbetween fragments', function () { + const text = "this is a text frame's payload"; + const payload = naclutil.decodeUTF8(text); + const chunkSize = 4; + const chunks = Math.ceil(text.length / chunkSize); + + assert(chunks == 8); + + let received = []; + ws.onmessage = (event) => { + received.push(event.data); + }; + + socket.onmessage = onOpenMessage(ws, true); + + // construct and send fragments in order + let frame = new wspackets.Frame(false, false, false, wspackets.opcodes.text, payload); + let fragments = frame.fragment(chunkSize, nullKey); + + for (let i = 0; i < fragments.length; i++) { + if (i == 4) { + // send a ping frame in-between data frames + socket.receive(wspackets.pingFrame([], nullKey)); + } + socket.receive(fragments[i]); + } + + // expect to have received one packet containing the whole text, and one ping packet + // and expect to have sent a pong packet in response to the ping + const expectedPong = wspackets.pongFrame([], nullKey); + assert.deepInclude(received, text); + assert.equal(received.length, 1, "websocket should have received exaclty one defragmented packets"); + assert.equal(socket.sentMessages.length, 1, "websocket should have sent only one frame"); + let sent = socket.sentMessages[0]; + assert.deepEqual(sent, expectedPong, "websocket should have sent a pong frame upong reception of a ping frame, inbetween data fragments"); + }); +}); \ No newline at end of file diff --git a/js-client/src/lightnion-websocket/websocket-client/test/mock-websocket.js b/js-client/src/lightnion-websocket/websocket-client/test/mock-websocket.js new file mode 100644 index 0000000..09c2fe9 --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/test/mock-websocket.js @@ -0,0 +1,64 @@ +/** + * A mock of a client WebSocket + */ + +import { WebSocketClient } from "../websocket-client.js"; +import { StreamHandler } from "../stream-handler.js"; + +export class MockWebSocket extends WebSocketClient { + + constructor(url, protocols = []) { + super(url, protocols); + + this._socket = new MockSocket(); + + this._socket.onmessage = (event) => { + this.onmessage(event); + }; + } +} + + +/** + * A Mock of a underlying socket for a WebSocket. + */ +class MockSocket { + + constructor() { + this.closed = false; + this.sentMessages = []; + this.receivedMessages = []; + this._streamHandler = new StreamHandler(); + } + + // Required Interface Methods + + send(data) { + this.sentMessages.push(data); + + // execute attached callback if present, + // this is used to ease unit testing + if (data.callback) { + data.callback(); + } + } + + close() { + if (this.closed) { + throw Error("cannot close socket: already closed"); + } + this.closed = true; + } + + // set by the websocket + onmessage() { + } + + // for testing + // fake reception of a message + receive(data) { + this.receivedMessages.push(data); + this.onmessage(data); + } + +} \ No newline at end of file diff --git a/js-client/src/lightnion-websocket/websocket-client/test/packets-utils.test.js b/js-client/src/lightnion-websocket/websocket-client/test/packets-utils.test.js new file mode 100644 index 0000000..5c340fa --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/test/packets-utils.test.js @@ -0,0 +1,22 @@ +// Tests for websocket packets utilities + +import { assert } from "chai"; +import naclutil from "tweetnacl-util"; +import { verifySecWebSocketAccept } from "../packets-utils.js"; + +describe("verifySecWebSocketAccept", function () { + + it("should work on rfc example", function () { + const key = naclutil.decodeBase64("dGhlIHNhbXBsZSBub25jZQ=="); + const resp = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="; + assert.isTrue(verifySecWebSocketAccept(key, resp)); + }); + + it("should not work on bad inputs", function () { + const key = naclutil.decodeBase64("dGhlIHNhsXBsZSBub25jZQ=="); + const resp = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="; + assert.isFalse(verifySecWebSocketAccept(key, resp)); + }); +}); + + diff --git a/js-client/src/lightnion-websocket/websocket-client/test/packets.test.js b/js-client/src/lightnion-websocket/websocket-client/test/packets.test.js new file mode 100644 index 0000000..dcf2c7e --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/test/packets.test.js @@ -0,0 +1,231 @@ +// Tests for websocket packets + +import { assert } from "chai"; +import { parseURL } from "../utils.js"; +import { parseHeaders, parseRequestLine } from "../../http/parsing.js"; +import * as wspackets from "../packets.js"; +import { FrameDefragmenter } from "../defragmenter.js"; +import * as http from "../../http/http.js"; +import naclutil from "tweetnacl-util"; + +describe("clientHandshake", function () { + /** + * See RFC 6455 4. + */ + + it("should be a HTTP GET request of version at least 1.1", function () { + let url = new URL("ws://example.com/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs] = wspackets.clientHandshake(host, port, resourceName); + let [method, , version] = parseRequestLine(hs.split("\r\n")[0]); + + // check status-code + assert.equal(method, http.methods.GET); + + // check version + let versionFloat = parseFloat(version.replace("HTTP/", "")); + if (isNaN(versionFloat)) { + throw `could not parse request line from ${hs}: version is not of the form 'HTTP/...'`; + } + + assert.isAtLeast(versionFloat, 1.1); + }); + + it("should have the request-uri match the ressource name", function () { + let url = new URL("ws://example.com/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs] = wspackets.clientHandshake(host, port, resourceName); + let [, requestURI] = parseRequestLine(hs.split("\r\n")[0]); + + assert.equal(requestURI, "/chat"); + }); + + it("should contain a 'host' header", function () { + let url = new URL("ws://example.com:1234/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs] = wspackets.clientHandshake(host, port, resourceName); + + let headers = hs.split("\r\n").slice(1).join("\r\n"); + let parsed = parseHeaders(headers); + + assert.equal(parsed["host"], "example.com:1234"); + }); + + it("should contain contain an 'upgrade' header field with value containing 'websocket'", function () { + let url = new URL("ws://example.com:1234/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs] = wspackets.clientHandshake(host, port, resourceName); + + let headers = hs.split("\r\n").slice(1).join("\r\n"); + let parsed = parseHeaders(headers); + + assert.include(parsed["upgrade"], "websocket"); + }); + + it("shoud contain a 'connection' header field with value containing 'upgrade'", function () { + let url = new URL("ws://example.com:1234/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs] = wspackets.clientHandshake(host, port, resourceName); + + let headers = hs.split("\r\n").slice(1).join("\r\n"); + let parsed = parseHeaders(headers); + + assert.include(parsed["upgrade"], "websocket"); + }); + + it("shoud contain a 'sec-websocket-key' header field", function () { + let url = new URL("ws://example.com:1234/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs, nonce] = wspackets.clientHandshake(host, port, resourceName); + let nonceB64 = naclutil.encodeBase64(nonce); + + let headers = hs.split("\r\n").slice(1).join("\r\n"); + let parsed = parseHeaders(headers); + + assert.equal(parsed["sec-websocket-key"], nonceB64); + }); + + it("should contain a 'origin' header field (browser client)", function () { + let url = new URL("ws://example.com:1234/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs] = wspackets.clientHandshake(host, port, resourceName); + + let headers = hs.split("\r\n").slice(1).join("\r\n"); + let parsed = parseHeaders(headers); + + assert.equal(parsed["origin"], "example.com"); + }); + + it("should contain a 'sec-websocket-version' header field with value '13'", function () { + let url = new URL("ws://example.com:1234/chat"); + let [host, port, resourceName] = parseURL(url); + let [hs] = wspackets.clientHandshake(host, port, resourceName); + + let headers = hs.split("\r\n").slice(1).join("\r\n"); + let parsed = parseHeaders(headers); + + assert.equal(parsed["sec-websocket-version"], "13"); + }); + + it("should contain a 'sec-websocket-protocol' field with comma separated values", function () { + let url = new URL("ws://example.com:1234/chat"); + let [host, port, resourceName] = parseURL(url); + let protocols = ["rfb", "sip"]; + let [hs] = wspackets.clientHandshake(host, port, resourceName, protocols); + + let headers = hs.split("\r\n").slice(1).join("\r\n"); + let parsed = parseHeaders(headers); + + assert.equal(parsed["sec-websocket-protocol"], "rfb, sip"); + }); + +}); + +describe("ws packet encapsulation", function () { + it("import", function () { + assert.ok(wspackets.Frame._encapsulate); + }); + + it("encapsulates small packets", function () { + const payloads = [ + ``, + `small`, + new Array(1 + 1).join('#'), + new Array(10 + 1).join('#'), + new Array(100 + 1).join('#'), + ]; + + payloads.forEach(payload => { + const payloadEncoded = naclutil.decodeUTF8(payload); + const pkt = wspackets.Frame._encapsulate(payloadEncoded, "1000", 1, new Uint8Array(4)); + assert.ok(pkt); + + const defrag = new FrameDefragmenter(); + defrag.add(pkt); + + const parsed = defrag.get(); + + assert.ok(parsed); + assert.deepEqual(parsed.payload, payloadEncoded); + }); + }); + + it("encapsulates medium packets", function () { + const payloads = [ + `this should be a payload of at least 126 bytes and less than 65536 bytes. + ----------------------------------------------------------------------------------------`, + new Array(200 + 1).join('#'), + new Array(500 + 1).join('#'), + new Array(1000 + 1).join('#'), + new Array(5000 + 1).join('#'), + new Array(10000 + 1).join('#'), + new Array(50000 + 1).join('#'), + ]; + + payloads.forEach(payload => { + const payloadEncoded = naclutil.decodeUTF8(payload); + const pkt = wspackets.Frame._encapsulate(payloadEncoded, "1000", 1, new Uint8Array(4)); + assert.ok(pkt); + const defrag = new FrameDefragmenter(); + defrag.add(pkt); + const parsed = defrag.get(); + assert.ok(parsed); + assert.deepEqual(parsed.payload, payloadEncoded); + }); + }); + + it("encapsulates large packets", function () { + const fragmentSize = 1000; + const payloads = [ + new Array(65536 + 1).join('#'), + new Array(65537 + 1).join('#'), + new Array(100000 + 1).join('#'), + ]; + + payloads.forEach(payload => { + // create packets + const payloadEncoded = naclutil.decodeUTF8(payload); + const frame = new wspackets.Frame(false, false, false, wspackets.opcodes.text, payloadEncoded); + const fragments = frame.fragment(1000, new Uint8Array(4)); + assert.equal(fragments.length, Math.ceil(payload.length / fragmentSize)); + + let defrag = new FrameDefragmenter(); + // parse packets + fragments.forEach(pkt => { + defrag.add(pkt); + }); + + let parsed = defrag.get(); + assert.ok(parsed); + assert.equal(parsed.opcode, frame.opcode); + assert.deepEqual(parsed.payload, frame.payload); + }); + }); + + it("should compute the masked payload correctly for a null key", function () { + const key = new Uint8Array(4); + const payload = naclutil.decodeUTF8("test string"); + const pkt = wspackets.Frame._encapsulate(payload, "1000", 1, key); + + const defrag = new FrameDefragmenter(); + defrag.add(pkt); + + const parsed = defrag.get(); + + assert.ok(parsed); + assert.deepEqual(parsed.payload, payload); + }); + +}); + +describe("isControlFrame", function () { + + it("should be correct for expected opcodes", function () { + assert.equal(wspackets.isControlFrame(wspackets.opcodes.continuation), false); + assert.equal(wspackets.isControlFrame(wspackets.opcodes.text), false); + assert.equal(wspackets.isControlFrame(wspackets.opcodes.binary), false); + assert.equal(wspackets.isControlFrame(wspackets.opcodes.close), true); + assert.equal(wspackets.isControlFrame(wspackets.opcodes.ping), true); + assert.equal(wspackets.isControlFrame(wspackets.opcodes.pong), true); + }); +}); diff --git a/js-client/src/lightnion-websocket/websocket-client/test/stream-handler.test.js b/js-client/src/lightnion-websocket/websocket-client/test/stream-handler.test.js new file mode 100644 index 0000000..40440fb --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/test/stream-handler.test.js @@ -0,0 +1,145 @@ +// Tests for stream data to websocket frames + +import { assert } from "chai"; +import { StreamHandler } from "../stream-handler.js"; +import { Frame, opcodes } from "../packets"; +import { concatenate } from "../utils.js"; + +describe("StreamHandler", function () { + + let streamHandler; + const payload1 = new Uint8Array(Array.from(Array(50).keys())); + const payload2 = new Uint8Array(Array.from(Array(20).keys())); + const payload3 = new Uint8Array(Array.from(Array(40).keys())); + const nullKey = new Uint8Array(4); + + beforeEach(function () { + streamHandler = new StreamHandler(); + }); + + it("should handle a single packet", function () { + const orig = Frame._encapsulate(payload1, "1000", opcodes.binary, nullKey); + + streamHandler.add(orig); + let frame = streamHandler.get(); + + assert.ok(frame); + assert.deepEqual(frame.payload, orig.payload); + }); + + + it("should handle a packet split into two", function () { + const orig = Frame._encapsulate(payload1, "1000", opcodes.binary, nullKey); + + let middle = Math.ceil(orig.length / 2); + + let origPart1 = orig.slice(0, middle); + let origPart2 = orig.slice(middle); + + let frame; + + frame = streamHandler.get(); + assert.notOk(frame); + + streamHandler.add(origPart1); + frame = streamHandler.get(); + assert.notOk(frame); + + streamHandler.add(origPart2); + frame = streamHandler.get(); + assert.ok(frame); + + assert.deepEqual(frame.payload, orig.payload); + }); + + it("should handle packet split into three", function () { + const orig = Frame._encapsulate(payload1, "1000", opcodes.binary, nullKey); + + let origPart1 = orig.slice(0, Math.ceil(orig.length / 3)); + let origPart2 = orig.slice(Math.ceil(orig.length / 3), Math.ceil(2 * orig.length / 3)); + let origPart3 = orig.slice(Math.ceil(2 * orig.length / 3)); + + let frame; + + frame = streamHandler.get(); + assert.notOk(frame); + + streamHandler.add(origPart1); + frame = streamHandler.get(); + assert.notOk(frame); + + streamHandler.add(origPart2); + frame = streamHandler.get(); + assert.notOk(frame); + + streamHandler.add(origPart3); + frame = streamHandler.get(); + assert.ok(frame); + + assert.deepEqual(frame.payload, orig.payload); + + }); + + it("should handle stream of split packets one by one", function () { + // here we send 3 packets, as 5 packets + // payloads are split/merged approximately like this: + // [111] | [111222] | [222] | [222222333] | [333] + const orig1 = Frame._encapsulate(payload1, "1000", opcodes.binary, nullKey); + const orig2 = Frame._encapsulate(payload2, "1000", opcodes.binary, nullKey); + const orig3 = Frame._encapsulate(payload3, "1000", opcodes.binary, nullKey); + + let split1 = orig1.slice(0, Math.ceil(orig1.length / 2)); + let split2 = concatenate( + orig1.slice(Math.ceil(orig1.length / 2)), + orig2.slice(0, Math.ceil(orig2.length / 4))); + let split3 = orig2.slice(Math.ceil(orig2.length / 4), Math.ceil(2 * orig2.length / 4)); + let split4 = concatenate( + orig2.slice(Math.ceil(2 * orig2.length / 4)), + orig3.slice(0, Math.ceil(orig3.length / 2))); + let split5 = orig3.slice(Math.ceil(orig3.length / 2)); + + let frames = []; + + streamHandler.add(split1); + assert.notOk(streamHandler.get()); + streamHandler.add(split2); + frames.push(streamHandler.get()); + streamHandler.add(split3); + assert.notOk(streamHandler.get()); + streamHandler.add(split4); + frames.push(streamHandler.get()); + streamHandler.add(split5); + frames.push(streamHandler.get()); + + assert.deepEqual(frames, [orig1, orig2, orig3]); + }); + + it("should handle stream of split packets in bulk", function () { + const orig1 = Frame._encapsulate(payload1, "1000", opcodes.binary, nullKey); + const orig2 = Frame._encapsulate(payload2, "1000", opcodes.binary, nullKey); + const orig3 = Frame._encapsulate(payload3, "1000", opcodes.binary, nullKey); + + let split1 = orig1.slice(0, Math.ceil(orig1.length / 2)); + let split2 = concatenate( + orig1.slice(Math.ceil(orig1.length / 2)), + orig2.slice(0, Math.ceil(orig2.length / 4))); + let split3 = orig2.slice(Math.ceil(orig2.length / 4), Math.ceil(2 * orig2.length / 4)); + let split4 = concatenate( + orig2.slice(Math.ceil(2 * orig2.length / 4)), + orig3.slice(0, Math.ceil(orig3.length / 2))); + let split5 = orig3.slice(Math.ceil(orig3.length / 2)); + + let splits = [split1, split2, split3, split4, split5]; + splits.forEach(s => streamHandler.add(s)); + + let frames = []; + let frame; + while ((frame = streamHandler.get()) !== undefined) { + frames.push(frame); + } + + assert.deepEqual(frames, [orig1, orig2, orig3]); + }); + + +}); \ No newline at end of file diff --git a/js-client/src/lightnion-websocket/websocket-client/test/utils.test.js b/js-client/src/lightnion-websocket/websocket-client/test/utils.test.js new file mode 100644 index 0000000..349aeb4 --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/test/utils.test.js @@ -0,0 +1,99 @@ +import { assert } from "chai"; +import { parseURL, maskWithKey } from "../utils.js"; + +describe("maskWithKey", function () { + it("should be involutory", function () { + const key = new Uint8Array([5, 3, 2, 12]); + + const payloads = [ + new Uint8Array([1, 2, 3, 4, 5, 6, 7]), + new Uint8Array([]), + new Uint8Array([0, 0, 0]), + new Uint8Array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]), + ]; + + payloads.forEach(payload => { + let decoded = maskWithKey(maskWithKey(payload, key), key); + assert.deepEqual(decoded, payload); + }); + }); +}); + +describe("parseURL", function () { + /** + * See https://www.w3.org/TR/2012/CR-websockets-20120920/#parse-a-websocket-url-s-components + */ + + // it("should fail on relative url", function () { + // // TODO + // }); + + it("should fail if scheme is not websocket", function () { + let url = new URL("http://127.0.0.1:8080/"); + let p = () => parseURL(url); + assert.throws(p); + }); + + it("should fail if url has a fragment", function () { + let url = new URL("ws://localhost:8080/that#thing"); + let p = () => parseURL(url); + assert.throws(p); + }); + + it("should set secure to false for ws: scheme", function () { + let url = new URL("ws://localhost:443/"); + let secure = parseURL(url)[3]; + assert.isFalse(secure); + }); + + it("should set secure to true for wss: scheme", function () { + let url = new URL("wss://localhost/"); + let secure = parseURL(url)[3]; + assert.isTrue(secure); + }); + + it("should set host as the url host in lowercase", function () { + let url = new URL("wss://MY.HOST.COM/path"); + let host = parseURL(url)[0]; + assert.equal("my.host.com", host); + }); + + it("should set port as the url port", function () { + let url = new URL("ws://localhost:443/"); + let port = parseURL(url)[1]; + assert.equal(port, 443); + }); + + + it("should set port implicitely according to scheme", function () { + let url = new URL("ws://localhost/"); + let port = parseURL(url)[1]; + assert.equal(port, 80); + }); + + it("should set port implicitely according to scheme", function () { + let url = new URL("wss://localhost/"); + let port = parseURL(url)[1]; + assert.equal(port, 443); + }); + + it("should set ressourceName as the path of url", function () { + let url = new URL("ws://localhost/this/is/the/path"); + let ressourceName = parseURL(url)[2]; + assert.equal(ressourceName, "/this/is/the/path"); + }); + + it("should set ressourceName to default if url path is empty", function () { + let url = new URL("ws://localhost"); + let ressourceName = parseURL(url)[2]; + assert.equal(ressourceName, "/"); + }); + + it("should have a single question mark followed by the query component in ressourceName if the url has a query component", function () { + // FIXME + let url = new URL("ws://localhost/?this=that&other=it"); + let ressourceName = parseURL(url)[2]; + assert.equal(ressourceName, "/?this=that&other=it"); + }); +}); + diff --git a/js-client/src/lightnion-websocket/websocket-client/test/websocket-client.test.js b/js-client/src/lightnion-websocket/websocket-client/test/websocket-client.test.js new file mode 100644 index 0000000..b87c3dd --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/test/websocket-client.test.js @@ -0,0 +1,181 @@ +// Tests for WebSocketClient. +// Tests ensuring that WebSocketClient implements the standardized interface. +// See: https://www.w3.org/TR/websockets/#the-websocket-interface + +import { WebSocketClient, binaryTypes } from "../websocket-client.js"; +import { assert } from "chai"; +import * as _ from "lodash"; +import { MessageEventClass } from "../mocks.js"; + +const Blob = require("cross-blob"); + +describe("WebSocket interface", function () { + + let testUrlString; + let testWS; + let testHandler; + + before(function () { + testUrlString = "ws://example.com/"; + testWS = new WebSocketClient(testUrlString); + testHandler = () => { }; + }); + + it("can be imported", function () { + assert.exists(WebSocketClient); + }); + + it("should have a readonly DOMString attribute 'url'", function () { + assert.property(testWS, "url"); + assert.equal(testWS.url, testUrlString); + assert.isTrue(_.isString(testWS.url)); + assert.throws(() => { testWS.url = undefined; }, TypeError); + }); + + it("should have defined ready state constants", function () { + assert.equal(WebSocketClient.CONNECTING, 0); + assert.equal(WebSocketClient.OPEN, 1); + assert.equal(WebSocketClient.CLOSING, 2); + assert.equal(WebSocketClient.CLOSED, 3); + }); + + it("should have a readonly unsigned short attribute 'readyState'", function () { + assert.property(testWS, "readyState"); + assert.isNumber(testWS.readyState); + assert.oneOf(testWS.readyState, [0, 1, 2, 3]); + assert.throws(() => { testWS.readyState = undefined; }, TypeError); + }); + + it("should have a readonly unsigned long attribute 'bufferedAmount'", function () { + assert.property(testWS, "bufferedAmount"); + assert.isNumber(testWS.bufferedAmount); + assert.isAtLeast(testWS.bufferedAmount, 0); + assert.throws(() => { testWS.bufferedAmount = undefined; }, TypeError); + }); + + it("should have an EventHandler attribute 'onopen'", function () { + assert.property(testWS, "onopen"); + assert.isTrue(_.isFunction(testWS.onopen)); + // should be able to set it + testWS.onopen = testHandler; + assert.equal(testWS.onopen, testHandler); + }); + + it("should have an EventHandler attribute 'onerror'", function () { + assert.property(testWS, "onerror"); + assert.isTrue(_.isFunction(testWS.onerror)); + // should be able to set it + testWS.onerror = testHandler; + assert.equal(testWS.onerror, testHandler); + }); + + it("should have an EventHandler attribute 'onclose'", function () { + assert.property(testWS, "onclose"); + assert.isTrue(_.isFunction(testWS.onclose)); + // should be able to set it + testWS.onclose = testHandler; + assert.equal(testWS.onclose, testHandler); + }); + + it("should have an EventHandler attribute 'onmessage'", function () { + assert.property(testWS, "onmessage"); + assert.isTrue(_.isFunction(testWS.onmessage)); + // should be able to set it + testWS.onmessage = testHandler; + assert.equal(testWS.onmessage, testHandler); + }); + + it("should have a readonly DOMString attribute 'extensions'", function () { + assert.property(testWS, "extensions"); + assert.isTrue(_.isString(testWS.extensions)); + assert.throws(() => { testWS.extensions = undefined; }, TypeError); + }); + + it("should have a readonly DOMString attribute 'protocol'", function () { + assert.property(testWS, "protocol"); + assert.isTrue(_.isString(testWS.protocol)); + assert.throws(() => { testWS.protocol = undefined; }, TypeError); + }); + + it("should have a 'close' method", function () { + assert.property(testWS, "close"); + assert.isTrue(_.isFunction(testWS.close)); + }); + + it("should have a DOMString attribute 'binaryType'", function () { + assert.property(testWS, "binaryType"); + assert.oneOf(testWS.binaryType, ["blob", "arraybuffer"]); + + // should be able to set it if acceptable value + testWS.binaryType = "arraybuffer"; + assert.equal(testWS.binaryType, "arraybuffer"); + testWS.binaryType = "blob"; + assert.equal(testWS.binaryType, "blob"); + assert.throws(() => { testWS.binaryType = ""; }, SyntaxError); + }); + + it("should have a 'send' method", function () { + assert.property(testWS, "send"); + assert.isTrue(_.isFunction(testWS.send)); + }); + +}); + + +describe("WebSocket events", function () { + let testUrlString; + let testWS; + + beforeEach(function () { + testUrlString = "ws://example.com/"; + testWS = new WebSocketClient(testUrlString); + }); + + it("should trigger a message event with a text data, when a message is received", function (done) { + testWS._readyState = WebSocketClient.OPEN; + const data = new Uint8Array(65, 66, 67, 68); + testWS.addEventListener("message", (event) => { + assert.deepEqual(event.data, data); + done(); + }); + // send message to the websocket + testWS._received(new MessageEventClass("message", { data: data })); + }); + + it("should trigger a message event with a blob data if binaryType was set to blob, when a message is received", function (done) { + testWS._readyState = WebSocketClient.OPEN; + testWS.binaryType = binaryTypes.blob; + const data = new Uint8Array(65, 66, 67, 68); + testWS.addEventListener("message", (event) => { + assert.isTrue(event.data instanceof Blob); + assert.deepEqual(event.data, new Blob(data)); + done(); + }); + // send message to the websocket + testWS._received(new MessageEventClass("message", { data: new Blob([data]) })); + }); + + it("should trigger a message event with an arraybuffer data if binaryType was set to arraybuffer, when a message is received", function (done) { + testWS._readyState = WebSocketClient.OPEN; + testWS.binaryType = binaryTypes.arraybuffer; + const data = new Uint8Array(65, 66, 67, 68); + testWS.addEventListener("message", (event) => { + assert.isTrue(event.data instanceof ArrayBuffer); + assert.deepEqual(event.data, data.buffer); + done(); + }); + // send message to the websocket + testWS._received(new MessageEventClass("message", { data: data.buffer })); + }); + + + it("should trigger a close event when asked to close", function (done) { + testWS._readyState = WebSocketClient.OPEN; + testWS.addEventListener("close", () => { + done(); + }); + testWS._close_the_websocket_connection(); + }); + + +}); \ No newline at end of file diff --git a/js-client/src/lightnion-websocket/websocket-client/utils.js b/js-client/src/lightnion-websocket/websocket-client/utils.js new file mode 100644 index 0000000..3afdfc9 --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/utils.js @@ -0,0 +1,93 @@ +/** + * Utility functions. + */ + + +/** + * Parse the given url. + * {@link https://www.w3.org/TR/2012/CR-websockets-20120920/#parse-a-websocket-url-s-components} + * @param {URL} url the url to parse + * @returns [host, port, ressourceName, secure] + * @throws error when url is incorrect for a websocket connection + * @private + */ +export function parseURL(url) { + // 1. if the url string is not an absolute URL, then fail this algorithm + const absoluteURLChecker = new RegExp('^(?:[a-z]+:)?//', 'i'); + if (!absoluteURLChecker.test(url.href)) { + throw `url is not absolute: ${url}`; + } + + // 2. resolve the url string, with the URL character encoding set to UTF-8. + + // 3. if url does not have a component whose value + // when converted to ASCII lowercase, is either "ws" or "wss", + // then fail this algorithm. + if (url.protocol !== "ws:" && url.protocol !== "wss:") { + throw `url scheme must be either 'ws:' or 'wss:', but is: ${url.protocol}`; + } + + // 4. f url has a component, then fail this algorithm. + if (url.hash.substr(1) !== "") { + throw `url cannot have a fragment: ${url}`; + } + + // 5. if the component of url is "ws", set secure to false; + // otherwise, the component is "wss", set secure to true. + const secure = url.protocol === "ws:" ? false : true; + + // 6. let host be the value of the component of url, + // converted to ASCII lowercase. + const host = url.hostname.toLowerCase(); + + // 7. If url has a component, then let port be that component's value; + // otherwise, there is no explicit port. + // 8. if there is no explicit port, then: if secure is false, let port be 80, + // otherwise let port be 443. + const port = url.port || (url.protocol === "ws:" ? "80" : "443"); + + // 9. let resource name be the value of the component (which might be empty) of url. + // 10. if resource name is the empty string, set it to a single character U+002F SOLIDUS (/). + let ressourceName = url.pathname || "/"; + + // 11. if url has a component, then append a single U+003F QUESTION MARK character (?) to resource name, + // followed by the value of the component. + if (url.search) { + ressourceName += url.search; + } + + // 12. return host, port, resource name, and secure. + return [host, port, ressourceName, secure]; +} + +/** + * Mask given input with given key, as specified for websocket masking + * @param {Uint8Array} x input to mask/unmask + * @param {Uint8Array} key 4-bytes key + * @private + */ +export function maskWithKey(x, key) { + let out = new Uint8Array(x.length); + for (let i = 0; i < x.length; i++) { + out[i] = x[i] ^ key[i % 4]; + } + return out; +} + +/** + * Concatenate Uint8Arrays. + * @private + */ +export function concatenate(...arrays) { + let len = 0; + for (let arr of arrays) { + len += arr.length; + } + let result = new Uint8Array(len); + let offset = 0; + for (let arr of arrays) { + result.set(arr, offset); + offset += arr.length; + } + return result; +} diff --git a/js-client/src/lightnion-websocket/websocket-client/websocket-client.js b/js-client/src/lightnion-websocket/websocket-client/websocket-client.js new file mode 100644 index 0000000..2fb3a14 --- /dev/null +++ b/js-client/src/lightnion-websocket/websocket-client/websocket-client.js @@ -0,0 +1,579 @@ +/** + * A definition of a WebSocket client. + * + * @module websocket-client + */ + +import { isNode } from 'browser-or-node'; +import { parseURL } from "./utils.js"; +import naclutil from "tweetnacl-util"; +import * as wspackets from "./packets.js"; +import * as wspacketsutils from "./packets-utils.js"; +import * as handlers from "./handlers.js"; +import * as httpParsing from "../http/parsing.js"; +import { EventTargetClass, MessageEventClass, CloseEventClass } from "./mocks.js"; +import { StreamHandler } from "./stream-handler.js"; +import { FrameDefragmenter } from "./defragmenter.js"; + +export let binaryTypes = { + blob: "blob", + arraybuffer: "arraybuffer", +}; + +/** + * An abstract WebSocket client. + * + * Uses an underlying socket to be supplied by implementing classes when calling {@linkcode WebSocketClient._start_opening_handshake}. + */ +export class WebSocketClient extends EventTargetClass { + // CONSTANTS + // static getters are used to implement static constants + static get CONNECTING() { return 0; } + static get OPEN() { return 1; } + static get CLOSING() { return 2; } + static get CLOSED() { return 3; } + + constructor(url, protocols = []) { + super(); + + if (protocols.length > 0) { + console.error(`websocket subprotocols are not yet supported: ${protocols}`); + } + + // url + this._url = new URL(url); + + // TODO: see https://www.w3.org/TR/websockets/#dom-websocket-bufferedamount + // need to use the underlying buffer measures as well, + // lightnion-js uses lnn.stream.tcp.cache.length + this._bufferedAmount = 0; + + this._extensions = ""; + this._protocol = ""; + this._readyState = WebSocketClient.CONNECTING; + this._binaryType = binaryTypes.blob; // defaults + + // 'private' event handlers + // these are the handlers called by the underlying socket + // each of them will call the user-defined handler (e.g. this.onmessage) after some processing + this.__onclose = (event) => { this.onclose(event); }; + this.__onerror = (event) => { this.onerror(event); }; + this.__onmessage = (event) => { this.onmessage(event); }; + this.__onopen = (event) => { this.onopen(event); }; + + // 'public' event handlers + this._onclose = () => { }; + this._onerror = () => { }; + this._onmessage = () => { }; + this._onopen = () => { }; + + + // true if the closing handshake has been initiated + this._the_websocket_closing_handshake_is_started = false; + + // for translation of stream to frames + this._streamHandler = new StreamHandler(); + + // for reception of fragmented message + this._frameDefragmenter = new FrameDefragmenter(); + + // check if duplicates in protocols + // TODO + // if (new Set(this.protocols).size != this.protocols.length) { + // throw SyntaxError(`duplicates in protocols: ${this.protocols}`); + // } + + + let origin = ""; + if (!isNode) { + origin = new URL(window.location.href); + } else { + origin = "http://localhost/"; + } + + // parse url + let secure; + try { + secure = parseURL(this._url)[3]; + } catch (err) { + throw SyntaxError(`could not parse url: ${err}`); + } + + if (secure && origin.protocol !== "https") { + throw Error(`SecurityError: cannot open non-secure websocket from a secure origin`); + } + + // transport level socket connection + // should be set when the handshake is requested + this._socket = undefined; + } + + // PROPERTIES + + // url: read-only DOMString + get url() { + return this._url.href; + } + + // readyState: read-only unsigned short + get readyState() { + return this._readyState; + } + + // bufferedAmount: read-only unsigned long + get bufferedAmount() { + return this._bufferedAmount; + } + + // extensions: read-only DOMString + get extensions() { + return this._extensions; + } + + // protocol: read-only DOMString + get protocol() { + return this._protocol; + } + + // binaryType: DOMString + get binaryType() { return this._binaryType; } + set binaryType(binaryType) { + switch (binaryType) { + case "blob": + this._binaryType = binaryTypes.blob; + break; + case "arraybuffer": + this._binaryType = binaryTypes.arraybuffer; + break; + default: + throw new SyntaxError(`websocket binaryType cannot be set to ${binaryType}, allowed values are 'blob' and 'arraybuffer'`); + } + } + + + // EVENT HANDLERS + + /** + * Get the onopen handler. + */ + get onopen() { + return this._onopen; + } + /** + * Set the onopen handler. + */ + set onopen(onopen) { + this._onopen = onopen; + } + + /** + * Get the onmessage handler. + */ + get onmessage() { + return this._onmessage; + } + + /** + * Set the onmessage handler. + */ + set onmessage(onmessage) { + this._onmessage = onmessage; + } + + /** + * Get the onerror handler. + */ + get onerror() { + return this._onerror; + } + /** + * Set the onerror handler. + */ + set onerror(onerror) { + this._onerror = onerror; + } + + /** + * Get the onclose handler. + */ + get onclose() { + return this._onclose; + } + /** + * Set the onclose handler. + */ + set onclose(onclose) { + this._onclose = onclose; + } + + + // INTERFACE METHODS + + /** + * Send to the websocket endpoint. + * @param {string|Blob|ArrayBuffer|ArrayBufferView} data the payload to send + */ + send(data) { + // FIXME: bufferedAmount, closing handshake started + + if (!(this._socket)) { + throw `Socket not initialized`; + } + + if (this._readyState === WebSocketClient.CONNECTING) { + throw `InvalidStateError: cannot send data while websocket is in CONNECTING state`; + } + + let frame; + if (typeof data === "string") { + // convert data to a sequence of Unicode characters + const payload = naclutil.decodeUTF8(data); + if (this._readyState === WebSocketClient.OPEN) { + frame = new wspackets.Frame(false, false, false, wspackets.opcodes.text, payload); + } + } else if (data instanceof Blob) { + frame = new wspackets.Frame(false, false, false, wspackets.opcodes.binary, data); + } else if (data instanceof ArrayBuffer) { + frame = new wspackets.Frame(false, false, false, wspackets.opcodes.binary, data); + } else { + // assume ArrayBufferView + // send data stored in the section of the buffer described by the ArrayBuffer object that the ArrayBufferView object references + frame = new wspackets.Frame(false, false, false, wspackets.opcodes.binary, data); + } + + if (frame) { + // console.debug("[WS] sending websocket message"); + // console.debug(frame); + this._socket.send(frame.encapsulate()); + } else { + // not connected or closing, ... + return; + } + } + + /** + * Close the WebSocket connection. + * @param {int} code + * @param {DOMString} reason + */ + close(code, reason) { + // check code + if (code && (code !== 1000 || (code >= 3000 && code <= 4999))) { + throw Error(`InvalidAccessError: code must be 1000 or in the range 3000-4999`); + } + + if (reason) { + const unicodeReason = naclutil.encodeUTF8(reason); + if (unicodeReason.byteLength > 123) { + throw SyntaxError(`reason is too long: ${reason}`); + } + } + + if (this._readyState === WebSocketClient.CLOSED || this._readyState === WebSocketClient.CLOSING) { + // do nothing + return; + } else if (this._readyState !== WebSocketClient.OPEN) { + // connection not yet established + // fail the websocket connection and set the readyState attribute's value to CLOSING + this._closing(); + this._fail_the_websocket_connection(); + } else if (!this._the_websocket_closing_handshake_is_started) { + // the closing handshake has not yet been started + // start the closing handshake and set the readyState attribute's value to CLOSING + this._closing(); + this._start_the_websocket_closing_handshake(code, reason); + } else { + this._closing(); + } + } + + // CLOSING THE CONNECTION + // https://tools.ietf.org/html/rfc6455#section-7 + + /** + * Close the WebSocket Connection + * @private + */ + _close_the_websocket_connection() { + // cleanly close the TLS & TCP connection + if (this._socket) { + this._socket.close(); + } + this._readyState = WebSocketClient.CLOSED; + this._closed(true); + } + + /** + * Start the WebSocket Closing Handshake + * @param {int} code status code for closing the connection + * @param {reason} string reason for closing the connection + * @private + */ + _start_the_websocket_closing_handshake(code, reason = undefined) { + if (!(this._socket)) { + throw `Socket not initialized`; + } + + this._the_websocket_closing_handshake_is_started = true; + this._socket.send(wspackets.closeFrame(code, reason)); + + // wait for the close control frame from the endpoint + // and _close_the_websocket_connection + // this is done in the onmessage callback + } + + /** + * Fail the WebSocket Connection. + * @private + */ + _fail_the_websocket_connection() { + this._close_the_websocket_connection(); + } + + // TASKS + + /** + * Task to run when "the WebSocket connection is established" + * @private + */ + _established() { + // 1. change the readyState attribute's value to OPEN + this._readyState = WebSocketClient.OPEN; + + // 2. TODO: change the extensions attribute's value to the extensions in use, if is not the null value + // this._extensions = + + // 3. TODO: change the protocol attribute's value to the subprotocol in use, if is not the null value + // this._protocol = + + // 4. TODO: act as if the user agent had received a set-cookie-string consisting of the cookies + // set during the server's opening handshake, for the URL url given to the WebSocket() constructor + // document.cookie = + + // 5. fire a simple event named open at the WebSocket object + this.dispatchEvent(new Event("open")); + } + + /** + * Task to run when "a WebSocket message has been received" + * @private + */ + _received(event) { + + // 1. If the readyState attribute's value is not OPEN (1), then abort these steps + if (this._readyState !== WebSocketClient.OPEN) { + return; + } + + // 2. let event be an event that uses the MessageEvent interface, + // with the event type message, which does not bubble, is not cancelable, + // and has no default action. + // 3. initialize event's origin attribute to the Unicode serialization of the origin of the URL + // that was passed to the WebSocket object's constructor. + // 4. - if type indicates that the data is Text, then initialize event's data attribute to data + // - if type indicates that the data is Binary, and binaryType is set to "blob", + // then initialize event's data attribute to a new Blob object that represents data as its raw data + // - if type indicates that the data is Binary, and binaryType is set to "arraybuffer", + // then initialize event's data attribute to a new read-only ArrayBuffer object whose contents are data + + // 2+3+4 already done before + + let e = new MessageEventClass("message", { + origin: this._url.href, + data: event.data, + }); + + // 5. dispatch event at the WebSocket object. + this.dispatchEvent(e); + } + + /** + * Task to run when "the WebSocket closing handshake is started" + * @private + */ + _closing() { + // change the readyState attribute to CLOSING (2) + this._readyState = WebSocketClient.CLOSING; + } + + + /** + * Task to run when "the WebSocket connection is closed" + * @private + */ + _closed(wasClean, code = 1005, reason = "") { + // 1. change the readyState attribute's value to CLOSED (3) + this._readyState = WebSocketClient.CLOSED; + + // 2. if the user agent was required to fail the WebSocket connection + // or the WebSocket connection is closed with prejudice, + // fire a simple event named error at the WebSocket object + + // TODO + + // 3. Create an event that uses the CloseEvent interface, + // with the event type close, which does not bubble, is not cancelable, has no default action, + // whose wasClean attribute is initialized to true if the connection closed cleanly and false otherwise, + // whose code attribute is initialized to the WebSocket connection close code, + // and whose reason attribute is initialized to the WebSocket connection close reason decoded as UTF-8, + // with error handling, and dispatch the event at the WebSocket object + + const event = new CloseEventClass("close", { + wasClean: wasClean, + code: code, + reason: reason, + }); + + this.dispatchEvent(event); + } + + // Handshake helper methods + + /** + * Perform the opening websocket handshake. + * Non-blocking, as needed when calling the method in the constructor. + * + * This method should be called by the constructor of the derived class, + * setting the socket specific to this derived class. + * + * @param socket underlying socket + */ + _start_opening_handshake(socket) { + // TODO: check interface + this._socket = socket; + + // parse url + let host, port, ressourceName, secure; + try { + [host, port, ressourceName, secure] = parseURL(this._url); + } catch (err) { + throw SyntaxError(`could not parse url: ${err}`); + } + + // perform handshake + this.__do_opening_handhake(host, port, ressourceName, secure).then(() => { + this._established(); + this._socket.onmessage = handlers.onOpenMessage(this); + this.__onopen(); + }).catch(() => { + this._readyState = WebSocketClient.CLOSED; + this._fail_the_websocket_connection(); + }); + } + + + /** + * Perform the WebSocket connection handshake. + * + * @returns Promise that resolves when connection was successfully established, + * or rejects otherwise with an error message. + * @private + */ + __do_opening_handhake(host, port, ressourceName, secure) { + if (secure) { + console.error("secure websocket not yet supported"); + } + + return new Promise((resolve, reject) => { + if (!(this._socket)) { + reject(`Socket not initialized`); + } + + let statusLine = ""; + let headerLines = []; + + const [clientHS, secWebSocketKey] = wspackets.clientHandshake(host, port, ressourceName); + + // change onmessage of underlying socket + this._socket.onmessage = (pkt) => { // TODO: refactor to avoid request ? + let payload = naclutil.encodeUTF8(pkt); + + // parse received packet as a HTTP websocket connection response + let lines = payload.split("\r\n"); + if (lines.length < 1) { + reject(`failed to connect to websocket: received empty http response`); + } + + if (statusLine) { + // following message (response was fragmented) + headerLines = headerLines.concat(lines); + } else { + // first message + statusLine = lines[0].split(" "); + headerLines = headerLines.concat(lines.slice(1)); + + // status code verification + if (statusLine.length < 3) { + reject(`failed to connect to websocket: invalid status line ${statusLine.join(" ")}`); + return; + } + + const statusCode = statusLine[1]; + + if (statusCode != "101") { + reject(`failed to connect to websocket: got status code ${statusCode}`); + return; + } + } + + if (headerLines[headerLines.length - 1] !== "") { + return; + } else { + // last line of headers, no body expected + // this means that this is the last packet expected + let headers = httpParsing.parseHeaders(headerLines.join("\r\n")); + + // verification of the headers + + // check for the upgrade header field + if (!("upgrade" in headers) || !(headers["upgrade"].toLowerCase().split(", ").includes("websocket"))) { + reject(`failed to connect to websoket: server handshake response invalid, does not contain 'upgrade: websocket' header line: ${headers}`); + return; + } + + // check for the connection header field + if (!("connection" in headers) || !(headers["connection"].toLowerCase().split(", ").includes("upgrade"))) { + reject(`failed to connect to websocket: server handshake response invalid, does not contain 'connection: upgrade' header line: ${headers}`); + return; + } + + // check for the sec-websocket-accept header field + if (!("sec-websocket-accept" in headers)) { + reject(`failed to connect to websocket: server handshake response invalid, does not contain 'sec-websocket-accept' header line: ${headers}`); + return; + } + + if (!wspacketsutils.verifySecWebSocketAccept(secWebSocketKey, headers["sec-websocket-accept"].trim())) { + reject(`failed to connect to websocket: 'sec-websocket-accept' could not be verified`); + return; + } + + // check for the sec-websocket-extensions header field + if ("sec-websocket-extensions" in headers) { + const serverExtensions = headers["sec-websocket-extensions"].split(", "); + // TODO: no support for extensions + if (serverExtensions.length > 1 || serverExtensions[0] !== "") { + reject(`failed to connect to websocket: extensions are not supported: ${headers["sec-websocket-extensions"]}`); + return; + } + } + + // check for the sec-websocket-protocol header field + if ("sec-websocket-protocol" in headers) { + const serverSubProtocols = headers["sec-websocket-protocol"].split(", "); + // TODO: no support for subprotocols + if (serverSubProtocols.length > 1 || serverSubProtocols[0] !== "") { + reject(`failed to connect to websocket: sub protocols are not supported: ${headers["sec-websocket-protocol"]}`); + return; + } + } + + resolve(); + } + }; + this._socket.send(naclutil.decodeUTF8(clientHS)); + }); + + } + +} diff --git a/js-client/src/util.js b/js-client/src/util.js index 1f399d4..565d3b9 100644 --- a/js-client/src/util.js +++ b/js-client/src/util.js @@ -1,6 +1,7 @@ /** - * @module utils * Utility functions used in the lightnion js-client module. + * + * @module utils */ import { sjcl } from "../vendor/sjcl.js"; From 4fdd8f83395280f7e54f1a27d0421ad146535c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Th=C3=A9venet?= Date: Wed, 5 Feb 2020 14:53:41 +0100 Subject: [PATCH 04/30] Added Lightnion WebSocket. An implementation of a WebSocket Client that is redirected through Tor thanks to Lightnion. Exported as `lnn.websocket`. See the readme. --- js-client/demo/websocket.html | 65 +++++++++ js-client/src/lightnion-websocket/README.md | 81 ++++++++++ .../lightnion-helpers.js | 138 ++++++++++++++++++ .../lightnion-websocket.js | 66 +++++++++ .../test/lws.test.js | 10 ++ .../lightnion-websocket.js | 7 + js-client/src/lnn.js | 4 + 7 files changed, 371 insertions(+) create mode 100644 js-client/demo/websocket.html create mode 100644 js-client/src/lightnion-websocket/README.md create mode 100644 js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-helpers.js create mode 100644 js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-websocket.js create mode 100644 js-client/src/lightnion-websocket/lightnion-websocket-client/test/lws.test.js diff --git a/js-client/demo/websocket.html b/js-client/demo/websocket.html new file mode 100644 index 0000000..6fac0cd --- /dev/null +++ b/js-client/demo/websocket.html @@ -0,0 +1,65 @@ + + + + + + lightnion websocket redirect echo demo + + + +

lightnion websocket redirect echo demo

+

+ Connects to a WebServer echo server "ws://echo.websocket.org", through Lightnion. +

+ +
+ + +
+ + +
    + + + + + + + + + \ No newline at end of file diff --git a/js-client/src/lightnion-websocket/README.md b/js-client/src/lightnion-websocket/README.md new file mode 100644 index 0000000..6e71c2e --- /dev/null +++ b/js-client/src/lightnion-websocket/README.md @@ -0,0 +1,81 @@ +# Lightnion WebSocket + +In this folder can be found an abstract implementation of a WebSocket client in JavaScript (`websocket-client`), + +The `WebSocketClient` abstract class could be used on top of other TCP sockets, for this, the implementing class should follow similar code as to the LightnionWebSocket (`lightnion-websocket-client/lightnion-websocket.js`). + +The `LightnionWebSocket` is a concrete implementation that uses a TCP socket that is routed through Tor thanks to Lightnion. + +This library aims to provide a WebSocket close to the usual [WebSocket client](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) available in browsers. + +## Usage + +The `LightnionWebSocket` is added to the `lnn` namespace, you can use it thanks to the bundle built for the Lightnion `js-client`. + +```html + + +``` + +## Example + +For an example of use, consult `js-client/demo/websocket.html`, which shows how to use the lightnion websocket. + +## Development + +### Package structure + +The library is split in different folders under `src/lightnion-websocket/`: + +- `websocket-client` + + Exports the (abstract) `WebSocketClient` class, which represents a general websocket client that may be used in both browser and node environment. It relies on an underlying socket, given to it when calling `_start_opening_handshake`. + +- `websocket-client-lightnion` + + Concrete implementation of a `WebSocketClient`, using lightnion redirection and lightnion constructed tcp socket. + + +### Missing features, important notes + +#### `WebSocketClient` + +- no correct bufferedAmount support (always replies 0), this would depend on the underlying socket. +- no WebSocket subprotocols support +- no WebSocket extensions support +- [WebSocket cookies](https://www.w3.org/TR/websockets/#feedback-from-the-protocol) ? +- [RFC6455 4.1](https://tools.ietf.org/html/rfc6455#page-15) requires that there should be no more than one connection in a connecting state to the same IP address. This is currently not enforced. + +### Integration Tests + +TODO + +### WebSocketClient socket interface + +The `WebSocketClient` class implemented requires an underlying TCP socket, currently with a specific interface: + +- a `send(data)` method to send raw data +- a `close()` method to close the socket +- a `closed` boolean property indicating if the socket is closed +- a `onmessage(data)` callback firing when offering available raw data to the upper layer + +### Node support + +Node support is not ready yet. However it should be possible to extend the `WebSocketClient` class to implement it over Node's TCP socket. + + +### Moving to Secure WebSockets + +Secure WebSockets (WSS) are WebSocket that work over a TLS connection, similarly to HTTPS. + +To enable this, look at the `lightnion-websocket-client/lightnion-helpers.js` file and rewrite commented `ltlsOpen` function. +Use this function in `LightnionWebSocket`'s constructor in place of `ltcpOpen` in `lightnion-websocket-client/lightnion-webscoket.js`. +One also need to implement it in `__do_opening_handhake` method in `websocket-client/websocket-client.js`. + +Due to errors like `cannot connect to a non-secure websocket from a secure origin`, we could not implement it. +To avoid the error, use a remote Lightnion Proxy or implement secure websockets in the Lightnion Proxy. + + diff --git a/js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-helpers.js b/js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-helpers.js new file mode 100644 index 0000000..3661bf7 --- /dev/null +++ b/js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-helpers.js @@ -0,0 +1,138 @@ +/** + * Helpers for the lightnion js-client code. + */ + +import { lnn } from "../../lnn.js"; + +/** + * A Lightnion tunelled TCP socket. + * @private + */ +export class LTCP { + // TODO: onclose + constructor(host) { + this.connected = false; + // TODO: document + // onmessage takes a UInt8Array argument + this.onmessage = (msg) => { console.error(`LTCP received non-handled message: ${msg}`); }; + this.host = host; + } + + send() { + throw "LTPC: undefined send method"; + } +} + +/** + * Connect to a Lightnion Proxy. + * @param {string} lnnHost host of the lightnion proxy + * @param {Number} lnnPort port of the lightnion proxy + * @returns a promise that resolves on connection success, and rejects in case of a failure; + * in case of success, return the lightnion endpoint, in case of failure, an error message + * @private + */ +export function lnnOpen(lnnHost, lnnPort) { + return new Promise((resolve, reject) => { + lnn.open(lnnHost, lnnPort, function (endpoint) { + if (endpoint.state != lnn.state.success) { + console.error("lightnion proxy connection failed"); + reject(`could not connect to lightnion proxy at ${lnnHost}:${lnnPort}`); + } + console.debug("lightnion proxy connection established"); + resolve(endpoint); + }); + }); +} + +// Connect to TCP endpoint +// return a promise that resolves on connection success, and rejects in case of failure +// in case of succes, return a TCP object, in case of failure, an error message +/** + * Connect to a TCP endpoint through a Lightnion proxy. + * + * @param lnnEndpoint the lightnion proxy endpoint object, returned by {@link lnnOpen} + * @param host host of the TCP endpoint + * @param port port of the TCP endpoint + * @private + */ +export function ltcpOpen(lnnEndpoint, host, port) { + + return new Promise((resolve, reject) => { + + let ltcp = new LTCP(host); + + function handler(socket) { + + let pkt; + + switch (socket.state) { + case lnn.state.created: + ltcp.connected = true; + ltcp.send = socket.send; + resolve(ltcp); + break; + case lnn.state.pending: + pkt = socket.recv(); + if (pkt !== undefined) { + ltcp.onmessage(pkt); + } + break; + case lnn.state.success: + ltcp.connected = false; + reject(`could not connect to TCP host at ${host}:${port}`); + break; + default: + break; + } + } + lnn.stream.tcp(lnnEndpoint, host, port, handler); + }); +} + +// TLS support. +// Uses forge.tls module. +// TODO: tests. +// export function ltlsOpen(lnnEndpoint, host, port) { + +// return ltcpOpen(lnnEndpoint, host, port).then(ltcp => { +// console.debug("tcp socket connected") +// return new Promise((resolve, reject) => { +// let tlsSocket = new LTCP(host); + +// // create tls client working on tcp +// let tlsClient = forge.tls.createConnection({ +// // see: https://github.com/digitalbazaar/forge#tls +// server: false, +// verify: function (connection, verified, depth, certs) { +// // FIXME +// return true; // skip cert. verif. (testing) +// }, +// connected: function (connection) { +// // (tls handshake finished, now ready to send) +// tlsSocket.onmessage = (req) => { tlsClient.process(lnn.enc.bin(req.recv())); }; +// tlsSocket.send = tlsClient.send; +// resolve(tlsSocket); +// }, +// tlsDataReady: function (connection) { +// // TLS -> TCP +// // (decode binary data into array before processing) +// ltcp.send(lnn.dec.bin(connection.tlsData.getBytes())); +// }, +// dataReady: function (connection) { +// // TLS -> Application +// // (receive decrypted data from the tls transport) +// var data = connection.data.getBytes(); +// onReceive(data); +// }, +// closed: function (connection) { +// console.info("tls connection closed"); +// }, +// error: function (connection, err) { +// console.error(`tls connection error: ${err}`); +// } +// }); +// console.debug("initiating tls handshake"); +// tlsClient.handshake(); +// }); +// }); +// } diff --git a/js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-websocket.js b/js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-websocket.js new file mode 100644 index 0000000..2d367a9 --- /dev/null +++ b/js-client/src/lightnion-websocket/lightnion-websocket-client/lightnion-websocket.js @@ -0,0 +1,66 @@ +/** + * @module lightnion-websocket + */ + +import { WebSocketClient } from "../websocket-client/websocket-client.js"; +import { lnnOpen, ltcpOpen } from "./lightnion-helpers.js"; +// import { ltlsOpen } from "./lightnion-helpers.js"; // TODO: TLS support + +/** + * LightnionWebSocket is a WebSocket client tunnelled through Lightnion. + */ +export default class LightnionWebSocket extends WebSocketClient { + + /** + * Create a LightnionWebSocket, a WebSocket tunelled through Tor via a Lightnion proxy. + * + * @param {string} url the WebSocket server URL + * @param {array} protocols a list of subprotocols to use, currently not-supported + * @param {string} lightnionHost the lightnion proxy host + * @param {Number} lightnionPort the lightnion proxy port + */ + constructor(url, protocols = [], lightnionHost = "localhost", lightnionPort = 4990) { + let urlP = new URL(url); + + let port = urlP.port; + if (!port) { + port = urlP.protocol == "ws:" ? "80" : "443"; + } + + super(urlP, protocols); + + // user defined event handlers + this.onmessage = () => { }; + this.onopen = () => { }; + this.onclose = () => { }; + this.onerror = () => { }; + + // schedule the tcp handshake to start when the underlying socket is ready + lnnOpen(lightnionHost, lightnionPort).then(lnnEndpoint => { + // open tcp socket to host, through lightnion + return ltcpOpen(lnnEndpoint, urlP.hostname, port); + // or open a tls socket + // return ltlsOpen(lnnEndpoint, urlP.hostname, port); + }).then(ltcp => { + console.debug("[LTCP]: connected"); + + // start websocket handshake protocol + this._start_opening_handshake(ltcp); + + // install handlers + this.__onmessage = (event) => { + this.onmessage(event); + }; + this.__onopen = (event) => { + this.onopen(event); + }; + this.__onclose = (event) => { + this.onclose(event); + }; + this.__onerror = (event) => { + this.onerror(event); + }; + + }); + } +} diff --git a/js-client/src/lightnion-websocket/lightnion-websocket-client/test/lws.test.js b/js-client/src/lightnion-websocket/lightnion-websocket-client/test/lws.test.js new file mode 100644 index 0000000..0bdefa9 --- /dev/null +++ b/js-client/src/lightnion-websocket/lightnion-websocket-client/test/lws.test.js @@ -0,0 +1,10 @@ +// Tests for LWS + +import { assert } from "chai"; +import LWS from "../lightnion-websocket.js"; + +describe("LightnionWebSocket", function () { + it("can be imported", function () { + assert.ok(LWS); + }); +}); diff --git a/js-client/src/lightnion-websocket/lightnion-websocket.js b/js-client/src/lightnion-websocket/lightnion-websocket.js index e69de29..097bb7b 100644 --- a/js-client/src/lightnion-websocket/lightnion-websocket.js +++ b/js-client/src/lightnion-websocket/lightnion-websocket.js @@ -0,0 +1,7 @@ +/* + * Exprots for Lightnion WebSocket Client. + * To use as a library. + */ + +import LightnionWebSocket from "./lightnion-websocket-client/lightnion-websocket.js"; +export default LightnionWebSocket; \ No newline at end of file diff --git a/js-client/src/lnn.js b/js-client/src/lnn.js index 4f4711b..43bf5c4 100644 --- a/js-client/src/lnn.js +++ b/js-client/src/lnn.js @@ -27,6 +27,7 @@ import * as relay from "./relay.js"; import * as signature from "./signature"; import * as stream from "./stream.js"; import * as utils from "./util.js"; +import LightnionWebSocket from "./lightnion-websocket/lightnion-websocket.js"; // header let lnn = header.lnn; @@ -114,6 +115,9 @@ lnn.dec.utf8 = utils.dec.utf8; lnn.dec.base64 = utils.dec.base64; lnn.dec.bin = utils.dec.bin; +// websocket +lnn.websocket = LightnionWebSocket; + window.lnn = lnn; export { lnn }; \ No newline at end of file From d32953776250227a20b38ca6d992a7e173d8aeef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Th=C3=A9venet?= Date: Thu, 6 Feb 2020 08:49:39 +0100 Subject: [PATCH 05/30] Added linting using eslint. Configuration is in `.eslintrc.json`. --- js-client/.eslintrc.json | 18 ++++++++++++++++++ js-client/Makefile | 6 +++--- 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 js-client/.eslintrc.json diff --git a/js-client/.eslintrc.json b/js-client/.eslintrc.json new file mode 100644 index 0000000..bb26bb7 --- /dev/null +++ b/js-client/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true, + "commonjs": true + }, + "extends": "eslint:recommended", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": {} +} \ No newline at end of file diff --git a/js-client/Makefile b/js-client/Makefile index cdfb7b4..13fca37 100644 --- a/js-client/Makefile +++ b/js-client/Makefile @@ -36,9 +36,9 @@ doc: jsdoc/index.html test: @./node_modules/mocha/bin/mocha -r jsdom-global/register --require esm --recursive --exclude "src/export.js" src/ -# # run javascript linter -# lint: -# ./node_modules/.bin/eslint src +# run javascript linter +lint: + ./node_modules/.bin/eslint src # clean built files clean: From 47c1b4c47dd164d374191fc1c570443655ab797a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20Th=C3=A9venet?= Date: Thu, 6 Feb 2020 11:54:06 +0100 Subject: [PATCH 06/30] Added integration tests for Lightnion WebSocket. Testing Lightnion WebSocket in a selenium-drived browser, with local test chutney network, local Lightnion proxy, and local WebSocket servers. See README.md in `js-client/integration-tests/lightnion-websocket/`. --- js-client/Makefile | 12 +- .../lightnion-websocket/README.md | 34 + .../lightnion-websocket/common/__init__.py | 0 .../lightnion-websocket/common/endpoint.py | 354 + .../lightnion-websocket/common/throughput.py | 12 + .../lightnion-websocket/config.py | 21 + .../lightnion-websocket/infra/lightnion.sh | 7 + .../lightnion-websocket/infra/setup.sh | 26 + .../lightnion-websocket/public/echo-chat.css | 53 + .../public/lws-echo-test.html | 78 + .../lightnion-websocket/public/lws.bundle.js | 39585 ++++++++++++++++ .../lightnion-websocket/requirements.txt | 4 + .../run_integration_tests.py | 22 + .../tests/lightion_websocket_test.py | 185 + .../tests/test_missing_websocket_server.py | 58 + .../tests/test_normal_behavior.py | 149 + .../lightnion-websocket/tests/utils.py | 47 + js-client/src/lightnion-websocket/README.md | 2 +- 18 files changed, 40647 insertions(+), 2 deletions(-) create mode 100644 js-client/integration-tests/lightnion-websocket/README.md create mode 100755 js-client/integration-tests/lightnion-websocket/common/__init__.py create mode 100755 js-client/integration-tests/lightnion-websocket/common/endpoint.py create mode 100644 js-client/integration-tests/lightnion-websocket/common/throughput.py create mode 100644 js-client/integration-tests/lightnion-websocket/config.py create mode 100755 js-client/integration-tests/lightnion-websocket/infra/lightnion.sh create mode 100755 js-client/integration-tests/lightnion-websocket/infra/setup.sh create mode 100644 js-client/integration-tests/lightnion-websocket/public/echo-chat.css create mode 100644 js-client/integration-tests/lightnion-websocket/public/lws-echo-test.html create mode 100644 js-client/integration-tests/lightnion-websocket/public/lws.bundle.js create mode 100644 js-client/integration-tests/lightnion-websocket/requirements.txt create mode 100644 js-client/integration-tests/lightnion-websocket/run_integration_tests.py create mode 100644 js-client/integration-tests/lightnion-websocket/tests/lightion_websocket_test.py create mode 100644 js-client/integration-tests/lightnion-websocket/tests/test_missing_websocket_server.py create mode 100755 js-client/integration-tests/lightnion-websocket/tests/test_normal_behavior.py create mode 100755 js-client/integration-tests/lightnion-websocket/tests/utils.py diff --git a/js-client/Makefile b/js-client/Makefile index 13fca37..1b482bc 100644 --- a/js-client/Makefile +++ b/js-client/Makefile @@ -1,4 +1,4 @@ -.PHONY: all install build test doc lint clean help submodules +.PHONY: all install build test doc lint clean help submodules integration # recursive wildcard rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) @@ -17,6 +17,8 @@ SJCL-BUILD = $(VENDOR)/sjcl.js DIST = ./dist LIGHTNION-BUNDLE = lightnion.bundle.js LIGHTNION-BUNDLE-DIST = $(DIST)/lightnion.bundle.js +LIGHTNION-BUNDLE-INTEGRATION-TESTS = integration-tests/lightnion-websocket/public/lws.bundle.js + JSDOC-DIST = jsdoc/ SOURCES = $(call rwildcard,src/) @@ -36,6 +38,10 @@ doc: jsdoc/index.html test: @./node_modules/mocha/bin/mocha -r jsdom-global/register --require esm --recursive --exclude "src/export.js" src/ +# build project for integration testing +integration: $(LIGHTNION-BUNDLE-INTEGRATION-TESTS) + cd integration-tests/lightnion-websocket/infra; sh setup.sh + # run javascript linter lint: ./node_modules/.bin/eslint src @@ -44,6 +50,7 @@ lint: clean: $(RM) $(LIGHTNION-BUNDLE) $(RM) $(DIST)/* + $(RM) $(LIGHTNION-BUNDLE-INTEGRATION-TESTS) $(RM) -r $(JSDOC-DIST) # clean built files and dependencies @@ -57,6 +64,9 @@ help: $(LIGHTNION-BUNDLE): $(LIGHTNION-BUNDLE-DIST) $(CP) $(LIGHTNION-BUNDLE-DIST) $@ +$(LIGHTNION-BUNDLE-INTEGRATION-TESTS): $(LIGHTNION-BUNDLE-DIST) + $(CP) $(LIGHTNION-BUNDLE-DIST) $@ + $(LIGHTNION-BUNDLE-DIST): $(SJCL-BUILD) $(SOURCES) npm run build diff --git a/js-client/integration-tests/lightnion-websocket/README.md b/js-client/integration-tests/lightnion-websocket/README.md new file mode 100644 index 0000000..07b3c84 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/README.md @@ -0,0 +1,34 @@ +# Integration Tests for Lightnion WebSocket + +## Requirements + +- Install [geckodriver](https://github.com/mozilla/geckodriver/releases) and add it to your PATH. +- Install `Tor` of version `0.3` (should be compatible with `lightnion`), instructions can be found [here](https://trac.torproject.org/projects/tor/wiki/TorRelayGuide#PlatformspecificInstructions). +- Install python requirements: +```bash +pip install -r requirements.txt +``` +- Install infrastructure dependencies: +```bash +cd ../.. && make integration +``` +# Running the tests + +```bash +python run_integration_test.py +``` + +Logs for `chutney` and `lightnion` will be found in `tests/logs`. + +## Notes + +### Troubleshooting + +- Launching chutney may fail because of paths being too long for unix socket. A solution is to move the project folder to a low level path like `/tmp`. + +### Infrastructure Components + +- `client`: a web browser client (selenium with geckodriver) +- `proxy`: a lightnion proxy +- `testnet`: a `testnet` simulated Tor network (chutney) +- `endpoint`: an endpoint for the websocket connection, the http server for the webpage and the lightnion code diff --git a/js-client/integration-tests/lightnion-websocket/common/__init__.py b/js-client/integration-tests/lightnion-websocket/common/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/js-client/integration-tests/lightnion-websocket/common/endpoint.py b/js-client/integration-tests/lightnion-websocket/common/endpoint.py new file mode 100755 index 0000000..89aa954 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/common/endpoint.py @@ -0,0 +1,354 @@ +from aiohttp import web +from http.server import HTTPServer, SimpleHTTPRequestHandler +import datetime +import ssl +import asyncio +import aiohttp +import logging +import threading +import logging +import time +import socket +import sys +from .throughput import UploadState + +# for throughtput LTCP tests, hardcoded... +NUM_PACKETS = 10000 +PACKET_SIZE = 1000 + +async def http_handler(request): + name = request.match_info.get("name", "Anonymous") + text = "Hello, " + name + return aiohttp.web.Response(text=text) + + +async def websocket_handler(request): + """WebSocket Echo Handler for integration testing.""" + ws = aiohttp.web.WebSocketResponse(compress=False) + await ws.prepare(request) + + peername = request.transport.get_extra_info("peername") + if peername is not None: + logging.info(f"peer connected: {peername}") + request.app.endpoint.ws_connected_peers.add(peername) + + async for msg in ws: + + logging.info(f"received websocket message: {msg}") + + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == "close": + await ws.close() + else: + response = msg.data + logging.info(f"sending websocket message: {response}") + await ws.send_str(response) + elif msg.type == aiohttp.WSMsgType.ERROR: + logging.info("ws connection closed with exception %s" % + ws.exception()) + + logging.info("websocket connection closed") + return ws + + +async def websocket_echo_handler(request): + """WebSocket Echo Handler for evaluation.""" + ws = aiohttp.web.WebSocketResponse() + await ws.prepare(request) + + async for msg in ws: + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == "close": + await ws.close() + else: + response = msg.data + await ws.send_str(response) + elif msg.type == aiohttp.WSMsgType.ERROR: + logging.info("ws connection closed with exception %s" % + ws.exception()) + + logging.info("websocket connection closed") + return ws + + +async def websocket_time_to_first_message_handler(request): + """WebSocket Time to first message handler for evaluation.""" + ws = aiohttp.web.WebSocketResponse() + await ws.prepare(request) + + async for msg in ws: + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == "close": + await ws.close() + else: + response = msg.data + # take the timestamp in ms + current_time_ms = int(datetime.datetime.now( + datetime.timezone.utc).timestamp() * 1000) # unix time + # send it as a string + await ws.send_str(f"{current_time_ms}") + elif msg.type == aiohttp.WSMsgType.ERROR: + logging.info("ws connection closed with exception %s" % + ws.exception()) + + logging.info("websocket connection closed") + return ws + + +async def websocket_upload_handler(request): + """WebSocket Upload Handler for evaluation. + + This is used to perform upload throughput tests from the javascript client. + """ + + ws = aiohttp.web.WebSocketResponse() + await ws.prepare(request) + endpoint = request.app.endpoint + + peername = request.transport.get_extra_info("peername") + if peername not in endpoint.upload_state_by_peer: + endpoint.upload_state_by_peer[peername] = UploadState() + + async for msg in ws: + if msg.type == aiohttp.WSMsgType.BINARY: + if not endpoint.upload_state_by_peer[peername].start_time: + # first packet received, record start time + endpoint.upload_state_by_peer[peername].start_time = int( + datetime.datetime.now().timestamp() * 1000) + + endpoint.upload_state_by_peer[peername].received_bytes += len( + msg.data) + + if (endpoint.upload_state_by_peer[peername].received_bytes >= endpoint.upload_state_by_peer[peername].expected_bytes): + end = int(datetime.datetime.now().timestamp() * 1000) + endpoint.upload_state_by_peer[peername].end_time = datetime.datetime.now( + ) + logging.info( + f"upload test ended for peer {peername}: received {expected_bytes} bytes") + + start = endpoint.upload_state_by_peer[peername].start_time + await ws.send_json({"start": start, "end": end}) + + elif msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == "close": + await ws.close() + else: + # signal message, indicating the expected byte count to receive + received = msg.json() + if ("upload_bytes" in received): + expected_bytes = received["upload_bytes"] + endpoint.upload_state_by_peer[peername].expected_bytes = expected_bytes + logging.info( + f"peer {peername} started upload test for {expected_bytes} bytes") + + elif msg.type == aiohttp.WSMsgType.ERROR: + logging.info("ws connection closed with exception %s" % + ws.exception()) + + logging.info("websocket connection closed") + return ws + + +async def websocket_download_handler(request): + """WebSocket Upload Handler for evaluation. + + This is used to perform upload throughput tests from the javascript client. + """ + + ws = aiohttp.web.WebSocketResponse() + await ws.prepare(request) + endpoint = request.app.endpoint + + async for msg in ws: + if msg.type == aiohttp.WSMsgType.TEXT: + if msg.data == "close": + await ws.close() + else: + # signal message, indicating the byte count to send, and to start sending + received = msg.json() + if ("packetCount" in received and "packetSize" in received): + packet_count = received["packetCount"] + packet_size = received["packetSize"] + + # craft packet + pkt_src = [i % 256 for i in range(packet_size)] + pkt = bytearray(pkt_src) + + # wait some time + await asyncio.sleep(0.5) + + for i in range(packet_count): + await ws.send_bytes(pkt) + + elif msg.type == aiohttp.WSMsgType.ERROR: + logging.info("ws connection closed with exception %s" % + ws.exception()) + + logging.info("websocket connection closed") + return ws + + +class Endpoint: + """A HTTP/WebSocket endpoint used to test lightnion javscript client.""" + + def __init__( + self, host: str = "localhost", http_port: int = 8080, ws_port: int = None + ): + """Construct a test endpoint. + + The test endpoint hosts a HTTP and WebSocket server, both can be served on the same port or different. + + Args: + host (str): the host of the webserver (default: 'localhost') + http_port (int): the port of the http server + ws_port (int): the port of the webserver, if None, the same as the http_port + """ + + self.host = host + self.http_port = http_port + self.ws_port = ws_port + + # the set of peers that connected to the websocket + self.ws_connected_peers = set() + + # upload state for peers having started a throughput evaluation + self.upload_state_by_peer = {} + + # setup http server + self.http_app = aiohttp.web.Application() + self.http_app.endpoint = self + self.http_app.add_routes( + [ + # serve static files in public/ directory under route '/public' + web.static("/public", "./public/", show_index=True) + ] + ) + + if ws_port is None or ws_port == http_port: + self.http_app.add_routes( + [ + # serve websocket under route '/ws', + # for integration testing + web.get("/ws", websocket_handler), + web.get("/ws-echo", websocket_echo_handler), + web.get("/ws-upload", websocket_upload_handler), + web.get("/ws-download", websocket_download_handler), + web.get("/ws-ttfm", websocket_time_to_first_message_handler) + ] + ) + self.ws_app = None + self.ws_runner = None + else: + # setup a different websocket server + self.ws_app = aiohttp.web.Application() + self.ws_app.endpoint = self + self.ws_app.add_routes( + [ + # serve websocke tunder route '/ws', + # for integration testing + web.get("/ws", websocket_handler), + web.get("/ws-echo", websocket_echo_handler), + web.get("/ws-upload", websocket_upload_handler), + web.get("/ws-download", websocket_download_handler), + web.get("/ws-ttfm", websocket_time_to_first_message_handler) + ] + ) + self.ws_runner = aiohttp.web.AppRunner(self.ws_app) + + self.http_runner = aiohttp.web.AppRunner(self.http_app) + + def start(self): + # set event-loop if not defined (maybe running in a thread) + try: + loop = asyncio.get_event_loop() + except: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + loop.run_until_complete(self.http_runner.setup()) + http_site = aiohttp.web.TCPSite( + self.http_runner, self.host, self.http_port) + loop.run_until_complete(http_site.start()) + logging.info("http endpoint: started") + logging.info(f"http endpoint: running on {self.host}:{self.http_port}") + + if self.ws_runner: + loop.run_until_complete(self.ws_runner.setup()) + ws_site = aiohttp.web.TCPSite( + self.ws_runner, self.host, self.ws_port) + loop.run_until_complete(ws_site.start()) + logging.info("ws endpoint: started") + logging.info(f"ws endpoint: running on {self.host}:{self.ws_port}") + + # TCP + # self.tcp_echo_thread = threading.Thread(target = self.tcp_echo, daemon=True) + # self.tcp_echo_thread.start() + + async def tcp_echo(reader, writer): + request = None + while True: + request = await reader.read(255) + writer.write(request) + await writer.drain() + writer.close() + + async def tcp_ttfm(reader, writer): + import math + request = None + while True: + request = await reader.read(255) + current_time_ms = int(datetime.datetime.now( + datetime.timezone.utc).timestamp() * 1000) # unix time + writer.write(current_time_ms.to_bytes(32, 'little')) + await writer.drain() + writer.close() + + async def tcp_dl(reader, writer): + import math + request = None + while True: + request = await reader.read(1000) + # craft packet + pkt_src = [i % 256 for i in range(PACKET_SIZE)] + pkt = bytearray(pkt_src) + + # wait some time + await asyncio.sleep(0.5) + + for i in range(NUM_PACKETS): + writer.write(pkt) + await writer.drain() + writer.close() + + async def tcp_ul(reader, writer): + import math + request = None + start_time = None + end_time = None + recv_bytes = 0 + while True: + request = await reader.read(1000) + # print(request) + recv_bytes += len(request) + if start_time is None: + start_time = int(datetime.datetime.now().timestamp() * 1000) + if end_time is None and recv_bytes == NUM_PACKETS * PACKET_SIZE: + end_time = int(datetime.datetime.now().timestamp() * 1000) + + writer.write(start_time.to_bytes(32, 'little')) + writer.write(end_time.to_bytes(32, 'little')) + await writer.drain() + + writer.close() + + loop = asyncio.get_event_loop() + loop.create_task(asyncio.start_server(tcp_echo, 'localhost', 8082)) + loop.create_task(asyncio.start_server(tcp_ttfm, 'localhost', 8083)) + loop.create_task(asyncio.start_server(tcp_dl, 'localhost', 8084)) + loop.create_task(asyncio.start_server(tcp_ul, 'localhost', 8085)) + + loop.run_forever() + + def stop(self): + self.socket.close() + os._exit(0) diff --git a/js-client/integration-tests/lightnion-websocket/common/throughput.py b/js-client/integration-tests/lightnion-websocket/common/throughput.py new file mode 100644 index 0000000..0db2c92 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/common/throughput.py @@ -0,0 +1,12 @@ +""" +Throughput evaluation helpers. +""" +from datetime import datetime + +class UploadState: + def __init__(self, start_time: datetime = None, end_time: datetime = None, expected_bytes: int = 0, received_bytes: int = 0): + self.start_time = start_time + self.end_time = end_time + self.expected_bytes = expected_bytes + self.received_bytes = received_bytes + diff --git a/js-client/integration-tests/lightnion-websocket/config.py b/js-client/integration-tests/lightnion-websocket/config.py new file mode 100644 index 0000000..ecfb0bf --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/config.py @@ -0,0 +1,21 @@ +HOST = "localhost" +HTTP_PORT = 8080 +WS_PORT = 8081 +TCP_PORT = 8082 +DEMO_PATH = "public/lws-echo-test.html" +EVALUATION_PATH = "public/evaluation/evaluation.html" + +WEBSOCKET_CONNECTING_WAIT = 5 # time to wait for the websocket to connect +WEBSOCKET_RESPONSE_WAIT = 2 # time to wait for the reception of a message +BROWSER_WAIT = 5 # time to wait for elements in the browser + +CHUTNEY = "./infra/chutney/chutney" +CHUTNEY_NET = "./infra/chutney/networks/basic" + +LIGHTNION_CWD = "./infra/lightnion" +LIGHTNION = "./venv/bin/python -m lightnion.proxy -s 127.0.0.1:5001 -d 7001 -c 8001 -vvv" + +LOG_DIRECTORY = "./logs" + +EVALUATION_WAIT = 1000 +EVALUATION_OUT_DIRECTORY = "./results" diff --git a/js-client/integration-tests/lightnion-websocket/infra/lightnion.sh b/js-client/integration-tests/lightnion-websocket/infra/lightnion.sh new file mode 100755 index 0000000..c99d44f --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/infra/lightnion.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# start lightnion for integration tests + +source venv/bin/activate +cd ../../../../ +export PYTHONPATH="$PWD" +python -m lightnion.proxy -s 127.0.0.1:5001 -d 7001 -c 8001 -vvv diff --git a/js-client/integration-tests/lightnion-websocket/infra/setup.sh b/js-client/integration-tests/lightnion-websocket/infra/setup.sh new file mode 100755 index 0000000..da8d505 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/infra/setup.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# setup dependencies for integration tests + +lightnion="../../../.." +lightnion-venv="venv/bin/activate" +chutney_dir="chutney" + + +# setup lightnion virtual environment +if [[ ! -e $lightnion_dir ]]; then + virtualenv venv + source venv/bin/activate + pip install -r "${lightnion}/requirements.txt" + pip install -r "${lightnion}/requirements-proxy.txt" +fi + + +# clone and setup chutney +if [[ ! -e $chutney_dir ]]; then + git clone https://git.torproject.org/chutney.git + # setup chutney from submodule in lightnion + cp ${lightnion_dir}/tools/chutney/* "${chutney_dir}/" + cd chutney + git apply sandbox_patch +fi + diff --git a/js-client/integration-tests/lightnion-websocket/public/echo-chat.css b/js-client/integration-tests/lightnion-websocket/public/echo-chat.css new file mode 100644 index 0000000..27d6640 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/public/echo-chat.css @@ -0,0 +1,53 @@ +.user-input { + text-align: center; +} + +h1 { + text-align: center; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font: 13px Helvetica, Arial; +} + +form { + background: #000; + padding: 3px; + position: fixed; + bottom: 0; + width: 100%; +} + +form input { + border: 0; + padding: 10px; + width: 90%; + margin-right: .5%; +} + +form button { + width: 9%; + background: rgb(130, 224, 255); + border: none; + padding: 10px; +} + +#messages { + list-style-type: none; + margin: 0; + padding: 0; +} + +#messages li { + padding: 5px 10px; +} + +#messages li:nth-child(odd) { + background: #eee; +} \ No newline at end of file diff --git a/js-client/integration-tests/lightnion-websocket/public/lws-echo-test.html b/js-client/integration-tests/lightnion-websocket/public/lws-echo-test.html new file mode 100644 index 0000000..34ed85e --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/public/lws-echo-test.html @@ -0,0 +1,78 @@ + + + + + + + + + + + lightnion websocket redirect echo demo + + + + + + + +

    lightnion websocket redirect echo demo

    + +
      +
      + + +
      + + + + + + + + + \ No newline at end of file diff --git a/js-client/integration-tests/lightnion-websocket/public/lws.bundle.js b/js-client/integration-tests/lightnion-websocket/public/lws.bundle.js new file mode 100644 index 0000000..86e5fb0 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/public/lws.bundle.js @@ -0,0 +1,39585 @@ +this.lightnion = this.lightnion || {}; +this.lightnion.bundle = (function (exports) { + 'use strict'; + + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function commonjsRequire () { + throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs'); + } + + function unwrapExports (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } + + function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; + } + + function getCjsExportFromNamespace (n) { + return n && n['default'] || n; + } + + var lib = createCommonjsModule(function (module, exports) { + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + + /* global window self */ + + var isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; + + /* eslint-disable no-restricted-globals */ + var isWebWorker = (typeof self === 'undefined' ? 'undefined' : _typeof(self)) === 'object' && self.constructor && self.constructor.name === 'DedicatedWorkerGlobalScope'; + /* eslint-enable no-restricted-globals */ + + var isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null; + + exports.isBrowser = isBrowser; + exports.isWebWorker = isWebWorker; + exports.isNode = isNode; + }); + + unwrapExports(lib); + var lib_1 = lib.isBrowser; + var lib_2 = lib.isWebWorker; + var lib_3 = lib.isNode; + + /** + * @module header + * @namespace + * @see lnn.open + * @see lnn.stream.tcp + * @see lnn.state + * @example + * lnn.open('proxy.server', 4990, function(endpoint) + * { + * if (endpoint.state != lnn.state.success) + * return + * tcp = lnn.stream.tcp(endpoint, 'api.ipify.org', 80, handler) + * tcp.send('GET / HTTP/1.1\r\nHost: api.ipify.org\r\n\r\n') + * }) + * + * function handler(request) + * { + * switch(request.state) + * { + * case lnn.state.created: console.log('ready') + * return + * case lnn.state.pending: + * console.log(lnn.enc.utf8(request.recv())) + * return + * case lnn.state.success: console.log('closed') + * return + * } + * } + * + */ + + let lnn$1 = {}; + + /** + * Common API constants. + * @namespace + */ + lnn$1.api = {}; + + /** + * Supported API version. + * @readonly + * @default + */ + lnn$1.api.version = "0.1"; + + /** + * Prefix used to craft API endpoints. + * @default + **/ + lnn$1.api.url = "/lightnion/api/v0.1"; + + /** + * Port used to craft websockets. + * @default + **/ + lnn$1.api.ws_port = "8765"; + + /** + * Request state enumeration. + * @enum + * @readonly + **/ + lnn$1.state = { + /** + * operation started + * @type channel + */ + started: 1, + /** + * /guard get success (channel only) + * @type channel + */ + guarded: 2, + /** + * circuit created + * @type channel + */ + created: 3, + /** + * circuit negotiation + * @type channel + */ + pending: 4, + /** circuit extended (channel only) + * @type channel + */ + extpath: 5, + /** + * ready to use + * @type channel + */ + success: 6, + /** + * operation started + * @type stream + */ + started: 1, + /** + * ready to use + * @type stream + */ + created: 3, + /** + * incoming data + * @type stream + */ + pending: 4, + /** + * completed or closed + * @type stream + */ + success: 6 + }; + + var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return "CORRUPT: "+this.message};this.message=a;},invalid:function(a){this.toString=function(){return "INVALID: "+this.message};this.message=a;},bug:function(a){this.toString=function(){return "BUG: "+this.message};this.message=a;},notReady:function(a){this.toString=function(){return "NOT READY: "+this.message};this.message=a;}}}; + sjcl.cipher.aes=function(a){this.A[0][0][0]||this.R();var b,c,d,e,f=this.A[0][4],g=this.A[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c;}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c& + 255]];}; + sjcl.cipher.aes.prototype={encrypt:function(a){return t(this,a,0)},decrypt:function(a){return t(this,a,1)},A:[[[],[],[],[],[]],[[],[],[],[],[]]],R:function(){var a=this.A[0],b=this.A[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,m,n,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1)for(n=g^g<<1^g<<2^g<<3^g<<4,n=n>>8^n&255^99,c[f]=n,d[n]=f,m=h[e=h[l=h[f]]],p=0x1010101*m^0x10001*e^0x101*l^0x1010100*f,m=0x101*h[n]^0x1010100*n,e=0;4>e;e++)a[e][f]=m=m<<24^m>>>8,b[e][n]=p=p<<24^p>>>8;for(e= + 0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0);}}; + function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,m=d.length/4-2,n,p=4,r=[0,0,0,0];h=a.A[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(n=0;n>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(n= + 0;4>n;n++)r[c?3&-n:n]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return r} + sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.aa(a.slice(b/32),32-(b&31)).slice(1);return void 0===c?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return ((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return !1;var c=0,d;for(d=0;d>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}}; + sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d>>8>>>8>>>8),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c>>g)>>>e),gm){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+n+"!");}h>e?(h-=e,f.push(l^m>>>h),l=m<>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.D,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;dh)throw new sjcl.exception.invalid("this isn't base64!");26>>e),g=h<<32-e):(e+=6,g^=h<<32-e);}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}}; + sjcl.codec.bytes={fromBits:function(a){var b=[],c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d>>24),e<<=8;return b},toBits:function(a){var b=[],c,d=0;for(c=0;cb;c++){e=!0;for(d=2;d*d<=c;d++)if(0===c%d){e= + !1;break}e&&(8>b&&(this.H[b]=a(Math.pow(c,.5))),this.b[b]=a(Math.pow(c,1/3)),b++);}},l:function(a){var b,c,d,e=this.g,f=this.b,g=e[0],h=e[1],k=e[2],l=e[3],m=e[4],n=e[5],p=e[6],r=e[7];for(b=0;64>b;b++)16>b?c=a[b]:(c=a[b+1&15],d=a[b+14&15],c=a[b&15]=(c>>>7^c>>>18^c>>>3^c<<25^c<<14)+(d>>>17^d>>>19^d>>>10^d<<15^d<<13)+a[b&15]+a[b+9&15]|0),c=c+r+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(p^m&(n^p))+f[b],r=p,p=n,n=m,m=l+c|0,l=k,k=h,h=g,g=c+(h&k^l&(h^k))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0;e[0]=e[0]+g| + 0;e[1]=e[1]+h|0;e[2]=e[2]+k|0;e[3]=e[3]+l|0;e[4]=e[4]+m|0;e[5]=e[5]+n|0;e[6]=e[6]+p|0;e[7]=e[7]+r|0;}};sjcl.hash.sha1=function(a){a?(this.g=a.g.slice(0),this.f=a.f.slice(0),this.c=a.c):this.reset();};sjcl.hash.sha1.hash=function(a){return (new sjcl.hash.sha1).update(a).finalize()}; + sjcl.hash.sha1.prototype={blockSize:512,reset:function(){this.g=this.H.slice(0);this.f=[];this.c=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.f=sjcl.bitArray.concat(this.f,a);b=this.c;a=this.c=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffffc;c++)k[c]=a[c];else k=a;c=h[0];d=h[1];e=h[2];f=h[3];g=h[4];for(a=0;79>=a;a++)16<=a&&(b=k[a-3]^k[a-8]^k[a-14]^k[a-16],k[a]=b<<1|b>>>31),b=19>=a?d&e|~d&f:39>=a?d^e^f:59>=a?d&e|d&f|e&f:79>=a?d^e^f:void 0,b=(c<<5|c>>>27)+b+g+k[a]+this.b[Math.floor(a/20)]|0,g=f,f=e,e=d<<30|d>>>2,d=c,c=b;h[0]=h[0]+c|0;h[1]=h[1]+d|0;h[2]=h[2]+e|0;h[3]=h[3]+f|0;h[4]=h[4]+g|0;}}; + sjcl.mode.ccm={name:"ccm",I:[],listenProgress:function(a){sjcl.mode.ccm.I.push(a);},unListenProgress:function(a){a=sjcl.mode.ccm.I.indexOf(a);-1k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c, + 8*(15-f));b=sjcl.mode.ccm.X(a,b,c,d,e,f);g=sjcl.mode.ccm.F(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.F(a,k,c,l,e,b);a=sjcl.mode.ccm.X(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match"); + return k.data},oa:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.o;d=[h.partial(8,(b.length?64:0)|d-2<<2|f-1)];d=h.concat(d,c);d[3]|=e;d=a.encrypt(d);if(b.length)for(c=h.bitLength(b)/8,65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c])),g=h.concat(g,b),b=0;be||16m&&(sjcl.mode.ccm.ga(g/ + k),m+=n),c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return {tag:d,data:h.clamp(b,l)}}}; + sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.U,k=sjcl.bitArray,l=k.o,m=[0,0,0,0];c=h(a.encrypt(c));var n,p=[];d=d||[];e=e||64;for(g=0;g+4e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c); + return a.encrypt(f(d(f(h,d(h))),g))},U:function(a){return [a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}}; + sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.F(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.F(!1,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},la:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.o;e=[0,0, + 0,0];f=b.slice(0);for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000);}return e},s:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;de&&(a=b.hash(a));for(d=0;dd||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],m=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(m.concat(b,[k]));for(g=1;gg;g++)e.push(0x100000000*Math.random()|0);for(g=0;g=1<this.w&&(this.w= + f);this.S++;this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.N=new sjcl.cipher.aes(this.b);for(d=0;4>d&&(this.m[d]=this.m[d]+1|0,!this.m[d]);d++);}for(d=0;d>>1;this.h[g].update([d,this.P++,2,b,f,a.length].concat(a));}break;case "string":void 0===b&&(b=a.length);this.h[g].update([d,this.P++,3,b,f,a.length]);this.h[g].update(a);break;default:k=1;}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.u[g]+=b;this.i+=b;h===this.B&&(this.isReady()!==this.B&&z("seeded",Math.max(this.w,this.i)),z("progress",this.getProgress()));}, + isReady:function(a){a=this.V[void 0!==a?a:this.O];return this.w&&this.w>=a?this.u[0]>this.ca&&(new Date).valueOf()>this.$?this.L|this.K:this.K:this.i>=a?this.L|this.B:this.B},getProgress:function(a){a=this.V[a?a:this.O];return this.w>=a?1:this.i>a?1:this.i/a},startCollectors:function(){if(!this.G){this.a={loadTimeCollector:A(this,this.na),mouseCollector:A(this,this.pa),keyboardCollector:A(this,this.ma),accelerometerCollector:A(this,this.fa),touchCollector:A(this,this.ra)};if(window.addEventListener)window.addEventListener("load", + this.a.loadTimeCollector,!1),window.addEventListener("mousemove",this.a.mouseCollector,!1),window.addEventListener("keypress",this.a.keyboardCollector,!1),window.addEventListener("devicemotion",this.a.accelerometerCollector,!1),window.addEventListener("touchmove",this.a.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector);else throw new sjcl.exception.bug("can't attach event"); + this.G=!0;}},stopCollectors:function(){this.G&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,!1),window.removeEventListener("mousemove",this.a.mouseCollector,!1),window.removeEventListener("keypress",this.a.keyboardCollector,!1),window.removeEventListener("devicemotion",this.a.accelerometerCollector,!1),window.removeEventListener("touchmove",this.a.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove", + this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.G=!1);},addEventListener:function(a,b){this.M[a][this.ha++]=b;},removeEventListener:function(a,b){var c,d,e=this.M[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;cb&&(a.m[b]=a.m[b]+1|0,!a.m[b]);b++);return a.N.encrypt(a.m)} + function A(a,b){return function(){b.apply(a,arguments);}}sjcl.random=new sjcl.prng(6); + a:try{var C,D,E,F;if(F="undefined"!==typeof module&&module.exports){var G;try{G=require("crypto");}catch(a){G=null;}F=D=G;}if(F&&D.randomBytes)C=D.randomBytes(128),C=new Uint32Array((new Uint8Array(C)).buffer),sjcl.random.addEntropy(C,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){E=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(E);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(E); + else break a;sjcl.random.addEntropy(E,1024,"crypto['getRandomValues']");}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a));} + sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},ka:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.j({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.j(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length|| + 4=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4> 24) & 0xff; + x[i+1] = (h >> 16) & 0xff; + x[i+2] = (h >> 8) & 0xff; + x[i+3] = h & 0xff; + x[i+4] = (l >> 24) & 0xff; + x[i+5] = (l >> 16) & 0xff; + x[i+6] = (l >> 8) & 0xff; + x[i+7] = l & 0xff; + } + + function vn(x, xi, y, yi, n) { + var i,d = 0; + for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i]; + return (1 & ((d - 1) >>> 8)) - 1; + } + + function crypto_verify_16(x, xi, y, yi) { + return vn(x,xi,y,yi,16); + } + + function crypto_verify_32(x, xi, y, yi) { + return vn(x,xi,y,yi,32); + } + + function core_salsa20(o, p, k, c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + x0 = x0 + j0 | 0; + x1 = x1 + j1 | 0; + x2 = x2 + j2 | 0; + x3 = x3 + j3 | 0; + x4 = x4 + j4 | 0; + x5 = x5 + j5 | 0; + x6 = x6 + j6 | 0; + x7 = x7 + j7 | 0; + x8 = x8 + j8 | 0; + x9 = x9 + j9 | 0; + x10 = x10 + j10 | 0; + x11 = x11 + j11 | 0; + x12 = x12 + j12 | 0; + x13 = x13 + j13 | 0; + x14 = x14 + j14 | 0; + x15 = x15 + j15 | 0; + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x1 >>> 0 & 0xff; + o[ 5] = x1 >>> 8 & 0xff; + o[ 6] = x1 >>> 16 & 0xff; + o[ 7] = x1 >>> 24 & 0xff; + + o[ 8] = x2 >>> 0 & 0xff; + o[ 9] = x2 >>> 8 & 0xff; + o[10] = x2 >>> 16 & 0xff; + o[11] = x2 >>> 24 & 0xff; + + o[12] = x3 >>> 0 & 0xff; + o[13] = x3 >>> 8 & 0xff; + o[14] = x3 >>> 16 & 0xff; + o[15] = x3 >>> 24 & 0xff; + + o[16] = x4 >>> 0 & 0xff; + o[17] = x4 >>> 8 & 0xff; + o[18] = x4 >>> 16 & 0xff; + o[19] = x4 >>> 24 & 0xff; + + o[20] = x5 >>> 0 & 0xff; + o[21] = x5 >>> 8 & 0xff; + o[22] = x5 >>> 16 & 0xff; + o[23] = x5 >>> 24 & 0xff; + + o[24] = x6 >>> 0 & 0xff; + o[25] = x6 >>> 8 & 0xff; + o[26] = x6 >>> 16 & 0xff; + o[27] = x6 >>> 24 & 0xff; + + o[28] = x7 >>> 0 & 0xff; + o[29] = x7 >>> 8 & 0xff; + o[30] = x7 >>> 16 & 0xff; + o[31] = x7 >>> 24 & 0xff; + + o[32] = x8 >>> 0 & 0xff; + o[33] = x8 >>> 8 & 0xff; + o[34] = x8 >>> 16 & 0xff; + o[35] = x8 >>> 24 & 0xff; + + o[36] = x9 >>> 0 & 0xff; + o[37] = x9 >>> 8 & 0xff; + o[38] = x9 >>> 16 & 0xff; + o[39] = x9 >>> 24 & 0xff; + + o[40] = x10 >>> 0 & 0xff; + o[41] = x10 >>> 8 & 0xff; + o[42] = x10 >>> 16 & 0xff; + o[43] = x10 >>> 24 & 0xff; + + o[44] = x11 >>> 0 & 0xff; + o[45] = x11 >>> 8 & 0xff; + o[46] = x11 >>> 16 & 0xff; + o[47] = x11 >>> 24 & 0xff; + + o[48] = x12 >>> 0 & 0xff; + o[49] = x12 >>> 8 & 0xff; + o[50] = x12 >>> 16 & 0xff; + o[51] = x12 >>> 24 & 0xff; + + o[52] = x13 >>> 0 & 0xff; + o[53] = x13 >>> 8 & 0xff; + o[54] = x13 >>> 16 & 0xff; + o[55] = x13 >>> 24 & 0xff; + + o[56] = x14 >>> 0 & 0xff; + o[57] = x14 >>> 8 & 0xff; + o[58] = x14 >>> 16 & 0xff; + o[59] = x14 >>> 24 & 0xff; + + o[60] = x15 >>> 0 & 0xff; + o[61] = x15 >>> 8 & 0xff; + o[62] = x15 >>> 16 & 0xff; + o[63] = x15 >>> 24 & 0xff; + } + + function core_hsalsa20(o,p,k,c) { + var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, + j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, + j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, + j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, + j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, + j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, + j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, + j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, + j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, + j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, + j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, + j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, + j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, + j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, + j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, + j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15, u; + + for (var i = 0; i < 20; i += 2) { + u = x0 + x12 | 0; + x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4 | 0; + x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1 | 0; + x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9 | 0; + x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6 | 0; + x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14 | 0; + x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11 | 0; + x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3 | 0; + x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7 | 0; + x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3 | 0; + x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0 | 0; + x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1 | 0; + x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2 | 0; + x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4 | 0; + x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5 | 0; + x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6 | 0; + x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7 | 0; + x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9 | 0; + x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10 | 0; + x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11 | 0; + x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8 | 0; + x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14 | 0; + x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15 | 0; + x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12 | 0; + x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13 | 0; + x15 ^= u<<18 | u>>>(32-18); + } + + o[ 0] = x0 >>> 0 & 0xff; + o[ 1] = x0 >>> 8 & 0xff; + o[ 2] = x0 >>> 16 & 0xff; + o[ 3] = x0 >>> 24 & 0xff; + + o[ 4] = x5 >>> 0 & 0xff; + o[ 5] = x5 >>> 8 & 0xff; + o[ 6] = x5 >>> 16 & 0xff; + o[ 7] = x5 >>> 24 & 0xff; + + o[ 8] = x10 >>> 0 & 0xff; + o[ 9] = x10 >>> 8 & 0xff; + o[10] = x10 >>> 16 & 0xff; + o[11] = x10 >>> 24 & 0xff; + + o[12] = x15 >>> 0 & 0xff; + o[13] = x15 >>> 8 & 0xff; + o[14] = x15 >>> 16 & 0xff; + o[15] = x15 >>> 24 & 0xff; + + o[16] = x6 >>> 0 & 0xff; + o[17] = x6 >>> 8 & 0xff; + o[18] = x6 >>> 16 & 0xff; + o[19] = x6 >>> 24 & 0xff; + + o[20] = x7 >>> 0 & 0xff; + o[21] = x7 >>> 8 & 0xff; + o[22] = x7 >>> 16 & 0xff; + o[23] = x7 >>> 24 & 0xff; + + o[24] = x8 >>> 0 & 0xff; + o[25] = x8 >>> 8 & 0xff; + o[26] = x8 >>> 16 & 0xff; + o[27] = x8 >>> 24 & 0xff; + + o[28] = x9 >>> 0 & 0xff; + o[29] = x9 >>> 8 & 0xff; + o[30] = x9 >>> 16 & 0xff; + o[31] = x9 >>> 24 & 0xff; + } + + function crypto_core_salsa20(out,inp,k,c) { + core_salsa20(out,inp,k,c); + } + + function crypto_core_hsalsa20(out,inp,k,c) { + core_hsalsa20(out,inp,k,c); + } + + var sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]); + // "expand 32-byte k" + + function crypto_stream_salsa20_xor(c,cpos,m,mpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + mpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = m[mpos+i] ^ x[i]; + } + return 0; + } + + function crypto_stream_salsa20(c,cpos,b,n,k) { + var z = new Uint8Array(16), x = new Uint8Array(64); + var u, i; + for (i = 0; i < 16; i++) z[i] = 0; + for (i = 0; i < 8; i++) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < 64; i++) c[cpos+i] = x[i]; + u = 1; + for (i = 8; i < 16; i++) { + u = u + (z[i] & 0xff) | 0; + z[i] = u & 0xff; + u >>>= 8; + } + b -= 64; + cpos += 64; + } + if (b > 0) { + crypto_core_salsa20(x,z,k,sigma); + for (i = 0; i < b; i++) c[cpos+i] = x[i]; + } + return 0; + } + + function crypto_stream(c,cpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20(c,cpos,d,sn,s); + } + + function crypto_stream_xor(c,cpos,m,mpos,d,n,k) { + var s = new Uint8Array(32); + crypto_core_hsalsa20(s,n,k,sigma); + var sn = new Uint8Array(8); + for (var i = 0; i < 8; i++) sn[i] = n[i+16]; + return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s); + } + + /* + * Port of Andrew Moon's Poly1305-donna-16. Public domain. + * https://github.com/floodyberry/poly1305-donna + */ + + var poly1305 = function(key) { + this.buffer = new Uint8Array(16); + this.r = new Uint16Array(10); + this.h = new Uint16Array(10); + this.pad = new Uint16Array(8); + this.leftover = 0; + this.fin = 0; + + var t0, t1, t2, t3, t4, t5, t6, t7; + + t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; + t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; + t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; + this.r[5] = ((t4 >>> 1)) & 0x1ffe; + t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; + t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + this.r[9] = ((t7 >>> 5)) & 0x007f; + + this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; + this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; + this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; + this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; + this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; + this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; + this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; + this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; + }; + + poly1305.prototype.blocks = function(m, mpos, bytes) { + var hibit = this.fin ? 0 : (1 << 11); + var t0, t1, t2, t3, t4, t5, t6, t7, c; + var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; + + var h0 = this.h[0], + h1 = this.h[1], + h2 = this.h[2], + h3 = this.h[3], + h4 = this.h[4], + h5 = this.h[5], + h6 = this.h[6], + h7 = this.h[7], + h8 = this.h[8], + h9 = this.h[9]; + + var r0 = this.r[0], + r1 = this.r[1], + r2 = this.r[2], + r3 = this.r[3], + r4 = this.r[4], + r5 = this.r[5], + r6 = this.r[6], + r7 = this.r[7], + r8 = this.r[8], + r9 = this.r[9]; + + while (bytes >= 16) { + t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; + t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; + t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; + h5 += ((t4 >>> 1)) & 0x1fff; + t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; + t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + h9 += ((t7 >>> 5)) | hibit; + + c = 0; + + d0 = c; + d0 += h0 * r0; + d0 += h1 * (5 * r9); + d0 += h2 * (5 * r8); + d0 += h3 * (5 * r7); + d0 += h4 * (5 * r6); + c = (d0 >>> 13); d0 &= 0x1fff; + d0 += h5 * (5 * r5); + d0 += h6 * (5 * r4); + d0 += h7 * (5 * r3); + d0 += h8 * (5 * r2); + d0 += h9 * (5 * r1); + c += (d0 >>> 13); d0 &= 0x1fff; + + d1 = c; + d1 += h0 * r1; + d1 += h1 * r0; + d1 += h2 * (5 * r9); + d1 += h3 * (5 * r8); + d1 += h4 * (5 * r7); + c = (d1 >>> 13); d1 &= 0x1fff; + d1 += h5 * (5 * r6); + d1 += h6 * (5 * r5); + d1 += h7 * (5 * r4); + d1 += h8 * (5 * r3); + d1 += h9 * (5 * r2); + c += (d1 >>> 13); d1 &= 0x1fff; + + d2 = c; + d2 += h0 * r2; + d2 += h1 * r1; + d2 += h2 * r0; + d2 += h3 * (5 * r9); + d2 += h4 * (5 * r8); + c = (d2 >>> 13); d2 &= 0x1fff; + d2 += h5 * (5 * r7); + d2 += h6 * (5 * r6); + d2 += h7 * (5 * r5); + d2 += h8 * (5 * r4); + d2 += h9 * (5 * r3); + c += (d2 >>> 13); d2 &= 0x1fff; + + d3 = c; + d3 += h0 * r3; + d3 += h1 * r2; + d3 += h2 * r1; + d3 += h3 * r0; + d3 += h4 * (5 * r9); + c = (d3 >>> 13); d3 &= 0x1fff; + d3 += h5 * (5 * r8); + d3 += h6 * (5 * r7); + d3 += h7 * (5 * r6); + d3 += h8 * (5 * r5); + d3 += h9 * (5 * r4); + c += (d3 >>> 13); d3 &= 0x1fff; + + d4 = c; + d4 += h0 * r4; + d4 += h1 * r3; + d4 += h2 * r2; + d4 += h3 * r1; + d4 += h4 * r0; + c = (d4 >>> 13); d4 &= 0x1fff; + d4 += h5 * (5 * r9); + d4 += h6 * (5 * r8); + d4 += h7 * (5 * r7); + d4 += h8 * (5 * r6); + d4 += h9 * (5 * r5); + c += (d4 >>> 13); d4 &= 0x1fff; + + d5 = c; + d5 += h0 * r5; + d5 += h1 * r4; + d5 += h2 * r3; + d5 += h3 * r2; + d5 += h4 * r1; + c = (d5 >>> 13); d5 &= 0x1fff; + d5 += h5 * r0; + d5 += h6 * (5 * r9); + d5 += h7 * (5 * r8); + d5 += h8 * (5 * r7); + d5 += h9 * (5 * r6); + c += (d5 >>> 13); d5 &= 0x1fff; + + d6 = c; + d6 += h0 * r6; + d6 += h1 * r5; + d6 += h2 * r4; + d6 += h3 * r3; + d6 += h4 * r2; + c = (d6 >>> 13); d6 &= 0x1fff; + d6 += h5 * r1; + d6 += h6 * r0; + d6 += h7 * (5 * r9); + d6 += h8 * (5 * r8); + d6 += h9 * (5 * r7); + c += (d6 >>> 13); d6 &= 0x1fff; + + d7 = c; + d7 += h0 * r7; + d7 += h1 * r6; + d7 += h2 * r5; + d7 += h3 * r4; + d7 += h4 * r3; + c = (d7 >>> 13); d7 &= 0x1fff; + d7 += h5 * r2; + d7 += h6 * r1; + d7 += h7 * r0; + d7 += h8 * (5 * r9); + d7 += h9 * (5 * r8); + c += (d7 >>> 13); d7 &= 0x1fff; + + d8 = c; + d8 += h0 * r8; + d8 += h1 * r7; + d8 += h2 * r6; + d8 += h3 * r5; + d8 += h4 * r4; + c = (d8 >>> 13); d8 &= 0x1fff; + d8 += h5 * r3; + d8 += h6 * r2; + d8 += h7 * r1; + d8 += h8 * r0; + d8 += h9 * (5 * r9); + c += (d8 >>> 13); d8 &= 0x1fff; + + d9 = c; + d9 += h0 * r9; + d9 += h1 * r8; + d9 += h2 * r7; + d9 += h3 * r6; + d9 += h4 * r5; + c = (d9 >>> 13); d9 &= 0x1fff; + d9 += h5 * r4; + d9 += h6 * r3; + d9 += h7 * r2; + d9 += h8 * r1; + d9 += h9 * r0; + c += (d9 >>> 13); d9 &= 0x1fff; + + c = (((c << 2) + c)) | 0; + c = (c + d0) | 0; + d0 = c & 0x1fff; + c = (c >>> 13); + d1 += c; + + h0 = d0; + h1 = d1; + h2 = d2; + h3 = d3; + h4 = d4; + h5 = d5; + h6 = d6; + h7 = d7; + h8 = d8; + h9 = d9; + + mpos += 16; + bytes -= 16; + } + this.h[0] = h0; + this.h[1] = h1; + this.h[2] = h2; + this.h[3] = h3; + this.h[4] = h4; + this.h[5] = h5; + this.h[6] = h6; + this.h[7] = h7; + this.h[8] = h8; + this.h[9] = h9; + }; + + poly1305.prototype.finish = function(mac, macpos) { + var g = new Uint16Array(10); + var c, mask, f, i; + + if (this.leftover) { + i = this.leftover; + this.buffer[i++] = 1; + for (; i < 16; i++) this.buffer[i] = 0; + this.fin = 1; + this.blocks(this.buffer, 0, 16); + } + + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + for (i = 2; i < 10; i++) { + this.h[i] += c; + c = this.h[i] >>> 13; + this.h[i] &= 0x1fff; + } + this.h[0] += (c * 5); + c = this.h[0] >>> 13; + this.h[0] &= 0x1fff; + this.h[1] += c; + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + this.h[2] += c; + + g[0] = this.h[0] + 5; + c = g[0] >>> 13; + g[0] &= 0x1fff; + for (i = 1; i < 10; i++) { + g[i] = this.h[i] + c; + c = g[i] >>> 13; + g[i] &= 0x1fff; + } + g[9] -= (1 << 13); + + mask = (c ^ 1) - 1; + for (i = 0; i < 10; i++) g[i] &= mask; + mask = ~mask; + for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; + + this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; + this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; + this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; + this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; + this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; + this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; + this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; + this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; + + f = this.h[0] + this.pad[0]; + this.h[0] = f & 0xffff; + for (i = 1; i < 8; i++) { + f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; + this.h[i] = f & 0xffff; + } + + mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff; + mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff; + mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff; + mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff; + mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff; + mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff; + mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff; + mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff; + mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff; + mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff; + mac[macpos+10] = (this.h[5] >>> 0) & 0xff; + mac[macpos+11] = (this.h[5] >>> 8) & 0xff; + mac[macpos+12] = (this.h[6] >>> 0) & 0xff; + mac[macpos+13] = (this.h[6] >>> 8) & 0xff; + mac[macpos+14] = (this.h[7] >>> 0) & 0xff; + mac[macpos+15] = (this.h[7] >>> 8) & 0xff; + }; + + poly1305.prototype.update = function(m, mpos, bytes) { + var i, want; + + if (this.leftover) { + want = (16 - this.leftover); + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + bytes -= want; + mpos += want; + this.leftover += want; + if (this.leftover < 16) + return; + this.blocks(this.buffer, 0, 16); + this.leftover = 0; + } + + if (bytes >= 16) { + want = bytes - (bytes % 16); + this.blocks(m, mpos, want); + mpos += want; + bytes -= want; + } + + if (bytes) { + for (i = 0; i < bytes; i++) + this.buffer[this.leftover + i] = m[mpos+i]; + this.leftover += bytes; + } + }; + + function crypto_onetimeauth(out, outpos, m, mpos, n, k) { + var s = new poly1305(k); + s.update(m, mpos, n); + s.finish(out, outpos); + return 0; + } + + function crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) { + var x = new Uint8Array(16); + crypto_onetimeauth(x,0,m,mpos,n,k); + return crypto_verify_16(h,hpos,x,0); + } + + function crypto_secretbox(c,m,d,n,k) { + var i; + if (d < 32) return -1; + crypto_stream_xor(c,0,m,0,d,n,k); + crypto_onetimeauth(c, 16, c, 32, d - 32, c); + for (i = 0; i < 16; i++) c[i] = 0; + return 0; + } + + function crypto_secretbox_open(m,c,d,n,k) { + var i; + var x = new Uint8Array(32); + if (d < 32) return -1; + crypto_stream(x,0,32,n,k); + if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1; + crypto_stream_xor(m,0,c,0,d,n,k); + for (i = 0; i < 32; i++) m[i] = 0; + return 0; + } + + function set25519(r, a) { + var i; + for (i = 0; i < 16; i++) r[i] = a[i]|0; + } + + function car25519(o) { + var i, v, c = 1; + for (i = 0; i < 16; i++) { + v = o[i] + c + 65535; + c = Math.floor(v / 65536); + o[i] = v - c * 65536; + } + o[0] += c-1 + 37 * (c-1); + } + + function sel25519(p, q, b) { + var t, c = ~(b-1); + for (var i = 0; i < 16; i++) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } + } + + function pack25519(o, n) { + var i, j, b; + var m = gf(), t = gf(); + for (i = 0; i < 16; i++) t[i] = n[i]; + car25519(t); + car25519(t); + car25519(t); + for (j = 0; j < 2; j++) { + m[0] = t[0] - 0xffed; + for (i = 1; i < 15; i++) { + m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); + m[i-1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); + b = (m[15]>>16) & 1; + m[14] &= 0xffff; + sel25519(t, m, 1-b); + } + for (i = 0; i < 16; i++) { + o[2*i] = t[i] & 0xff; + o[2*i+1] = t[i]>>8; + } + } + + function neq25519(a, b) { + var c = new Uint8Array(32), d = new Uint8Array(32); + pack25519(c, a); + pack25519(d, b); + return crypto_verify_32(c, 0, d, 0); + } + + function par25519(a) { + var d = new Uint8Array(32); + pack25519(d, a); + return d[0] & 1; + } + + function unpack25519(o, n) { + var i; + for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8); + o[15] &= 0x7fff; + } + + function A(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] + b[i]; + } + + function Z(o, a, b) { + for (var i = 0; i < 16; i++) o[i] = a[i] - b[i]; + } + + function M(o, a, b) { + var v, c, + t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, + t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, + t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, + t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, + b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11], + b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + + v = a[0]; + t0 += v * b0; + t1 += v * b1; + t2 += v * b2; + t3 += v * b3; + t4 += v * b4; + t5 += v * b5; + t6 += v * b6; + t7 += v * b7; + t8 += v * b8; + t9 += v * b9; + t10 += v * b10; + t11 += v * b11; + t12 += v * b12; + t13 += v * b13; + t14 += v * b14; + t15 += v * b15; + v = a[1]; + t1 += v * b0; + t2 += v * b1; + t3 += v * b2; + t4 += v * b3; + t5 += v * b4; + t6 += v * b5; + t7 += v * b6; + t8 += v * b7; + t9 += v * b8; + t10 += v * b9; + t11 += v * b10; + t12 += v * b11; + t13 += v * b12; + t14 += v * b13; + t15 += v * b14; + t16 += v * b15; + v = a[2]; + t2 += v * b0; + t3 += v * b1; + t4 += v * b2; + t5 += v * b3; + t6 += v * b4; + t7 += v * b5; + t8 += v * b6; + t9 += v * b7; + t10 += v * b8; + t11 += v * b9; + t12 += v * b10; + t13 += v * b11; + t14 += v * b12; + t15 += v * b13; + t16 += v * b14; + t17 += v * b15; + v = a[3]; + t3 += v * b0; + t4 += v * b1; + t5 += v * b2; + t6 += v * b3; + t7 += v * b4; + t8 += v * b5; + t9 += v * b6; + t10 += v * b7; + t11 += v * b8; + t12 += v * b9; + t13 += v * b10; + t14 += v * b11; + t15 += v * b12; + t16 += v * b13; + t17 += v * b14; + t18 += v * b15; + v = a[4]; + t4 += v * b0; + t5 += v * b1; + t6 += v * b2; + t7 += v * b3; + t8 += v * b4; + t9 += v * b5; + t10 += v * b6; + t11 += v * b7; + t12 += v * b8; + t13 += v * b9; + t14 += v * b10; + t15 += v * b11; + t16 += v * b12; + t17 += v * b13; + t18 += v * b14; + t19 += v * b15; + v = a[5]; + t5 += v * b0; + t6 += v * b1; + t7 += v * b2; + t8 += v * b3; + t9 += v * b4; + t10 += v * b5; + t11 += v * b6; + t12 += v * b7; + t13 += v * b8; + t14 += v * b9; + t15 += v * b10; + t16 += v * b11; + t17 += v * b12; + t18 += v * b13; + t19 += v * b14; + t20 += v * b15; + v = a[6]; + t6 += v * b0; + t7 += v * b1; + t8 += v * b2; + t9 += v * b3; + t10 += v * b4; + t11 += v * b5; + t12 += v * b6; + t13 += v * b7; + t14 += v * b8; + t15 += v * b9; + t16 += v * b10; + t17 += v * b11; + t18 += v * b12; + t19 += v * b13; + t20 += v * b14; + t21 += v * b15; + v = a[7]; + t7 += v * b0; + t8 += v * b1; + t9 += v * b2; + t10 += v * b3; + t11 += v * b4; + t12 += v * b5; + t13 += v * b6; + t14 += v * b7; + t15 += v * b8; + t16 += v * b9; + t17 += v * b10; + t18 += v * b11; + t19 += v * b12; + t20 += v * b13; + t21 += v * b14; + t22 += v * b15; + v = a[8]; + t8 += v * b0; + t9 += v * b1; + t10 += v * b2; + t11 += v * b3; + t12 += v * b4; + t13 += v * b5; + t14 += v * b6; + t15 += v * b7; + t16 += v * b8; + t17 += v * b9; + t18 += v * b10; + t19 += v * b11; + t20 += v * b12; + t21 += v * b13; + t22 += v * b14; + t23 += v * b15; + v = a[9]; + t9 += v * b0; + t10 += v * b1; + t11 += v * b2; + t12 += v * b3; + t13 += v * b4; + t14 += v * b5; + t15 += v * b6; + t16 += v * b7; + t17 += v * b8; + t18 += v * b9; + t19 += v * b10; + t20 += v * b11; + t21 += v * b12; + t22 += v * b13; + t23 += v * b14; + t24 += v * b15; + v = a[10]; + t10 += v * b0; + t11 += v * b1; + t12 += v * b2; + t13 += v * b3; + t14 += v * b4; + t15 += v * b5; + t16 += v * b6; + t17 += v * b7; + t18 += v * b8; + t19 += v * b9; + t20 += v * b10; + t21 += v * b11; + t22 += v * b12; + t23 += v * b13; + t24 += v * b14; + t25 += v * b15; + v = a[11]; + t11 += v * b0; + t12 += v * b1; + t13 += v * b2; + t14 += v * b3; + t15 += v * b4; + t16 += v * b5; + t17 += v * b6; + t18 += v * b7; + t19 += v * b8; + t20 += v * b9; + t21 += v * b10; + t22 += v * b11; + t23 += v * b12; + t24 += v * b13; + t25 += v * b14; + t26 += v * b15; + v = a[12]; + t12 += v * b0; + t13 += v * b1; + t14 += v * b2; + t15 += v * b3; + t16 += v * b4; + t17 += v * b5; + t18 += v * b6; + t19 += v * b7; + t20 += v * b8; + t21 += v * b9; + t22 += v * b10; + t23 += v * b11; + t24 += v * b12; + t25 += v * b13; + t26 += v * b14; + t27 += v * b15; + v = a[13]; + t13 += v * b0; + t14 += v * b1; + t15 += v * b2; + t16 += v * b3; + t17 += v * b4; + t18 += v * b5; + t19 += v * b6; + t20 += v * b7; + t21 += v * b8; + t22 += v * b9; + t23 += v * b10; + t24 += v * b11; + t25 += v * b12; + t26 += v * b13; + t27 += v * b14; + t28 += v * b15; + v = a[14]; + t14 += v * b0; + t15 += v * b1; + t16 += v * b2; + t17 += v * b3; + t18 += v * b4; + t19 += v * b5; + t20 += v * b6; + t21 += v * b7; + t22 += v * b8; + t23 += v * b9; + t24 += v * b10; + t25 += v * b11; + t26 += v * b12; + t27 += v * b13; + t28 += v * b14; + t29 += v * b15; + v = a[15]; + t15 += v * b0; + t16 += v * b1; + t17 += v * b2; + t18 += v * b3; + t19 += v * b4; + t20 += v * b5; + t21 += v * b6; + t22 += v * b7; + t23 += v * b8; + t24 += v * b9; + t25 += v * b10; + t26 += v * b11; + t27 += v * b12; + t28 += v * b13; + t29 += v * b14; + t30 += v * b15; + + t0 += 38 * t16; + t1 += 38 * t17; + t2 += 38 * t18; + t3 += 38 * t19; + t4 += 38 * t20; + t5 += 38 * t21; + t6 += 38 * t22; + t7 += 38 * t23; + t8 += 38 * t24; + t9 += 38 * t25; + t10 += 38 * t26; + t11 += 38 * t27; + t12 += 38 * t28; + t13 += 38 * t29; + t14 += 38 * t30; + // t15 left as is + + // first car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + // second car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + o[ 0] = t0; + o[ 1] = t1; + o[ 2] = t2; + o[ 3] = t3; + o[ 4] = t4; + o[ 5] = t5; + o[ 6] = t6; + o[ 7] = t7; + o[ 8] = t8; + o[ 9] = t9; + o[10] = t10; + o[11] = t11; + o[12] = t12; + o[13] = t13; + o[14] = t14; + o[15] = t15; + } + + function S(o, a) { + M(o, a, a); + } + + function inv25519(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 253; a >= 0; a--) { + S(c, c); + if(a !== 2 && a !== 4) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; + } + + function pow2523(o, i) { + var c = gf(); + var a; + for (a = 0; a < 16; a++) c[a] = i[a]; + for (a = 250; a >= 0; a--) { + S(c, c); + if(a !== 1) M(c, c, i); + } + for (a = 0; a < 16; a++) o[a] = c[a]; + } + + function crypto_scalarmult(q, n, p) { + var z = new Uint8Array(32); + var x = new Float64Array(80), r, i; + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(); + for (i = 0; i < 31; i++) z[i] = n[i]; + z[31]=(n[31]&127)|64; + z[0]&=248; + unpack25519(x,p); + for (i = 0; i < 16; i++) { + b[i]=x[i]; + d[i]=a[i]=c[i]=0; + } + a[0]=d[0]=1; + for (i=254; i>=0; --i) { + r=(z[i>>>3]>>>(i&7))&1; + sel25519(a,b,r); + sel25519(c,d,r); + A(e,a,c); + Z(a,a,c); + A(c,b,d); + Z(b,b,d); + S(d,e); + S(f,a); + M(a,c,a); + M(c,b,e); + A(e,a,c); + Z(a,a,c); + S(b,a); + Z(c,d,f); + M(a,c,_121665); + A(a,a,d); + M(c,c,a); + M(a,d,f); + M(d,b,x); + S(b,e); + sel25519(a,b,r); + sel25519(c,d,r); + } + for (i = 0; i < 16; i++) { + x[i+16]=a[i]; + x[i+32]=c[i]; + x[i+48]=b[i]; + x[i+64]=d[i]; + } + var x32 = x.subarray(32); + var x16 = x.subarray(16); + inv25519(x32,x32); + M(x16,x16,x32); + pack25519(q,x16); + return 0; + } + + function crypto_scalarmult_base(q, n) { + return crypto_scalarmult(q, n, _9); + } + + function crypto_box_keypair(y, x) { + randombytes(x, 32); + return crypto_scalarmult_base(y, x); + } + + function crypto_box_beforenm(k, y, x) { + var s = new Uint8Array(32); + crypto_scalarmult(s, x, y); + return crypto_core_hsalsa20(k, _0, s, sigma); + } + + var crypto_box_afternm = crypto_secretbox; + var crypto_box_open_afternm = crypto_secretbox_open; + + function crypto_box(c, m, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_afternm(c, m, d, n, k); + } + + function crypto_box_open(m, c, d, n, y, x) { + var k = new Uint8Array(32); + crypto_box_beforenm(k, y, x); + return crypto_box_open_afternm(m, c, d, n, k); + } + + var K = [ + 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, + 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, + 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, + 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, + 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, + 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, + 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, + 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, + 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, + 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, + 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, + 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, + 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, + 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, + 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, + 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, + 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, + 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, + 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, + 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, + 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, + 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, + 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, + 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, + 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, + 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, + 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, + 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, + 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, + 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, + 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, + 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, + 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, + 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, + 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, + 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, + 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, + 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, + 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, + 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 + ]; + + function crypto_hashblocks_hl(hh, hl, m, n) { + var wh = new Int32Array(16), wl = new Int32Array(16), + bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7, + bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7, + th, tl, i, j, h, l, a, b, c, d; + + var ah0 = hh[0], + ah1 = hh[1], + ah2 = hh[2], + ah3 = hh[3], + ah4 = hh[4], + ah5 = hh[5], + ah6 = hh[6], + ah7 = hh[7], + + al0 = hl[0], + al1 = hl[1], + al2 = hl[2], + al3 = hl[3], + al4 = hl[4], + al5 = hl[5], + al6 = hl[6], + al7 = hl[7]; + + var pos = 0; + while (n >= 128) { + for (i = 0; i < 16; i++) { + j = 8 * i + pos; + wh[i] = (m[j+0] << 24) | (m[j+1] << 16) | (m[j+2] << 8) | m[j+3]; + wl[i] = (m[j+4] << 24) | (m[j+5] << 16) | (m[j+6] << 8) | m[j+7]; + } + for (i = 0; i < 80; i++) { + bh0 = ah0; + bh1 = ah1; + bh2 = ah2; + bh3 = ah3; + bh4 = ah4; + bh5 = ah5; + bh6 = ah6; + bh7 = ah7; + + bl0 = al0; + bl1 = al1; + bl2 = al2; + bl3 = al3; + bl4 = al4; + bl5 = al5; + bl6 = al6; + bl7 = al7; + + // add + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma1 + h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32)))); + l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Ch + h = (ah4 & ah5) ^ (~ah4 & ah6); + l = (al4 & al5) ^ (~al4 & al6); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // K + h = K[i*2]; + l = K[i*2+1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // w + h = wh[i%16]; + l = wl[i%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + th = c & 0xffff | d << 16; + tl = a & 0xffff | b << 16; + + // add + h = th; + l = tl; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + // Sigma0 + h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32)))); + l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32)))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // Maj + h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2); + l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh7 = (c & 0xffff) | (d << 16); + bl7 = (a & 0xffff) | (b << 16); + + // add + h = bh3; + l = bl3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = th; + l = tl; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + bh3 = (c & 0xffff) | (d << 16); + bl3 = (a & 0xffff) | (b << 16); + + ah1 = bh0; + ah2 = bh1; + ah3 = bh2; + ah4 = bh3; + ah5 = bh4; + ah6 = bh5; + ah7 = bh6; + ah0 = bh7; + + al1 = bl0; + al2 = bl1; + al3 = bl2; + al4 = bl3; + al5 = bl4; + al6 = bl5; + al7 = bl6; + al0 = bl7; + + if (i%16 === 15) { + for (j = 0; j < 16; j++) { + // add + h = wh[j]; + l = wl[j]; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = wh[(j+9)%16]; + l = wl[(j+9)%16]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma0 + th = wh[(j+1)%16]; + tl = wl[(j+1)%16]; + h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7); + l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + // sigma1 + th = wh[(j+14)%16]; + tl = wl[(j+14)%16]; + h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6); + l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6))); + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + wh[j] = (c & 0xffff) | (d << 16); + wl[j] = (a & 0xffff) | (b << 16); + } + } + } + + // add + h = ah0; + l = al0; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[0]; + l = hl[0]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[0] = ah0 = (c & 0xffff) | (d << 16); + hl[0] = al0 = (a & 0xffff) | (b << 16); + + h = ah1; + l = al1; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[1]; + l = hl[1]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[1] = ah1 = (c & 0xffff) | (d << 16); + hl[1] = al1 = (a & 0xffff) | (b << 16); + + h = ah2; + l = al2; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[2]; + l = hl[2]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[2] = ah2 = (c & 0xffff) | (d << 16); + hl[2] = al2 = (a & 0xffff) | (b << 16); + + h = ah3; + l = al3; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[3]; + l = hl[3]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[3] = ah3 = (c & 0xffff) | (d << 16); + hl[3] = al3 = (a & 0xffff) | (b << 16); + + h = ah4; + l = al4; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[4]; + l = hl[4]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[4] = ah4 = (c & 0xffff) | (d << 16); + hl[4] = al4 = (a & 0xffff) | (b << 16); + + h = ah5; + l = al5; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[5]; + l = hl[5]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[5] = ah5 = (c & 0xffff) | (d << 16); + hl[5] = al5 = (a & 0xffff) | (b << 16); + + h = ah6; + l = al6; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[6]; + l = hl[6]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[6] = ah6 = (c & 0xffff) | (d << 16); + hl[6] = al6 = (a & 0xffff) | (b << 16); + + h = ah7; + l = al7; + + a = l & 0xffff; b = l >>> 16; + c = h & 0xffff; d = h >>> 16; + + h = hh[7]; + l = hl[7]; + + a += l & 0xffff; b += l >>> 16; + c += h & 0xffff; d += h >>> 16; + + b += a >>> 16; + c += b >>> 16; + d += c >>> 16; + + hh[7] = ah7 = (c & 0xffff) | (d << 16); + hl[7] = al7 = (a & 0xffff) | (b << 16); + + pos += 128; + n -= 128; + } + + return n; + } + + function crypto_hash(out, m, n) { + var hh = new Int32Array(8), + hl = new Int32Array(8), + x = new Uint8Array(256), + i, b = n; + + hh[0] = 0x6a09e667; + hh[1] = 0xbb67ae85; + hh[2] = 0x3c6ef372; + hh[3] = 0xa54ff53a; + hh[4] = 0x510e527f; + hh[5] = 0x9b05688c; + hh[6] = 0x1f83d9ab; + hh[7] = 0x5be0cd19; + + hl[0] = 0xf3bcc908; + hl[1] = 0x84caa73b; + hl[2] = 0xfe94f82b; + hl[3] = 0x5f1d36f1; + hl[4] = 0xade682d1; + hl[5] = 0x2b3e6c1f; + hl[6] = 0xfb41bd6b; + hl[7] = 0x137e2179; + + crypto_hashblocks_hl(hh, hl, m, n); + n %= 128; + + for (i = 0; i < n; i++) x[i] = m[b-n+i]; + x[n] = 128; + + n = 256-128*(n<112?1:0); + x[n-9] = 0; + ts64(x, n-8, (b / 0x20000000) | 0, b << 3); + crypto_hashblocks_hl(hh, hl, x, n); + + for (i = 0; i < 8; i++) ts64(out, 8*i, hh[i], hl[i]); + + return 0; + } + + function add(p, q) { + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(), + g = gf(), h = gf(), t = gf(); + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); + } + + function cswap(p, q, b) { + var i; + for (i = 0; i < 4; i++) { + sel25519(p[i], q[i], b); + } + } + + function pack(r, p) { + var tx = gf(), ty = gf(), zi = gf(); + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; + } + + function scalarmult(p, q, s) { + var b, i; + set25519(p[0], gf0); + set25519(p[1], gf1); + set25519(p[2], gf1); + set25519(p[3], gf0); + for (i = 255; i >= 0; --i) { + b = (s[(i/8)|0] >> (i&7)) & 1; + cswap(p, q, b); + add(q, p); + add(p, p); + cswap(p, q, b); + } + } + + function scalarbase(p, s) { + var q = [gf(), gf(), gf(), gf()]; + set25519(q[0], X); + set25519(q[1], Y); + set25519(q[2], gf1); + M(q[3], X, Y); + scalarmult(p, q, s); + } + + function crypto_sign_keypair(pk, sk, seeded) { + var d = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()]; + var i; + + if (!seeded) randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p, d); + pack(pk, p); + + for (i = 0; i < 32; i++) sk[i+32] = pk[i]; + return 0; + } + + var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); + + function modL(r, x) { + var carry, i, j, k; + for (i = 63; i >= 32; --i) { + carry = 0; + for (j = i - 32, k = i - 12; j < k; ++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = (x[j] + 128) >> 8; + x[j] -= carry * 256; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for (j = 0; j < 32; j++) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for (j = 0; j < 32; j++) x[j] -= carry * L[j]; + for (i = 0; i < 32; i++) { + x[i+1] += x[i] >> 8; + r[i] = x[i] & 255; + } + } + + function reduce(r) { + var x = new Float64Array(64), i; + for (i = 0; i < 64; i++) x[i] = r[i]; + for (i = 0; i < 64; i++) r[i] = 0; + modL(r, x); + } + + // Note: difference from C - smlen returned, not passed as argument. + function crypto_sign(sm, m, n, sk) { + var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64); + var i, j, x = new Float64Array(64); + var p = [gf(), gf(), gf(), gf()]; + + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + var smlen = n + 64; + for (i = 0; i < n; i++) sm[64 + i] = m[i]; + for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]; + + crypto_hash(r, sm.subarray(32), n+32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for (i = 32; i < 64; i++) sm[i] = sk[i]; + crypto_hash(h, sm, n + 64); + reduce(h); + + for (i = 0; i < 64; i++) x[i] = 0; + for (i = 0; i < 32; i++) x[i] = r[i]; + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + x[i+j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return smlen; + } + + function unpackneg(r, p) { + var t = gf(), chk = gf(), num = gf(), + den = gf(), den2 = gf(), den4 = gf(), + den6 = gf(); + + set25519(r[2], gf1); + unpack25519(r[1], p); + S(num, r[1]); + M(den, num, D); + Z(num, num, r[2]); + A(den, r[2], den); + + S(den2, den); + S(den4, den2); + M(den6, den4, den2); + M(t, den6, num); + M(t, t, den); + + pow2523(t, t); + M(t, t, num); + M(t, t, den); + M(t, t, den); + M(r[0], t, den); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) M(r[0], r[0], I); + + S(chk, r[0]); + M(chk, chk, den); + if (neq25519(chk, num)) return -1; + + if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]); + + M(r[3], r[0], r[1]); + return 0; + } + + function crypto_sign_open(m, sm, n, pk) { + var i; + var t = new Uint8Array(32), h = new Uint8Array(64); + var p = [gf(), gf(), gf(), gf()], + q = [gf(), gf(), gf(), gf()]; + + if (n < 64) return -1; + + if (unpackneg(q, pk)) return -1; + + for (i = 0; i < n; i++) m[i] = sm[i]; + for (i = 0; i < 32; i++) m[i+32] = pk[i]; + crypto_hash(h, m, n); + reduce(h); + scalarmult(p, q, h); + + scalarbase(q, sm.subarray(32)); + add(p, q); + pack(t, p); + + n -= 64; + if (crypto_verify_32(sm, 0, t, 0)) { + for (i = 0; i < n; i++) m[i] = 0; + return -1; + } + + for (i = 0; i < n; i++) m[i] = sm[i + 64]; + return n; + } + + var crypto_secretbox_KEYBYTES = 32, + crypto_secretbox_NONCEBYTES = 24, + crypto_secretbox_ZEROBYTES = 32, + crypto_secretbox_BOXZEROBYTES = 16, + crypto_scalarmult_BYTES = 32, + crypto_scalarmult_SCALARBYTES = 32, + crypto_box_PUBLICKEYBYTES = 32, + crypto_box_SECRETKEYBYTES = 32, + crypto_box_BEFORENMBYTES = 32, + crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES, + crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES, + crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES, + crypto_sign_BYTES = 64, + crypto_sign_PUBLICKEYBYTES = 32, + crypto_sign_SECRETKEYBYTES = 64, + crypto_sign_SEEDBYTES = 32, + crypto_hash_BYTES = 64; + + nacl.lowlevel = { + crypto_core_hsalsa20: crypto_core_hsalsa20, + crypto_stream_xor: crypto_stream_xor, + crypto_stream: crypto_stream, + crypto_stream_salsa20_xor: crypto_stream_salsa20_xor, + crypto_stream_salsa20: crypto_stream_salsa20, + crypto_onetimeauth: crypto_onetimeauth, + crypto_onetimeauth_verify: crypto_onetimeauth_verify, + crypto_verify_16: crypto_verify_16, + crypto_verify_32: crypto_verify_32, + crypto_secretbox: crypto_secretbox, + crypto_secretbox_open: crypto_secretbox_open, + crypto_scalarmult: crypto_scalarmult, + crypto_scalarmult_base: crypto_scalarmult_base, + crypto_box_beforenm: crypto_box_beforenm, + crypto_box_afternm: crypto_box_afternm, + crypto_box: crypto_box, + crypto_box_open: crypto_box_open, + crypto_box_keypair: crypto_box_keypair, + crypto_hash: crypto_hash, + crypto_sign: crypto_sign, + crypto_sign_keypair: crypto_sign_keypair, + crypto_sign_open: crypto_sign_open, + + crypto_secretbox_KEYBYTES: crypto_secretbox_KEYBYTES, + crypto_secretbox_NONCEBYTES: crypto_secretbox_NONCEBYTES, + crypto_secretbox_ZEROBYTES: crypto_secretbox_ZEROBYTES, + crypto_secretbox_BOXZEROBYTES: crypto_secretbox_BOXZEROBYTES, + crypto_scalarmult_BYTES: crypto_scalarmult_BYTES, + crypto_scalarmult_SCALARBYTES: crypto_scalarmult_SCALARBYTES, + crypto_box_PUBLICKEYBYTES: crypto_box_PUBLICKEYBYTES, + crypto_box_SECRETKEYBYTES: crypto_box_SECRETKEYBYTES, + crypto_box_BEFORENMBYTES: crypto_box_BEFORENMBYTES, + crypto_box_NONCEBYTES: crypto_box_NONCEBYTES, + crypto_box_ZEROBYTES: crypto_box_ZEROBYTES, + crypto_box_BOXZEROBYTES: crypto_box_BOXZEROBYTES, + crypto_sign_BYTES: crypto_sign_BYTES, + crypto_sign_PUBLICKEYBYTES: crypto_sign_PUBLICKEYBYTES, + crypto_sign_SECRETKEYBYTES: crypto_sign_SECRETKEYBYTES, + crypto_sign_SEEDBYTES: crypto_sign_SEEDBYTES, + crypto_hash_BYTES: crypto_hash_BYTES, + + gf: gf, + D: D, + L: L, + pack25519: pack25519, + unpack25519: unpack25519, + M: M, + A: A, + S: S, + Z: Z, + pow2523: pow2523, + add: add, + set25519: set25519, + modL: modL, + scalarmult: scalarmult, + scalarbase: scalarbase, + }; + + /* High-level API */ + + function checkLengths(k, n) { + if (k.length !== crypto_secretbox_KEYBYTES) throw new Error('bad key size'); + if (n.length !== crypto_secretbox_NONCEBYTES) throw new Error('bad nonce size'); + } + + function checkBoxLengths(pk, sk) { + if (pk.length !== crypto_box_PUBLICKEYBYTES) throw new Error('bad public key size'); + if (sk.length !== crypto_box_SECRETKEYBYTES) throw new Error('bad secret key size'); + } + + function checkArrayTypes() { + for (var i = 0; i < arguments.length; i++) { + if (!(arguments[i] instanceof Uint8Array)) + throw new TypeError('unexpected type, use Uint8Array'); + } + } + + function cleanup(arr) { + for (var i = 0; i < arr.length; i++) arr[i] = 0; + } + + nacl.randomBytes = function(n) { + var b = new Uint8Array(n); + randombytes(b, n); + return b; + }; + + nacl.secretbox = function(msg, nonce, key) { + checkArrayTypes(msg, nonce, key); + checkLengths(key, nonce); + var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); + var c = new Uint8Array(m.length); + for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i]; + crypto_secretbox(c, m, m.length, nonce, key); + return c.subarray(crypto_secretbox_BOXZEROBYTES); + }; + + nacl.secretbox.open = function(box, nonce, key) { + checkArrayTypes(box, nonce, key); + checkLengths(key, nonce); + var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length); + var m = new Uint8Array(c.length); + for (var i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i]; + if (c.length < 32) return null; + if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return null; + return m.subarray(crypto_secretbox_ZEROBYTES); + }; + + nacl.secretbox.keyLength = crypto_secretbox_KEYBYTES; + nacl.secretbox.nonceLength = crypto_secretbox_NONCEBYTES; + nacl.secretbox.overheadLength = crypto_secretbox_BOXZEROBYTES; + + nacl.scalarMult = function(n, p) { + checkArrayTypes(n, p); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult(q, n, p); + return q; + }; + + nacl.scalarMult.base = function(n) { + checkArrayTypes(n); + if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); + var q = new Uint8Array(crypto_scalarmult_BYTES); + crypto_scalarmult_base(q, n); + return q; + }; + + nacl.scalarMult.scalarLength = crypto_scalarmult_SCALARBYTES; + nacl.scalarMult.groupElementLength = crypto_scalarmult_BYTES; + + nacl.box = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox(msg, nonce, k); + }; + + nacl.box.before = function(publicKey, secretKey) { + checkArrayTypes(publicKey, secretKey); + checkBoxLengths(publicKey, secretKey); + var k = new Uint8Array(crypto_box_BEFORENMBYTES); + crypto_box_beforenm(k, publicKey, secretKey); + return k; + }; + + nacl.box.after = nacl.secretbox; + + nacl.box.open = function(msg, nonce, publicKey, secretKey) { + var k = nacl.box.before(publicKey, secretKey); + return nacl.secretbox.open(msg, nonce, k); + }; + + nacl.box.open.after = nacl.secretbox.open; + + nacl.box.keyPair = function() { + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_box_SECRETKEYBYTES); + crypto_box_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; + }; + + nacl.box.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_box_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); + crypto_scalarmult_base(pk, secretKey); + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; + }; + + nacl.box.publicKeyLength = crypto_box_PUBLICKEYBYTES; + nacl.box.secretKeyLength = crypto_box_SECRETKEYBYTES; + nacl.box.sharedKeyLength = crypto_box_BEFORENMBYTES; + nacl.box.nonceLength = crypto_box_NONCEBYTES; + nacl.box.overheadLength = nacl.secretbox.overheadLength; + + nacl.sign = function(msg, secretKey) { + checkArrayTypes(msg, secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length); + crypto_sign(signedMsg, msg, msg.length, secretKey); + return signedMsg; + }; + + nacl.sign.open = function(signedMsg, publicKey) { + checkArrayTypes(signedMsg, publicKey); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var tmp = new Uint8Array(signedMsg.length); + var mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey); + if (mlen < 0) return null; + var m = new Uint8Array(mlen); + for (var i = 0; i < m.length; i++) m[i] = tmp[i]; + return m; + }; + + nacl.sign.detached = function(msg, secretKey) { + var signedMsg = nacl.sign(msg, secretKey); + var sig = new Uint8Array(crypto_sign_BYTES); + for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i]; + return sig; + }; + + nacl.sign.detached.verify = function(msg, sig, publicKey) { + checkArrayTypes(msg, sig, publicKey); + if (sig.length !== crypto_sign_BYTES) + throw new Error('bad signature size'); + if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) + throw new Error('bad public key size'); + var sm = new Uint8Array(crypto_sign_BYTES + msg.length); + var m = new Uint8Array(crypto_sign_BYTES + msg.length); + var i; + for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]; + for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i]; + return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); + }; + + nacl.sign.keyPair = function() { + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + crypto_sign_keypair(pk, sk); + return {publicKey: pk, secretKey: sk}; + }; + + nacl.sign.keyPair.fromSecretKey = function(secretKey) { + checkArrayTypes(secretKey); + if (secretKey.length !== crypto_sign_SECRETKEYBYTES) + throw new Error('bad secret key size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i]; + return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; + }; + + nacl.sign.keyPair.fromSeed = function(seed) { + checkArrayTypes(seed); + if (seed.length !== crypto_sign_SEEDBYTES) + throw new Error('bad seed size'); + var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); + var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); + for (var i = 0; i < 32; i++) sk[i] = seed[i]; + crypto_sign_keypair(pk, sk, true); + return {publicKey: pk, secretKey: sk}; + }; + + nacl.sign.publicKeyLength = crypto_sign_PUBLICKEYBYTES; + nacl.sign.secretKeyLength = crypto_sign_SECRETKEYBYTES; + nacl.sign.seedLength = crypto_sign_SEEDBYTES; + nacl.sign.signatureLength = crypto_sign_BYTES; + + nacl.hash = function(msg) { + checkArrayTypes(msg); + var h = new Uint8Array(crypto_hash_BYTES); + crypto_hash(h, msg, msg.length); + return h; + }; + + nacl.hash.hashLength = crypto_hash_BYTES; + + nacl.verify = function(x, y) { + checkArrayTypes(x, y); + // Zero length arguments are considered not equal. + if (x.length === 0 || y.length === 0) return false; + if (x.length !== y.length) return false; + return (vn(x, 0, y, 0, x.length) === 0) ? true : false; + }; + + nacl.setPRNG = function(fn) { + randombytes = fn; + }; + + (function() { + // Initialize PRNG if environment provides CSPRNG. + // If not, methods calling randombytes will throw. + var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null; + if (crypto && crypto.getRandomValues) { + // Browsers. + var QUOTA = 65536; + nacl.setPRNG(function(x, n) { + var i, v = new Uint8Array(n); + for (i = 0; i < n; i += QUOTA) { + crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA))); + } + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } else if (typeof commonjsRequire !== 'undefined') { + // Node.js. + crypto = require$$7; + if (crypto && crypto.randomBytes) { + nacl.setPRNG(function(x, n) { + var i, v = crypto.randomBytes(n); + for (i = 0; i < n; i++) x[i] = v[i]; + cleanup(v); + }); + } + } + })(); + + })( module.exports ? module.exports : (self.nacl = self.nacl || {})); + }); + + let ntor = {}; + + /** + * Number of bytes to derive from successful ntor handshakes. + * @readonly + * @default + */ + ntor.keybytes = 92; + + /** + * Protocol identifier, prefix tweaks used in ntor handshakes various hashes. + * @readonly + * @default + * + * @see ntor.tweaks + */ + ntor.protoid = "ntor-curve25519-sha256-1"; + + /** + * Tweaks used in ntor handshakes for various hashes and key derivation. + * @enum + * @readonly + * + * @see ntor.hash + */ + ntor.tweaks = { + /** + * rfc5869 Expand {info} + * @type kdf + */ + expand: ntor.protoid + ":key_expand", + /** + * rfc5869 Extract {salt} + * @type kdf + */ + key: ntor.protoid + ":key_extract", + /** + * H({secret_input}, t_verify) + * @type ntor + */ + verify: ntor.protoid + ":verify", + /** + * suffix of {auth_input} + * @type ntor + */ + server: ntor.protoid + "Server", + /** + * H({auth_input}, t_mac) + * @type ntor + */ + mac: ntor.protoid + ":mac" + }; + + /** + * Tweaked pseudo-random function factory, see {@link ntor.hash}. + * + * @param {ntor.tweaks} tweak tweak to use + * @return {hash_t} + * + * @see ntor.hash + */ + ntor.hash_factory = function (tweak) { + tweak = ntor.tweaks[tweak]; + tweak = sjcl.codec.utf8String.toBits(tweak); + + /** + * Tweaked pseudo-random function used by {@link ntor}, returned + * by {@link ntor.hash_factory}. + * + * @interface hash_t + * @see ntor.hash + * + * @property {Object} hmac underlying hmac provider + */ + var hash = { + hmac: new sjcl.misc.hmac(tweak), + /** + * Compute parent tweaked pseudo-random function on provided data. + * + * @function + * @name hash_t#encrypt + * @param {Uint8Array} data input data + */ + encrypt: function (data) { + data = enc.bits(data); + data = hash.hmac.encrypt(data); + return dec.bits(data) + } + }; + return hash + }; + + /** + * Tweaked pseudo-random functions used in ntor handshakes. + * @enum + * @type hash_t + * + * @see ntor.tweaks + */ + ntor.hash = { + /** + * used for H({secret_input}, t_verify) during ntor handshakes + */ + verify: ntor.hash_factory("verify"), + /** + * used for H({auth_input}, t_mac) during ntor handshakes + */ + mac: ntor.hash_factory("mac"), + /** + * used for extraction during ntor handshakes key derivation + */ + prk: ntor.hash_factory("key") + }; + + /** + * Compute ntor key derivation from given material to n bytes. + * + * @param {Uint8Array} material ntor {secret_input} handshake + * @param {int} n number of bytes to output + * @return {Uint8Array} + */ + ntor.kdf = function (material, n) { + material = ntor.hash.prk.encrypt(material); + var hash = new sjcl.misc.hmac(enc.bits(material)); + + var tweak = ntor.tweaks["expand"]; + tweak = sjcl.codec.utf8String.toBits(tweak); + + var idx = 1; + var out = enc.bits([]); + var last = enc.bits([]); + while (sjcl.bitArray.bitLength(out) < n * 8) { + var idxbits = enc.bits([idx]); + var current = sjcl.bitArray.concat(tweak, idxbits); + + last = hash.encrypt(sjcl.bitArray.concat(last, current)); + out = sjcl.bitArray.concat(out, last); + idx = idx + 1; + } + + return dec.bits(sjcl.bitArray.clamp(out, n * 8)) + }; + + + /** + * Compute the first part of a ntor handshake, + * writes a {@link half_t} in {@link endpoint_t#material}. + * + * @param {endpoint_t} endpoint state where to store half-finished material + * @param {Object} descriptor node descriptor to handshake with + * @param {Boolean} encode if true, returns base64 (default: true) + * @return {Uint8Array|string} + * + * @see ntor.shake + */ + ntor.hand = function (endpoint, descriptor, encode) { + if (encode === undefined) + encode = true; + if (descriptor === undefined) + descriptor = endpoint.guard; + + var identity = dec.base64(descriptor.router.identity + "="); + var onionkey = dec.base64(descriptor["ntor-onion-key"]); + + /** + * Internal object, half-finished ntor handshake state in {@link + * endpoint_t#material}, created by: + *
        + *
      • {@link ntor.hand} + *
      • {@link ntor.fast} + *
      • {@link lnn.auth} + *
      + * Captures cryptographic state required to finish the handshake. + * + * @interface half_t + * + * @property {Object} ntor key pair + * @property {Uint8Array} identity node identity + * @property {Uint8Array} onionkey node public key + */ + endpoint.material = { + ntor: naclFast.box.keyPair(), + identity: identity, + onionkey: onionkey + }; + + var pubkey = endpoint.material.ntor.publicKey; + var length = identity.length + onionkey.length + pubkey.length; + + var payload = new Uint8Array(length); + payload.set(identity, 0); + payload.set(onionkey, identity.length); + payload.set(pubkey, identity.length + onionkey.length); + + if (encode) + return enc.base64(payload) + return payload + }; + + /** + * Just as {@link ntor.hand} but without node identity and onion key – used + * by {@link lnn.fast}, writes a {@link half_t} in {@link endpoint_t#material}. + * + *
      Note: always returns base64-encoded handshake.
      + * + * @param {endpoint_t} endpoint state where to store half-finished material + * @return {string} + * + * @see lnn.fast + */ + ntor.fast = function (endpoint) { + endpoint.material = {}; + endpoint.material.ntor = naclFast.box.keyPair(); + endpoint.material.identity = null; + endpoint.material.onionkey = null; + return enc.base64(endpoint.material.ntor.publicKey) + }; + + /** + * Compute the second part of a ntor handshake read + * from {@link endpoint_t#material}, returns derived bytes suitable as + * {@link ntor.slice} input. + * + *
      Note: returns null if handshake is invalid.
      + * + * @param {endpoint_t} endpoint state where to read half-finished material + * @param {Uint8Array|string} data server part of the handshake + * @param {boolean} encoded if true, decode data as base64 + * (default: true) + * @return {Uint8Array|null} + * + * @see ntor.hand + */ + ntor.shake = function (endpoint, data, encoded) { + if (encoded === undefined) + encoded = true; + if (encoded) + data = dec.base64(data); + + var client_pubkey = endpoint.material.ntor.publicKey; + var client_secret = endpoint.material.ntor.secretKey; + var server_pubkey = data.slice(0, naclFast.scalarMult.scalarLength); + var server_auth = data.slice(naclFast.scalarMult.scalarLength); + + var identity = endpoint.material.identity; + var onionkey = endpoint.material.onionkey; + + var exp_share = naclFast.scalarMult(client_secret, server_pubkey); + var exp_onion = naclFast.scalarMult(client_secret, onionkey); + + var protoid = dec.utf8(ntor.protoid); + var length = exp_share.length * 2 + identity.length + onionkey.length * 3; + var off = 0; + + var secret_input = new Uint8Array(length + protoid.length); + secret_input.set(exp_share, off); off += exp_share.length; + secret_input.set(exp_onion, off); off += exp_onion.length; + secret_input.set(identity, off); off += identity.length; + secret_input.set(onionkey, off); off += onionkey.length; + secret_input.set(client_pubkey, off); off += client_pubkey.length; + secret_input.set(server_pubkey, off); off += server_pubkey.length; + secret_input.set(protoid, off); + var verify = ntor.hash.verify.encrypt(secret_input); + + var server = dec.utf8(ntor.tweaks["server"]); + var length = verify.length + identity.length + onionkey.length * 3; + var off = 0; + + var auth_input = new Uint8Array(length + server.length); + auth_input.set(verify, off); off += verify.length; + auth_input.set(identity, off); off += identity.length; + auth_input.set(onionkey, off); off += onionkey.length; + auth_input.set(server_pubkey, off); off += server_pubkey.length; + auth_input.set(client_pubkey, off); off += client_pubkey.length; + auth_input.set(server, off); + var client_auth = ntor.hash.mac.encrypt(auth_input); + + var valid = true; + length = client_auth.length; + for (var i = 0; i < length; i++) { + if (client_auth[i] != server_auth[i]) + valid = false; + } + + var zero_onion = 0; + var zero_share = 0; + length = exp_onion.length; + for (var i = 0; i < length; i++) { + if (exp_onion[i] == 0) + zero_onion = zero_onion + 1; + if (exp_share[i] == 0) + zero_share = zero_share + 1; + } + + if (zero_onion == exp_onion.length || zero_share == exp_share.length) + valid = false; + + if (valid) { + return ntor.kdf(secret_input, ntor.keybytes) + } + return null + }; + + /** + * Build a shared cryptographic {@link material_t} for + * {@link endpoint_t#material} from the output of {@link ntor.shake}. + * + *
      +	 * Note: assume KEY_LEN == 16 (aes256) and HASH_LEN == 20 (sha1) internally.
      +	 * 
      + * + * @param {Uint8Array} material exactly {@link ntor.keybytes} + * bytes + * @return {material_t} + */ + ntor.slice = function (material) { + var k = 16; // KEY_LEN + var h = 20; // HASH_LEN + + /** + * Internal object, stores shared cryptographic material + * as {@link endpoint_t#material}, returned by {@link ntor.slice}. + * + * @interface material_t + * @see ntor.slice + * + * @property {Uint8Array} key_hash unused + * @property {Uint8Array} forward_key used in {@link forward_t} + * @property {Uint8Array} forward_digest used in {@link forward_t} + * @property {Uint8Array} backward_key used in {@link backward_t} + * @property {Uint8Array} backward_digest used in {@link backward_t} + */ + var material = { + key_hash: material.slice(h * 2 + k * 2), + forward_digest: material.slice(0, h), + backward_digest: material.slice(h, h * 2), + forward_key: material.slice(h * 2, h * 2 + k), + backward_key: material.slice(h * 2 + k, h * 2 + k * 2) + }; + return material + }; + + // (function only used for proxy auth, not a part of regular ntor handshake) + + /** + *
      +	 * Note: this function is used for proxy-server authentication and is not a
      +	 * part of regular ntor handshakes nor the Tor specification.
      +	 * 
      + * + * Take an endpoint that uses the proxy-server authentication API (such as one + * configured through {@link lnn.auth}) and the base64-encoded fields "auth" + * and "data" as returned by the proxy-server, then returns the decoded data + * if and only if the authentication succeeded. + * + */ + ntor.auth = function (endpoint, client, data) { + var pending_material = endpoint.material; + endpoint.material = endpoint.auth; + + var data = dec.base64(data); + var material = ntor.shake(endpoint, client); + if (material == null) + throw "Invalid auth." + endpoint.material = pending_material; + + var key = material.slice(0, 32); + var nonce = material.slice(32, 32 + 24); + data = naclFast.secretbox.open(data, nonce, key); + return JSON.parse(enc.utf8(data)) + }; + + /** + * @module relay + */ + + let relay = {}; + relay.payload_len = 509; + relay.data_len = relay.payload_len - 11; + relay.full_len = 5 + relay.payload_len; + relay.cmd = { + "begin": 1, 1: "begin", + "data": 2, 2: "data", + "end": 3, 3: "end", + "connected": 4, 4: "connected", + "sendme": 5, 5: "sendme", + "extend": 6, 6: "extend", + "extended": 7, 7: "extended", + "truncate": 8, 8: "truncate", + "truncated": 9, 9: "truncated", + "drop": 10, 10: "drop", + "resolve": 11, 11: "resolve", + "resolved": 12, 12: "resolved", + "begin_dir": 13, 13: "begin_dir", + "extend2": 14, 14: "extend2", + "extended2": 15, 15: "extended2" + }; + + relay.pack = function (cmd, stream_id, data) { + if (data === undefined) + data = new Uint8Array(0); + if (stream_id === undefined) + stream_id = 0; + + if (typeof (data) == "string") + data = dec.utf8(data); + + var cell = new Uint8Array(relay.full_len); /* padded with \x00 */ + var view = new DataView(cell.buffer); + + view.setUint32(0, 2147483648 /* fake circuit_id */, false); + view.setUint8(4, 3 /* RELAY CELL */, false); + view.setUint8(5, relay.cmd[cmd], false); + view.setUint16(6, 0 /* recognized */, false); + view.setUint16(8, stream_id, false); + // (implicit 4-bytes zeroed digest at offset 10) + view.setUint16(14, data.length, false); + cell.set(data, 16); + + return cell + }; + + relay.extend = function (handshake, host, port, identity, eidentity) { + // (assuming that host is an IPv4) + var addr = new Uint8Array(host.split(".")); + if (addr.join(".") != host) + throw "Invalid extend IPv4 address, fatal." + + port = parseInt(port); + if (typeof (identity) == "string") + identity = dec.base64(identity); + if (typeof (eidentity) == "string") + eidentity = dec.base64(eidentity + "="); + + var nspec = 2; + if (eidentity !== undefined) + nspec += 1; + + var length = (1 // Number of link specifiers + + 1 + 1 + 6 // 1. IPv4 addr+port + + 1 + 1 + identity.length // 2. Legacy identity + + 2 // Client handshake type (0x00002 ntor) + + 2 // Client handshake length + + handshake.length); // Actual handshake content + + if (nspec == 3) + length += 1 + 1 + eidentity.length; // 3. Ed25519 identity + + var off = 0; + var data = new Uint8Array(length); + var view = new DataView(data.buffer); + view.setUint8(off, nspec /* nb of specifiers */, false); off += 1; + + view.setUint8(off, 0 /* TLS-over-TCP IPv4 specifier */, false); off += 1; + view.setUint8(off, 6, false); off += 1; /* length 1 byte */ + data.set(addr, off); off += 4; /* address 4 bytes */ + view.setUint16(off, port, false); off += 2; /* port 2 bytes */ + + view.setUint8(off, 2 /* Legacy identity specifier */, false); off += 1; + view.setUint8(off, identity.length, false); off += 1; + data.set(identity, off); off += identity.length; + + if (nspec == 3) { + view.setUint8(off, 3 /* Ed25519 identity specifier */, false); off += 1; + view.setUint8(off, eidentity.length, false); off += 1; + data.set(eidentity, off); off += eidentity.length; + } + + view.setUint16(off, 2 /* handshake: 0x00002 ntor */, false); off += 2; + view.setUint16(off, handshake.length, false); off += 2; + data.set(handshake, off); + + return data + }; + + relay.begin = function (host, port) { + let valid = false; + if (host.match("(\\d\+\\.){3}\\d\+")) + valid = true; + if (host.match("^\\[[\\d:]*\\]$")) + valid = true; + if (!valid && host.slice(-1) != ".") + host = host + "."; + if (host.match("^([a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)*$")) + valid = true; + if (host.slice(-1) == ".") + host = host.slice(0, -1); + + if (!valid) + throw "Invalid host provided?" + var address = dec.utf8(host + ":" + port); + + var data = new Uint8Array(address.length + 1 + 4); // (1o null, 4o flags) + data.set(address, 0); + data[address.length + 1 + 3] = 5; // flags IPv6 okay+preferred and IPv4 okay + + return data + }; + + /** + * @module onion + */ + + function ctr(key) { + var key = enc.bits(key); + var aes = new sjcl.cipher.aes(key); + + var ctr = { + prf: aes, + nonce: 0, + buffer: new Uint8Array(0), + extend: function (n) { + var length = (Math.floor(n / 16) + 1) * 16; + var remains = ctr.buffer; + ctr.buffer = new Uint8Array(length + remains.length); + ctr.buffer.set(remains, 0); + + for (var idx = remains.length; idx < ctr.buffer.length; idx += 16) { + var nonce = new Uint8Array(16); + new DataView(nonce.buffer).setUint32(12, ctr.nonce, false); + + nonce = enc.bits(nonce); + var pad = dec.bits(ctr.prf.encrypt(nonce)); + + ctr.buffer.set(pad, idx); + ctr.nonce = ctr.nonce + 1; + } + }, + process: function (data) { + if (data.length > ctr.buffer.length) + ctr.extend(data.length); + + var data = data.slice(0); + for (var idx = 0; idx < data.length; idx++) { + data[idx] ^= ctr.buffer[idx]; + } + ctr.buffer = ctr.buffer.slice(data.length); + + return data + } + }; + return ctr + } + + function sha(digest) { + var digest = enc.bits(digest); + + var sha = { + hash: new sjcl.hash.sha1(), + digest: function (data) { + sha.hash.update(enc.bits(data)); + data = new sjcl.hash.sha1(sha.hash).finalize(); + return dec.bits(data) + } + }; + + sha.hash.update(digest); + return sha + } + + function forward(endpoint) { + var early = 8; + var layers = []; + if (endpoint.forward != null) { + layers = endpoint.forward.layers; + layers.push(endpoint.forward); + early = endpoint.forward.early; + } + + var forward = { + iv: 0, + ctr: ctr(endpoint.material.forward_key), + sha: sha(endpoint.material.forward_digest), + early: early, // (first 8 relay cells will be replaced by relay_early) + layers: layers, + encrypt: function (cell) { + if ((cell.length) != relay.full_len) + throw "Invalid size for cell, fatal." + + var body = cell.slice(5); + for (var idx = 0; idx < forward.layers.length; idx++) { + body.set(forward.layers[idx].ctr.process(body), 0); + } + cell.set(forward.ctr.process(body), 5); + + if (forward.early > 0 && cell[4] == 3 /* relay */) { + forward.early = forward.early - 1; + cell[4] = 9; /* relay_early */ + } + return cell + }, + digest: function (cell) { + if ((cell.length) != relay.full_len) + throw "Invalid size for cell, fatal." + + var body = cell.slice(5); + body.set(new Uint8Array(4), 5); + return forward.sha.digest(body).slice(0, 4) + } + }; + return forward + } + + function backward(endpoint) { + var layers = []; + if (endpoint.backward != null) { + layers = endpoint.backward.layers; + layers.push(endpoint.backward); + } + + var backward = { + iv: 0, + ctr: ctr(endpoint.material.backward_key), + sha: sha(endpoint.material.backward_digest), + layers: layers, + decrypt: function (cell) { + if ((cell.length) != relay.full_len) + throw "Invalid size for cell, fatal." + + var body = cell.slice(5); + + for (var idx = 0; idx < backward.layers.length; idx++) { + body.set(backward.layers[idx].ctr.process(body), 0); + + cell.set(body, 5); + + var recognized = cell.slice(6, 8); + if (recognized[0] == recognized[1] && recognized[0] == 0) { + var digest = cell.slice(10, 14); + var expect = backward.layers[idx].digest(cell); + + var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false); + + if (expect[0] == digest[0] && + expect[1] == digest[1] && + expect[2] == digest[2] && + expect[3] == digest[3]) { + if (length <= relay.data_len) { + console.log("Warning: Cell sent by intermediate \ + tor node, after " + (idx + 1) + " hop(s)"); + return cell + } + } + } + } + + cell.set(backward.ctr.process(body), 5); + var digest = cell.slice(10, 14); + cell.set(new Uint8Array(4), 10); + + var recognized = cell.slice(6, 8); + if (!(recognized[0] == recognized[1] && recognized[0] == 0)) { + throw "Invalid cell recognized field." + } + + var expect = backward.digest(cell); + if (!( digest[0] == expect[0] + && digest[1] == expect[1] + && digest[2] == expect[2] + && digest[3] == expect[3])) { + throw "Invalid cell digest." + } + + var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false); + if (length > relay.data_len) { + throw "Invalid cell data length." + } + + return cell + + + }, + digest: function (cell) { + if ((cell.length) != relay.full_len) + throw "Invalid size for cell, fatal." + + var body = cell.slice(5); + body.set(new Uint8Array(4), 5); + return backward.sha.digest(body).slice(0, 4) + } + }; + return backward + } + + function build(endpoint, cmd, stream_id, data) { + var cell = relay.pack(cmd, stream_id, data); + cell.set(endpoint.forward.digest(cell), 10); + return endpoint.forward.encrypt(cell) + } + + function peel(endpoint, cell) { + var cell = endpoint.backward.decrypt(cell); + + + + var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false); + + var id = new DataView(cell.slice(8, 10).buffer).getUint16(0, false); + var cmd = relay.cmd[cell.slice(5, 6)[0]]; + var data = cell.slice(16, 16 + length); + var relay_ = { cmd: cmd, stream_id: id, data: data }; + + return relay_ + } + + /** + * @module consensusParser + */ + + let consensusParser = {}; + + consensusParser.parse = function (rawText, flavor = 'microdesc') { + if (typeof rawText !== 'string') throw `Error: the consensus must be given as a string` + consensusParser.lines = rawText.split('\n'); + consensusParser.words = consensusParser.lines[0].split(' '); + consensusParser.consensus = {}; + consensusParser.validFlags = ['Authority', 'BadExit', 'Exit', 'Fast', 'Guard', 'HSDir', 'NoEdConsensus', 'Stable', 'StaleDesc', 'Running', 'Valid', 'V2Dir']; + consensusParser.index = 0; + consensusParser.totalLines = consensusParser.lines.length; + + if (flavor != 'unflavored' && flavor != 'microdesc') { + throw 'Error: Unexpected flavor' + } + consensusParser.consensus['flavor'] = flavor; + + consensusParser.consumeHeaders(); + consensusParser.consumeAuthority(); + consensusParser.consumeRouters(); + consensusParser.consumeFooter(); + + return consensusParser.consensus + }; + + //----------------------------------HEADERS PARSER-------------------------------- + + /** + * Function that parses the headers + */ + consensusParser.consumeHeaders = function () { + consensusParser.consumeNetworkStatusVersion(); + consensusParser.consumeVoteStatus(); + consensusParser.consumeConsensusMethod(); + consensusParser.consumeDate('valid-after'); + consensusParser.consumeDate('fresh-until'); + consensusParser.consumeDate('valid-until'); + consensusParser.consumeVotingDelay(); + consensusParser.tryConsumeVersions('client-versions'); + consensusParser.tryConsumeVersions('server-versions'); + + while (consensusParser.words[0] === 'package') { + consensusParser.consumePackage(); + } + + consensusParser.consumeKnownFlags(); + consensusParser.tryConsumeProtocols('recommended-client-protocols'); + consensusParser.tryConsumeProtocols('recommended-relay-protocols'); + consensusParser.tryConsumeProtocols('required-client-protocols'); + consensusParser.tryConsumeProtocols('required-relay-protocols'); + consensusParser.tryConsumeParams(); + consensusParser.tryConsumeShareRand('shared-rand-previous-value'); + consensusParser.tryConsumeShareRand('shared-rand-current-value'); + + }; + + /** + * Parse the field network-status-version + */ + consensusParser.consumeNetworkStatusVersion = function () { + let expectedLength = 2; + if (consensusParser.consensus.flavor == 'microdesc') { + expectedLength = 3; + if (consensusParser.words[2] != 'microdesc') + throw 'Error: Flavor mismatch in header.' + } + + let version = consensusParser.tryParseKeyValueInteger('network-status-version', expectedLength); + consensusParser.consensus['headers'] = { + 'network-status-version': { + 'version': version, + 'flavor': consensusParser.consensus.flavor + } + }; + + consensusParser.nextLine(); + }; + + /** + * Parse the field vote-status + * @throws WrongParameterException if status is not consensus + */ + consensusParser.consumeVoteStatus = function () { + let status = consensusParser.tryParseKeyValueString('vote-status'); + if (status !== 'consensus') throw `WrongParameterException: vote-status must be consensus` + consensusParser.consensus['headers']['vote-status'] = status; + consensusParser.nextLine(); + }; + + /** + * Parse the field consensus-method + */ + consensusParser.consumeConsensusMethod = function () { + consensusParser.consensus['headers']['consensus-method'] = consensusParser.tryParseKeyValueInteger('consensus-method'); + consensusParser.nextLine(); + }; + + /** + * Parse the fields valid-after, fresh-until and valid-until + * @param {strin} word + */ + consensusParser.consumeDate = function (word) { + consensusParser.consensus['headers'][word] = consensusParser.tryParseDate(word); + consensusParser.nextLine(); + }; + + /** + * Parse the field voting-delay + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongParameterException if consensusParser.words[1] or consensusParser.words[2] is not a number + * @throws WrongFormatException if consensusParser.words.length is not 3 + */ + consensusParser.consumeVotingDelay = function () { + consensusParser.checkFormat(3, 'voting-delay'); + if (isNaN(consensusParser.words[1])) throw `WrongParameterException: ${words[1]} is not a number` + if (isNaN(consensusParser.words[2])) throw `WrongParameterException: ${words[2]} is not a number` + + consensusParser.consensus['headers']['voting-delay'] = { + 'vote': Number(consensusParser.words[1]), + 'dist': Number(consensusParser.words[2]) + }; + + consensusParser.nextLine(); + }; + + /** + * Try to parse the fields client-versions or server-versions if they are present + * @param {string} word either client-versions or server-versions + */ + consensusParser.tryConsumeVersions = function (word) { + + if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` + if (consensusParser.words[0] === word) { + consensusParser.consensus['headers'][word] = consensusParser.tryParseCommaSeparatedList(word); + consensusParser.nextLine(); + } + }; + + /** + * Parses the field package + * @throws WrongFormatException if consensusParser.words.length is smaller than 5 + */ + consensusParser.consumePackage = function () { + + if (consensusParser.words.length < 5) throw `WrongFormatException: at least 5 fields are expected` + if (consensusParser.consensus['headers']['package'] === undefined) consensusParser.consensus['headers']['package'] = []; + + let pack = { + 'name': consensusParser.words[1], + 'version': consensusParser.words[2], + 'url': consensusParser.words[3] + }; + let remaining = consensusParser.words.splice(4, consensusParser.words.length); + let digests = {}; + + for (let digest of remaining) { + let tmp = digest.split('='); + digests[tmp[0]] = tmp[1]; + } + + pack['digests'] = digests; + consensusParser.consensus['headers']['package'].push(pack); + consensusParser.nextLine(); + }; + + /** + * Parses the field package + * @throws NotValidFlagException if one of the flags is not in the valid flag list + */ + consensusParser.consumeKnownFlags = function () { + consensusParser.consensus['headers']['flags'] = consensusParser.tryParseFlags(); + consensusParser.nextLine(); + }; + + /** + * Try to parse the fields recommended-client-protocols, recommended-relay-protocols, required-client-protocols and required-client-protocols if they are present + * @param {string} word either client-versions or server-versions + */ + consensusParser.tryConsumeProtocols = function (word) { + if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` + if (consensusParser.words[0] === word) { + consensusParser.consensus['headers'][word] = consensusParser.tryParseRanges(consensusParser.words.splice(1, consensusParser.words.length)); + consensusParser.nextLine(); + } + + }; + /** + * Try to parse the field params if it is present + */ + consensusParser.tryConsumeParams = function () { + if (consensusParser.words[0] === 'params') { + consensusParser.consensus['headers']['params'] = consensusParser.tryParseParams(); + consensusParser.nextLine(); + } + }; + + /** + * Try to parse the fields shared-rand-previous-value and shared-rand-current-value if they are present + * @param {string} word specify the field + */ + consensusParser.tryConsumeShareRand = function (word) { + if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` + if (consensusParser.words[0] === word) { + let reveals = Number(consensusParser.words[1]); + let value = consensusParser.words[2]; + + if (!consensusParser.isBase64(value)) throw `InvalidParameterException: value ${value} must be in hexadecimal` + + consensusParser.consensus['headers'][word] = { + 'NumReveals': reveals, + 'Value': value + }; + + consensusParser.nextLine(); + } + }; + + //-------------------AUTHORITY PARSER-------------------------------- + /** + * Parses the authority part of the consensus + * @throws InvalidIPException if address or IP are not valid IP addresses + * @throws InvalidPortException if dirport or orport are not valid ports + */ + consensusParser.consumeAuthority = function () { + if (consensusParser.words[0] !== 'dir-source') throw `WrongFieldException: there must be at least one dir-source` + consensusParser.consensus['dir-sources'] = []; + + while (consensusParser.words[0] === 'dir-source') { + consensusParser.consumeDirSource(); + } + }; + + /** + * Parse a dir-source + * @throws InvalidIPException if the IP-address is not valid + * @throws InvalidPortException if dirport or orport are not valid + * @throws InvalidParameterException if the vote-digest is not in hexadecimal + */ + consensusParser.consumeDirSource = function () { + let dirSource = {}; + consensusParser.checkFormat(7, 'dir-source'); + + dirSource['nickname'] = consensusParser.words[1]; + + if (!consensusParser.isHex(consensusParser.words[2])) throw `InvalidParameterException: vote-digest ${consensusParser.words[2]} must be in hexadecimal` + dirSource['identity'] = consensusParser.words[2].toUpperCase(); + + dirSource['hostname'] = consensusParser.words[3]; + + if (!consensusParser.isValidIP(consensusParser.words[4])) throw `InvalidIPException: ${consensusParser.words[4]} is not a valid IP` + + dirSource['address'] = consensusParser.words[4]; + + if (!consensusParser.isValidPort(Number(consensusParser.words[5])) || !consensusParser.isValidPort(Number(consensusParser.words[6]))) throw `InvalidPortException` + + dirSource['dirport'] = Number(consensusParser.words[5]); + dirSource['orport'] = Number(consensusParser.words[6]); + + consensusParser.nextLine(); + dirSource['contact'] = consensusParser.words.splice(1, consensusParser.words.length).join(' '); + consensusParser.nextLine(); + let digest = consensusParser.tryParseKeyValueString('vote-digest').toUpperCase(); + + if (!consensusParser.isHex(digest)) throw `InvalidParameterException: vote-digest ${digest} must be in hexadecimal` + + dirSource['vote-digest'] = digest; + consensusParser.consensus['dir-sources'].push(dirSource); + consensusParser.nextLine(); + + + }; + + //-------------------ROUTER PARSER----------------------------------- + /** + * Consume each router status entry + * @throws WrongFieldException if there is no router entry + */ + consensusParser.consumeRouters = function () { + if (consensusParser.words[0] !== 'r') throw `WrongFieldException: there must be at least one router` + consensusParser.consensus['routers'] = []; + + while (consensusParser.words[0] === 'r') { + let router = {}; + consensusParser.consumeRfield(router); + + if (consensusParser.words[0] === 'a') router['a'] = []; + while (consensusParser.words[0] === 'a') { + consensusParser.consumeAfield(router); + } + + if (consensusParser.consensus.flavor == 'microdesc') { + consensusParser.consumeMfield(router); + } + + consensusParser.consumeSfield(router); + consensusParser.tryConsumeVfield(router); + consensusParser.tryConsumePrField(router); + consensusParser.tryConsumeWfield(router); + consensusParser.tryConsumePfield(router); + + consensusParser.consensus['routers'].push(router); + } + + }; + + /** + * Parses the field 'r' of the router status entry + * @param {} router + * @throws InvalidParameterException if the fields are not valid + */ + consensusParser.consumeRfield = function (router) { + let len = 9; + if (consensusParser.consensus.flavor == 'microdesc') len = 8; + consensusParser.checkFormat(len, 'r'); + + router['nickname'] = consensusParser.words[1]; + + if (!consensusParser.isBase64(consensusParser.words[2] + "=")) throw `InvalidParameterException: identity ${consensusParser.words[2]} must be in base64` + router['identity'] = consensusParser.words[2]; + + let nxt = 3; + if (consensusParser.consensus.flavor == 'unflavored') { + if (!consensusParser.isBase64(consensusParser.words[3] + "=")) throw `InvalidParameterException: digest ${consensusParser.words[3]} must be in base64` + router['digest'] = consensusParser.words[3]; + nxt += 1; + } + + if (!consensusParser.isValidDate(consensusParser.words[nxt])) throw `InvalidParameterException: date ${consensusParser.words[nxt]} must have the format YYYY-MM-DD` + router['date'] = consensusParser.words[nxt]; + + if (!consensusParser.isValidTime(consensusParser.words[nxt + 1])) throw `InvalidParameterException: time ${consensusParser.words[nxt + 1]} must have the format HH:MM:SS` + router['time'] = consensusParser.words[nxt + 1]; + + if (!consensusParser.isValidIP(consensusParser.words[nxt + 2])) throw `InvalidParameterException: IP ${consensusParser.words[nxt + 2]} must be a valid IP address` + router['address'] = consensusParser.words[nxt + 2]; + + if (!consensusParser.isValidPort(Number(consensusParser.words[nxt + 3]))) throw `InvalidParameterException: ORPort ${consensusParser.words[nxt + 3]} must be a valid port` + router['orport'] = Number(consensusParser.words[nxt + 3]); + + if (!consensusParser.isValidPort(Number(consensusParser.words[nxt + 4]))) throw `InvalidParameterException: DirPort ${consensusParser.words[nxt + 4]} must be a valid port` + router['dirport'] = Number(consensusParser.words[nxt + 4]); + + consensusParser.nextLine(); + }; + + /** + * Parses the field 'a' of the router status entry + * @param {} router + * @throws InvalidParameterException if the fields are not valid + */ + consensusParser.consumeAfield = function (router) { + let i = consensusParser.words[1].indexOf("]"); + let address = consensusParser.words[1].slice(1, i); + if (!consensusParser.isValidIP(address)) throw `InvalidParameterException: IP ${address} must be a valid IP address` + + let guessedType = 'IPv6'; + if (consensusParser.isIPv4(address)) { + guessedType = 'IPv4'; + } + + let port = Number(consensusParser.words[1].slice(address.length + 3, consensusParser.words[1].length)); + + if (!consensusParser.isValidPort(port)) throw `InvalidParameterException: port ${port} must be a valid port` + + router['a'].push({ + 'ip': address, + 'port': port, + 'type': guessedType + }); + + consensusParser.nextLine(); + + }; + + /** + * Parses the field 's' of the router status entry + * @param {} router + */ + consensusParser.consumeSfield = function (router) { + router['flags'] = consensusParser.tryParseFlags(); + consensusParser.nextLine(); + }; + + /** + * Tries to parse the field 'v' of the router status entry + * @param {} router + */ + consensusParser.tryConsumeVfield = function (router) { + if (consensusParser.words[0] === 'v') { + consensusParser.checkFormat(3, 'v'); + router['version'] = consensusParser.words.splice(1, consensusParser.words.length).join(' '); + consensusParser.nextLine(); + } + }; + /** + * Tries to parse the field 'v' of the router status entry + * @param {} router + */ + consensusParser.tryConsumePrField = function (router) { + if (consensusParser.words[0] === 'pr') { + router['protocols'] = consensusParser.tryParseRanges(consensusParser.words.splice(1, consensusParser.words.length)); + consensusParser.nextLine(); + } + }; + /** + * Tries to parse the field 'w' of the router status entry + * @param {} router + */ + consensusParser.tryConsumeWfield = function (router) { + if (consensusParser.words[0] === 'w') { + router['w'] = consensusParser.tryParseParams(); + consensusParser.nextLine(); + } + }; + /** + * Tries to parse the field 'p' of the router status entry + * @param {} router + */ + consensusParser.tryConsumePfield = function (router) { + if (consensusParser.words[0] === 'p') { + consensusParser.checkFormat(3, 'p'); + if (consensusParser.words[1] !== 'accept' && consensusParser.words[1] !== 'reject') throw `WrongParameterException: ${consensusParser.words[1]} must be either accept or reject` + + + let portList = consensusParser.parse_range_once(consensusParser.words[2]); + + router['exit-policy'] = { + 'type': consensusParser.words[1], + 'PortList': portList + }; + consensusParser.nextLine(); + } + }; + + /** + * Parses the field 'm' of the router status entry (for microdesc flavor) + * @param {} router + */ + consensusParser.consumeMfield = function (router) { + consensusParser.checkFormat(2, 'm'); + + if (!consensusParser.isBase64(consensusParser.words[1] + "=")) throw `InvalidParameterException: digest ${consensusParser.words[1]} must be in base64` + router['micro-digest'] = consensusParser.words[1]; + + consensusParser.nextLine(); + }; + + + //-------------------FOOTER PARSER ---------------------------------- + + /** + * Consume the footer + * @throws WrongFieldException if there is no footer or no signature + */ + consensusParser.consumeFooter = function () { + if (consensusParser.words[0] !== 'directory-footer') throw `WrongFieldException: there must be a footer` + consensusParser.nextLine(); + consensusParser.consensus['footer'] = {}; + consensusParser.tryConsumeBandwidthWeights(); + + if (consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: there must be at least one signature` + consensusParser.consensus['footer']['directory-signatures'] = []; + + while (consensusParser.words[0] === 'directory-signature') { + consensusParser.consensus['footer']['directory-signatures'].push(consensusParser.consumeSignature()); + } + + }; + + /** + * Tries to consume the bandwidth weights + */ + consensusParser.tryConsumeBandwidthWeights = function () { + if (consensusParser.words[0] === 'bandwidth-weights') { + consensusParser.consensus['footer']['bandwidth-weights'] = consensusParser.tryParseParams(); + consensusParser.nextLine(); + } + }; + + /** + * Consumes the signature + * @throws WrongFieldException if the first field is not directory-signature + * @throws InvalidParameterException if either the identity or the signing-key-digest are not in hexadecimal + */ + consensusParser.consumeSignature = function () { + if (consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: next field must be directory-signature` + let length = consensusParser.words.length; + + let algo; + let remaining; + if (length === 4) { + algo = consensusParser.words[1]; + remaining = consensusParser.words.splice(2, length); + } else if (length === 3) { + algo = 'sha1'; + remaining = consensusParser.words.splice(1, length); + } + else throw `WrongParameterException: directory-signature has 3 or 4 arguments` + + let identity = remaining[0]; + if (!consensusParser.isHex(identity)) throw `InvalidParameterException: the identity ${identity} must be in hexadecimal` + + let digest = remaining[1]; + if (!consensusParser.isHex(digest)) throw `InvalidParameterException: the signing-key-digest ${digest} must be in hexadecimal` + + consensusParser.nextLine(); + + let signature = consensusParser.parseSignature(); + if (consensusParser.index < consensusParser.totalLines - 1) consensusParser.nextLine(); + + return { + 'Algorithm': algo, + 'identity': identity, + 'signing-key-digest': digest, + 'signature': signature + } + }; + //-------------------GENERAL PARSER----------------------------------- + + /** + * Parses lines with the format "field value" where value is an integer and field must be equal to word and return value. + * @param {string} word indicates to which field we are adding the newly parsed line + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongParameterException if consensusParser.words[1] is not a number + * @throws WrongFormatException if consensusParser.words.length is not 2 + */ + consensusParser.tryParseKeyValueInteger = function (word, expectedLength = 2) { + consensusParser.checkFormat(expectedLength, word); + if (isNaN(consensusParser.words[1])) throw `WrongParameterException: ${consensusParser.words[1]} is not a number` + + return Math.floor(consensusParser.words[1]) + }; + + /** + * Parses lines with the format "field value" where value is a string and field must be equal to word and return value. + * @param {string} word indicates to which field we are adding the newly parsed line + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongFormatException if consensusParser.words.length is not 2 + */ + consensusParser.tryParseKeyValueString = function (word) { + consensusParser.checkFormat(2, word); + return consensusParser.words[1] + }; + + /** + * Parses lines with the format "field YYYY-MM-DD HH:MM:SS" where field must be equal to word and return a date object + * @param {string} word indicates to which field we are adding the newly parsed line + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongFormatException if consensusParser.words.length is not 2 + * @throws NonValidDateException if the date is not valid + * @throws NonValidTimeException if the time is not valid + */ + consensusParser.tryParseDate = function (word) { + consensusParser.checkFormat(3, word); + if (!consensusParser.isValidDate(consensusParser.words[1])) throw `NonValidDateException: ${consensusParser.words[1]} is not a valid date` + if (!consensusParser.isValidTime(consensusParser.words[2])) throw `NonValidTimeException: ${consensusParser.words[2]} is not a valid time` + + return { + "date": consensusParser.words[1], + "time": consensusParser.words[2] + } + }; + + /** + * Parses lines with the format "field list" where list is a comma separated list, returns the list as an array + * @param {string} word indicates to which field we are adding the newly parsed line + * @throws NotEqualException if consensusParser.words[0] != word + * @throws WrongFormatException if consensusParser.words.length is not 2 + */ + consensusParser.tryParseCommaSeparatedList = function (word) { + consensusParser.checkFormat(2, word); + return consensusParser.words[1].split(",") + }; + + /** + * Parse the ranges of the protocols + * @param pairs Array of entries => Keyword=Values where values is the range + */ + consensusParser.tryParseRanges = function (pairs) { + let content = {}; + + for (let pair of pairs) { + if (pair.includes("=")) { + let tmp = pair.split("="); + content[tmp[0]] = consensusParser.parse_range_once(tmp[1]); + } + } + + return content + }; + + /** + * Helper function to parse the ranges of the protocols + * @param value the range we want to parse + */ + consensusParser.parse_range_once = function (value) { + value = value.split(','); + let subvalues = []; + + for (let subvalue of value) { + if (subvalue.includes('-')) { + let lowHigh = subvalue.split('-'); + let low = Number(lowHigh[0]); + let high = Number(lowHigh[1]); + + if (low === high - 1) { + subvalues.push([low, high]); + } else { + subvalues.push([[low, high]]); + } + } else { + subvalues.push([Number(subvalue)]); + } + } + return subvalues + }; + /** + * Parse the flags + * @throws NotValidFlagException if one of the flags is not valid + */ + consensusParser.tryParseFlags = function () { + let flags = consensusParser.words.splice(1, consensusParser.words.length); + + for (let f of flags) { + if (!consensusParser.validFlags.includes(f)) throw `NotValidFlagException: ${f} is not a valid flag` + } + + return flags + }; + + /** + * Parse signature + * @throws WrongFormatException if the line does not start with ----BEGIN + */ + consensusParser.parseSignature = function () { + if (consensusParser.words[0] !== '-----BEGIN') throw `WrongFormatException` + consensusParser.nextLine(); + let signature = ''; + while (consensusParser.lines[consensusParser.index] !== "-----END SIGNATURE-----") { + signature += consensusParser.lines[consensusParser.index]; + consensusParser.nextLine(); + } + return signature + }; + + + /** + * parase parameters + */ + consensusParser.tryParseParams = function () { + let content = {}; + for (let param of consensusParser.words.splice(1, consensusParser.words.length)) { + let tmp = param.split('='); + content[tmp[0]] = Number(tmp[1]); + } + return content + }; + + /** + * Check if the string in date has the format YYYY-MM-DD + * @param {string} time String representing the date + */ + consensusParser.isValidDate = function (date) { + if (typeof date !== 'string') return false + let regex = /^\d{4}[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$/; + return regex.test(date) + }; + + /**Check if the string time has the format HH:MM:SS + * @param {string} time String representing the time + */ + consensusParser.isValidTime = function (time) { + if (typeof time !== 'string') return false + let regex = /^(0[0-9]|1[0-9]|2[0-3])[:][0-5][0-9][:][0-5][0-9]$/; + return regex.test(time) + }; + + /** + * Check if the IP address is valid (either IPv4 or IPv6) + * @param {string} IP the address we want to check + */ + consensusParser.isValidIP = function (IP) { + let regex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/; + return regex.test(IP) + }; + + /** + * Check if the IP is an IPv4 address + * @param {string} IP + */ + consensusParser.isIPv4 = function (IP) { + let regex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; + return regex.test(IP) + }; + + /** + * Check if the given port is valid + * @param {number} port + */ + consensusParser.isValidPort = function (port) { + if (isNaN(port)) return false + //TODO: < or <= ? + return port >= 0 && port <= 65535 + }; + + /** + * Check if the given string is in hexadecimal + * @param {string} str + */ + consensusParser.isHex = function (str) { + let regex = /^[a-fA-F0-9]+$/; + return regex.test(str) + }; + + /** + * Check if the given string is in base 64 + * @param {string} str + */ + consensusParser.isBase64 = function (str) { + let regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; + return regex.test(str) + }; + + /** + * Updates consensusParser.index and consensusParser.words + * @throws EndOfFileException if the end of the file has already been reached + */ + consensusParser.nextLine = function () { + if (consensusParser.index >= consensusParser.totalLines) throw `EndOfFileException: there are no lines to parse` + consensusParser.words = consensusParser.lines[++consensusParser.index].split(" "); + }; + + /** + * Checks if words has the expected size and that words[0] is equal to word + * @param {number} expectedLength the expected length of words + * @param {string} expectedWord the expected word[0] + */ + consensusParser.checkFormat = function (expectedLength, expectedWord) { + if (consensusParser.words.length != expectedLength) throw `WrongFormatException: ${expectedLength} fields are expected` + if (consensusParser.words[0] != expectedWord) throw `NotEqualException:b ${expectedWord} is not equal to ${consensusParser.words[0]}` + }; + + /** + * @module parser + */ + + let parser = {}; + + parser.descriptors = { + line_count: 0, + total_lines: -1, + lines: undefined, + valid_bridge_distribution: ["none", "any", "https", "email", "moat", "hyphae"], + + exactly_once: ["router", "bandwidth", "published", "onion-key", "signing-key", "router-signatures"], + exactly_once_mic: ["onion-key", "policy", "ipv6-policy"], + + parse: function (raw_descriptors, flavor = 'microdesc') { + if (flavor != 'unflavored' && flavor != 'microdesc') { + throw 'Error: Unexpected flavor' + } + + let descriptors = []; + parser.descriptors.lines = raw_descriptors.split('\n'); + parser.descriptors.line_count = 0; + parser.descriptors.total_lines = parser.descriptors.lines.length; + parser.descriptors.flavor = flavor; + + while (parser.descriptors.line_count < parser.descriptors.total_lines) { + if (parser.descriptors.lines[parser.descriptors.line_count] === "") { + parser.descriptors.line_count++; + continue + } + + let descriptor = parser.descriptors.consume_one_node(); + descriptor['flavor'] = flavor; + descriptors.push(descriptor); + } + return descriptors + }, + validate: function (descriptors, consensus, flavor = 'microdesc', fail_on_missing = false) { + let digest_name = (flavor == 'unflavored') ? 'digest' : 'micro-digest'; + let digests = []; + for (let idx = 0; idx < consensus['routers'].length; idx++) { + let router = consensus['routers'][idx]; + digests.push(router[digest_name]); + } + + let obtained = []; + for (let idx = 0; idx < descriptors.length; idx++) { + obtained.push(descriptors[idx][digest_name]); + } + + let invalid = []; + console.log(obtained.length); + for (let idx = 0; idx < digests.length; idx++) { + let digest = digests[idx]; + if (obtained.includes(digest)) { + obtained.splice(obtained.indexOf(digest), 1); + } + else + invalid.push(digest); + } + console.log(obtained.length); + + if (obtained.length) { + throw `Invalid descriptors found` + } + + if (fail_on_missing && invalid.length > 0) + throw `Failed to obtain some descriptors` + } + }; + parser.descriptors.consume_one_node = function () { + + if (parser.descriptors.lines[parser.descriptors.line_count].startsWith('@type')) parser.descriptors.line_count++; + if (parser.descriptors.lines[parser.descriptors.line_count] === "") { + parser.descriptors.line_count++; + } + + let descriptor = {}; + let startLine = parser.descriptors.line_count; + + if (parser.descriptors.flavor == 'unflavored') { + descriptor = parser.descriptors.consume_router(descriptor); + descriptor = parser.descriptors.try_consume_identity_ed25519(descriptor); + } else { + descriptor = parser.descriptors.consume_onion_key(descriptor); + } + + let line = parser.descriptors.lines[parser.descriptors.line_count]; + + + while (true) { + if (parser.descriptors.flavor == 'unflavored') { + if (line.startsWith("router-signature")) + break + } else { + if (parser.descriptors.line_count == parser.descriptors.total_lines + || line.startsWith('@type') || line.startsWith('onion-key')) + break + } + + + let index_sp = line.indexOf(" "); + let first_word = (index_sp === -1) ? line : line.substring(0, index_sp); + switch (first_word) { + case "master-key-ed25519": + descriptor = parser.descriptors.consume_master_key_ed25519(descriptor); + break + case "platform": + descriptor = parser.descriptors.consume_platform(descriptor); + break + case "published": + descriptor = parser.descriptors.consume_published(descriptor); + break + case "bandwidth": + descriptor = parser.descriptors.consume_bandwidth(descriptor); + break + case "fingerprint": + descriptor = parser.descriptors.consume_fingerprint(descriptor); + break + case "hibernating": + descriptor = parser.descriptors.consume_hibernating(descriptor); + break + case "uptime": + descriptor = parser.descriptors.consume_uptime(descriptor); + break + case "extra-info-digest": + descriptor = parser.descriptors.consume_extra_info_digest(descriptor); + break + case "caches-extra-info": + descriptor = parser.descriptors.consume_single_word_line("caches-extra-info", descriptor); + break + case "onion-key": + descriptor = parser.descriptors.consume_onion_key(descriptor); + break + case "onion-key-crosscert": + descriptor = parser.descriptors.consume_onion_key_crosscert(descriptor); + break + case "ntor-onion-key": + descriptor = parser.descriptors.consume_base64_digest('ntor-onion-key', descriptor); + break + case "ntor-onion-key-crosscert": + descriptor = parser.descriptors.consume_ntor_onion_key_crosscert(descriptor); + break + case "accept": + descriptor = parser.descriptors.consume_exit_policy("accept", descriptor); + break + case "reject": + descriptor = parser.descriptors.consume_exit_policy("reject", descriptor); + break + case "signing-key": + descriptor = parser.descriptors.consume_signing_key(descriptor); + break + case "ipv6-policy": + descriptor = parser.consume_exit_policy('ipv6-policy', parser.descriptors.lines, parser.descriptors.line_count++, descriptor); + break + case "router-sig-ed25519": + descriptor = parser.descriptors.consume_router_sig_ed25519(descriptor); + break + case "contact": + descriptor = parser.consume_contact(parser.descriptors.lines, parser.descriptors.line_count++, descriptor); + break + case "bridge-distribution": + descriptor = parser.descriptors.consume_bridge_distribution(descriptor); + break + case "family": + descriptor = parser.descriptors.consume_family(descriptor); + break + case "read-history": + descriptor = parser.descriptors.consume_history("read", descriptor); + break + case "write-history": + descriptor = parser.descriptors.consume_history("write", descriptor); + break + case "eventdns": + descriptor = parser.descriptors.consume_eventdns(descriptor); + break + case "hidden-service-dir": + descriptor = parser.descriptors.consume_single_word_line("hidden-service-dir", descriptor); + break + case "allow-single-hop-exits": + descriptor = parser.descriptors.consume_single_word_line("allow-single-hop-exits", descriptor); + break + case "tunnelled-dir-server": + descriptor = parser.descriptors.consume_single_word_line("tunnelled-dir-server", descriptor); + break + case "proto": + descriptor = parser.consume_proto("proto", parser.descriptors.lines, parser.descriptors.line_count++, descriptor); + break + case "p": + descriptor = parser.consume_exit_policy('p', parser.descriptors.lines, parser.descriptors.line_count++, descriptor); + break + case "p6": + descriptor = parser.consume_exit_policy('p6', parser.descriptors.lines, parser.descriptors.line_count++, descriptor); + break + case "id": + descriptor = parser.descriptors.consume_id(descriptor); + break + default: + ++parser.descriptors.line_count; + break + } + line = parser.descriptors.lines[parser.descriptors.line_count]; + + } + + + if (descriptor['ipv6-policy'] === undefined) descriptor['ipv6-policy'] = { + "type": "reject", + "PortList": [[1, 65535]] + }; + if (descriptor['policy'] === undefined) { + descriptor['policy'] = { + "type": "reject", + "PortList": [[1, 65535]] + }; + } + + + let fields = parser.descriptors.exactly_once_mic; + let endLine = parser.descriptors.line_count; //include till router-signature + + if (parser.descriptors.flavor == 'unflavored') { + endLine += 1; //include till router-signature + descriptor = parser.descriptors.consume_router_signature(descriptor); + fields = parser.descriptors.exactly_once; + } + if (!parser.descriptors.check_exactly_once(descriptor, fields)) throw "Invalid descriptor: some mandatory fields are not present" + + let fullDesc = ""; + for (let i = startLine; i < endLine; i++) { + if (parser.descriptors.lines[i] == "") + continue + fullDesc += (parser.descriptors.lines[i] + '\n'); + } + + if (parser.descriptors.flavor == 'unflavored') { + let digest = sjcl.hash.sha1.hash(fullDesc); + digest = enc.base64(dec.bits(digest)); + + + while (digest.length > 0 && digest[digest.length - 1] == '=') + digest = digest.slice(0, -1); + descriptor['digest'] = digest; + } + else { + let mdigest = sjcl.hash.sha256.hash(fullDesc); + mdigest = dec.bits(mdigest); + mdigest = enc.base64(mdigest); + + while (mdigest.length > 0 && mdigest[mdigest.length - 1] == '=') + mdigest = mdigest.slice(0, -1); + descriptor['micro-digest'] = mdigest; + } + return descriptor + }; + + /** + * Checks that all mandatory fields of the descriptor were parsed + */ + parser.descriptors.check_exactly_once = function (descriptor, fields) { + + if (descriptor['ipv6-policy'] === undefined) ; + + let parsed = true; + if (descriptor['identity-ed25519'] !== undefined) { + parsed = descriptor["ntor-onion-key-crosscert"] !== undefined && descriptor["onion-key-crosscert"] !== undefined && descriptor["router-sig-ed25519"] !== undefined; + } else { + parsed = descriptor["router-sig-ed25519"] === undefined; + } + + return parsed && fields.every(field => descriptor[field] !== undefined) + }; + + /** + * Consume the field router of the descriptor + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_router = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); + parser.check_format(6, 'router', words); + + if (!parser.is_valid_nickname(words[1])) throw `Invalid nickname: ${words[1]} contains non-alphanumeric characters` + if (!parser.is_valid_ipv4(words[2])) throw `Invalid address: ${words[2]} is not a valid iPv4 address` + if (!parser.is_valid_port(words[3])) throw `Invalid port: ${words[3]} is not a valid port (0 to 65535)` + if (!parser.is_valid_port(words[4])) throw `Invalid port: ${words[4]} is not a valid port (0 to 65535)` + if (!parser.is_valid_port(words[5])) throw `Invalid port: ${words[5]} is not a valid port (0 to 65535)` + + descriptor['router'] = { + "nickname": words[1], + "address": words[2], + "orport": Number(words[3]), + "socksport": Number(words[4]), + "dirport": Number(words[5]) + }; + + ++parser.descriptors.line_count; + + return descriptor + }; + /** + * Consume try to consume the identity ed25519 certificate and its master key + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.try_consume_identity_ed25519 = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); + if (words[0] === 'identity-ed25519') { + parser.check_format(1, 'identity-ed25519', words); + ++parser.descriptors.line_count; + + let [offset, certificate] = parser.consume_pem(parser.descriptors.lines, parser.descriptors.line_count); + parser.descriptors.line_count += offset + 1; + descriptor['identity'] = { + "type": "ed25519", + "cert": certificate + }; + + return descriptor + } + + return descriptor + }; + + parser.descriptors.consume_id = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); + + parser.check_format(3, 'id', words); + let type = words[1]; + + if (type != 'rsa1024' && type != 'ed25519') + throw `Unexpected identity type ${type}` + + parser.check_reused('identity', descriptor); + if (!parser.is_valid_base64(parser.add_ending(words[2]))) + throw `Invalid master key: the master key ${words[2]} must be in base64` + + descriptor['identity'] = { + "type": type, + "master-key": words[2] + }; + + ++parser.descriptors.line_count; + return descriptor + }; + + /** + * Parse the master-key-ed25519 + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_master_key_ed25519 = function (descriptor) { + + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); + parser.check_format(2, 'master-key-ed25519', words); + parser.check_reused('master-key-ed25519', descriptor); + let key = words[1]; + if (!parser.is_valid_base64(parser.add_ending(key))) throw `Invalid master key: the master key ${words[1]} must be in base64` + descriptor['identity']['master-key'] = key; + parser.descriptors.line_count++; + + return descriptor + }; + + /** + * Consume the line if it starts with platform + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_platform = function (descriptor) { + parser.check_reused("platform", descriptor); + let line = parser.descriptors.lines[parser.descriptors.line_count]; + let platform = line.substring("platform".length + 1); + descriptor['platform'] = platform; + parser.descriptors.line_count++; + return descriptor + }; + + /** + * Consume the time of the published field + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_published = function (descriptor) { + parser.check_reused('published', descriptor); + descriptor['published'] = parser.consume_date('published', parser.descriptors.lines[parser.descriptors.line_count]); + ++parser.descriptors.line_count; + return descriptor + }; + + /** + * Consume the bandwidth fields + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_bandwidth = function (descriptor) { + parser.check_reused('bandwidth', descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(4, 'bandwidth', words); + + let avg = Number(words[1]); + let burst = Number(words[2]); + let obs = Number(words[3]); + + if (avg < 0 || burst < 0 || obs < 0) throw `Invalid bandwidth: must be non-negative` + + descriptor['bandwidth'] = { + "avg": avg, + "burst": burst, + "observed": obs + }; + + return descriptor + }; + + /** + * Consume the fingerprint field + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_fingerprint = function (descriptor) { + parser.check_reused('fingerprint', descriptor); + let line = parser.descriptors.lines[parser.descriptors.line_count++]; + let index_sp = line.indexOf(" "); + let fingerprint = line.substring(index_sp + 1); + + let bytes = fingerprint.split(" "); + let join_bytes = bytes.join(""); + if (bytes.length != 10) throw `Invalid fingerprint: wrong size` + if (!parser.is_valid_hex(join_bytes)) throw `Invalid fingerprint: not a hex string` + + let identity = sjcl.codec.hex.toBits(join_bytes); + identity = sjcl.codec.base64.fromBits(identity).replace("=", ""); + + descriptor['fingerprint'] = fingerprint; + descriptor['router']['identity'] = identity; + + return descriptor + }; + + /** + * Consume the hibernating field + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_hibernating = function (descriptor) { + parser.check_reused('hibernating', descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(2, 'hibernating', words); + + let b = Number(words[1]); + if (b !== 0 && b !== 1) throw `Invalid boolean` + descriptor['hibernating'] = b; + return descriptor + }; + + /** + * Consume the uptime field + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_uptime = function (descriptor) { + parser.check_reused('uptime', descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(2, 'uptime', words); + + let uptime = Number(words[1]); + + if (uptime < 0) throw `Invalid uptime: uptime must be non-negative` + + descriptor['uptime'] = uptime; + + return descriptor + }; + + /** + * Consume the onion key + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_onion_key = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(" "); + parser.check_reused('onion-key', descriptor); + parser.check_format(1, 'onion-key', words); + return parser.descriptors.consume_key('onion-key', descriptor) + }; + + /** + * Consume the extra info digest + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_extra_info_digest = function (descriptor) { + parser.check_reused('extra-info-digest', descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + if (words.length != 2 && words.length != 3) throw `Invalid format: 1 or 2 fields are expected` + + let sha1 = words[1]; + if (!parser.is_valid_hex(sha1)) throw `Invalid encoding: the sha1 digest must be in hexadecimal` + descriptor["extra-info-digest"] = { + "sha1": sha1 + }; + + if (words.length === 3) { + let sha256 = words[2]; + if (!parser.is_valid_base64(parser.add_ending(sha256))) throw `Invalid encoding: the sha256 digest must base 64` + descriptor['extra-info-digest']['sha256'] = sha256; + } + + return descriptor + }; + + /** + * Consume the single word line + * @param {string} type the field + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_single_word_line = function (type, descriptor) { + parser.check_reused(type, descriptor); + descriptor[type] = 'true'; + ++parser.descriptors.line_count; + + return descriptor + }; + + /** + * Consume the RSA signature generated using the onion-key + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_onion_key_crosscert = function (descriptor) { + parser.check_reused('onion-key-crosscert', descriptor); + return parser.descriptors.consume_key('onion-key-crosscert', descriptor) + }; + + /** + * Consume the ntor onion key of the descriptor + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_ntor_onion_key_crosscert = function (descriptor) { + + parser.check_reused('ntor-onion-key-crosscert', descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count].split(" "); + parser.check_format(2, 'ntor-onion-key-crosscert', words); + + let bit = Number(words[1]); + if (bit != 0 && bit != 1) throw "Invalid bit for ntor-onion-key-crosscert" + + let [offset, cert] = parser.consume_pem(parser.descriptors.lines, ++parser.descriptors.line_count); + parser.descriptors.line_count += offset + 1; + + descriptor['ntor-onion-key-crosscert'] = { + "bit": bit, + "cert": cert + }; + + return descriptor + + }; + + /** + * Consume the ED25519 signature + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_router_sig_ed25519 = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(2, "router-sig-ed25519", words); + parser.check_reused("router-signatures", descriptor); + + let signature = words[1]; + + if (!parser.is_valid_base64(parser.add_ending(signature))) throw "Invalid digest: must be a base 64 string" + + descriptor["router-signatures"] = { + "ed25519": signature, + }; + + return descriptor + }; + + /** + * Consume the PKCS1 padded signature of the descriptor + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_router_signature = function (descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); + if (words[0] === 'router-signature') { + parser.check_format(1, 'router-signature', words); + ++parser.descriptors.line_count; + + let [offset, signature] = parser.consume_pem(parser.descriptors.lines, parser.descriptors.line_count); + parser.descriptors.line_count += offset + 1; + + if (descriptor["router-signatures"] === undefined) { + descriptor["router-signatures"] = {}; + } + + descriptor["router-signatures"]["rsa"] = signature; + + return descriptor + } + }; + + /** + * Consume the field bridge-distribution + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_bridge_distribution = function (descriptor) { + parser.check_reused('bridge-distribution', descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(2, 'bridge-distribution', words); + let dist = words[1]; + if (!parser.descriptors.valid_bridge_distribution.includes(dist)) dist = "none"; + + descriptor['bridge-distribution'] = dist; + + return descriptor + + }; + + /** + * Consume the field family + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_family = function (descriptor) { + parser.check_reused("family", descriptor); + + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + let family = words.splice(1); + + descriptor['family'] = family; + + return descriptor + }; + /** + * Consume the history fields + * @param {string} type the type of history + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_history = function (type, descriptor) { + let field = type + "-history"; + parser.check_reused(field, descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(6, type + "-history", words); + + let date = words[1]; + if (!parser.is_valid_date(date)) throw "Invalid date" + + let time = words[2]; + if (!parser.is_valid_time(time)) throw "Invalid time" + + let interval = Number(words[3].substring(1)); + let bytes = words[5].split(",").map(x => Number(x)); + + descriptor[field] = { + "date": date, + "time": time, + "interval": interval, + "bytes": bytes + }; + + return descriptor + }; + + /** + * Consume the field eventdns + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_eventdns = function (descriptor) { + parser.check_reused("eventdns", descriptor); + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(2, "eventdns", words); + + let bool = Number(words[1]); + + if (bool != 0 && bool != 1) throw "Invalid boolean" + + decriptor["eventdns"] = bool; + return descriptor + }; + + /** + * Consume field with a base 64 digest + * @param {String} field the field we want to parse + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_base64_digest = function (field, descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(2, field, words); + parser.check_reused(field, descriptor); + + let key = words[1]; + + if (!parser.is_valid_base64(parser.add_ending(key))) throw "Invalid digest: must be a base 64 string" + + descriptor[field] = key; + + return descriptor + }; + + /** + * Consume the signing keys + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_signing_key = function (descriptor) { + parser.check_reused('signing-key', descriptor); + return parser.descriptors.consume_key('signing-key', descriptor) + }; + + /** + * Parse the accept and reject exit policies and their exitpattern + * @param {string} type either reject or accept + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_exit_policy = function (type, descriptor) { + let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); + parser.check_format(2, type, words); + + if (descriptor['policy'] === undefined) { + descriptor['policy'] = { + "type": "exitpattern", + "rules": [] + }; + } + + let rule = { + "type": type, + "pattern": words[1] + }; + + descriptor['policy']["rules"].push(rule); + + return descriptor + }; + + /** + * Consume the key of the given field and update the descriptor + * @param {string} field the field of the descriptor + * @param {object} descriptor the currently being built decriptors object + * @returns {Object} the updated descriptor + */ + parser.descriptors.consume_key = function (field, descriptor) { + let [offset, key] = parser.consume_pem(parser.descriptors.lines, ++parser.descriptors.line_count); + parser.descriptors.line_count += offset + 1; + descriptor[field] = key; + return descriptor + }; + + /** + * Checks if words has the expected size and that the first word of the line is equal to a given word + * @param {number} expected_length the expected length of the line + * @param {string} expected_word the expected word + * @param {Array} words the line splitted into words + */ + parser.check_format = function (expected_length, expected_word, words) { + if (words.length != expected_length) { + throw `wrong_format_exception: ${expected_length} fields are expected` + } else if (words[0] !== expected_word) { + throw `not_equal_exception: ${expected_word} is not equal to ${words[0]}` + } + }; + + /** + * Check if the IP is an IPv4 address + * @param {string} IP + */ + parser.is_valid_ipv4 = function (IP) { + let regex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; + return regex.test(IP) + }; + + /** + * Check if the given port is valid + * @param {number} port + */ + parser.is_valid_port = function (port) { + if (isNaN(port)) return false + return port >= 0 && port <= 65535 + }; + + /** + * Check if the given nickname is valid + * @param {string} nickname the nickname we want to verify + * @returns {boolean} the validity of the nickname + */ + parser.is_valid_nickname = function (nickname) { + let regex = /^[a-z0-9]+$/i; + return regex.test(nickname) + }; + + /** + * Check if the given string is in base 64 + * @param {string} str + */ + parser.is_valid_base64 = function (str) { + let regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; + return regex.test(str) + }; + /** + * Check if the given string is in hexadecimal + * @param {string} str + */ + parser.is_valid_hex = function (str) { + let regex = /^[a-fA-F0-9]+$/; + return regex.test(str) + }; + + /** + * Consume a PEM format field + * @param {Array} lines the splitted textfield + * @param {Number} start where the pem starts + * @param {function} base_function optional function to verifiy the base + * @returns {Array} tuple containing the parsed pem and the offset + */ + parser.consume_pem = function (lines, start) { + let offset = 0; + let content = ''; + if (!lines[start].startsWith('-----BEGIN')) throw `Invalid signature, certificate or key: must begin with "-----BEGIN"` + offset++; + while (!lines[start + offset].startsWith("-----END")) { + content += lines[start + offset]; + offset++; + } + + if (!parser.is_valid_base64(content)) throw "Invalid PEM: must be in base 64" + + return [offset, content] + }; + + /** + * Parse ranges + * @param {string} ranges format: Keyword=Values... + * @returns {object} the parsed ranges + */ + parser.parse_range = function (ranges) { + let content = {}; + for (let pair of ranges) { + if (pair.includes("=")) { + let tmp = pair.split("="); + content[tmp[0]] = parser.parse_range_once(tmp[1]); + } + } + return content + }; + + /** + * This function parses ranges with the format nbr,nbr,.. where nbr is either an integer or 2 integers separated by a comma + * @param {string} value the sting we want to parse + * @returns {Array} a list containing the ranges + */ + parser.parse_range_once = function (value) { + value = value.split(','); + let subvalues = []; + + for (let subvalue of value) { + if (subvalue.includes('-')) { + let lowHigh = subvalue.split('-'); + let low = Number(lowHigh[0]); + let high = Number(lowHigh[1]); + + subvalues.push([low, high]); + } else { + subvalues.push([Number(subvalue)]); + } + } + return subvalues + }; + + /** + * This function parses the exit policies formatted as: field (accept/reject) PortList + * @param {string} field the field we want to parse + * @param {Array} lines the raw file split by '\n' + * @param {Number} index the index of the line + * @param {object} node the node we want to update + * @returns the updated node + */ + parser.consume_exit_policy = function (field, lines, index, node) { + parser.check_reused(field, node); + let words = lines[index].split(" "); + parser.check_format(3, field, words); + + let policy = words[1]; + if (policy !== 'accept' && policy !== 'reject') throw "Invalid policy: policy must either be accept or reject" + + let ranges = parser.parse_range_once(words[2]); + + if (field == 'p') field = 'policy'; + if (field == 'p6') field = 'ipv6-policy'; + + node[field] = { + 'type': policy, + 'PortList': ranges + }; + + return node + }; + + /** + * This function parses the contacts + * @param {string} field the field we want to parse + * @param {Array} lines the raw file split by '\n' + * @param {Number} index the index of the line + * @param {object} node the node we want to update + * @returns the updated node + */ + parser.consume_contact = function (lines, index, node) { + parser.check_reused("contact", node); + let contact = lines[index].substring("contact".length + 1); + node["contact"] = contact; + + return node + }; + + + /** + * Check if the string in date has the format YYYY-MM-DD + * @param {string} time String representing the date + */ + parser.is_valid_date = function (date) { + if (typeof date !== 'string') return false + let regex = /^\d{4}[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$/; + return regex.test(date) + }; + + /**Check if the string time has the format HH:MM:SS + * @param {string} time String representing the time + */ + parser.is_valid_time = function (time) { + if (typeof time !== 'string') return false + let regex = /^(0[0-9]|1[0-9]|2[0-3])[:][0-5][0-9][:][0-5][0-9]$/; + return regex.test(time) + }; + + /** + * Consume the line containing a date with the format field YYYY-MM-DD HH:MM:SS + * @param {string} field the field we are consuming + * @param {string} line the line we are consuming + * @returns {object} object containing both the date and the time + */ + parser.consume_date = function (field, line) { + let words = line.split(" "); + parser.check_format(3, field, words); + + if (!parser.is_valid_date(words[1])) throw `Invalid date: ${words[1]} is not a valid date` + if (!parser.is_valid_time(words[2])) throw `Invalid time: ${words[2]} is not a valid time` + + return { + "date": words[1], + "time": words[2] + } + }; + + /** + * Consume the lines of protocols composed by ranges + * @param {string} type either protocols or proto + * @param {Array} lines the raw file split by '\n' + * @param {Number} index the index of the line + * @param {object} node the node we want to update + * @returns the updated node + */ + parser.consume_proto = function (type, lines, index, node) { + parser.check_reused(type, node); + let ranges = lines[index].split(" ").splice(1); + node[type] = parser.parse_range(ranges); + return node + }; + + /** + * Check if the field has already been parsed for the descriptor + * @param {string} field the field we want to verify + * @param {object} node the node for which we don't want a repetition of field + */ + parser.check_reused = function (field, node) { + if (node[field] !== undefined) throw `The field ${field} appears more than once` + }; + + /** + * Add the ending = for a base64 string + * @param {string} str the string we want to modify + * @returns {string} base 64 string with correct ending = + */ + parser.add_ending = function (str) { + if (str.length % 4 !== 0) { + let rem = str.length % 4; + for (let i = 0; i < 4 - rem; i++) str += '='; + } + return str + }; + + /** + * @module path + */ + + let path = {}; + + /** + * This function selects a path from the parsed consensus and parsed descriptors + * Flavor is 'unflavored' + * + * @param {Object} consensus a parsed consensus + * @param {Object} descriptors parsed descriptors of the routers in the consensus + * @param {Bool} isChutney boolean used to indicate if the path selection is done with routers from chutney + */ + path.select = function (consensus, descriptors, isChutney) { + if (isChutney === undefined) { + path["isChutney"] = false; + } else { + path["isChutney"] = isChutney; + } + + //build a hashmap of descriptor where the keys are the identity + path["descriptorsMap"] = {}; + + for (let descriptor of descriptors) { + let identity = descriptor['router'].identity; + path.descriptorsMap[identity] = descriptor; + } + + //pre-process consensus by filering the routers that do not obey + //the minimal constraints + path["consensus"] = consensus['routers'].filter(r => path.obeyMinimalConstraints(r)); + + //path selection + path["exit"] = path.chooseGoodExit(consensus); + path["guard"] = path.chooseGoodGuard(consensus); + path["middle"] = path.chooseGoodMiddle(consensus); + + //TODO: it should create/return a new path and not the descriptors + return [path.guard, path.middle, path.exit] + }; + + //assumes microdesc flavor. + path.select_end_path = function (consensus, descriptors, guard, isChutney, tcp_ports) { + if (isChutney === undefined) { + path["isChutney"] = false; + } else { + path["isChutney"] = isChutney; + } + + //build a hashmap of descriptor where the keys are the identity + let consMap = {}; + for (let router of consensus['routers']) { + consMap[router['micro-digest']] = router; + } + + path["descriptorsMap"] = {}; + + for (let descriptor of descriptors) { + descriptor['router'] = consMap[descriptor['micro-digest']]; + descriptor['bandwidth'] = {}; + descriptor['bandwidth']['avg'] = descriptor['router']['w']['Bandwidth']; + + let identity = descriptor['router'].identity; + path.descriptorsMap[identity] = descriptor; + } + + //pre-process consensus by filering the routers that do not obey + //the minimal constraints + console.log(consensus['routers'].length); + console.log(descriptors.length); + path["consensus"] = consensus['routers'].filter(r => path.obeyMinimalConstraints(r)); + console.log(path["consensus"].length); + + //path selection + path["guard"] = guard; + path["exit"] = path.chooseGoodExitGivenGuard(tcp_ports); + path["middle"] = path.chooseGoodMiddle(); + + //TODO: it should create/return a new path and not the descriptors + return [path.middle, path.exit] + }; + + /** + * This function checks if the given router obeys the minimal constraints needed for a router to be selected + * + * @param {Object} router the router subpart of one of the nodes of the parsed consensus + */ + path.obeyMinimalConstraints = function (router) { + let des = path.descriptorsMap[router['identity']]; + let flags = router['flags']; + + if (des === undefined) return false + if (!flags.includes("Valid")) return false + if (!flags.includes("Running")) return false + if (!router['version'].startsWith("Tor 0.3.")) return false + + if (des['identity']['type'] !== 'ed25519') return false + + return true + }; + + /** + * This function takes candidates and choose one at random weighted by its bandwidth average + * + * @param {Array} candidates the list of candidates + */ + + path.weightedRandomChoice = function (candidates) { + let total = 0; + + for (let candidate of candidates) { + let des = path.descriptorsMap[candidate['identity']]; + if (des !== undefined) { + total += des['bandwidth']['avg']; + } + } + + let r = Math.random() * total; + let upto = 0; + + for (let router of candidates) { + let des = path.descriptorsMap[router['identity']]; + + if (des !== undefined) { + let bandwidth = des['bandwidth']['avg']; + + if (upto + bandwidth >= r) return des + else upto += bandwidth; + } + + } + + throw "No candidate has been chosen" + }; + + /** + * This function checks if 2 routers are part of the same 16-subnet + * + * @param {Object} des1 the descriptor of the first router + * @param {Object} des2 the descriptor of the second router + * + */ + path.inSame16Subnet = function (des1, des2) { + + if (path.isChutney) { + return false + } + + let addr1 = des1['router']['address'].split("."); + let addr2 = des2['router']['address'].split("."); + + return addr1[0] === addr2[0] && addr1[1] === addr2[1] + }; + + /** + * This function checks if 2 routers are part of the same family + * + * @param {Object} des1 the descriptor of the first router + * @param {Object} des2 the descriptor of the second router + */ + path.inSameFamily = function (des1, des2) { + if (des1['family'] != undefined && des2['family'] != undefined) { + for (let fam of des1['family']) { + if (des2['family'].includes(fam)) return true + } + } + + return false + }; + + /** + * This function choose a good exit given the TOR path selection rules + */ + path.chooseGoodExit = function () { + let candidates = path.consensus.filter(path.isGoodExit); + return path.weightedRandomChoice(candidates) + }; + + path.chooseGoodExitGivenGuard = function (tcp_ports) { + let candidates = path.consensus.filter(r => path.isGoodExitGivenGuard(r, tcp_ports)); + console.log("Exit candidates: " + candidates.length); + return path.weightedRandomChoice(candidates) + }; + + /** + * This function checks if the given router is a suitable candidate to become an exit + * + * @param {Object} router the router subpart of one of the nodes of the parsed consensus + */ + path.isGoodExit = function (router) { + let flags = router['flags']; + if (!flags.includes('Exit') || flags.includes('BadExit')) return false + + if (router['exit-policy'] === undefined) + router['exit-policy'] = path.descriptorsMap[router.identity]['policy']; + if (router['exit-policy']['type'] !== 'accept') return false + + return true + + }; + + path.isGoodExitGivenGuard = function (router, tcp_ports) { + let flags = router['flags']; + if (!flags.includes('Exit') || flags.includes('BadExit')) return false + let des = path.descriptorsMap[router.identity]; + + + if (router['exit-policy'] === undefined) + router['exit-policy'] = des['policy']; + + let port_arr = router['exit-policy']['PortList']; + for (let i = 0; i < tcp_ports.length; i++) { + let found = false; + let cur_port = tcp_ports[i]; + + for (let j = 0; j < port_arr.length; j++) { + if (port_arr[j][0] == cur_port) { + found = true; + break + } + else if (port_arr[j].length == 2) { + if (port_arr[j][0] <= cur_port && cur_port <= port_arr[j][1]) { + found = true; + break + } + } + } + + if (router['exit-policy']['type'] == 'accept') { + if (!found) return false + } + else { + if (found) return false + } + } + + if (des === undefined) { + return false + } + + if (des["router"]["identity"] === path.guard["router"]["identity"]) { + return false + } + + if (path.inSame16Subnet(des, path.guard)) return false + if (path.inSameFamily(des, path.guard)) return false + + return true + }; + + /** + * This function choose a good guard given the TOR path selection rules. + * + * Note: this implements a lightweight version of the TOR path selection, where the selection based on the different + * sets is put aside + * + */ + path.chooseGoodGuard = function () { + let candidates = path.consensus.filter(r => path.isGoodGuard(r)); + return path.weightedRandomChoice(candidates) + }; + + /** + * This function checks if the given router is a suitable candidate to become a guard + * + * @param {Object} router the router subpart of one of the nodes of the parsed consensus + */ + path.isGoodGuard = function (router) { + let flags = router['flags']; + let des = path.descriptorsMap[router.identity]; + + if (des === undefined) { + return false + } + + if (des["router"]["identity"] === path.exit["router"]["identity"]) { + return false + } + + if (!flags.includes('Guard')) return false + if (!flags.includes('Stable')) return false + if (!flags.includes('V2Dir')) return false + if (path.inSame16Subnet(des, path.exit)) return false + if (path.inSameFamily(des, path.exit)) return false + + return true + }; + + /** + * This function choose a good middle given the TOR path selection rules + */ + path.chooseGoodMiddle = function () { + let candidates = path.consensus.filter(r => path.isGoodMiddle(r)); + return path.weightedRandomChoice(candidates) + }; + + /** + * This function checks if the given router is a suitable candidate to become a middle node + * + * @param {Object} router the router subpart of one of the nodes of the parsed consensus + */ + path.isGoodMiddle = function (router) { + let des = path.descriptorsMap[router.identity]; + + if (des === undefined) { + return false + } + + if (des["router"]["identity"] === path.exit["router"]["identity"] || des["router"]["identity"] === path.guard["router"]["identity"]) { + return false + } + + if (path.inSame16Subnet(des, path.guard)) return false + if (path.inSame16Subnet(des, path.exit)) return false + if (path.inSameFamily(des, path.guard)) return false + if (path.inSameFamily(des, path.exit)) return false + + return true + }; + + /** + * @module post + */ + + + + function create(endpoint, success, error) { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 201) { + var info = JSON.parse(rq.responseText); + if (endpoint.auth != null) { + info = ntor.auth(endpoint, info["auth"], info["data"]); + } + endpoint.id = info["id"]; + endpoint.url = endpoint.urls.channels + "/" + info["id"]; + endpoint.path = info["path"]; + + if (endpoint.fast) { + endpoint.guard = info["guard"]; + endpoint.material.identity = dec.base64( + info["guard"].router.identity + "="); + endpoint.material.onionkey = dec.base64( + info["guard"]["ntor-onion-key"]); + } + + var material = ntor.shake(endpoint, info["ntor"]); + if (material == null) + throw "Invalid guard handshake." + + material = ntor.slice(material); + endpoint.material = material; + + endpoint.forward = forward(endpoint); + endpoint.backward = backward(endpoint); + if (success !== undefined) + success(endpoint); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + + var payload = null; + if (endpoint.fast) + payload = ntor.fast(endpoint); + else + payload = ntor.hand(endpoint); + + payload = { ntor: payload }; + if (endpoint.auth != null) { + payload["auth"] = enc.base64(endpoint.auth.ntor.publicKey); + } + payload = JSON.stringify(payload); + + rq.open("POST", endpoint.urls.channels, true); + rq.setRequestHeader("Content-type", "application/json"); + rq.send(payload); + } + + + function circuit_info(endpoint, success, error, select_path, tcp_ports) { + if (select_path === undefined) { + select_path = false; + } + + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 201) { + var info = JSON.parse(rq.responseText); + if (endpoint.auth != null) { + info = ntor.auth(endpoint, info["auth"], info["data"]); + } + + endpoint.id = info["id"]; + endpoint.url = endpoint.urls.channels + "/" + info["id"]; + + + if (endpoint.fast) { + endpoint.guard = info["guard"]; + } + + if (!select_path) + endpoint.path = info["path"]; + else { + endpoint.consensus = consensusParser.parse(endpoint.consensus_raw); + endpoint.descriptors = parser.descriptors.parse(endpoint.descriptors_raw); + parser.descriptors.validate(endpoint.descriptors, endpoint.consensus); + + endpoint.path = path.select_end_path(endpoint.consensus, endpoint.descriptors, endpoint.guard, true, tcp_ports); + console.log(endpoint.guard); + console.log(endpoint.path); + } + + if (success !== undefined) + success(endpoint, info); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + + var payload = {}; + /** + if (endpoint.fast) + payload = ntor.fast(endpoint) + else + payload = ntor.hand(endpoint) + + payload = {ntor: payload}*/ + if (endpoint.auth != null) { + payload["auth"] = enc.base64(endpoint.auth.ntor.publicKey); + } + payload["select_path"] = select_path.toString(); + payload = JSON.stringify(payload); + + rq.open("POST", endpoint.urls.channels, true); + rq.setRequestHeader("Content-type", "application/json"); + rq.send(payload); + } + + function handshake(endpoint, info, success, error) { + //var handshake = info['handshake'] + var normal_handler = endpoint.io.handler; + + var handler = function (endpoint, material) { + endpoint.io.handler = normal_handler; + //var material = endpoint.io.recv() + + material = ntor.shake(endpoint, material.slice(7, 7 + 64), false); + + if (material == null) + throw "Invalid guard handshake." + + + material = ntor.slice(material); + endpoint.material = material; + + endpoint.forward = forward(endpoint); + endpoint.backward = backward(endpoint); + + if (success !== undefined) + success(endpoint); + }; + + endpoint.io.handler = handler; + + var handshake = new Uint8Array(relay.full_len); + var payload = ntor.hand(endpoint, endpoint.guard, false); + + + var view = new DataView(handshake.buffer); + view.setUint32(0, 2147483648 /* fake circuit_id */, false); + view.setUint8(4, 10 /* CREATE2 CELL */, false); + view.setUint16(5, 2 /* ntor handshake */, false); + view.setUint16(7, payload.length, false); + handshake.set(payload, 9); + + + endpoint.io.send(handshake); + } + + function channel(endpoint, success, error) { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 201) { + var cells = JSON.parse(rq.responseText)["cells"]; + if (cells === undefined) { + if (endpoint.io.error !== undefined) + endpoint.io.error(endpoint); + return + } + + var pending = endpoint.io.pending; + if (pending > 0 && endpoint.io.success !== undefined) + endpoint.io.success(endpoint); + + if (cells.length > 0) { + endpoint.io.incoming = endpoint.io.incoming.concat(cells); + if (endpoint.io.handler !== undefined) + endpoint.io.handler(endpoint); + } + + endpoint.io.outcoming = endpoint.io.outcoming.slice(pending); + endpoint.io.pending = 0; + + if (success !== undefined) + success(endpoint); + } + else if (rq.readyState == 4) { + if (endpoint.io.error !== undefined) + endpoint.io.error(endpoint); + + if (error !== undefined) + error(endpoint, rq.status); + } + }; + + endpoint.io.pending = endpoint.io.outcoming.length; + + rq.open("POST", endpoint.url, true); + rq.setRequestHeader("Content-type", "application/json"); + rq.send(JSON.stringify({ cells: endpoint.io.outcoming })); + } + + function extend(endpoint, descriptor, success, error) { + var hand = ntor.hand(endpoint, descriptor, false); + + var eidentity = descriptor["identity"]["master-key"]; // (assuming ed25519) + var identity = endpoint.material.identity; + var addr = descriptor["router"]["address"]; + var port = descriptor["router"]["orport"]; + + var data = relay.extend(hand, addr, port, identity, eidentity); + var cell = build(endpoint, "extend2", 0, data); + + var extend_error = error; + var extend_success = success; + var normal_handler = endpoint.io.handler; + + var handler = function (endpoint, data) { + endpoint.io.handler = normal_handler; + + var cell = peel(endpoint, data); + if (cell == null || cell.cmd != "extended2") { + if (extend_error !== undefined) + return extend_error(endpoint) + throw "Invalid answer, expecting extended2 cell, fatal!" + } + + var view = new DataView(cell.data.buffer); + var length = view.getUint16(0, false); + var data = cell.data.slice(2, 2 + length); + + var material = ntor.shake(endpoint, data, false); + material = ntor.slice(material); + endpoint.material = material; + + if (material == null && extend_error !== undefined) + return extend_error(endpoint) + + endpoint.forward = forward(endpoint); + endpoint.backward = backward(endpoint); + + if (extend_success !== undefined) + extend_success(endpoint); + }; + + endpoint.io.handler = handler; + endpoint.io.send(cell); + } + + + function close(endpoint, success, error) { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 202) { + if (success !== undefined) + success("Circuit closed"); + } + else if (rq.readyState == 4 && error !== undefined) { + error("Error in closing circuit"); + } + }; + + rq.open("DELETE", endpoint.url, true); + rq.send(); + } + + /** + * @module io + */ + + const polling = (endpoint, handler, success, error) => new Polling(endpoint, handler, success, error); + + class Polling { + constructor(endpoint, handler, success, error) { + this.incoming = []; + this.outcoming = []; + this.pending = 0; + this.handler = handler; + this.success = success; + this.error = error; + this.cell = null; + + this.endpoint = endpoint; + + endpoint.io = this; + } + + poll() { + setTimeout(function () { + channel(this.endpoint, this.poll); + }, 100); + } + + send(cell) { + this.outcoming.push(enc.base64(cell)); + } + + recv() { + if (this.incoming.length < 1) { return undefined; } + + this.cell = this.incoming.shift(); + return dec.base64(this.cell); + } + + start() { + channel(this.endpoint, this.poll); + } + } + + function socket(endpoint, handler, success, error) { + if (handler === undefined) + handler = function (endpoint) { }; + if (success === undefined) + success = function (endpoint) { }; + if (error === undefined) + error = function (endpoint) { }; + + var io = { + event: null, + socket: null, + closed: false, + incoming: [], + outcoming: [], + handler: handler, + success: success, + error: error, + cell: null, + cell_recv: 0, + //cell_sent: 0, + send: function (cell) { + io.outcoming.push(cell); + + //io.cell_sent += 1 + //var cell_repr = Array.from(cell.slice(0,20)).map(function(x) {return x.toString(16).padStart(2, '0')}).join('') + //console.log("cell ", io.cell_sent.toString(), " sent to wbskt ", cell_repr) + }, + recv: function () { + if (io.incoming.length < 1) + return undefined + + io.cell = io.incoming.shift(); + + io.cell_recv += 1; + var cell_repr = Array.from(io.cell.slice(0, 20)).map(function (x) { return x.toString(16).padStart(2, '0') }).join(''); + console.log("cell recv by wbskt ", cell_repr); + + return io.cell + }, + start: function () { } + }; + var socket = new WebSocket(endpoint.urls.socket + "/" + endpoint.id); + + socket.binaryType = "arraybuffer"; + socket.onopen = function (event) { + io.event = event; + io.success(endpoint); + + while (io.outcoming.length > 0) + io.socket.send(io.outcoming.shift()); + + io.send = function (cell) { + if (io.closed) + throw "Unable to send, connection closed." + io.socket.send(cell.buffer); + + //io.cell_sent += 1 + //var cell_repr = Array.from(cell.slice(0,20)).map(function(x) {return x.toString(16).padStart(2, '0')}).join('') + //console.log("cell ", io.cell_sent.toString(), " sent to wbskt ", cell_repr) + }; + }; + socket.onerror = function (event) { + io.event = event; + io.error(endpoint); + }; + socket.onmessage = function (event) { + io.event = event; + + var data = new Uint8Array(event.data); + + var cell_repr = Array.from(data.slice(0, 20)).map(function (x) { return x.toString(16).padStart(2, '0') }).join(''); + console.log("cell recv by wbskt ", cell_repr); + + // io.incoming.push(data) + io.cell = data; + io.handler(endpoint, data); + }; + socket.onclose = function (event) { + io.event = event; + io.closed = true; + io.error(endpoint); + }; + + endpoint.io = io; + endpoint.io.socket = socket; + return io + } + + /** + * GET operations. + * @module get + * @namespace + * @see lnn.get.guard + */ + + /** + * Perform GET /guard and update endpoint accordingly, + * see {@link endpoint_t#guard}. + * + * @param {endpoint_t} endpoint endpoint in use, stores answer + * @param {callback} success optional, called on success + * @param {callback} error optional, called on error + * @example + * // Note: lnn.open perform these steps for you whenever needed. + * endpoint = lnn.endpoint('localhost', 4990) + * lnn.get.guard(endpoint, function (endpoint) + * { + * console.log('Guard identity:', endpoint.guard.router.identity) + * }) + * // (can also have error callback: function (endpoint, xhttp_status) { }) + */ + function guard(endpoint, success, error) { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { + endpoint.guard = JSON.parse(rq.responseText); + if (success !== undefined) + success(endpoint); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + rq.open("GET", endpoint.urls.guard, true); + rq.send(); + } + + /** + * Perform GET /consensus and update endpoint accordingly, + * see {@link endpoint_t#consensus}. + * + *
      +	 * Note: provided for testing purposes and currently have no use.
      +	 * 
      + * + * Usage and parameters are similar to {@link lnn.get.guard}, stores the + * consensus as parsed from the proxy-server answer. + * + * @param {endpoint_t} endpoint endpoint in use, stores answer + * @param {callback} success optional, called on success + * @param {callback} error optional, called on error + * + * @see lnn.get.guard + */ + function consensus(endpoint, success, error) { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { + endpoint.consensus = JSON.parse(rq.responseText); + if (success !== undefined) + success(endpoint); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + rq.open("GET", endpoint.urls.consensus, true); + rq.send(); + } + + /** + * Perform GET /descriptors + */ + function descriptors(endpoint, success, error) { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { + endpoint.descriptors = JSON.parse(rq.responseText); + + if (success !== undefined) success(endpoint); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + + rq.open("GET", endpoint.urls.descriptors, true); + rq.send(); + } + + function consensus_raw(endpoint, success, error, flavor = 'microdesc') { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { + endpoint.consensus_raw = rq.responseText; + if (success !== undefined) + success(endpoint); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + rq.open("GET", endpoint.urls.consensus + "-raw/" + flavor, true); + rq.send(); + } + + /** + * Perform GET /descriptors + */ + function descriptors_raw(endpoint, success, error, flavor = 'microdesc') { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { + endpoint.descriptors_raw = rq.responseText; + + if (success !== undefined) success(endpoint); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + + rq.open("GET", endpoint.urls.descriptors + "-raw/" + flavor, true); + rq.send(); + } + + function signing_keys(endpoint, success, error) { + var rq = new XMLHttpRequest(); + rq.onreadystatechange = function () { + if (rq.readyState == 4 && rq.status == 200) { + endpoint.signing_keys = JSON.parse(rq.responseText); + + if (success !== undefined) success(endpoint); + } + else if (rq.readyState == 4 && error !== undefined) { + error(endpoint, rq.status); + } + }; + + rq.open("GET", endpoint.urls.signing_keys, true); + rq.send(); + } + + var BigInteger = createCommonjsModule(function (module) { + var bigInt = (function (undefined$1) { + + var BASE = 1e7, + LOG_BASE = 7, + MAX_INT = 9007199254740992, + MAX_INT_ARR = smallToArray(MAX_INT), + DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"; + + var supportsNativeBigInt = typeof BigInt === "function"; + + function Integer(v, radix, alphabet, caseSensitive) { + if (typeof v === "undefined") return Integer[0]; + if (typeof radix !== "undefined") return +radix === 10 && !alphabet ? parseValue(v) : parseBase(v, radix, alphabet, caseSensitive); + return parseValue(v); + } + + function BigInteger(value, sign) { + this.value = value; + this.sign = sign; + this.isSmall = false; + } + BigInteger.prototype = Object.create(Integer.prototype); + + function SmallInteger(value) { + this.value = value; + this.sign = value < 0; + this.isSmall = true; + } + SmallInteger.prototype = Object.create(Integer.prototype); + + function NativeBigInt(value) { + this.value = value; + } + NativeBigInt.prototype = Object.create(Integer.prototype); + + function isPrecise(n) { + return -MAX_INT < n && n < MAX_INT; + } + + function smallToArray(n) { // For performance reasons doesn't reference BASE, need to change this function if BASE changes + if (n < 1e7) + return [n]; + if (n < 1e14) + return [n % 1e7, Math.floor(n / 1e7)]; + return [n % 1e7, Math.floor(n / 1e7) % 1e7, Math.floor(n / 1e14)]; + } + + function arrayToSmall(arr) { // If BASE changes this function may need to change + trim(arr); + var length = arr.length; + if (length < 4 && compareAbs(arr, MAX_INT_ARR) < 0) { + switch (length) { + case 0: return 0; + case 1: return arr[0]; + case 2: return arr[0] + arr[1] * BASE; + default: return arr[0] + (arr[1] + arr[2] * BASE) * BASE; + } + } + return arr; + } + + function trim(v) { + var i = v.length; + while (v[--i] === 0); + v.length = i + 1; + } + + function createArray(length) { // function shamelessly stolen from Yaffle's library https://github.com/Yaffle/BigInteger + var x = new Array(length); + var i = -1; + while (++i < length) { + x[i] = 0; + } + return x; + } + + function truncate(n) { + if (n > 0) return Math.floor(n); + return Math.ceil(n); + } + + function add(a, b) { // assumes a and b are arrays with a.length >= b.length + var l_a = a.length, + l_b = b.length, + r = new Array(l_a), + carry = 0, + base = BASE, + sum, i; + for (i = 0; i < l_b; i++) { + sum = a[i] + b[i] + carry; + carry = sum >= base ? 1 : 0; + r[i] = sum - carry * base; + } + while (i < l_a) { + sum = a[i] + carry; + carry = sum === base ? 1 : 0; + r[i++] = sum - carry * base; + } + if (carry > 0) r.push(carry); + return r; + } + + function addAny(a, b) { + if (a.length >= b.length) return add(a, b); + return add(b, a); + } + + function addSmall(a, carry) { // assumes a is array, carry is number with 0 <= carry < MAX_INT + var l = a.length, + r = new Array(l), + base = BASE, + sum, i; + for (i = 0; i < l; i++) { + sum = a[i] - base + carry; + carry = Math.floor(sum / base); + r[i] = sum - carry * base; + carry += 1; + } + while (carry > 0) { + r[i++] = carry % base; + carry = Math.floor(carry / base); + } + return r; + } + + BigInteger.prototype.add = function (v) { + var n = parseValue(v); + if (this.sign !== n.sign) { + return this.subtract(n.negate()); + } + var a = this.value, b = n.value; + if (n.isSmall) { + return new BigInteger(addSmall(a, Math.abs(b)), this.sign); + } + return new BigInteger(addAny(a, b), this.sign); + }; + BigInteger.prototype.plus = BigInteger.prototype.add; + + SmallInteger.prototype.add = function (v) { + var n = parseValue(v); + var a = this.value; + if (a < 0 !== n.sign) { + return this.subtract(n.negate()); + } + var b = n.value; + if (n.isSmall) { + if (isPrecise(a + b)) return new SmallInteger(a + b); + b = smallToArray(Math.abs(b)); + } + return new BigInteger(addSmall(b, Math.abs(a)), a < 0); + }; + SmallInteger.prototype.plus = SmallInteger.prototype.add; + + NativeBigInt.prototype.add = function (v) { + return new NativeBigInt(this.value + parseValue(v).value); + }; + NativeBigInt.prototype.plus = NativeBigInt.prototype.add; + + function subtract(a, b) { // assumes a and b are arrays with a >= b + var a_l = a.length, + b_l = b.length, + r = new Array(a_l), + borrow = 0, + base = BASE, + i, difference; + for (i = 0; i < b_l; i++) { + difference = a[i] - borrow - b[i]; + if (difference < 0) { + difference += base; + borrow = 1; + } else borrow = 0; + r[i] = difference; + } + for (i = b_l; i < a_l; i++) { + difference = a[i] - borrow; + if (difference < 0) difference += base; + else { + r[i++] = difference; + break; + } + r[i] = difference; + } + for (; i < a_l; i++) { + r[i] = a[i]; + } + trim(r); + return r; + } + + function subtractAny(a, b, sign) { + var value; + if (compareAbs(a, b) >= 0) { + value = subtract(a, b); + } else { + value = subtract(b, a); + sign = !sign; + } + value = arrayToSmall(value); + if (typeof value === "number") { + if (sign) value = -value; + return new SmallInteger(value); + } + return new BigInteger(value, sign); + } + + function subtractSmall(a, b, sign) { // assumes a is array, b is number with 0 <= b < MAX_INT + var l = a.length, + r = new Array(l), + carry = -b, + base = BASE, + i, difference; + for (i = 0; i < l; i++) { + difference = a[i] + carry; + carry = Math.floor(difference / base); + difference %= base; + r[i] = difference < 0 ? difference + base : difference; + } + r = arrayToSmall(r); + if (typeof r === "number") { + if (sign) r = -r; + return new SmallInteger(r); + } return new BigInteger(r, sign); + } + + BigInteger.prototype.subtract = function (v) { + var n = parseValue(v); + if (this.sign !== n.sign) { + return this.add(n.negate()); + } + var a = this.value, b = n.value; + if (n.isSmall) + return subtractSmall(a, Math.abs(b), this.sign); + return subtractAny(a, b, this.sign); + }; + BigInteger.prototype.minus = BigInteger.prototype.subtract; + + SmallInteger.prototype.subtract = function (v) { + var n = parseValue(v); + var a = this.value; + if (a < 0 !== n.sign) { + return this.add(n.negate()); + } + var b = n.value; + if (n.isSmall) { + return new SmallInteger(a - b); + } + return subtractSmall(b, Math.abs(a), a >= 0); + }; + SmallInteger.prototype.minus = SmallInteger.prototype.subtract; + + NativeBigInt.prototype.subtract = function (v) { + return new NativeBigInt(this.value - parseValue(v).value); + }; + NativeBigInt.prototype.minus = NativeBigInt.prototype.subtract; + + BigInteger.prototype.negate = function () { + return new BigInteger(this.value, !this.sign); + }; + SmallInteger.prototype.negate = function () { + var sign = this.sign; + var small = new SmallInteger(-this.value); + small.sign = !sign; + return small; + }; + NativeBigInt.prototype.negate = function () { + return new NativeBigInt(-this.value); + }; + + BigInteger.prototype.abs = function () { + return new BigInteger(this.value, false); + }; + SmallInteger.prototype.abs = function () { + return new SmallInteger(Math.abs(this.value)); + }; + NativeBigInt.prototype.abs = function () { + return new NativeBigInt(this.value >= 0 ? this.value : -this.value); + }; + + + function multiplyLong(a, b) { + var a_l = a.length, + b_l = b.length, + l = a_l + b_l, + r = createArray(l), + base = BASE, + product, carry, i, a_i, b_j; + for (i = 0; i < a_l; ++i) { + a_i = a[i]; + for (var j = 0; j < b_l; ++j) { + b_j = b[j]; + product = a_i * b_j + r[i + j]; + carry = Math.floor(product / base); + r[i + j] = product - carry * base; + r[i + j + 1] += carry; + } + } + trim(r); + return r; + } + + function multiplySmall(a, b) { // assumes a is array, b is number with |b| < BASE + var l = a.length, + r = new Array(l), + base = BASE, + carry = 0, + product, i; + for (i = 0; i < l; i++) { + product = a[i] * b + carry; + carry = Math.floor(product / base); + r[i] = product - carry * base; + } + while (carry > 0) { + r[i++] = carry % base; + carry = Math.floor(carry / base); + } + return r; + } + + function shiftLeft(x, n) { + var r = []; + while (n-- > 0) r.push(0); + return r.concat(x); + } + + function multiplyKaratsuba(x, y) { + var n = Math.max(x.length, y.length); + + if (n <= 30) return multiplyLong(x, y); + n = Math.ceil(n / 2); + + var b = x.slice(n), + a = x.slice(0, n), + d = y.slice(n), + c = y.slice(0, n); + + var ac = multiplyKaratsuba(a, c), + bd = multiplyKaratsuba(b, d), + abcd = multiplyKaratsuba(addAny(a, b), addAny(c, d)); + + var product = addAny(addAny(ac, shiftLeft(subtract(subtract(abcd, ac), bd), n)), shiftLeft(bd, 2 * n)); + trim(product); + return product; + } + + // The following function is derived from a surface fit of a graph plotting the performance difference + // between long multiplication and karatsuba multiplication versus the lengths of the two arrays. + function useKaratsuba(l1, l2) { + return -0.012 * l1 - 0.012 * l2 + 0.000015 * l1 * l2 > 0; + } + + BigInteger.prototype.multiply = function (v) { + var n = parseValue(v), + a = this.value, b = n.value, + sign = this.sign !== n.sign, + abs; + if (n.isSmall) { + if (b === 0) return Integer[0]; + if (b === 1) return this; + if (b === -1) return this.negate(); + abs = Math.abs(b); + if (abs < BASE) { + return new BigInteger(multiplySmall(a, abs), sign); + } + b = smallToArray(abs); + } + if (useKaratsuba(a.length, b.length)) // Karatsuba is only faster for certain array sizes + return new BigInteger(multiplyKaratsuba(a, b), sign); + return new BigInteger(multiplyLong(a, b), sign); + }; + + BigInteger.prototype.times = BigInteger.prototype.multiply; + + function multiplySmallAndArray(a, b, sign) { // a >= 0 + if (a < BASE) { + return new BigInteger(multiplySmall(b, a), sign); + } + return new BigInteger(multiplyLong(b, smallToArray(a)), sign); + } + SmallInteger.prototype._multiplyBySmall = function (a) { + if (isPrecise(a.value * this.value)) { + return new SmallInteger(a.value * this.value); + } + return multiplySmallAndArray(Math.abs(a.value), smallToArray(Math.abs(this.value)), this.sign !== a.sign); + }; + BigInteger.prototype._multiplyBySmall = function (a) { + if (a.value === 0) return Integer[0]; + if (a.value === 1) return this; + if (a.value === -1) return this.negate(); + return multiplySmallAndArray(Math.abs(a.value), this.value, this.sign !== a.sign); + }; + SmallInteger.prototype.multiply = function (v) { + return parseValue(v)._multiplyBySmall(this); + }; + SmallInteger.prototype.times = SmallInteger.prototype.multiply; + + NativeBigInt.prototype.multiply = function (v) { + return new NativeBigInt(this.value * parseValue(v).value); + }; + NativeBigInt.prototype.times = NativeBigInt.prototype.multiply; + + function square(a) { + //console.assert(2 * BASE * BASE < MAX_INT); + var l = a.length, + r = createArray(l + l), + base = BASE, + product, carry, i, a_i, a_j; + for (i = 0; i < l; i++) { + a_i = a[i]; + carry = 0 - a_i * a_i; + for (var j = i; j < l; j++) { + a_j = a[j]; + product = 2 * (a_i * a_j) + r[i + j] + carry; + carry = Math.floor(product / base); + r[i + j] = product - carry * base; + } + r[i + l] = carry; + } + trim(r); + return r; + } + + BigInteger.prototype.square = function () { + return new BigInteger(square(this.value), false); + }; + + SmallInteger.prototype.square = function () { + var value = this.value * this.value; + if (isPrecise(value)) return new SmallInteger(value); + return new BigInteger(square(smallToArray(Math.abs(this.value))), false); + }; + + NativeBigInt.prototype.square = function (v) { + return new NativeBigInt(this.value * this.value); + }; + + function divMod1(a, b) { // Left over from previous version. Performs faster than divMod2 on smaller input sizes. + var a_l = a.length, + b_l = b.length, + base = BASE, + result = createArray(b.length), + divisorMostSignificantDigit = b[b_l - 1], + // normalization + lambda = Math.ceil(base / (2 * divisorMostSignificantDigit)), + remainder = multiplySmall(a, lambda), + divisor = multiplySmall(b, lambda), + quotientDigit, shift, carry, borrow, i, l, q; + if (remainder.length <= a_l) remainder.push(0); + divisor.push(0); + divisorMostSignificantDigit = divisor[b_l - 1]; + for (shift = a_l - b_l; shift >= 0; shift--) { + quotientDigit = base - 1; + if (remainder[shift + b_l] !== divisorMostSignificantDigit) { + quotientDigit = Math.floor((remainder[shift + b_l] * base + remainder[shift + b_l - 1]) / divisorMostSignificantDigit); + } + // quotientDigit <= base - 1 + carry = 0; + borrow = 0; + l = divisor.length; + for (i = 0; i < l; i++) { + carry += quotientDigit * divisor[i]; + q = Math.floor(carry / base); + borrow += remainder[shift + i] - (carry - q * base); + carry = q; + if (borrow < 0) { + remainder[shift + i] = borrow + base; + borrow = -1; + } else { + remainder[shift + i] = borrow; + borrow = 0; + } + } + while (borrow !== 0) { + quotientDigit -= 1; + carry = 0; + for (i = 0; i < l; i++) { + carry += remainder[shift + i] - base + divisor[i]; + if (carry < 0) { + remainder[shift + i] = carry + base; + carry = 0; + } else { + remainder[shift + i] = carry; + carry = 1; + } + } + borrow += carry; + } + result[shift] = quotientDigit; + } + // denormalization + remainder = divModSmall(remainder, lambda)[0]; + return [arrayToSmall(result), arrayToSmall(remainder)]; + } + + function divMod2(a, b) { // Implementation idea shamelessly stolen from Silent Matt's library http://silentmatt.com/biginteger/ + // Performs faster than divMod1 on larger input sizes. + var a_l = a.length, + b_l = b.length, + result = [], + part = [], + base = BASE, + guess, xlen, highx, highy, check; + while (a_l) { + part.unshift(a[--a_l]); + trim(part); + if (compareAbs(part, b) < 0) { + result.push(0); + continue; + } + xlen = part.length; + highx = part[xlen - 1] * base + part[xlen - 2]; + highy = b[b_l - 1] * base + b[b_l - 2]; + if (xlen > b_l) { + highx = (highx + 1) * base; + } + guess = Math.ceil(highx / highy); + do { + check = multiplySmall(b, guess); + if (compareAbs(check, part) <= 0) break; + guess--; + } while (guess); + result.push(guess); + part = subtract(part, check); + } + result.reverse(); + return [arrayToSmall(result), arrayToSmall(part)]; + } + + function divModSmall(value, lambda) { + var length = value.length, + quotient = createArray(length), + base = BASE, + i, q, remainder, divisor; + remainder = 0; + for (i = length - 1; i >= 0; --i) { + divisor = remainder * base + value[i]; + q = truncate(divisor / lambda); + remainder = divisor - q * lambda; + quotient[i] = q | 0; + } + return [quotient, remainder | 0]; + } + + function divModAny(self, v) { + var value, n = parseValue(v); + if (supportsNativeBigInt) { + return [new NativeBigInt(self.value / n.value), new NativeBigInt(self.value % n.value)]; + } + var a = self.value, b = n.value; + var quotient; + if (b === 0) throw new Error("Cannot divide by zero"); + if (self.isSmall) { + if (n.isSmall) { + return [new SmallInteger(truncate(a / b)), new SmallInteger(a % b)]; + } + return [Integer[0], self]; + } + if (n.isSmall) { + if (b === 1) return [self, Integer[0]]; + if (b == -1) return [self.negate(), Integer[0]]; + var abs = Math.abs(b); + if (abs < BASE) { + value = divModSmall(a, abs); + quotient = arrayToSmall(value[0]); + var remainder = value[1]; + if (self.sign) remainder = -remainder; + if (typeof quotient === "number") { + if (self.sign !== n.sign) quotient = -quotient; + return [new SmallInteger(quotient), new SmallInteger(remainder)]; + } + return [new BigInteger(quotient, self.sign !== n.sign), new SmallInteger(remainder)]; + } + b = smallToArray(abs); + } + var comparison = compareAbs(a, b); + if (comparison === -1) return [Integer[0], self]; + if (comparison === 0) return [Integer[self.sign === n.sign ? 1 : -1], Integer[0]]; + + // divMod1 is faster on smaller input sizes + if (a.length + b.length <= 200) + value = divMod1(a, b); + else value = divMod2(a, b); + + quotient = value[0]; + var qSign = self.sign !== n.sign, + mod = value[1], + mSign = self.sign; + if (typeof quotient === "number") { + if (qSign) quotient = -quotient; + quotient = new SmallInteger(quotient); + } else quotient = new BigInteger(quotient, qSign); + if (typeof mod === "number") { + if (mSign) mod = -mod; + mod = new SmallInteger(mod); + } else mod = new BigInteger(mod, mSign); + return [quotient, mod]; + } + + BigInteger.prototype.divmod = function (v) { + var result = divModAny(this, v); + return { + quotient: result[0], + remainder: result[1] + }; + }; + NativeBigInt.prototype.divmod = SmallInteger.prototype.divmod = BigInteger.prototype.divmod; + + + BigInteger.prototype.divide = function (v) { + return divModAny(this, v)[0]; + }; + NativeBigInt.prototype.over = NativeBigInt.prototype.divide = function (v) { + return new NativeBigInt(this.value / parseValue(v).value); + }; + SmallInteger.prototype.over = SmallInteger.prototype.divide = BigInteger.prototype.over = BigInteger.prototype.divide; + + BigInteger.prototype.mod = function (v) { + return divModAny(this, v)[1]; + }; + NativeBigInt.prototype.mod = NativeBigInt.prototype.remainder = function (v) { + return new NativeBigInt(this.value % parseValue(v).value); + }; + SmallInteger.prototype.remainder = SmallInteger.prototype.mod = BigInteger.prototype.remainder = BigInteger.prototype.mod; + + BigInteger.prototype.pow = function (v) { + var n = parseValue(v), + a = this.value, + b = n.value, + value, x, y; + if (b === 0) return Integer[1]; + if (a === 0) return Integer[0]; + if (a === 1) return Integer[1]; + if (a === -1) return n.isEven() ? Integer[1] : Integer[-1]; + if (n.sign) { + return Integer[0]; + } + if (!n.isSmall) throw new Error("The exponent " + n.toString() + " is too large."); + if (this.isSmall) { + if (isPrecise(value = Math.pow(a, b))) + return new SmallInteger(truncate(value)); + } + x = this; + y = Integer[1]; + while (true) { + if (b & 1 === 1) { + y = y.times(x); + --b; + } + if (b === 0) break; + b /= 2; + x = x.square(); + } + return y; + }; + SmallInteger.prototype.pow = BigInteger.prototype.pow; + + NativeBigInt.prototype.pow = function (v) { + var n = parseValue(v); + var a = this.value, b = n.value; + var _0 = BigInt(0), _1 = BigInt(1), _2 = BigInt(2); + if (b === _0) return Integer[1]; + if (a === _0) return Integer[0]; + if (a === _1) return Integer[1]; + if (a === BigInt(-1)) return n.isEven() ? Integer[1] : Integer[-1]; + if (n.isNegative()) return new NativeBigInt(_0); + var x = this; + var y = Integer[1]; + while (true) { + if ((b & _1) === _1) { + y = y.times(x); + --b; + } + if (b === _0) break; + b /= _2; + x = x.square(); + } + return y; + }; + + BigInteger.prototype.modPow = function (exp, mod) { + exp = parseValue(exp); + mod = parseValue(mod); + if (mod.isZero()) throw new Error("Cannot take modPow with modulus 0"); + var r = Integer[1], + base = this.mod(mod); + if (exp.isNegative()) { + exp = exp.multiply(Integer[-1]); + base = base.modInv(mod); + } + while (exp.isPositive()) { + if (base.isZero()) return Integer[0]; + if (exp.isOdd()) r = r.multiply(base).mod(mod); + exp = exp.divide(2); + base = base.square().mod(mod); + } + return r; + }; + NativeBigInt.prototype.modPow = SmallInteger.prototype.modPow = BigInteger.prototype.modPow; + + function compareAbs(a, b) { + if (a.length !== b.length) { + return a.length > b.length ? 1 : -1; + } + for (var i = a.length - 1; i >= 0; i--) { + if (a[i] !== b[i]) return a[i] > b[i] ? 1 : -1; + } + return 0; + } + + BigInteger.prototype.compareAbs = function (v) { + var n = parseValue(v), + a = this.value, + b = n.value; + if (n.isSmall) return 1; + return compareAbs(a, b); + }; + SmallInteger.prototype.compareAbs = function (v) { + var n = parseValue(v), + a = Math.abs(this.value), + b = n.value; + if (n.isSmall) { + b = Math.abs(b); + return a === b ? 0 : a > b ? 1 : -1; + } + return -1; + }; + NativeBigInt.prototype.compareAbs = function (v) { + var a = this.value; + var b = parseValue(v).value; + a = a >= 0 ? a : -a; + b = b >= 0 ? b : -b; + return a === b ? 0 : a > b ? 1 : -1; + }; + + BigInteger.prototype.compare = function (v) { + // See discussion about comparison with Infinity: + // https://github.com/peterolson/BigInteger.js/issues/61 + if (v === Infinity) { + return -1; + } + if (v === -Infinity) { + return 1; + } + + var n = parseValue(v), + a = this.value, + b = n.value; + if (this.sign !== n.sign) { + return n.sign ? 1 : -1; + } + if (n.isSmall) { + return this.sign ? -1 : 1; + } + return compareAbs(a, b) * (this.sign ? -1 : 1); + }; + BigInteger.prototype.compareTo = BigInteger.prototype.compare; + + SmallInteger.prototype.compare = function (v) { + if (v === Infinity) { + return -1; + } + if (v === -Infinity) { + return 1; + } + + var n = parseValue(v), + a = this.value, + b = n.value; + if (n.isSmall) { + return a == b ? 0 : a > b ? 1 : -1; + } + if (a < 0 !== n.sign) { + return a < 0 ? -1 : 1; + } + return a < 0 ? 1 : -1; + }; + SmallInteger.prototype.compareTo = SmallInteger.prototype.compare; + + NativeBigInt.prototype.compare = function (v) { + if (v === Infinity) { + return -1; + } + if (v === -Infinity) { + return 1; + } + var a = this.value; + var b = parseValue(v).value; + return a === b ? 0 : a > b ? 1 : -1; + }; + NativeBigInt.prototype.compareTo = NativeBigInt.prototype.compare; + + BigInteger.prototype.equals = function (v) { + return this.compare(v) === 0; + }; + NativeBigInt.prototype.eq = NativeBigInt.prototype.equals = SmallInteger.prototype.eq = SmallInteger.prototype.equals = BigInteger.prototype.eq = BigInteger.prototype.equals; + + BigInteger.prototype.notEquals = function (v) { + return this.compare(v) !== 0; + }; + NativeBigInt.prototype.neq = NativeBigInt.prototype.notEquals = SmallInteger.prototype.neq = SmallInteger.prototype.notEquals = BigInteger.prototype.neq = BigInteger.prototype.notEquals; + + BigInteger.prototype.greater = function (v) { + return this.compare(v) > 0; + }; + NativeBigInt.prototype.gt = NativeBigInt.prototype.greater = SmallInteger.prototype.gt = SmallInteger.prototype.greater = BigInteger.prototype.gt = BigInteger.prototype.greater; + + BigInteger.prototype.lesser = function (v) { + return this.compare(v) < 0; + }; + NativeBigInt.prototype.lt = NativeBigInt.prototype.lesser = SmallInteger.prototype.lt = SmallInteger.prototype.lesser = BigInteger.prototype.lt = BigInteger.prototype.lesser; + + BigInteger.prototype.greaterOrEquals = function (v) { + return this.compare(v) >= 0; + }; + NativeBigInt.prototype.geq = NativeBigInt.prototype.greaterOrEquals = SmallInteger.prototype.geq = SmallInteger.prototype.greaterOrEquals = BigInteger.prototype.geq = BigInteger.prototype.greaterOrEquals; + + BigInteger.prototype.lesserOrEquals = function (v) { + return this.compare(v) <= 0; + }; + NativeBigInt.prototype.leq = NativeBigInt.prototype.lesserOrEquals = SmallInteger.prototype.leq = SmallInteger.prototype.lesserOrEquals = BigInteger.prototype.leq = BigInteger.prototype.lesserOrEquals; + + BigInteger.prototype.isEven = function () { + return (this.value[0] & 1) === 0; + }; + SmallInteger.prototype.isEven = function () { + return (this.value & 1) === 0; + }; + NativeBigInt.prototype.isEven = function () { + return (this.value & BigInt(1)) === BigInt(0); + }; + + BigInteger.prototype.isOdd = function () { + return (this.value[0] & 1) === 1; + }; + SmallInteger.prototype.isOdd = function () { + return (this.value & 1) === 1; + }; + NativeBigInt.prototype.isOdd = function () { + return (this.value & BigInt(1)) === BigInt(1); + }; + + BigInteger.prototype.isPositive = function () { + return !this.sign; + }; + SmallInteger.prototype.isPositive = function () { + return this.value > 0; + }; + NativeBigInt.prototype.isPositive = SmallInteger.prototype.isPositive; + + BigInteger.prototype.isNegative = function () { + return this.sign; + }; + SmallInteger.prototype.isNegative = function () { + return this.value < 0; + }; + NativeBigInt.prototype.isNegative = SmallInteger.prototype.isNegative; + + BigInteger.prototype.isUnit = function () { + return false; + }; + SmallInteger.prototype.isUnit = function () { + return Math.abs(this.value) === 1; + }; + NativeBigInt.prototype.isUnit = function () { + return this.abs().value === BigInt(1); + }; + + BigInteger.prototype.isZero = function () { + return false; + }; + SmallInteger.prototype.isZero = function () { + return this.value === 0; + }; + NativeBigInt.prototype.isZero = function () { + return this.value === BigInt(0); + }; + + BigInteger.prototype.isDivisibleBy = function (v) { + var n = parseValue(v); + if (n.isZero()) return false; + if (n.isUnit()) return true; + if (n.compareAbs(2) === 0) return this.isEven(); + return this.mod(n).isZero(); + }; + NativeBigInt.prototype.isDivisibleBy = SmallInteger.prototype.isDivisibleBy = BigInteger.prototype.isDivisibleBy; + + function isBasicPrime(v) { + var n = v.abs(); + if (n.isUnit()) return false; + if (n.equals(2) || n.equals(3) || n.equals(5)) return true; + if (n.isEven() || n.isDivisibleBy(3) || n.isDivisibleBy(5)) return false; + if (n.lesser(49)) return true; + // we don't know if it's prime: let the other functions figure it out + } + + function millerRabinTest(n, a) { + var nPrev = n.prev(), + b = nPrev, + r = 0, + d, i, x; + while (b.isEven()) b = b.divide(2), r++; + next: for (i = 0; i < a.length; i++) { + if (n.lesser(a[i])) continue; + x = bigInt(a[i]).modPow(b, n); + if (x.isUnit() || x.equals(nPrev)) continue; + for (d = r - 1; d != 0; d--) { + x = x.square().mod(n); + if (x.isUnit()) return false; + if (x.equals(nPrev)) continue next; + } + return false; + } + return true; + } + + // Set "strict" to true to force GRH-supported lower bound of 2*log(N)^2 + BigInteger.prototype.isPrime = function (strict) { + var isPrime = isBasicPrime(this); + if (isPrime !== undefined$1) return isPrime; + var n = this.abs(); + var bits = n.bitLength(); + if (bits <= 64) + return millerRabinTest(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]); + var logN = Math.log(2) * bits.toJSNumber(); + var t = Math.ceil((strict === true) ? (2 * Math.pow(logN, 2)) : logN); + for (var a = [], i = 0; i < t; i++) { + a.push(bigInt(i + 2)); + } + return millerRabinTest(n, a); + }; + NativeBigInt.prototype.isPrime = SmallInteger.prototype.isPrime = BigInteger.prototype.isPrime; + + BigInteger.prototype.isProbablePrime = function (iterations, rng) { + var isPrime = isBasicPrime(this); + if (isPrime !== undefined$1) return isPrime; + var n = this.abs(); + var t = iterations === undefined$1 ? 5 : iterations; + for (var a = [], i = 0; i < t; i++) { + a.push(bigInt.randBetween(2, n.minus(2), rng)); + } + return millerRabinTest(n, a); + }; + NativeBigInt.prototype.isProbablePrime = SmallInteger.prototype.isProbablePrime = BigInteger.prototype.isProbablePrime; + + BigInteger.prototype.modInv = function (n) { + var t = bigInt.zero, newT = bigInt.one, r = parseValue(n), newR = this.abs(), q, lastT, lastR; + while (!newR.isZero()) { + q = r.divide(newR); + lastT = t; + lastR = r; + t = newT; + r = newR; + newT = lastT.subtract(q.multiply(newT)); + newR = lastR.subtract(q.multiply(newR)); + } + if (!r.isUnit()) throw new Error(this.toString() + " and " + n.toString() + " are not co-prime"); + if (t.compare(0) === -1) { + t = t.add(n); + } + if (this.isNegative()) { + return t.negate(); + } + return t; + }; + + NativeBigInt.prototype.modInv = SmallInteger.prototype.modInv = BigInteger.prototype.modInv; + + BigInteger.prototype.next = function () { + var value = this.value; + if (this.sign) { + return subtractSmall(value, 1, this.sign); + } + return new BigInteger(addSmall(value, 1), this.sign); + }; + SmallInteger.prototype.next = function () { + var value = this.value; + if (value + 1 < MAX_INT) return new SmallInteger(value + 1); + return new BigInteger(MAX_INT_ARR, false); + }; + NativeBigInt.prototype.next = function () { + return new NativeBigInt(this.value + BigInt(1)); + }; + + BigInteger.prototype.prev = function () { + var value = this.value; + if (this.sign) { + return new BigInteger(addSmall(value, 1), true); + } + return subtractSmall(value, 1, this.sign); + }; + SmallInteger.prototype.prev = function () { + var value = this.value; + if (value - 1 > -MAX_INT) return new SmallInteger(value - 1); + return new BigInteger(MAX_INT_ARR, true); + }; + NativeBigInt.prototype.prev = function () { + return new NativeBigInt(this.value - BigInt(1)); + }; + + var powersOfTwo = [1]; + while (2 * powersOfTwo[powersOfTwo.length - 1] <= BASE) powersOfTwo.push(2 * powersOfTwo[powersOfTwo.length - 1]); + var powers2Length = powersOfTwo.length, highestPower2 = powersOfTwo[powers2Length - 1]; + + function shift_isSmall(n) { + return Math.abs(n) <= BASE; + } + + BigInteger.prototype.shiftLeft = function (v) { + var n = parseValue(v).toJSNumber(); + if (!shift_isSmall(n)) { + throw new Error(String(n) + " is too large for shifting."); + } + if (n < 0) return this.shiftRight(-n); + var result = this; + if (result.isZero()) return result; + while (n >= powers2Length) { + result = result.multiply(highestPower2); + n -= powers2Length - 1; + } + return result.multiply(powersOfTwo[n]); + }; + NativeBigInt.prototype.shiftLeft = SmallInteger.prototype.shiftLeft = BigInteger.prototype.shiftLeft; + + BigInteger.prototype.shiftRight = function (v) { + var remQuo; + var n = parseValue(v).toJSNumber(); + if (!shift_isSmall(n)) { + throw new Error(String(n) + " is too large for shifting."); + } + if (n < 0) return this.shiftLeft(-n); + var result = this; + while (n >= powers2Length) { + if (result.isZero() || (result.isNegative() && result.isUnit())) return result; + remQuo = divModAny(result, highestPower2); + result = remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0]; + n -= powers2Length - 1; + } + remQuo = divModAny(result, powersOfTwo[n]); + return remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0]; + }; + NativeBigInt.prototype.shiftRight = SmallInteger.prototype.shiftRight = BigInteger.prototype.shiftRight; + + function bitwise(x, y, fn) { + y = parseValue(y); + var xSign = x.isNegative(), ySign = y.isNegative(); + var xRem = xSign ? x.not() : x, + yRem = ySign ? y.not() : y; + var xDigit = 0, yDigit = 0; + var xDivMod = null, yDivMod = null; + var result = []; + while (!xRem.isZero() || !yRem.isZero()) { + xDivMod = divModAny(xRem, highestPower2); + xDigit = xDivMod[1].toJSNumber(); + if (xSign) { + xDigit = highestPower2 - 1 - xDigit; // two's complement for negative numbers + } + + yDivMod = divModAny(yRem, highestPower2); + yDigit = yDivMod[1].toJSNumber(); + if (ySign) { + yDigit = highestPower2 - 1 - yDigit; // two's complement for negative numbers + } + + xRem = xDivMod[0]; + yRem = yDivMod[0]; + result.push(fn(xDigit, yDigit)); + } + var sum = fn(xSign ? 1 : 0, ySign ? 1 : 0) !== 0 ? bigInt(-1) : bigInt(0); + for (var i = result.length - 1; i >= 0; i -= 1) { + sum = sum.multiply(highestPower2).add(bigInt(result[i])); + } + return sum; + } + + BigInteger.prototype.not = function () { + return this.negate().prev(); + }; + NativeBigInt.prototype.not = SmallInteger.prototype.not = BigInteger.prototype.not; + + BigInteger.prototype.and = function (n) { + return bitwise(this, n, function (a, b) { return a & b; }); + }; + NativeBigInt.prototype.and = SmallInteger.prototype.and = BigInteger.prototype.and; + + BigInteger.prototype.or = function (n) { + return bitwise(this, n, function (a, b) { return a | b; }); + }; + NativeBigInt.prototype.or = SmallInteger.prototype.or = BigInteger.prototype.or; + + BigInteger.prototype.xor = function (n) { + return bitwise(this, n, function (a, b) { return a ^ b; }); + }; + NativeBigInt.prototype.xor = SmallInteger.prototype.xor = BigInteger.prototype.xor; + + var LOBMASK_I = 1 << 30, LOBMASK_BI = (BASE & -BASE) * (BASE & -BASE) | LOBMASK_I; + function roughLOB(n) { // get lowestOneBit (rough) + // SmallInteger: return Min(lowestOneBit(n), 1 << 30) + // BigInteger: return Min(lowestOneBit(n), 1 << 14) [BASE=1e7] + var v = n.value, + x = typeof v === "number" ? v | LOBMASK_I : + typeof v === "bigint" ? v | BigInt(LOBMASK_I) : + v[0] + v[1] * BASE | LOBMASK_BI; + return x & -x; + } + + function integerLogarithm(value, base) { + if (base.compareTo(value) <= 0) { + var tmp = integerLogarithm(value, base.square(base)); + var p = tmp.p; + var e = tmp.e; + var t = p.multiply(base); + return t.compareTo(value) <= 0 ? { p: t, e: e * 2 + 1 } : { p: p, e: e * 2 }; + } + return { p: bigInt(1), e: 0 }; + } + + BigInteger.prototype.bitLength = function () { + var n = this; + if (n.compareTo(bigInt(0)) < 0) { + n = n.negate().subtract(bigInt(1)); + } + if (n.compareTo(bigInt(0)) === 0) { + return bigInt(0); + } + return bigInt(integerLogarithm(n, bigInt(2)).e).add(bigInt(1)); + }; + NativeBigInt.prototype.bitLength = SmallInteger.prototype.bitLength = BigInteger.prototype.bitLength; + + function max(a, b) { + a = parseValue(a); + b = parseValue(b); + return a.greater(b) ? a : b; + } + function min(a, b) { + a = parseValue(a); + b = parseValue(b); + return a.lesser(b) ? a : b; + } + function gcd(a, b) { + a = parseValue(a).abs(); + b = parseValue(b).abs(); + if (a.equals(b)) return a; + if (a.isZero()) return b; + if (b.isZero()) return a; + var c = Integer[1], d, t; + while (a.isEven() && b.isEven()) { + d = min(roughLOB(a), roughLOB(b)); + a = a.divide(d); + b = b.divide(d); + c = c.multiply(d); + } + while (a.isEven()) { + a = a.divide(roughLOB(a)); + } + do { + while (b.isEven()) { + b = b.divide(roughLOB(b)); + } + if (a.greater(b)) { + t = b; b = a; a = t; + } + b = b.subtract(a); + } while (!b.isZero()); + return c.isUnit() ? a : a.multiply(c); + } + function lcm(a, b) { + a = parseValue(a).abs(); + b = parseValue(b).abs(); + return a.divide(gcd(a, b)).multiply(b); + } + function randBetween(a, b, rng) { + a = parseValue(a); + b = parseValue(b); + var usedRNG = rng || Math.random; + var low = min(a, b), high = max(a, b); + var range = high.subtract(low).add(1); + if (range.isSmall) return low.add(Math.floor(usedRNG() * range)); + var digits = toBase(range, BASE).value; + var result = [], restricted = true; + for (var i = 0; i < digits.length; i++) { + var top = restricted ? digits[i] : BASE; + var digit = truncate(usedRNG() * top); + result.push(digit); + if (digit < top) restricted = false; + } + return low.add(Integer.fromArray(result, BASE, false)); + } + + var parseBase = function (text, base, alphabet, caseSensitive) { + alphabet = alphabet || DEFAULT_ALPHABET; + text = String(text); + if (!caseSensitive) { + text = text.toLowerCase(); + alphabet = alphabet.toLowerCase(); + } + var length = text.length; + var i; + var absBase = Math.abs(base); + var alphabetValues = {}; + for (i = 0; i < alphabet.length; i++) { + alphabetValues[alphabet[i]] = i; + } + for (i = 0; i < length; i++) { + var c = text[i]; + if (c === "-") continue; + if (c in alphabetValues) { + if (alphabetValues[c] >= absBase) { + if (c === "1" && absBase === 1) continue; + throw new Error(c + " is not a valid digit in base " + base + "."); + } + } + } + base = parseValue(base); + var digits = []; + var isNegative = text[0] === "-"; + for (i = isNegative ? 1 : 0; i < text.length; i++) { + var c = text[i]; + if (c in alphabetValues) digits.push(parseValue(alphabetValues[c])); + else if (c === "<") { + var start = i; + do { i++; } while (text[i] !== ">" && i < text.length); + digits.push(parseValue(text.slice(start + 1, i))); + } + else throw new Error(c + " is not a valid character"); + } + return parseBaseFromArray(digits, base, isNegative); + }; + + function parseBaseFromArray(digits, base, isNegative) { + var val = Integer[0], pow = Integer[1], i; + for (i = digits.length - 1; i >= 0; i--) { + val = val.add(digits[i].times(pow)); + pow = pow.times(base); + } + return isNegative ? val.negate() : val; + } + + function stringify(digit, alphabet) { + alphabet = alphabet || DEFAULT_ALPHABET; + if (digit < alphabet.length) { + return alphabet[digit]; + } + return "<" + digit + ">"; + } + + function toBase(n, base) { + base = bigInt(base); + if (base.isZero()) { + if (n.isZero()) return { value: [0], isNegative: false }; + throw new Error("Cannot convert nonzero numbers to base 0."); + } + if (base.equals(-1)) { + if (n.isZero()) return { value: [0], isNegative: false }; + if (n.isNegative()) + return { + value: [].concat.apply([], Array.apply(null, Array(-n.toJSNumber())) + .map(Array.prototype.valueOf, [1, 0]) + ), + isNegative: false + }; + + var arr = Array.apply(null, Array(n.toJSNumber() - 1)) + .map(Array.prototype.valueOf, [0, 1]); + arr.unshift([1]); + return { + value: [].concat.apply([], arr), + isNegative: false + }; + } + + var neg = false; + if (n.isNegative() && base.isPositive()) { + neg = true; + n = n.abs(); + } + if (base.isUnit()) { + if (n.isZero()) return { value: [0], isNegative: false }; + + return { + value: Array.apply(null, Array(n.toJSNumber())) + .map(Number.prototype.valueOf, 1), + isNegative: neg + }; + } + var out = []; + var left = n, divmod; + while (left.isNegative() || left.compareAbs(base) >= 0) { + divmod = left.divmod(base); + left = divmod.quotient; + var digit = divmod.remainder; + if (digit.isNegative()) { + digit = base.minus(digit).abs(); + left = left.next(); + } + out.push(digit.toJSNumber()); + } + out.push(left.toJSNumber()); + return { value: out.reverse(), isNegative: neg }; + } + + function toBaseString(n, base, alphabet) { + var arr = toBase(n, base); + return (arr.isNegative ? "-" : "") + arr.value.map(function (x) { + return stringify(x, alphabet); + }).join(''); + } + + BigInteger.prototype.toArray = function (radix) { + return toBase(this, radix); + }; + + SmallInteger.prototype.toArray = function (radix) { + return toBase(this, radix); + }; + + NativeBigInt.prototype.toArray = function (radix) { + return toBase(this, radix); + }; + + BigInteger.prototype.toString = function (radix, alphabet) { + if (radix === undefined$1) radix = 10; + if (radix !== 10) return toBaseString(this, radix, alphabet); + var v = this.value, l = v.length, str = String(v[--l]), zeros = "0000000", digit; + while (--l >= 0) { + digit = String(v[l]); + str += zeros.slice(digit.length) + digit; + } + var sign = this.sign ? "-" : ""; + return sign + str; + }; + + SmallInteger.prototype.toString = function (radix, alphabet) { + if (radix === undefined$1) radix = 10; + if (radix != 10) return toBaseString(this, radix, alphabet); + return String(this.value); + }; + + NativeBigInt.prototype.toString = SmallInteger.prototype.toString; + + NativeBigInt.prototype.toJSON = BigInteger.prototype.toJSON = SmallInteger.prototype.toJSON = function () { return this.toString(); }; + + BigInteger.prototype.valueOf = function () { + return parseInt(this.toString(), 10); + }; + BigInteger.prototype.toJSNumber = BigInteger.prototype.valueOf; + + SmallInteger.prototype.valueOf = function () { + return this.value; + }; + SmallInteger.prototype.toJSNumber = SmallInteger.prototype.valueOf; + NativeBigInt.prototype.valueOf = NativeBigInt.prototype.toJSNumber = function () { + return parseInt(this.toString(), 10); + }; + + function parseStringValue(v) { + if (isPrecise(+v)) { + var x = +v; + if (x === truncate(x)) + return supportsNativeBigInt ? new NativeBigInt(BigInt(x)) : new SmallInteger(x); + throw new Error("Invalid integer: " + v); + } + var sign = v[0] === "-"; + if (sign) v = v.slice(1); + var split = v.split(/e/i); + if (split.length > 2) throw new Error("Invalid integer: " + split.join("e")); + if (split.length === 2) { + var exp = split[1]; + if (exp[0] === "+") exp = exp.slice(1); + exp = +exp; + if (exp !== truncate(exp) || !isPrecise(exp)) throw new Error("Invalid integer: " + exp + " is not a valid exponent."); + var text = split[0]; + var decimalPlace = text.indexOf("."); + if (decimalPlace >= 0) { + exp -= text.length - decimalPlace - 1; + text = text.slice(0, decimalPlace) + text.slice(decimalPlace + 1); + } + if (exp < 0) throw new Error("Cannot include negative exponent part for integers"); + text += (new Array(exp + 1)).join("0"); + v = text; + } + var isValid = /^([0-9][0-9]*)$/.test(v); + if (!isValid) throw new Error("Invalid integer: " + v); + if (supportsNativeBigInt) { + return new NativeBigInt(BigInt(sign ? "-" + v : v)); + } + var r = [], max = v.length, l = LOG_BASE, min = max - l; + while (max > 0) { + r.push(+v.slice(min, max)); + min -= l; + if (min < 0) min = 0; + max -= l; + } + trim(r); + return new BigInteger(r, sign); + } + + function parseNumberValue(v) { + if (supportsNativeBigInt) { + return new NativeBigInt(BigInt(v)); + } + if (isPrecise(v)) { + if (v !== truncate(v)) throw new Error(v + " is not an integer."); + return new SmallInteger(v); + } + return parseStringValue(v.toString()); + } + + function parseValue(v) { + if (typeof v === "number") { + return parseNumberValue(v); + } + if (typeof v === "string") { + return parseStringValue(v); + } + if (typeof v === "bigint") { + return new NativeBigInt(v); + } + return v; + } + // Pre-define numbers in range [-999,999] + for (var i = 0; i < 1000; i++) { + Integer[i] = parseValue(i); + if (i > 0) Integer[-i] = parseValue(-i); + } + // Backwards compatibility + Integer.one = Integer[1]; + Integer.zero = Integer[0]; + Integer.minusOne = Integer[-1]; + Integer.max = max; + Integer.min = min; + Integer.gcd = gcd; + Integer.lcm = lcm; + Integer.isInstance = function (x) { return x instanceof BigInteger || x instanceof SmallInteger || x instanceof NativeBigInt; }; + Integer.randBetween = randBetween; + + Integer.fromArray = function (digits, base, isNegative) { + return parseBaseFromArray(digits.map(parseValue), parseValue(base || 10), isNegative); + }; + + return Integer; + })(); + + // Node.js check + if ( module.hasOwnProperty("exports")) { + module.exports = bigInt; + } + }); + + /** + * @module signature + */ + + /** + * This function verifies the given raw consensus + * + * Note 1: TOR does not perform a full PKCS#1 v1.5 signature (RFC 2313) as mentioned in the TOR's reference. + * The padding of the data that must be signed is done following the reference (see subsection 8.1 of the + * RFC 2313 for more details), however the digest is not wrapped into the data structure described in the + * subsection 10.1.2. This is the reason why RSA is performed manually. + * + * Note 2: must be included in the HTML file using this function. + * + * @param {String} raw_cons the consensus we want to verify + * @param {Object} keys object mapping the authorities' fingerprint to their key with the following format: + * fingerprint:{ + * pem: key_pem //the key in pem format + * modulus: modulus //the modulus of the key as a string + * exponent: exponent //the exponent of the key as a string + * } + * @param {Number} minimal the minimal percentage of the signatures that must be verified in order to verify the consensus + * @returns {Boolean} the result of the verification + */ + function verify(raw_cons, keys, minimal, flavor = 'microdesc') { + if (minimal === undefined) { + minimal = 0.5; + } else if (minimal <= 0 || minimal > 1) { + throw 'The minimal percentage must be between 0 (not included) and 1' + } + + let nbr_verified = 0; + let total = 0; + + //get the hash of the consensus + let split_cons = raw_cons.split('directory-signature '); + raw_cons = split_cons[0] + "directory-signature "; + + let hash = (flavor == 'unflavored') ? sjcl.hash.sha1.hash(raw_cons) : sjcl.hash.sha256.hash(raw_cons); + hash = sjcl.codec.hex.fromBits(hash); + + // Get the signatures and the signing keys + let sig_and_keys_digests = get_sig_and_keys_digests(split_cons.splice(1)); + + for (let fingerprint in sig_and_keys_digests) { + total++; + + let key = keys[fingerprint]; + let e = BigInteger(key["exponent"]); + let n = BigInteger(key["modulus"]); + let key_digest = sig_and_keys_digests[fingerprint]["signing-key-digest"]; + + if (key === undefined || !verify_key(key["pem"], key_digest)) continue + + let signature = sig_and_keys_digests[fingerprint]["signature"]; + let sig_big_int = get_signature_big_int(signature); + let padded_hash = get_hash(sig_big_int, e, n); + let recovered_hash = get_hash_from_rsa_cipher(padded_hash); + + nbr_verified = (recovered_hash === undefined || recovered_hash !== hash) ? nbr_verified : nbr_verified + 1; + } + + return nbr_verified > minimal * total + } + + /** + * This function get the digest encrypted by the RSA corresponding to given the exponent and modulus + * + * @param {BigInteger} signature the encrypted signature + * @param {BigInteger} exponent the exponent of the key + * @param {BigInteger} modulus the modulus of the key + * @returns {String} the padded hash + */ + function get_hash(signature, exponent, modulus) { + let padded_hash = signature.modPow(exponent, modulus).toString(16); + let size = modulus.toString(16).length; + let offset = size - padded_hash.length; + for (let i = 0; i < offset; i++) { + padded_hash = "0" + padded_hash; + } + return padded_hash + } + + /** + * This function verifies that the key corresponds to one that signed the consensus + * + * @param {string} key the key with the format pem + * @param {string} key_digest the hex digest extracted from the consensus + */ + function verify_key(key, key_digest) { + let raw_key = key.split('\n'); + let b_index = raw_key.indexOf("-----BEGIN RSA PUBLIC KEY-----"); + let e_index = raw_key.indexOf("-----END RSA PUBLIC KEY-----"); + + raw_key = raw_key.splice(b_index + 1, e_index - b_index - 1).join(""); + raw_key = sjcl.codec.base64.toBits(raw_key); + let hash = sjcl.hash.sha1.hash(raw_key); + hash = sjcl.codec.hex.fromBits(hash); + return hash.toUpperCase() === key_digest.toUpperCase() + } + + + /** + * This function gets the signatures and the signing key digests from the authority section of the consensus + * + * @param {Array} remaining the remaining part of the consensus after the split by "directory-signature " + * @returns {object} the following mapping: + * fingerprint:{ + * signature-key-digest + * signature + * } + */ + function get_sig_and_keys_digests(remaining) { + let sign_and_digests = {}; + for (let r of remaining) { + if (r !== '') { + let split = r.split('\n'); + let b_index = split.indexOf("-----BEGIN SIGNATURE-----"); + let e_index = split.indexOf("-----END SIGNATURE-----"); + let sign = split.splice(b_index + 1, e_index - b_index - 1).join(""); + let digests = split[0].split(" "); + + let [fingerprint, key_hex_digest] = (digests.length == 2) ? digests : digests.splice(1); + + sign_and_digests[fingerprint] = { + "signing-key-digest": key_hex_digest, + "signature": sign + }; + } + } + return sign_and_digests + } + + /** + * + * This function transforms a signature in base64 into a bigInteger + * @param {string} signature the signature encoded in base64 + * @returns {BigInteger} the integer corresponding to the signature + */ + function get_signature_big_int(signature) { + let sig_hex = sjcl.codec.hex.fromBits(sjcl.codec.base64.toBits(signature)); + let sig = BigInteger(sig_hex, 16); + return sig + } + + /** + * Verifies that the cipher has the required format and extract the substring corresponding to the hash of the consensus + * + * @param {string} cipher the padded hash of the consensus + * @returns {string} the hash of the consensus + */ + function get_hash_from_rsa_cipher(padded_hash) { + + if (!padded_hash.startsWith("0001")) return undefined + padded_hash = padded_hash.substring(4); + let sep_index = padded_hash.indexOf("00"); + + for (let i = 1; i < sep_index; i++) { + if (padded_hash.charAt(i) !== "f") return undefined + } + + return padded_hash.substring(sep_index + 2) + } + + /** + * @module stream + */ + + let stream = {}; + stream.entrancy = 0; + + class Backend { + constructor(error) { + const sendMe = function (cell, endpoint) { + if (cell.cmd == "sendme") { + endpoint.stream.sendme += 1; + endpoint.stream.deliverywindow += 100; + // flush the send queue for the circuit + + while (endpoint.stream.deliverywindow > 0 && endpoint.stream.tosend.length > 0) { + const ncell = endpoint.stream.tosend.shift(); + endpoint.io.send(ncell); + endpoint.stream.deliverywindow -= 1; + } + } else { + error(endpoint); + throw "Got unexpected control cell."; + } + }; + + this.id = 0; + this.tosend = []; + this.sendme = 0; + this.handles = { 0: { callback: sendMe } }; + this.packagewindow = 1000; // circuit-level receiving window + this.deliverywindow = 1000; // circuit level sending window + } + + register(handle) { + this.id += 1; + handle.id = this.id; + handle.packagewindow = 500; // stream-level receiving window + handle.deliverywindow = 500; // stream level sending window + this.handles[this.id] = handle; + return this.id; + } + + send(cell, endpoint) { + if (this.deliverywindow > 0) { + // if we can send + endpoint.io.send(cell); + this.deliverywindow -= 1; + } else { + // add to the send queue, will be sent when "sendme" is received. + this.tosend.push(cell); + } + } + + } + + class Raw { + constructor(endpoint, handler) { + this.id = null; + this.data = []; + this.cell = null; + this.state = lnn$1.state.started; + this.packagewindow = null; + this.deliverywindow = null; + this.tosend = []; + this.endpoint = endpoint; + this.handler = handler; + + // let id = endpoint.stream.register(this); + this.handler(this); + } + + send(cmd, data) { + const cell = build( + this.endpoint, cmd, this.id, data); + + if (cmd != "data") { + this.endpoint.io.send(cell); // non-data cells dont affect congestion control + return; + } + + if (this.deliverywindow > 0) { // send if stream level window is non zero + this.endpoint.stream.send(cell, this.endpoint); // send thru circuit level window + this.deliverywindow -= 1; + } else { + this.tosend.push(cell); // add to queue of stream level window + } + } + + recv() { + const data = this.data; + this.data = []; + return data; + } + + callback(cell) { + if (cell.cmd == "connected") { + this.state = lnn$1.state.created; + } + if (cell.cmd == "end") { + this.state = lnn$1.state.success; + } + + if (cell.cmd == "sendme") { // receive stream level sendme + this.deliverywindow += 50; + while (this.deliverywindow > 0 && this.tosend.length > 0) { + const ncell = this.tosend.shift(); + this.endpoint.stream.send(ncell, this.endpoint); + this.deliverywindow -= 1; + } + } + + this.data.push(cell); + this.handler(this); + + if (cell.cmd == "connected") { + this.state = lnn$1.state.pending; + } + } + } + + class Dir { + constructor(endpoint, path, handler) { + this.id = null; + this.data = ""; + this.cell = null; + this.state = lnn$1.state.started; + this.packagewindow = null; + this.deliverywindow = null; + this.tosend = []; + this.endpoint = endpoint; + + this.handler = handler; + this.path = path; + + const id = endpoint.stream.register(this); + let cell = build(endpoint, "begin_dir", id); + endpoint.io.send(cell); + + let data = "GET " + path + " HTTP/1.0\r\n"; + data += "Accept-Encoding: identity\r\n\r\n"; + data = dec.utf8(data); + + cell = build(endpoint, "data", id, data); + this.deliverywindow -= 1; + endpoint.stream.send(cell, endpoint); + + this.handler(this); + } + + send() { + throw "No send method on directory streams."; + } + + recv() { + const data = this.data; + this.data = ""; + return data; + } + + callback(cell) { + if (cell.cmd == "connected") { + this.state = lnn$1.state.created; + this.handler(this); + this.state = lnn$1.state.pending; + } + if (cell.cmd == "end") { + this.state = lnn$1.state.success; + this.handler(this); + } + if (cell.cmd == "sendme") { + this.deliverywindow += 50; + while (this.deliverywindow > 0 && this.tosend.length > 0) { + const ncell = this.tosend.shift(); + this.endpoint.stream.send(ncell, this.endpoint); + this.deliverywindow -= 1; + } + } + + if (cell.cmd != "data") { return; } + + this.data += enc.utf8(cell.data); + this.handler(this); + } + } + + class TCP { + constructor(endPoint, host, port, handler) { + this.id = null; + this.data = new Uint8Array(0); + this.cell = null; + this.cache = []; + + this.state = lnn$1.state.started; + this.packagewindow = null; + this.deliverywindow = null; + this.tosend = []; + this.endpoint = endPoint; + this.retries = 0; + + this.host = host; + this.port = port; + this.handler = handler; + + // WL: Get new identifier for stream? + const id = endPoint.stream.register(this); + + // WL: Create a BEGIN package containing host and port of the server? + const data = relay.begin(host, port); + + // WL: Construct the cell around it? + const cell = build(endPoint, "begin", id, data); + + // WL: Send that sell to start the process? + this.endpoint.io.send(cell); + + this.handler(this); + + this.send = this.send.bind(this); + + } + + send(send_data) { + if (send_data !== undefined) { + this.cache.push(send_data); + } + + if (this.state == lnn$1.state.started) { // not yet recvd reply for relay begin + return; + } + + while (this.cache.length) { + let data = this.cache.shift(); + + if (typeof (data) == "string") { + data = lnn$1.dec.utf8(data); + } + + const payload = new Uint8Array(lnn$1.relay.data_len); + + while (data.length > payload.length) { + payload.set(data.slice(0, payload.length), 0); + data = data.slice(payload.length); + + const cell = lnn$1.onion.build( + this.endpoint, "data", this.id, payload); + + if (this.deliverywindow > 0) { + this.endpoint.stream.send(cell, this.endpoint); + this.deliverywindow -= 1; + } else { + this.tosend.push(cell); + } + + } + + const cell = lnn$1.onion.build( + this.endpoint, "data", this.id, data); + + if (this.deliverywindow > 0) { + this.endpoint.stream.send(cell, this.endpoint); + this.deliverywindow -= 1; + } else { + this.tosend.push(cell); + } + } + } + + + + callback(cell) { + console.log(cell.cmd); + if (cell.cmd == "connected") { + this.state = lnn$1.state.created; + this.retries = 0; + this.send(); + } + if (cell.cmd == "end") { + if (cell.data[0] == 4) { // REASON EXIT_POLICY + if (this.retries == 3) { // threshold for retrying + console.log('Retries limit exceeded. Cant connect to host. '); + this.state = lnn$1.state.success; + this.retries = 0; + } else { + this.retries += 1; + console.log("Retrying to build circuit, retry#: " + this.retries); + + let ports = [80, 443]; + + if (!ports.includes(this.port)) { + ports.push(this.port); + } + + lnn$1.open( + this.endpoint.host, + this.endpoint.port, + this.success_on_open, + this.error_on_open, + undefined, + this.endpoint.fast, + this.endpoint.auth, + this.endpoint.select_path, + ports + ); + } + } else { + this.state = lnn$1.state.success; + } + } + if (cell.cmd == "data") { + const data = this.data; + this.data = new Uint8Array(data.length + cell.data.length); + this.data.set(data, 0); + this.data.set(cell.data, data.length); + } + if (cell.cmd == "sendme") { + + this.deliverywindow += 50; + while (this.deliverywindow > 0 && this.tosend.length > 0) { + const ncell = this.tosend.shift(); + this.endpoint.stream.send(ncell, this.endpoint); + this.deliverywindow -= 1; + } + } + + this.handler(this); + if (cell.cmd == "connected") { + this.state = lnn$1.state.pending; + } + } + + recv() { + const data = this.data; + this.data = new Uint8Array(0); + return data; + } + + close() { + let data = new Uint8Array(1); + data[0] = 6; // reason done + const cell = build(this.endpoint, "end", this.id, data); + this.endpoint.io.send(cell); + } + + success_on_open(endp) { + if (endp.consensus === null) + endp.consensus = this.endpoint.consensus; + if (endp.descriptors === null) + endp.descriptors = this.endpoint.descriptors; + if (endp.consensus_raw === null) + endp.consensus_raw = this.endpoint.consensus_raw; + if (endp.descriptors_raw === null) + endp.descriptors_raw = this.endpoint.descriptors_raw; + if (endp.signing_keys === null) + endp.signing_keys = this.endpoint.signing_keys; + + this.endpoint = endp; + + const id = this.endpoint.stream.register(this); + const data = lnn$1.relay.begin(this.host, this.port); + const cell = lnn$1.onion.build(this.endpoint, "begin", id, data); + this.endpoint.io.send(cell); + + this.handler(this); + } + + + error_on_open(error_msg) { + throw error_msg; + } + } + + stream.handler = function (endpoint, cell) { + stream.entrancy += 1; + if (stream.entrancy > 1) { + console.log("ENTRANCY BUG"); + } + + if (cell[4] != 3) { // (relay cell only) + console.log("Got non-relay cell, dropped: ", cell[4]); + stream.entrancy -= 1; + return; + } + + cell = peel(endpoint, cell); + if (cell === null) { + console.log("Got invalid cell, dropped."); + stream.entrancy -= 1; + return; + } + + if (!(cell.stream_id in endpoint.stream.handles)) { + console.log("Got cell outside stream, dropped: ", cell.stream_id); + stream.entrancy -= 1; + return; + } + + let handle = endpoint.stream.handles[cell.stream_id]; + if (cell.cmd == "end") + delete endpoint.stream.handles[cell.stream_id]; + + handle.cell = cell; + handle.callback(cell, endpoint); + + /* handle circuit-level sendme */ + + + if (cell.cmd == "data") { + endpoint.stream.packagewindow -= 1; + } + console.log('Update window: ', endpoint.stream.packagewindow); + if (endpoint.stream.packagewindow < 900) { + //console.log("Circuit window is ", endpoint.stream.packagewindow) + //console.log("Sending circuit level sendme cell now ", endpoint.io.counter) + endpoint.io.send(build(endpoint, 'sendme')); + endpoint.stream.packagewindow += 100; + } + + /* handle stream-level sendme */ + if (cell.cmd == "data") { + handle.packagewindow -= 1; + } + if (handle.packagewindow < 450) { + //console.log("Stream window is ", handle.packagewindow) + //console.log("Sending stream level sendme cell now ", endpoint.io.counter) + cell = build(endpoint, 'sendme', handle.id); + endpoint.io.send(cell); + handle.packagewindow += 50; + } + + stream.entrancy -= 1; + }; + + stream.backend = (error) => new Backend(error); + stream.raw = (endpoint, handler) => new Raw(endpoint, handler); + stream.dir = (endpoint, path, handler) => new Dir(endpoint, path, handler); + stream.tcp = (endPoint, host, port, handler) => new TCP(endPoint, host, port, handler); + + /** + * @module api + */ + + function fast(host, port, success, error, io, select_path) { + if (select_path === undefined) + select_path = true; + return open(host, port, success, error, io, true, null, select_path) + } + + function auth(host, port, suffix, success, error, io, select_path) { + if (select_path === undefined) + select_path = true; + if (typeof (suffix) == "string") { + suffix = suffix.replace(/-/g, "+").replace(/_/g, "/"); + suffix = dec.base64(suffix); + } + if (enc.utf8(suffix.slice(0, 5)) != "auth ") + throw "Invalid prefix in auth. suffix!" + + suffix = suffix.slice(5); + if (suffix.length != 20 + 32) + throw "Invalid auth. suffix length!" + + return open(host, port, success, error, io, true, { + identity: suffix.slice(0, 20), + onionkey: suffix.slice(20), + ntor: nacl.box.keyPair() + }, select_path) + } + + function open(host, port, success, error, io, fast, auth, select_path, tcp_ports) { + let endpoint$1 = endpoint(host, port); + if (io === undefined) + io = socket; + if (fast === undefined) + fast = false; + if (error === undefined) + error = function () { }; + if (success === undefined) + success = function () { }; + if (select_path === undefined) + select_path = true; + if (tcp_ports === undefined) + tcp_ports = [80, 443]; + + endpoint$1.fast = fast; + endpoint$1.auth = auth; + endpoint$1.select_path = select_path; + + var cb = { + guard: function (endpoint) { + endpoint.state = lnn.state.guarded; + + + circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports); + }, + startWebSocket: function (endpoint, info) { + console.log('called startWebSocket cb'); + endpoint.stream = stream.backend(error); + io(endpoint, stream.handler, function (endpoint) { + var state = endpoint.state; + + endpoint.state = lnn.state.pending; + + endpoint.state = state; + }, error); + endpoint.io.start(); + + handshake(endpoint, info, cb.create); + }, + create: function (endpoint) { + console.log('called create cb'); + endpoint.state = lnn.state.created; + + + extend(endpoint, endpoint.path[0], cb.extend, error); + }, + extend: function (endpoint) { + console.log('called extend cb'); + endpoint.state = lnn.state.extpath; + + + extend(endpoint, endpoint.path[1], cb.success, error); + }, + success: function (endpoint) { + console.log('called success cb'); + endpoint.state = lnn.state.success; + success(endpoint); + endpoint.io.success = function () { }; + } + }; + + endpoint$1.state = lnn.state.started; + + + if (select_path) { + consensus_raw(endpoint$1, function () { + signing_keys(endpoint$1, function () { + if (!verify(endpoint$1.consensus_raw, endpoint$1.signing_keys, 0.5)) { + throw "signature verification failed." + } + console.log("signature verification success"); + descriptors_raw(endpoint$1, function () { + if (endpoint$1.fast) + circuit_info(endpoint$1, cb.startWebSocket, error, select_path, tcp_ports); + else + guard(endpoint$1, cb.guard, error); + + }, function () { + throw "Failed to fetch raw descriptors" + }); + }, function () { + throw "Failed to fetch signing keys" + }); + }, function () { + throw "Failed to fetch raw consensus!" + }); + } + else { + // fast channel: one-request channel creation (no guard pinning) + if (endpoint$1.fast) + circuit_info(endpoint$1, cb.startWebSocket, error, select_path, tcp_ports); + else + guard(endpoint$1, cb.guard, error); + } + + return endpoint$1 + } + + + /***** high level apis ****/ + + let agents = [ + "curl/7.61.0", + "curl/7.60.0", + "curl/7.59.0", + "curl/7.58.0", + "curl/7.57.0", + "curl/7.56.1", + "curl/7.56.0", + "curl/7.55.1", + "curl/7.55.0", + "curl/7.54.1", + "curl/7.54.0", + "curl/7.53.1", + "curl/7.53.0", + "curl/7.52.1", + "curl/7.52.0", + "curl/7.51.0", + "curl/7.50.3", + "curl/7.50.2", + "curl/7.50.1", + "curl/7.50.0", + "curl/7.50.0", + "curl/7.49.1", + "curl/7.49.0", + "curl/7.48.0", + "curl/7.47.1", + "curl/7.47.0", + "curl/7.46.0", + "curl/7.45.0", + "curl/7.44.0", + "curl/7.43.0", + "curl/7.42.1", + "curl/7.42.0", + "curl/7.41.0", + "curl/7.40.0", + "curl/7.39.0", + "curl/7.38.0" + ]; + + function send_req(endpoint, url, method, data, data_type, success, error) { + var agent = agents[Math.floor(Math.random() * agents.length)]; + + var data_recv = ''; + var length = null; + var rawlen = 0; + var headers = null; + var handler = function (request) { + if (request.state == lnn.state.success) { + error('Connection closed'); + return + } + + if (request.state != lnn.state.pending) + return + + var payload = request.recv(); + rawlen += payload.length; + data_recv += enc.utf8(payload); + + + if (length == null) { + if (data_recv.match('\r\n\r\n')) { + headers = data_recv.split('\r\n\r\n')[0]; + var len = headers.match('Content-Length: ([^\r]*)'); + length = parseInt(len[1]); + } + } + + if (headers == null || length == null || rawlen < headers.length + length) + return + + request.close(); + console.log("Stream closed"); + + success({ + headers: headers, + data: data_recv.slice(headers.length + 4) + }); + success = function (request) { }; + }; + + if (url.slice(0, 7) == "http://") + url = url.slice(7); + else { + error('Urls must start with http://'); + return + } + + var path = "/" + url.split("/").slice(1).join("/"); + var host = null; + if (url.match("/") == null) + host = url; + else + host = url.split("/", 1)[0]; + + var port = "80"; + if (host.match(":") != null) + port = host.split(":", 2)[1]; + + if (method != "GET" && method != "POST") { + error('Unsupported method'); + return + } + + if (data_type != "json" && data_type != "form") { + error('Unsupported content type'); + return + } + + if (data_type == "json") + data_type = "application/json"; + else + data_type = "application/x-www-form-urlencoded"; + + if (method == "GET" && data.length > 0) { + data = "?" + data; + path += data; + path = encodeURI(path); + } + else if (data_type == "application/x-www-form-urlencoded") { + data = encodeURI(data); + } + + var payload = [ + [method, path, "HTTP/1.1"].join(" "), + ["Host:", host].join(" "), + ["User-Agent:", agent].join(" "), + ["Accept:", "*/*"].join(" ")]; + + if (method == "POST") { + payload.push(["Content-Length:", data.length].join(" ")); + payload.push(["Content-Type:", data_type].join(" ")); + payload = payload.join("\r\n") + "\r\n\r\n" + data + "\r\n"; + } + else { + payload = payload.join("\r\n") + "\r\n\r\n"; + } + + + console.log(payload); + + host = host.split(':')[0]; + stream.tcp(endpoint, host, port, handler).send(payload); + } + + function http_request(url, method, data, data_type, success, error, tor_host, tor_port) { + if (tor_host === undefined) + tor_host = 'localhost'; + if (tor_port === undefined) + tor_port = 4990; + if (error === undefined) + error = function () { }; + if (success === undefined) + success = function () { }; + + var closed = false; + + var channel = open( + tor_host, tor_port, function (endpoint) { + if (endpoint.state != lnn.state.success) { + return + } + + send_req(endpoint, url, method, data, data_type, function (request) { + //close circuit here. + if (!closed) { + endpoint.close(function (success_msg) { console.log(success_msg); }); + closed = true; + } + success(request); + }, function (message) { + //close circuit here + if (!closed) { + endpoint.close(function (success_msg) { console.log(success_msg); }); + closed = true; + } + error(message); + }); + + } + , function () { + error("Connection establishment failed"); + } + ); + } + + /** + * @module endpoint + */ + + + /** + * Create an empty endpoint object, consider using {@link lnn.open} first. + * + * @todo TODO: migrate from http+ws to https+wss + * @todo TODO: use only one port for https+wss + * + * @param {string} host (ex: localhost, example.com) + * @param {string} port (ex: 4990, 8080, 5000, 443…) + * @return {endpoint_t} + */ + function endpoint(host, port) { + var http = "http://" + host + ":" + port.toString(); + http += lnn$1.api.url; + + var ws = "ws://" + host + ":" + lnn$1.api.ws_port; + ws += lnn$1.api.url; + + /** + * Internal object, stores API urls used for parent endpoint calls. + * + *
      +	     * Note: {@link lnn.api.ws_port} is inlined in .ws and .socket
      +	     *       (used by {@link lnn.io.socket}).
      +	     * 
      + * + * @interface endpoint_t~urls_t + * @see endpoint_t + * + * @property {string} ws websocket base url + * @property {string} http http calls base url + * @property {string} guard GET /consensus + * @property {string} consensus GET /consensus + * @property {string} socket websocket endpoint + * @property {string} channels POST+DELETE /channels + * @property {string} consensus GET /consensus + */ + var urls = { + ws: ws, + http: http, + guard: http + "/guard", + socket: ws + "/channels", + channels: http + "/channels", + consensus: http + "/consensus", + descriptors: http + "/descriptors", + signing_keys: http + "/signing-keys" + }; + + /** + * Captures the state of a channel, returned by {@link lnn.open}. + * + * @interface endpoint_t + * @see lnn.endpoint + * + * @property {lnn.state} state channel state + * @property {io.io_t} io io adapter in use + * @property {endpoint_t~urls_t} urls static API urls in use + * @property {backend_t} stream stream backend in use + * @property {backward_t} backward backward cryptographic state + * @property {forward_t} forward forward cryptographic state + * @property {material_t|half_t} material shared cryptographic material + * @property {null|half_t} auth stores {@link lnn.auth} + * material + * @property {Boolean} fast is {@link lnn.fast} + * in use? + */ + var endpoint = { + /** + * Host in use, as given to {@link lnn.endpoint} factory. + * + * @name endpoint_t#host + * @readonly + */ + host: host, + /** + * Port in use, as given to {@link lnn.endpoint} factory. + * + * @name endpoint_t#port + * @readonly + */ + port: port, + fast: null, + auth: null, + urls: urls, + io: null, + state: 0, + /** + * Last shared cryptographic material retrieved, written by: + *
        + *
      • {@link lnn.post.create} + *
      • {@link lnn.post.extend} + *
      • {@link lnn.ntor.hand} + *
      • {@link lnn.ntor.fast} + *
      • {@link lnn.ntor.auth} + *
      + * + * Either stores {@link material_t} or {@link half_t}. + * + * @name endpoint_t#material + * @type {material_t|half_t} + * + * @see lnn.ntor.hand + */ + material: null, + forward: null, + backward: null, + /** + * Identifier of the channel in used, written by successful a + * {@link lnn.post.create} call. + * @name endpoint_t#id + * @readonly + * @default null + */ + id: null, + /** + * Polling url endpoint used for polling io requests. + * @see lnn.post.channel + * @see lnn.io.polling + * + * @name endpoint_t#url + * @readonly + * @default null + */ + url: null, + /** + * Middle and Exit nodes descriptors obtained by {@link lnn.open} + * during channel setup. + * + *
      +	         * Note: writing this field will NOT change the path in use.
      +	         * 
      + * + * @name endpoint_t#path + * @readonly + * @default null + */ + path: null, + /** + * Guard descriptor obtained by {@link lnn.open} during channel + * setup, written by {@link lnn.get.guard}. + * + * @name endpoint_t#guard + * @readonly + * @default null + */ + guard: null, + stream: null, + /** + * Consensus obtained by {@link lnn.get.consensus} upon request. + * + * @name endpoint_t#consensus + * @readonly + * @default null + */ + consensus: null, + + /** + * Consensus obtained by {@link lnn.get.descriptors} upon request + * @name endpoint_t#descriptors + * @readonly + * @default null + */ + descriptors: null, + consensus_raw: null, + descriptors_raw: null, + signing_keys: null, + + select_path: false, + + /*perform http get/post request*/ + + http_request: function (url, method, data, data_type, success, error) { + if (error === undefined) + error = function () { }; + if (success === undefined) + success = function () { }; + + send_req(endpoint, url, method, data, data_type, success, error); + }, + + /*destroy the circuit*/ + close: function (success, error) { + close(endpoint, success, error); + } + }; + + return endpoint + } + + /** + * Utility functions. + */ + + + /** + * Parse the given url. + * {@link https://www.w3.org/TR/2012/CR-websockets-20120920/#parse-a-websocket-url-s-components} + * @param {URL} url the url to parse + * @returns [host, port, ressourceName, secure] + * @throws error when url is incorrect for a websocket connection + * @private + */ + function parseURL(url) { + // 1. if the url string is not an absolute URL, then fail this algorithm + const absoluteURLChecker = new RegExp('^(?:[a-z]+:)?//', 'i'); + if (!absoluteURLChecker.test(url.href)) { + throw `url is not absolute: ${url}`; + } + + // 2. resolve the url string, with the URL character encoding set to UTF-8. + + // 3. if url does not have a component whose value + // when converted to ASCII lowercase, is either "ws" or "wss", + // then fail this algorithm. + if (url.protocol !== "ws:" && url.protocol !== "wss:") { + throw `url scheme must be either 'ws:' or 'wss:', but is: ${url.protocol}`; + } + + // 4. f url has a component, then fail this algorithm. + if (url.hash.substr(1) !== "") { + throw `url cannot have a fragment: ${url}`; + } + + // 5. if the component of url is "ws", set secure to false; + // otherwise, the component is "wss", set secure to true. + const secure = url.protocol === "ws:" ? false : true; + + // 6. let host be the value of the component of url, + // converted to ASCII lowercase. + const host = url.hostname.toLowerCase(); + + // 7. If url has a component, then let port be that component's value; + // otherwise, there is no explicit port. + // 8. if there is no explicit port, then: if secure is false, let port be 80, + // otherwise let port be 443. + const port = url.port || (url.protocol === "ws:" ? "80" : "443"); + + // 9. let resource name be the value of the component (which might be empty) of url. + // 10. if resource name is the empty string, set it to a single character U+002F SOLIDUS (/). + let ressourceName = url.pathname || "/"; + + // 11. if url has a component, then append a single U+003F QUESTION MARK character (?) to resource name, + // followed by the value of the component. + if (url.search) { + ressourceName += url.search; + } + + // 12. return host, port, resource name, and secure. + return [host, port, ressourceName, secure]; + } + + /** + * Mask given input with given key, as specified for websocket masking + * @param {Uint8Array} x input to mask/unmask + * @param {Uint8Array} key 4-bytes key + * @private + */ + function maskWithKey(x, key) { + let out = new Uint8Array(x.length); + for (let i = 0; i < x.length; i++) { + out[i] = x[i] ^ key[i % 4]; + } + return out; + } + + /** + * Concatenate Uint8Arrays. + * @private + */ + function concatenate(...arrays) { + let len = 0; + for (let arr of arrays) { + len += arr.length; + } + let result = new Uint8Array(len); + let offset = 0; + for (let arr of arrays) { + result.set(arr, offset); + offset += arr.length; + } + return result; + } + + /** + * Packet crafting for the WebSocket protocol. + * + * WebSocket frame (RFC 6455): + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|M| Payload len | Extended payload length | + * |I|S|S|S| (4) |A| (7) | (16/64) | + * |N|V|V|V| |S| | (if payload len==126/127) | + * | |1|2|3| |K| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | |Masking-key, if MASK set to 1 | + * +-------------------------------+-------------------------------+ + * | Masking-key (continued) | Payload Data... | + * +---------------------------------------------------------------| + * + */ + + /** + * Construct the HTTP packet send by the client during the WebSocket handshake. + * @returns {Array} [pkt, nonce] the HTTP client handshake packet as a string, with the Uint8Array SecWebSocketKey nonce used in it + * @private + */ + function clientHandshake(host, port, resourceName, protocols = []) { + // TODO: + // - Sec-WebSocket-Protocol + // - Sec-WebSocket-Extensions + + // create the nonce: base64 encoded 16 random bytes + const nonce = naclFast.randomBytes(16); + const nonceB64 = naclUtil.encodeBase64(nonce); + + // create the http packet + let fields = [ + ["GET", `${resourceName}`, "HTTP/1.1"], + ["Host:", `${host}:${port}`], + ["Connection:", "Upgrade"], + ["Upgrade:", "websocket"], + ["Sec-WebSocket-Key:", `${nonceB64}`], + ["Origin:", `${host}`], + ["Sec-WebSocket-Version:", "13"], + ]; + + if (Array.isArray(protocols) && protocols.length > 0) { + fields.push(["Sec-WebSocket-Protocol:", protocols.join(", ")]); + } + + const pkt = fields.map(s => s.join(" ")).join("\r\n") + "\r\n\r\n"; + + return [pkt, nonce]; + } + + /** + * The GUID used for the Sec-WebSocket verification. + * @private + */ + const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + /** + * Construct a pong frame. + * @param {Uint8Array} payload the pong payload, usually the application data of the received ping + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @private + */ + function pongFrame(payload, maskingKey = undefined) { + return Frame._encapsulate(payload, "1000", opcodes.pong, maskingKey); + } + + /** + * Construct a close frame + * @param {Number} code status code for closing the connection (2bytes) + * @param {reason} string reason for closing the connection + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @private + */ + function closeFrame(code, reason = undefined, maskingKey = undefined) { + if (code < 0 || code >= 65536) { + throw `cannot encode int ${code} to 2 bytes`; + } + let payload = new Uint8Array([ + code >> 8, + code & 255 + ]); + if (reason) { + payload = concatenate(concatenate, naclUtil.decodeUTF8(reason)); + } + + return Frame._encapsulate(payload, "1000", opcodes.close, maskingKey); + } + + let opcodes = { + continuation: 0, + text: 1, + binary: 2, + // x3-7 reserved for further non-control frames + close: 8, + ping: 9, + pong: 10, + // xB-F reserved for further control frames + }; + + let isControlFrame = (opcode) => (opcode & 8) === 8; + + /** + * Represent a WebSocket frame, not fragmented. + * + * See websocket framing protocol: + * {@link https://tools.ietf.org/html/rfc6455#section-5.2}. + * @private + */ + class Frame { + + /** + * Construct a WebSocket Frame. + * + * @param {Boolean} rsv1 + * @param {Boolean} rsv2 + * @param {Boolean} rsv3 + * @param {Integer} opcode + * @param {Uint8Array} payload + */ + constructor(rsv1, rsv2, rsv3, opcode, payload) { + this.rsv1 = rsv1 ? "1" : "0"; + this.rsv2 = rsv2 ? "1" : "0"; + this.rsv3 = rsv3 ? "1" : "0"; + this.opcode = opcode; + this.payload = payload; + } + + // Return true if the frame represents a control frame + isControl() { + return isControlFrame(this.opcode); + } + + /** + * Encapsulate Frame into a WebSocket packet in byte array format. + * + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @returns {Uint8Array} packet + */ + encapsulate(maskingKey = undefined) { + const flags = "1".concat(this.rsv1, this.rsv2, this.rsv3); + return Frame._encapsulate(this.payload, flags, this.opcode, maskingKey); + } + + /** + * Fragment frame into several websocket packets. + * To be used in place of the `encapsulate` method when fragmentation is needed. + * + * @param {int} chunkSize the maximum length of a (websocket) payload, in bytes + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @returns {Array} an array of Uint8Array, that contains in-order websocket-encapsulated packets + */ + fragment(chunkSize, maskingKey = undefined) { + // chunk payload into smaller payloads + let payloads = []; + for (let i = 0; i < this.payload.length; i += chunkSize) { + payloads.push(this.payload.slice(i, i + chunkSize)); + } + + // create packets + let packets = []; + for (let i = 0; i < payloads.length; i++) { + // only the last fragment has the FIN flag set + const finFlag = (i !== (payloads.length - 1)) ? "0" : "1"; + const flags = finFlag.concat(this.rsv1, this.rsv2, this.rsv3); + // only the first fragment has the opcode set + const code = (i === 0) ? this.opcode : opcodes.continuation; + + packets.push(Frame._encapsulate(payloads[i], flags, code, maskingKey)); + } + + return packets; + } + + /** + * Encapsulate given data into a WebSocket packet in byte array format. + * + * @param {Uint8Array} payload the packet payload + * @param {string} flags the first 4 bits of the packet, FIN/RSV1/RSV2/RSV3 in bitstring format + * @param {int} opcode the integer opcode + * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes + * @returns {Uint8Array} packet + */ + static _encapsulate(payload, flags = "1000", opcode = 1, maskingKey = undefined) { + const opcodeBits = opcode.toString(2).padStart(4, '0'); + + let payloadLen; + if (payload.length >= 126) { + if (payload.length < 65536) { + // use next two bytes to encode the payload length + let code = 126; + payloadLen = code.toString(2).padStart(7, '0'); + payloadLen += payload.length.toString(2).padStart(16, '0'); + + } else { + if (payload.length > 2 ^ (8 * 8)) { + throw `Error: payload too large for the websocket protocol`; + } + // use next eight bytes to encode the payload length + let code = 127; + payloadLen = code.toString(2).padStart(7, '0'); + payloadLen += payload.length.toString(2).padStart(64, '0'); + } + } else { + payloadLen = payload.length.toString(2).padStart(7, '0'); + } + + let mask = '1'; + if (maskingKey === undefined) { + // create a nonce + maskingKey = new Uint8Array(naclFast.randomBytes(4)); + } + const maskedPayload = maskWithKey(payload, maskingKey); + + function bitstringToUint8Array(bitstring) { + const len = Math.ceil(bitstring.length / 8); + let out = new Uint8Array(len); + for (let i = 0; i < len; i++) { + out[i] = parseInt(bitstring.slice(8 * i, 8 * i + 8), 2); + } + return out; + } + + let headerStart = bitstringToUint8Array(flags + opcodeBits + mask + payloadLen); + + return Uint8Array.from([...headerStart, ...maskingKey, ...maskedPayload]); + } + } + + /** + * Node.js module for Forge. + * + * @author Dave Longley + * + * Copyright 2011-2016 Digital Bazaar, Inc. + */ + var forge = { + // default options + options: { + usePureJavaScript: false + } + }; + + /** + * Base-N/Base-X encoding/decoding functions. + * + * Original implementation from base-x: + * https://github.com/cryptocoinjs/base-x + * + * Which is MIT licensed: + * + * The MIT License (MIT) + * + * Copyright base-x contributors (c) 2016 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + var api = {}; + var baseN = api; + + // baseN alphabet indexes + var _reverseAlphabets = {}; + + /** + * BaseN-encodes a Uint8Array using the given alphabet. + * + * @param input the Uint8Array to encode. + * @param maxline the maximum number of encoded characters per line to use, + * defaults to none. + * + * @return the baseN-encoded output string. + */ + api.encode = function(input, alphabet, maxline) { + if(typeof alphabet !== 'string') { + throw new TypeError('"alphabet" must be a string.'); + } + if(maxline !== undefined && typeof maxline !== 'number') { + throw new TypeError('"maxline" must be a number.'); + } + + var output = ''; + + if(!(input instanceof Uint8Array)) { + // assume forge byte buffer + output = _encodeWithByteBuffer(input, alphabet); + } else { + var i = 0; + var base = alphabet.length; + var first = alphabet.charAt(0); + var digits = [0]; + for(i = 0; i < input.length; ++i) { + for(var j = 0, carry = input[i]; j < digits.length; ++j) { + carry += digits[j] << 8; + digits[j] = carry % base; + carry = (carry / base) | 0; + } + + while(carry > 0) { + digits.push(carry % base); + carry = (carry / base) | 0; + } + } + + // deal with leading zeros + for(i = 0; input[i] === 0 && i < input.length - 1; ++i) { + output += first; + } + // convert digits to a string + for(i = digits.length - 1; i >= 0; --i) { + output += alphabet[digits[i]]; + } + } + + if(maxline) { + var regex = new RegExp('.{1,' + maxline + '}', 'g'); + output = output.match(regex).join('\r\n'); + } + + return output; + }; + + /** + * Decodes a baseN-encoded (using the given alphabet) string to a + * Uint8Array. + * + * @param input the baseN-encoded input string. + * + * @return the Uint8Array. + */ + api.decode = function(input, alphabet) { + if(typeof input !== 'string') { + throw new TypeError('"input" must be a string.'); + } + if(typeof alphabet !== 'string') { + throw new TypeError('"alphabet" must be a string.'); + } + + var table = _reverseAlphabets[alphabet]; + if(!table) { + // compute reverse alphabet + table = _reverseAlphabets[alphabet] = []; + for(var i = 0; i < alphabet.length; ++i) { + table[alphabet.charCodeAt(i)] = i; + } + } + + // remove whitespace characters + input = input.replace(/\s/g, ''); + + var base = alphabet.length; + var first = alphabet.charAt(0); + var bytes = [0]; + for(var i = 0; i < input.length; i++) { + var value = table[input.charCodeAt(i)]; + if(value === undefined) { + return; + } + + for(var j = 0, carry = value; j < bytes.length; ++j) { + carry += bytes[j] * base; + bytes[j] = carry & 0xff; + carry >>= 8; + } + + while(carry > 0) { + bytes.push(carry & 0xff); + carry >>= 8; + } + } + + // deal with leading zeros + for(var k = 0; input[k] === first && k < input.length - 1; ++k) { + bytes.push(0); + } + + if(typeof Buffer !== 'undefined') { + return Buffer.from(bytes.reverse()); + } + + return new Uint8Array(bytes.reverse()); + }; + + function _encodeWithByteBuffer(input, alphabet) { + var i = 0; + var base = alphabet.length; + var first = alphabet.charAt(0); + var digits = [0]; + for(i = 0; i < input.length(); ++i) { + for(var j = 0, carry = input.at(i); j < digits.length; ++j) { + carry += digits[j] << 8; + digits[j] = carry % base; + carry = (carry / base) | 0; + } + + while(carry > 0) { + digits.push(carry % base); + carry = (carry / base) | 0; + } + } + + var output = ''; + + // deal with leading zeros + for(i = 0; input.at(i) === 0 && i < input.length() - 1; ++i) { + output += first; + } + // convert digits to a string + for(i = digits.length - 1; i >= 0; --i) { + output += alphabet[digits[i]]; + } + + return output; + } + + var util_1 = createCommonjsModule(function (module) { + /** + * Utility functions for web applications. + * + * @author Dave Longley + * + * Copyright (c) 2010-2018 Digital Bazaar, Inc. + */ + + + + /* Utilities API */ + var util = module.exports = forge.util = forge.util || {}; + + // define setImmediate and nextTick + (function() { + // use native nextTick (unless we're in webpack) + // webpack (or better node-libs-browser polyfill) sets process.browser. + // this way we can detect webpack properly + if(typeof process !== 'undefined' && process.nextTick && !process.browser) { + util.nextTick = process.nextTick; + if(typeof setImmediate === 'function') { + util.setImmediate = setImmediate; + } else { + // polyfill setImmediate with nextTick, older versions of node + // (those w/o setImmediate) won't totally starve IO + util.setImmediate = util.nextTick; + } + return; + } + + // polyfill nextTick with native setImmediate + if(typeof setImmediate === 'function') { + util.setImmediate = function() { return setImmediate.apply(undefined, arguments); }; + util.nextTick = function(callback) { + return setImmediate(callback); + }; + return; + } + + /* Note: A polyfill upgrade pattern is used here to allow combining + polyfills. For example, MutationObserver is fast, but blocks UI updates, + so it needs to allow UI updates periodically, so it falls back on + postMessage or setTimeout. */ + + // polyfill with setTimeout + util.setImmediate = function(callback) { + setTimeout(callback, 0); + }; + + // upgrade polyfill to use postMessage + if(typeof window !== 'undefined' && + typeof window.postMessage === 'function') { + var msg = 'forge.setImmediate'; + var callbacks = []; + util.setImmediate = function(callback) { + callbacks.push(callback); + // only send message when one hasn't been sent in + // the current turn of the event loop + if(callbacks.length === 1) { + window.postMessage(msg, '*'); + } + }; + function handler(event) { + if(event.source === window && event.data === msg) { + event.stopPropagation(); + var copy = callbacks.slice(); + callbacks.length = 0; + copy.forEach(function(callback) { + callback(); + }); + } + } + window.addEventListener('message', handler, true); + } + + // upgrade polyfill to use MutationObserver + if(typeof MutationObserver !== 'undefined') { + // polyfill with MutationObserver + var now = Date.now(); + var attr = true; + var div = document.createElement('div'); + var callbacks = []; + new MutationObserver(function() { + var copy = callbacks.slice(); + callbacks.length = 0; + copy.forEach(function(callback) { + callback(); + }); + }).observe(div, {attributes: true}); + var oldSetImmediate = util.setImmediate; + util.setImmediate = function(callback) { + if(Date.now() - now > 15) { + now = Date.now(); + oldSetImmediate(callback); + } else { + callbacks.push(callback); + // only trigger observer when it hasn't been triggered in + // the current turn of the event loop + if(callbacks.length === 1) { + div.setAttribute('a', attr = !attr); + } + } + }; + } + + util.nextTick = util.setImmediate; + })(); + + // check if running under Node.js + util.isNodejs = + typeof process !== 'undefined' && process.versions && process.versions.node; + + + // 'self' will also work in Web Workers (instance of WorkerGlobalScope) while + // it will point to `window` in the main thread. + // To remain compatible with older browsers, we fall back to 'window' if 'self' + // is not available. + util.globalScope = (function() { + if(util.isNodejs) { + return commonjsGlobal; + } + + return typeof self === 'undefined' ? window : self; + })(); + + // define isArray + util.isArray = Array.isArray || function(x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + + // define isArrayBuffer + util.isArrayBuffer = function(x) { + return typeof ArrayBuffer !== 'undefined' && x instanceof ArrayBuffer; + }; + + // define isArrayBufferView + util.isArrayBufferView = function(x) { + return x && util.isArrayBuffer(x.buffer) && x.byteLength !== undefined; + }; + + /** + * Ensure a bits param is 8, 16, 24, or 32. Used to validate input for + * algorithms where bit manipulation, JavaScript limitations, and/or algorithm + * design only allow for byte operations of a limited size. + * + * @param n number of bits. + * + * Throw Error if n invalid. + */ + function _checkBitsParam(n) { + if(!(n === 8 || n === 16 || n === 24 || n === 32)) { + throw new Error('Only 8, 16, 24, or 32 bits supported: ' + n); + } + } + + // TODO: set ByteBuffer to best available backing + util.ByteBuffer = ByteStringBuffer; + + /** Buffer w/BinaryString backing */ + + /** + * Constructor for a binary string backed byte buffer. + * + * @param [b] the bytes to wrap (either encoded as string, one byte per + * character, or as an ArrayBuffer or Typed Array). + */ + function ByteStringBuffer(b) { + // TODO: update to match DataBuffer API + + // the data in this buffer + this.data = ''; + // the pointer for reading from this buffer + this.read = 0; + + if(typeof b === 'string') { + this.data = b; + } else if(util.isArrayBuffer(b) || util.isArrayBufferView(b)) { + if(typeof Buffer !== 'undefined' && b instanceof Buffer) { + this.data = b.toString('binary'); + } else { + // convert native buffer to forge buffer + // FIXME: support native buffers internally instead + var arr = new Uint8Array(b); + try { + this.data = String.fromCharCode.apply(null, arr); + } catch(e) { + for(var i = 0; i < arr.length; ++i) { + this.putByte(arr[i]); + } + } + } + } else if(b instanceof ByteStringBuffer || + (typeof b === 'object' && typeof b.data === 'string' && + typeof b.read === 'number')) { + // copy existing buffer + this.data = b.data; + this.read = b.read; + } + + // used for v8 optimization + this._constructedStringLength = 0; + } + util.ByteStringBuffer = ByteStringBuffer; + + /* Note: This is an optimization for V8-based browsers. When V8 concatenates + a string, the strings are only joined logically using a "cons string" or + "constructed/concatenated string". These containers keep references to one + another and can result in very large memory usage. For example, if a 2MB + string is constructed by concatenating 4 bytes together at a time, the + memory usage will be ~44MB; so ~22x increase. The strings are only joined + together when an operation requiring their joining takes place, such as + substr(). This function is called when adding data to this buffer to ensure + these types of strings are periodically joined to reduce the memory + footprint. */ + var _MAX_CONSTRUCTED_STRING_LENGTH = 4096; + util.ByteStringBuffer.prototype._optimizeConstructedString = function(x) { + this._constructedStringLength += x; + if(this._constructedStringLength > _MAX_CONSTRUCTED_STRING_LENGTH) { + // this substr() should cause the constructed string to join + this.data.substr(0, 1); + this._constructedStringLength = 0; + } + }; + + /** + * Gets the number of bytes in this buffer. + * + * @return the number of bytes in this buffer. + */ + util.ByteStringBuffer.prototype.length = function() { + return this.data.length - this.read; + }; + + /** + * Gets whether or not this buffer is empty. + * + * @return true if this buffer is empty, false if not. + */ + util.ByteStringBuffer.prototype.isEmpty = function() { + return this.length() <= 0; + }; + + /** + * Puts a byte in this buffer. + * + * @param b the byte to put. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putByte = function(b) { + return this.putBytes(String.fromCharCode(b)); + }; + + /** + * Puts a byte in this buffer N times. + * + * @param b the byte to put. + * @param n the number of bytes of value b to put. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.fillWithByte = function(b, n) { + b = String.fromCharCode(b); + var d = this.data; + while(n > 0) { + if(n & 1) { + d += b; + } + n >>>= 1; + if(n > 0) { + b += b; + } + } + this.data = d; + this._optimizeConstructedString(n); + return this; + }; + + /** + * Puts bytes in this buffer. + * + * @param bytes the bytes (as a binary encoded string) to put. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putBytes = function(bytes) { + this.data += bytes; + this._optimizeConstructedString(bytes.length); + return this; + }; + + /** + * Puts a UTF-16 encoded string into this buffer. + * + * @param str the string to put. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putString = function(str) { + return this.putBytes(util.encodeUtf8(str)); + }; + + /** + * Puts a 16-bit integer in this buffer in big-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putInt16 = function(i) { + return this.putBytes( + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); + }; + + /** + * Puts a 24-bit integer in this buffer in big-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putInt24 = function(i) { + return this.putBytes( + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); + }; + + /** + * Puts a 32-bit integer in this buffer in big-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putInt32 = function(i) { + return this.putBytes( + String.fromCharCode(i >> 24 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); + }; + + /** + * Puts a 16-bit integer in this buffer in little-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putInt16Le = function(i) { + return this.putBytes( + String.fromCharCode(i & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF)); + }; + + /** + * Puts a 24-bit integer in this buffer in little-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putInt24Le = function(i) { + return this.putBytes( + String.fromCharCode(i & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF)); + }; + + /** + * Puts a 32-bit integer in this buffer in little-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putInt32Le = function(i) { + return this.putBytes( + String.fromCharCode(i & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 24 & 0xFF)); + }; + + /** + * Puts an n-bit integer in this buffer in big-endian order. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putInt = function(i, n) { + _checkBitsParam(n); + var bytes = ''; + do { + n -= 8; + bytes += String.fromCharCode((i >> n) & 0xFF); + } while(n > 0); + return this.putBytes(bytes); + }; + + /** + * Puts a signed n-bit integer in this buffer in big-endian order. Two's + * complement representation is used. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putSignedInt = function(i, n) { + // putInt checks n + if(i < 0) { + i += 2 << (n - 1); + } + return this.putInt(i, n); + }; + + /** + * Puts the given buffer into this buffer. + * + * @param buffer the buffer to put into this one. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.putBuffer = function(buffer) { + return this.putBytes(buffer.getBytes()); + }; + + /** + * Gets a byte from this buffer and advances the read pointer by 1. + * + * @return the byte. + */ + util.ByteStringBuffer.prototype.getByte = function() { + return this.data.charCodeAt(this.read++); + }; + + /** + * Gets a uint16 from this buffer in big-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ + util.ByteStringBuffer.prototype.getInt16 = function() { + var rval = ( + this.data.charCodeAt(this.read) << 8 ^ + this.data.charCodeAt(this.read + 1)); + this.read += 2; + return rval; + }; + + /** + * Gets a uint24 from this buffer in big-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ + util.ByteStringBuffer.prototype.getInt24 = function() { + var rval = ( + this.data.charCodeAt(this.read) << 16 ^ + this.data.charCodeAt(this.read + 1) << 8 ^ + this.data.charCodeAt(this.read + 2)); + this.read += 3; + return rval; + }; + + /** + * Gets a uint32 from this buffer in big-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ + util.ByteStringBuffer.prototype.getInt32 = function() { + var rval = ( + this.data.charCodeAt(this.read) << 24 ^ + this.data.charCodeAt(this.read + 1) << 16 ^ + this.data.charCodeAt(this.read + 2) << 8 ^ + this.data.charCodeAt(this.read + 3)); + this.read += 4; + return rval; + }; + + /** + * Gets a uint16 from this buffer in little-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ + util.ByteStringBuffer.prototype.getInt16Le = function() { + var rval = ( + this.data.charCodeAt(this.read) ^ + this.data.charCodeAt(this.read + 1) << 8); + this.read += 2; + return rval; + }; + + /** + * Gets a uint24 from this buffer in little-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ + util.ByteStringBuffer.prototype.getInt24Le = function() { + var rval = ( + this.data.charCodeAt(this.read) ^ + this.data.charCodeAt(this.read + 1) << 8 ^ + this.data.charCodeAt(this.read + 2) << 16); + this.read += 3; + return rval; + }; + + /** + * Gets a uint32 from this buffer in little-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ + util.ByteStringBuffer.prototype.getInt32Le = function() { + var rval = ( + this.data.charCodeAt(this.read) ^ + this.data.charCodeAt(this.read + 1) << 8 ^ + this.data.charCodeAt(this.read + 2) << 16 ^ + this.data.charCodeAt(this.read + 3) << 24); + this.read += 4; + return rval; + }; + + /** + * Gets an n-bit integer from this buffer in big-endian order and advances the + * read pointer by ceil(n/8). + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ + util.ByteStringBuffer.prototype.getInt = function(n) { + _checkBitsParam(n); + var rval = 0; + do { + // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits. + rval = (rval << 8) + this.data.charCodeAt(this.read++); + n -= 8; + } while(n > 0); + return rval; + }; + + /** + * Gets a signed n-bit integer from this buffer in big-endian order, using + * two's complement, and advances the read pointer by n/8. + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ + util.ByteStringBuffer.prototype.getSignedInt = function(n) { + // getInt checks n + var x = this.getInt(n); + var max = 2 << (n - 2); + if(x >= max) { + x -= max << 1; + } + return x; + }; + + /** + * Reads bytes out as a binary encoded string and clears them from the + * buffer. Note that the resulting string is binary encoded (in node.js this + * encoding is referred to as `binary`, it is *not* `utf8`). + * + * @param count the number of bytes to read, undefined or null for all. + * + * @return a binary encoded string of bytes. + */ + util.ByteStringBuffer.prototype.getBytes = function(count) { + var rval; + if(count) { + // read count bytes + count = Math.min(this.length(), count); + rval = this.data.slice(this.read, this.read + count); + this.read += count; + } else if(count === 0) { + rval = ''; + } else { + // read all bytes, optimize to only copy when needed + rval = (this.read === 0) ? this.data : this.data.slice(this.read); + this.clear(); + } + return rval; + }; + + /** + * Gets a binary encoded string of the bytes from this buffer without + * modifying the read pointer. + * + * @param count the number of bytes to get, omit to get all. + * + * @return a string full of binary encoded characters. + */ + util.ByteStringBuffer.prototype.bytes = function(count) { + return (typeof(count) === 'undefined' ? + this.data.slice(this.read) : + this.data.slice(this.read, this.read + count)); + }; + + /** + * Gets a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * + * @return the byte. + */ + util.ByteStringBuffer.prototype.at = function(i) { + return this.data.charCodeAt(this.read + i); + }; + + /** + * Puts a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * @param b the byte to put. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.setAt = function(i, b) { + this.data = this.data.substr(0, this.read + i) + + String.fromCharCode(b) + + this.data.substr(this.read + i + 1); + return this; + }; + + /** + * Gets the last byte without modifying the read pointer. + * + * @return the last byte. + */ + util.ByteStringBuffer.prototype.last = function() { + return this.data.charCodeAt(this.data.length - 1); + }; + + /** + * Creates a copy of this buffer. + * + * @return the copy. + */ + util.ByteStringBuffer.prototype.copy = function() { + var c = util.createBuffer(this.data); + c.read = this.read; + return c; + }; + + /** + * Compacts this buffer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.compact = function() { + if(this.read > 0) { + this.data = this.data.slice(this.read); + this.read = 0; + } + return this; + }; + + /** + * Clears this buffer. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.clear = function() { + this.data = ''; + this.read = 0; + return this; + }; + + /** + * Shortens this buffer by triming bytes off of the end of this buffer. + * + * @param count the number of bytes to trim off. + * + * @return this buffer. + */ + util.ByteStringBuffer.prototype.truncate = function(count) { + var len = Math.max(0, this.length() - count); + this.data = this.data.substr(this.read, len); + this.read = 0; + return this; + }; + + /** + * Converts this buffer to a hexadecimal string. + * + * @return a hexadecimal string. + */ + util.ByteStringBuffer.prototype.toHex = function() { + var rval = ''; + for(var i = this.read; i < this.data.length; ++i) { + var b = this.data.charCodeAt(i); + if(b < 16) { + rval += '0'; + } + rval += b.toString(16); + } + return rval; + }; + + /** + * Converts this buffer to a UTF-16 string (standard JavaScript string). + * + * @return a UTF-16 string. + */ + util.ByteStringBuffer.prototype.toString = function() { + return util.decodeUtf8(this.bytes()); + }; + + /** End Buffer w/BinaryString backing */ + + /** Buffer w/UInt8Array backing */ + + /** + * FIXME: Experimental. Do not use yet. + * + * Constructor for an ArrayBuffer-backed byte buffer. + * + * The buffer may be constructed from a string, an ArrayBuffer, DataView, or a + * TypedArray. + * + * If a string is given, its encoding should be provided as an option, + * otherwise it will default to 'binary'. A 'binary' string is encoded such + * that each character is one byte in length and size. + * + * If an ArrayBuffer, DataView, or TypedArray is given, it will be used + * *directly* without any copying. Note that, if a write to the buffer requires + * more space, the buffer will allocate a new backing ArrayBuffer to + * accommodate. The starting read and write offsets for the buffer may be + * given as options. + * + * @param [b] the initial bytes for this buffer. + * @param options the options to use: + * [readOffset] the starting read offset to use (default: 0). + * [writeOffset] the starting write offset to use (default: the + * length of the first parameter). + * [growSize] the minimum amount, in bytes, to grow the buffer by to + * accommodate writes (default: 1024). + * [encoding] the encoding ('binary', 'utf8', 'utf16', 'hex') for the + * first parameter, if it is a string (default: 'binary'). + */ + function DataBuffer(b, options) { + // default options + options = options || {}; + + // pointers for read from/write to buffer + this.read = options.readOffset || 0; + this.growSize = options.growSize || 1024; + + var isArrayBuffer = util.isArrayBuffer(b); + var isArrayBufferView = util.isArrayBufferView(b); + if(isArrayBuffer || isArrayBufferView) { + // use ArrayBuffer directly + if(isArrayBuffer) { + this.data = new DataView(b); + } else { + // TODO: adjust read/write offset based on the type of view + // or specify that this must be done in the options ... that the + // offsets are byte-based + this.data = new DataView(b.buffer, b.byteOffset, b.byteLength); + } + this.write = ('writeOffset' in options ? + options.writeOffset : this.data.byteLength); + return; + } + + // initialize to empty array buffer and add any given bytes using putBytes + this.data = new DataView(new ArrayBuffer(0)); + this.write = 0; + + if(b !== null && b !== undefined) { + this.putBytes(b); + } + + if('writeOffset' in options) { + this.write = options.writeOffset; + } + } + util.DataBuffer = DataBuffer; + + /** + * Gets the number of bytes in this buffer. + * + * @return the number of bytes in this buffer. + */ + util.DataBuffer.prototype.length = function() { + return this.write - this.read; + }; + + /** + * Gets whether or not this buffer is empty. + * + * @return true if this buffer is empty, false if not. + */ + util.DataBuffer.prototype.isEmpty = function() { + return this.length() <= 0; + }; + + /** + * Ensures this buffer has enough empty space to accommodate the given number + * of bytes. An optional parameter may be given that indicates a minimum + * amount to grow the buffer if necessary. If the parameter is not given, + * the buffer will be grown by some previously-specified default amount + * or heuristic. + * + * @param amount the number of bytes to accommodate. + * @param [growSize] the minimum amount, in bytes, to grow the buffer by if + * necessary. + */ + util.DataBuffer.prototype.accommodate = function(amount, growSize) { + if(this.length() >= amount) { + return this; + } + growSize = Math.max(growSize || this.growSize, amount); + + // grow buffer + var src = new Uint8Array( + this.data.buffer, this.data.byteOffset, this.data.byteLength); + var dst = new Uint8Array(this.length() + growSize); + dst.set(src); + this.data = new DataView(dst.buffer); + + return this; + }; + + /** + * Puts a byte in this buffer. + * + * @param b the byte to put. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putByte = function(b) { + this.accommodate(1); + this.data.setUint8(this.write++, b); + return this; + }; + + /** + * Puts a byte in this buffer N times. + * + * @param b the byte to put. + * @param n the number of bytes of value b to put. + * + * @return this buffer. + */ + util.DataBuffer.prototype.fillWithByte = function(b, n) { + this.accommodate(n); + for(var i = 0; i < n; ++i) { + this.data.setUint8(b); + } + return this; + }; + + /** + * Puts bytes in this buffer. The bytes may be given as a string, an + * ArrayBuffer, a DataView, or a TypedArray. + * + * @param bytes the bytes to put. + * @param [encoding] the encoding for the first parameter ('binary', 'utf8', + * 'utf16', 'hex'), if it is a string (default: 'binary'). + * + * @return this buffer. + */ + util.DataBuffer.prototype.putBytes = function(bytes, encoding) { + if(util.isArrayBufferView(bytes)) { + var src = new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength); + var len = src.byteLength - src.byteOffset; + this.accommodate(len); + var dst = new Uint8Array(this.data.buffer, this.write); + dst.set(src); + this.write += len; + return this; + } + + if(util.isArrayBuffer(bytes)) { + var src = new Uint8Array(bytes); + this.accommodate(src.byteLength); + var dst = new Uint8Array(this.data.buffer); + dst.set(src, this.write); + this.write += src.byteLength; + return this; + } + + // bytes is a util.DataBuffer or equivalent + if(bytes instanceof util.DataBuffer || + (typeof bytes === 'object' && + typeof bytes.read === 'number' && typeof bytes.write === 'number' && + util.isArrayBufferView(bytes.data))) { + var src = new Uint8Array(bytes.data.byteLength, bytes.read, bytes.length()); + this.accommodate(src.byteLength); + var dst = new Uint8Array(bytes.data.byteLength, this.write); + dst.set(src); + this.write += src.byteLength; + return this; + } + + if(bytes instanceof util.ByteStringBuffer) { + // copy binary string and process as the same as a string parameter below + bytes = bytes.data; + encoding = 'binary'; + } + + // string conversion + encoding = encoding || 'binary'; + if(typeof bytes === 'string') { + var view; + + // decode from string + if(encoding === 'hex') { + this.accommodate(Math.ceil(bytes.length / 2)); + view = new Uint8Array(this.data.buffer, this.write); + this.write += util.binary.hex.decode(bytes, view, this.write); + return this; + } + if(encoding === 'base64') { + this.accommodate(Math.ceil(bytes.length / 4) * 3); + view = new Uint8Array(this.data.buffer, this.write); + this.write += util.binary.base64.decode(bytes, view, this.write); + return this; + } + + // encode text as UTF-8 bytes + if(encoding === 'utf8') { + // encode as UTF-8 then decode string as raw binary + bytes = util.encodeUtf8(bytes); + encoding = 'binary'; + } + + // decode string as raw binary + if(encoding === 'binary' || encoding === 'raw') { + // one byte per character + this.accommodate(bytes.length); + view = new Uint8Array(this.data.buffer, this.write); + this.write += util.binary.raw.decode(view); + return this; + } + + // encode text as UTF-16 bytes + if(encoding === 'utf16') { + // two bytes per character + this.accommodate(bytes.length * 2); + view = new Uint16Array(this.data.buffer, this.write); + this.write += util.text.utf16.encode(view); + return this; + } + + throw new Error('Invalid encoding: ' + encoding); + } + + throw Error('Invalid parameter: ' + bytes); + }; + + /** + * Puts the given buffer into this buffer. + * + * @param buffer the buffer to put into this one. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putBuffer = function(buffer) { + this.putBytes(buffer); + buffer.clear(); + return this; + }; + + /** + * Puts a string into this buffer. + * + * @param str the string to put. + * @param [encoding] the encoding for the string (default: 'utf16'). + * + * @return this buffer. + */ + util.DataBuffer.prototype.putString = function(str) { + return this.putBytes(str, 'utf16'); + }; + + /** + * Puts a 16-bit integer in this buffer in big-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putInt16 = function(i) { + this.accommodate(2); + this.data.setInt16(this.write, i); + this.write += 2; + return this; + }; + + /** + * Puts a 24-bit integer in this buffer in big-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putInt24 = function(i) { + this.accommodate(3); + this.data.setInt16(this.write, i >> 8 & 0xFFFF); + this.data.setInt8(this.write, i >> 16 & 0xFF); + this.write += 3; + return this; + }; + + /** + * Puts a 32-bit integer in this buffer in big-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putInt32 = function(i) { + this.accommodate(4); + this.data.setInt32(this.write, i); + this.write += 4; + return this; + }; + + /** + * Puts a 16-bit integer in this buffer in little-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putInt16Le = function(i) { + this.accommodate(2); + this.data.setInt16(this.write, i, true); + this.write += 2; + return this; + }; + + /** + * Puts a 24-bit integer in this buffer in little-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putInt24Le = function(i) { + this.accommodate(3); + this.data.setInt8(this.write, i >> 16 & 0xFF); + this.data.setInt16(this.write, i >> 8 & 0xFFFF, true); + this.write += 3; + return this; + }; + + /** + * Puts a 32-bit integer in this buffer in little-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putInt32Le = function(i) { + this.accommodate(4); + this.data.setInt32(this.write, i, true); + this.write += 4; + return this; + }; + + /** + * Puts an n-bit integer in this buffer in big-endian order. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return this buffer. + */ + util.DataBuffer.prototype.putInt = function(i, n) { + _checkBitsParam(n); + this.accommodate(n / 8); + do { + n -= 8; + this.data.setInt8(this.write++, (i >> n) & 0xFF); + } while(n > 0); + return this; + }; + + /** + * Puts a signed n-bit integer in this buffer in big-endian order. Two's + * complement representation is used. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.putSignedInt = function(i, n) { + _checkBitsParam(n); + this.accommodate(n / 8); + if(i < 0) { + i += 2 << (n - 1); + } + return this.putInt(i, n); + }; + + /** + * Gets a byte from this buffer and advances the read pointer by 1. + * + * @return the byte. + */ + util.DataBuffer.prototype.getByte = function() { + return this.data.getInt8(this.read++); + }; + + /** + * Gets a uint16 from this buffer in big-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ + util.DataBuffer.prototype.getInt16 = function() { + var rval = this.data.getInt16(this.read); + this.read += 2; + return rval; + }; + + /** + * Gets a uint24 from this buffer in big-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ + util.DataBuffer.prototype.getInt24 = function() { + var rval = ( + this.data.getInt16(this.read) << 8 ^ + this.data.getInt8(this.read + 2)); + this.read += 3; + return rval; + }; + + /** + * Gets a uint32 from this buffer in big-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ + util.DataBuffer.prototype.getInt32 = function() { + var rval = this.data.getInt32(this.read); + this.read += 4; + return rval; + }; + + /** + * Gets a uint16 from this buffer in little-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ + util.DataBuffer.prototype.getInt16Le = function() { + var rval = this.data.getInt16(this.read, true); + this.read += 2; + return rval; + }; + + /** + * Gets a uint24 from this buffer in little-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ + util.DataBuffer.prototype.getInt24Le = function() { + var rval = ( + this.data.getInt8(this.read) ^ + this.data.getInt16(this.read + 1, true) << 8); + this.read += 3; + return rval; + }; + + /** + * Gets a uint32 from this buffer in little-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ + util.DataBuffer.prototype.getInt32Le = function() { + var rval = this.data.getInt32(this.read, true); + this.read += 4; + return rval; + }; + + /** + * Gets an n-bit integer from this buffer in big-endian order and advances the + * read pointer by n/8. + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ + util.DataBuffer.prototype.getInt = function(n) { + _checkBitsParam(n); + var rval = 0; + do { + // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits. + rval = (rval << 8) + this.data.getInt8(this.read++); + n -= 8; + } while(n > 0); + return rval; + }; + + /** + * Gets a signed n-bit integer from this buffer in big-endian order, using + * two's complement, and advances the read pointer by n/8. + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ + util.DataBuffer.prototype.getSignedInt = function(n) { + // getInt checks n + var x = this.getInt(n); + var max = 2 << (n - 2); + if(x >= max) { + x -= max << 1; + } + return x; + }; + + /** + * Reads bytes out as a binary encoded string and clears them from the + * buffer. + * + * @param count the number of bytes to read, undefined or null for all. + * + * @return a binary encoded string of bytes. + */ + util.DataBuffer.prototype.getBytes = function(count) { + // TODO: deprecate this method, it is poorly named and + // this.toString('binary') replaces it + // add a toTypedArray()/toArrayBuffer() function + var rval; + if(count) { + // read count bytes + count = Math.min(this.length(), count); + rval = this.data.slice(this.read, this.read + count); + this.read += count; + } else if(count === 0) { + rval = ''; + } else { + // read all bytes, optimize to only copy when needed + rval = (this.read === 0) ? this.data : this.data.slice(this.read); + this.clear(); + } + return rval; + }; + + /** + * Gets a binary encoded string of the bytes from this buffer without + * modifying the read pointer. + * + * @param count the number of bytes to get, omit to get all. + * + * @return a string full of binary encoded characters. + */ + util.DataBuffer.prototype.bytes = function(count) { + // TODO: deprecate this method, it is poorly named, add "getString()" + return (typeof(count) === 'undefined' ? + this.data.slice(this.read) : + this.data.slice(this.read, this.read + count)); + }; + + /** + * Gets a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * + * @return the byte. + */ + util.DataBuffer.prototype.at = function(i) { + return this.data.getUint8(this.read + i); + }; + + /** + * Puts a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * @param b the byte to put. + * + * @return this buffer. + */ + util.DataBuffer.prototype.setAt = function(i, b) { + this.data.setUint8(i, b); + return this; + }; + + /** + * Gets the last byte without modifying the read pointer. + * + * @return the last byte. + */ + util.DataBuffer.prototype.last = function() { + return this.data.getUint8(this.write - 1); + }; + + /** + * Creates a copy of this buffer. + * + * @return the copy. + */ + util.DataBuffer.prototype.copy = function() { + return new util.DataBuffer(this); + }; + + /** + * Compacts this buffer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.compact = function() { + if(this.read > 0) { + var src = new Uint8Array(this.data.buffer, this.read); + var dst = new Uint8Array(src.byteLength); + dst.set(src); + this.data = new DataView(dst); + this.write -= this.read; + this.read = 0; + } + return this; + }; + + /** + * Clears this buffer. + * + * @return this buffer. + */ + util.DataBuffer.prototype.clear = function() { + this.data = new DataView(new ArrayBuffer(0)); + this.read = this.write = 0; + return this; + }; + + /** + * Shortens this buffer by triming bytes off of the end of this buffer. + * + * @param count the number of bytes to trim off. + * + * @return this buffer. + */ + util.DataBuffer.prototype.truncate = function(count) { + this.write = Math.max(0, this.length() - count); + this.read = Math.min(this.read, this.write); + return this; + }; + + /** + * Converts this buffer to a hexadecimal string. + * + * @return a hexadecimal string. + */ + util.DataBuffer.prototype.toHex = function() { + var rval = ''; + for(var i = this.read; i < this.data.byteLength; ++i) { + var b = this.data.getUint8(i); + if(b < 16) { + rval += '0'; + } + rval += b.toString(16); + } + return rval; + }; + + /** + * Converts this buffer to a string, using the given encoding. If no + * encoding is given, 'utf8' (UTF-8) is used. + * + * @param [encoding] the encoding to use: 'binary', 'utf8', 'utf16', 'hex', + * 'base64' (default: 'utf8'). + * + * @return a string representation of the bytes in this buffer. + */ + util.DataBuffer.prototype.toString = function(encoding) { + var view = new Uint8Array(this.data, this.read, this.length()); + encoding = encoding || 'utf8'; + + // encode to string + if(encoding === 'binary' || encoding === 'raw') { + return util.binary.raw.encode(view); + } + if(encoding === 'hex') { + return util.binary.hex.encode(view); + } + if(encoding === 'base64') { + return util.binary.base64.encode(view); + } + + // decode to text + if(encoding === 'utf8') { + return util.text.utf8.decode(view); + } + if(encoding === 'utf16') { + return util.text.utf16.decode(view); + } + + throw new Error('Invalid encoding: ' + encoding); + }; + + /** End Buffer w/UInt8Array backing */ + + /** + * Creates a buffer that stores bytes. A value may be given to populate the + * buffer with data. This value can either be string of encoded bytes or a + * regular string of characters. When passing a string of binary encoded + * bytes, the encoding `raw` should be given. This is also the default. When + * passing a string of characters, the encoding `utf8` should be given. + * + * @param [input] a string with encoded bytes to store in the buffer. + * @param [encoding] (default: 'raw', other: 'utf8'). + */ + util.createBuffer = function(input, encoding) { + // TODO: deprecate, use new ByteBuffer() instead + encoding = encoding || 'raw'; + if(input !== undefined && encoding === 'utf8') { + input = util.encodeUtf8(input); + } + return new util.ByteBuffer(input); + }; + + /** + * Fills a string with a particular value. If you want the string to be a byte + * string, pass in String.fromCharCode(theByte). + * + * @param c the character to fill the string with, use String.fromCharCode + * to fill the string with a byte value. + * @param n the number of characters of value c to fill with. + * + * @return the filled string. + */ + util.fillString = function(c, n) { + var s = ''; + while(n > 0) { + if(n & 1) { + s += c; + } + n >>>= 1; + if(n > 0) { + c += c; + } + } + return s; + }; + + /** + * Performs a per byte XOR between two byte strings and returns the result as a + * string of bytes. + * + * @param s1 first string of bytes. + * @param s2 second string of bytes. + * @param n the number of bytes to XOR. + * + * @return the XOR'd result. + */ + util.xorBytes = function(s1, s2, n) { + var s3 = ''; + var b = ''; + var t = ''; + var i = 0; + var c = 0; + for(; n > 0; --n, ++i) { + b = s1.charCodeAt(i) ^ s2.charCodeAt(i); + if(c >= 10) { + s3 += t; + t = ''; + c = 0; + } + t += String.fromCharCode(b); + ++c; + } + s3 += t; + return s3; + }; + + /** + * Converts a hex string into a 'binary' encoded string of bytes. + * + * @param hex the hexadecimal string to convert. + * + * @return the binary-encoded string of bytes. + */ + util.hexToBytes = function(hex) { + // TODO: deprecate: "Deprecated. Use util.binary.hex.decode instead." + var rval = ''; + var i = 0; + if(hex.length & 1 == 1) { + // odd number of characters, convert first character alone + i = 1; + rval += String.fromCharCode(parseInt(hex[0], 16)); + } + // convert 2 characters (1 byte) at a time + for(; i < hex.length; i += 2) { + rval += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + return rval; + }; + + /** + * Converts a 'binary' encoded string of bytes to hex. + * + * @param bytes the byte string to convert. + * + * @return the string of hexadecimal characters. + */ + util.bytesToHex = function(bytes) { + // TODO: deprecate: "Deprecated. Use util.binary.hex.encode instead." + return util.createBuffer(bytes).toHex(); + }; + + /** + * Converts an 32-bit integer to 4-big-endian byte string. + * + * @param i the integer. + * + * @return the byte string. + */ + util.int32ToBytes = function(i) { + return ( + String.fromCharCode(i >> 24 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); + }; + + // base64 characters, reverse mapping + var _base64 = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var _base64Idx = [ + /*43 -43 = 0*/ + /*'+', 1, 2, 3,'/' */ + 62, -1, -1, -1, 63, + + /*'0','1','2','3','4','5','6','7','8','9' */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + + /*15, 16, 17,'=', 19, 20, 21 */ + -1, -1, -1, 64, -1, -1, -1, + + /*65 - 43 = 22*/ + /*'A','B','C','D','E','F','G','H','I','J','K','L','M', */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + + /*'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' */ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + + /*91 - 43 = 48 */ + /*48, 49, 50, 51, 52, 53 */ + -1, -1, -1, -1, -1, -1, + + /*97 - 43 = 54*/ + /*'a','b','c','d','e','f','g','h','i','j','k','l','m' */ + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + + /*'n','o','p','q','r','s','t','u','v','w','x','y','z' */ + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + ]; + + // base58 characters (Bitcoin alphabet) + var _base58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + + /** + * Base64 encodes a 'binary' encoded string of bytes. + * + * @param input the binary encoded string of bytes to base64-encode. + * @param maxline the maximum number of encoded characters per line to use, + * defaults to none. + * + * @return the base64-encoded output. + */ + util.encode64 = function(input, maxline) { + // TODO: deprecate: "Deprecated. Use util.binary.base64.encode instead." + var line = ''; + var output = ''; + var chr1, chr2, chr3; + var i = 0; + while(i < input.length) { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + // encode 4 character group + line += _base64.charAt(chr1 >> 2); + line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4)); + if(isNaN(chr2)) { + line += '=='; + } else { + line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6)); + line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63); + } + + if(maxline && line.length > maxline) { + output += line.substr(0, maxline) + '\r\n'; + line = line.substr(maxline); + } + } + output += line; + return output; + }; + + /** + * Base64 decodes a string into a 'binary' encoded string of bytes. + * + * @param input the base64-encoded input. + * + * @return the binary encoded string. + */ + util.decode64 = function(input) { + // TODO: deprecate: "Deprecated. Use util.binary.base64.decode instead." + + // remove all non-base64 characters + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + + var output = ''; + var enc1, enc2, enc3, enc4; + var i = 0; + + while(i < input.length) { + enc1 = _base64Idx[input.charCodeAt(i++) - 43]; + enc2 = _base64Idx[input.charCodeAt(i++) - 43]; + enc3 = _base64Idx[input.charCodeAt(i++) - 43]; + enc4 = _base64Idx[input.charCodeAt(i++) - 43]; + + output += String.fromCharCode((enc1 << 2) | (enc2 >> 4)); + if(enc3 !== 64) { + // decoded at least 2 bytes + output += String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2)); + if(enc4 !== 64) { + // decoded 3 bytes + output += String.fromCharCode(((enc3 & 3) << 6) | enc4); + } + } + } + + return output; + }; + + /** + * Encodes the given string of characters (a standard JavaScript + * string) as a binary encoded string where the bytes represent + * a UTF-8 encoded string of characters. Non-ASCII characters will be + * encoded as multiple bytes according to UTF-8. + * + * @param str a standard string of characters to encode. + * + * @return the binary encoded string. + */ + util.encodeUtf8 = function(str) { + return unescape(encodeURIComponent(str)); + }; + + /** + * Decodes a binary encoded string that contains bytes that + * represent a UTF-8 encoded string of characters -- into a + * string of characters (a standard JavaScript string). + * + * @param str the binary encoded string to decode. + * + * @return the resulting standard string of characters. + */ + util.decodeUtf8 = function(str) { + return decodeURIComponent(escape(str)); + }; + + // binary encoding/decoding tools + // FIXME: Experimental. Do not use yet. + util.binary = { + raw: {}, + hex: {}, + base64: {}, + base58: {}, + baseN : { + encode: baseN.encode, + decode: baseN.decode + } + }; + + /** + * Encodes a Uint8Array as a binary-encoded string. This encoding uses + * a value between 0 and 255 for each character. + * + * @param bytes the Uint8Array to encode. + * + * @return the binary-encoded string. + */ + util.binary.raw.encode = function(bytes) { + return String.fromCharCode.apply(null, bytes); + }; + + /** + * Decodes a binary-encoded string to a Uint8Array. This encoding uses + * a value between 0 and 255 for each character. + * + * @param str the binary-encoded string to decode. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ + util.binary.raw.decode = function(str, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(str.length); + } + offset = offset || 0; + var j = offset; + for(var i = 0; i < str.length; ++i) { + out[j++] = str.charCodeAt(i); + } + return output ? (j - offset) : out; + }; + + /** + * Encodes a 'binary' string, ArrayBuffer, DataView, TypedArray, or + * ByteBuffer as a string of hexadecimal characters. + * + * @param bytes the bytes to convert. + * + * @return the string of hexadecimal characters. + */ + util.binary.hex.encode = util.bytesToHex; + + /** + * Decodes a hex-encoded string to a Uint8Array. + * + * @param hex the hexadecimal string to convert. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ + util.binary.hex.decode = function(hex, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(Math.ceil(hex.length / 2)); + } + offset = offset || 0; + var i = 0, j = offset; + if(hex.length & 1) { + // odd number of characters, convert first character alone + i = 1; + out[j++] = parseInt(hex[0], 16); + } + // convert 2 characters (1 byte) at a time + for(; i < hex.length; i += 2) { + out[j++] = parseInt(hex.substr(i, 2), 16); + } + return output ? (j - offset) : out; + }; + + /** + * Base64-encodes a Uint8Array. + * + * @param input the Uint8Array to encode. + * @param maxline the maximum number of encoded characters per line to use, + * defaults to none. + * + * @return the base64-encoded output string. + */ + util.binary.base64.encode = function(input, maxline) { + var line = ''; + var output = ''; + var chr1, chr2, chr3; + var i = 0; + while(i < input.byteLength) { + chr1 = input[i++]; + chr2 = input[i++]; + chr3 = input[i++]; + + // encode 4 character group + line += _base64.charAt(chr1 >> 2); + line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4)); + if(isNaN(chr2)) { + line += '=='; + } else { + line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6)); + line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63); + } + + if(maxline && line.length > maxline) { + output += line.substr(0, maxline) + '\r\n'; + line = line.substr(maxline); + } + } + output += line; + return output; + }; + + /** + * Decodes a base64-encoded string to a Uint8Array. + * + * @param input the base64-encoded input string. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ + util.binary.base64.decode = function(input, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(Math.ceil(input.length / 4) * 3); + } + + // remove all non-base64 characters + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + + offset = offset || 0; + var enc1, enc2, enc3, enc4; + var i = 0, j = offset; + + while(i < input.length) { + enc1 = _base64Idx[input.charCodeAt(i++) - 43]; + enc2 = _base64Idx[input.charCodeAt(i++) - 43]; + enc3 = _base64Idx[input.charCodeAt(i++) - 43]; + enc4 = _base64Idx[input.charCodeAt(i++) - 43]; + + out[j++] = (enc1 << 2) | (enc2 >> 4); + if(enc3 !== 64) { + // decoded at least 2 bytes + out[j++] = ((enc2 & 15) << 4) | (enc3 >> 2); + if(enc4 !== 64) { + // decoded 3 bytes + out[j++] = ((enc3 & 3) << 6) | enc4; + } + } + } + + // make sure result is the exact decoded length + return output ? (j - offset) : out.subarray(0, j); + }; + + // add support for base58 encoding/decoding with Bitcoin alphabet + util.binary.base58.encode = function(input, maxline) { + return util.binary.baseN.encode(input, _base58, maxline); + }; + util.binary.base58.decode = function(input, maxline) { + return util.binary.baseN.decode(input, _base58, maxline); + }; + + // text encoding/decoding tools + // FIXME: Experimental. Do not use yet. + util.text = { + utf8: {}, + utf16: {} + }; + + /** + * Encodes the given string as UTF-8 in a Uint8Array. + * + * @param str the string to encode. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ + util.text.utf8.encode = function(str, output, offset) { + str = util.encodeUtf8(str); + var out = output; + if(!out) { + out = new Uint8Array(str.length); + } + offset = offset || 0; + var j = offset; + for(var i = 0; i < str.length; ++i) { + out[j++] = str.charCodeAt(i); + } + return output ? (j - offset) : out; + }; + + /** + * Decodes the UTF-8 contents from a Uint8Array. + * + * @param bytes the Uint8Array to decode. + * + * @return the resulting string. + */ + util.text.utf8.decode = function(bytes) { + return util.decodeUtf8(String.fromCharCode.apply(null, bytes)); + }; + + /** + * Encodes the given string as UTF-16 in a Uint8Array. + * + * @param str the string to encode. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ + util.text.utf16.encode = function(str, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(str.length * 2); + } + var view = new Uint16Array(out.buffer); + offset = offset || 0; + var j = offset; + var k = offset; + for(var i = 0; i < str.length; ++i) { + view[k++] = str.charCodeAt(i); + j += 2; + } + return output ? (j - offset) : out; + }; + + /** + * Decodes the UTF-16 contents from a Uint8Array. + * + * @param bytes the Uint8Array to decode. + * + * @return the resulting string. + */ + util.text.utf16.decode = function(bytes) { + return String.fromCharCode.apply(null, new Uint16Array(bytes.buffer)); + }; + + /** + * Deflates the given data using a flash interface. + * + * @param api the flash interface. + * @param bytes the data. + * @param raw true to return only raw deflate data, false to include zlib + * header and trailer. + * + * @return the deflated data as a string. + */ + util.deflate = function(api, bytes, raw) { + bytes = util.decode64(api.deflate(util.encode64(bytes)).rval); + + // strip zlib header and trailer if necessary + if(raw) { + // zlib header is 2 bytes (CMF,FLG) where FLG indicates that + // there is a 4-byte DICT (alder-32) block before the data if + // its 5th bit is set + var start = 2; + var flg = bytes.charCodeAt(1); + if(flg & 0x20) { + start = 6; + } + // zlib trailer is 4 bytes of adler-32 + bytes = bytes.substring(start, bytes.length - 4); + } + + return bytes; + }; + + /** + * Inflates the given data using a flash interface. + * + * @param api the flash interface. + * @param bytes the data. + * @param raw true if the incoming data has no zlib header or trailer and is + * raw DEFLATE data. + * + * @return the inflated data as a string, null on error. + */ + util.inflate = function(api, bytes, raw) { + // TODO: add zlib header and trailer if necessary/possible + var rval = api.inflate(util.encode64(bytes)).rval; + return (rval === null) ? null : util.decode64(rval); + }; + + /** + * Sets a storage object. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param obj the storage object, null to remove. + */ + var _setStorageObject = function(api, id, obj) { + if(!api) { + throw new Error('WebStorage not available.'); + } + + var rval; + if(obj === null) { + rval = api.removeItem(id); + } else { + // json-encode and base64-encode object + obj = util.encode64(JSON.stringify(obj)); + rval = api.setItem(id, obj); + } + + // handle potential flash error + if(typeof(rval) !== 'undefined' && rval.rval !== true) { + var error = new Error(rval.error.message); + error.id = rval.error.id; + error.name = rval.error.name; + throw error; + } + }; + + /** + * Gets a storage object. + * + * @param api the storage interface. + * @param id the storage ID to use. + * + * @return the storage object entry or null if none exists. + */ + var _getStorageObject = function(api, id) { + if(!api) { + throw new Error('WebStorage not available.'); + } + + // get the existing entry + var rval = api.getItem(id); + + /* Note: We check api.init because we can't do (api == localStorage) + on IE because of "Class doesn't support Automation" exception. Only + the flash api has an init method so this works too, but we need a + better solution in the future. */ + + // flash returns item wrapped in an object, handle special case + if(api.init) { + if(rval.rval === null) { + if(rval.error) { + var error = new Error(rval.error.message); + error.id = rval.error.id; + error.name = rval.error.name; + throw error; + } + // no error, but also no item + rval = null; + } else { + rval = rval.rval; + } + } + + // handle decoding + if(rval !== null) { + // base64-decode and json-decode data + rval = JSON.parse(util.decode64(rval)); + } + + return rval; + }; + + /** + * Stores an item in local storage. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param key the key for the item. + * @param data the data for the item (any javascript object/primitive). + */ + var _setItem = function(api, id, key, data) { + // get storage object + var obj = _getStorageObject(api, id); + if(obj === null) { + // create a new storage object + obj = {}; + } + // update key + obj[key] = data; + + // set storage object + _setStorageObject(api, id, obj); + }; + + /** + * Gets an item from local storage. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param key the key for the item. + * + * @return the item. + */ + var _getItem = function(api, id, key) { + // get storage object + var rval = _getStorageObject(api, id); + if(rval !== null) { + // return data at key + rval = (key in rval) ? rval[key] : null; + } + + return rval; + }; + + /** + * Removes an item from local storage. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param key the key for the item. + */ + var _removeItem = function(api, id, key) { + // get storage object + var obj = _getStorageObject(api, id); + if(obj !== null && key in obj) { + // remove key + delete obj[key]; + + // see if entry has no keys remaining + var empty = true; + for(var prop in obj) { + empty = false; + break; + } + if(empty) { + // remove entry entirely if no keys are left + obj = null; + } + + // set storage object + _setStorageObject(api, id, obj); + } + }; + + /** + * Clears the local disk storage identified by the given ID. + * + * @param api the storage interface. + * @param id the storage ID to use. + */ + var _clearItems = function(api, id) { + _setStorageObject(api, id, null); + }; + + /** + * Calls a storage function. + * + * @param func the function to call. + * @param args the arguments for the function. + * @param location the location argument. + * + * @return the return value from the function. + */ + var _callStorageFunction = function(func, args, location) { + var rval = null; + + // default storage types + if(typeof(location) === 'undefined') { + location = ['web', 'flash']; + } + + // apply storage types in order of preference + var type; + var done = false; + var exception = null; + for(var idx in location) { + type = location[idx]; + try { + if(type === 'flash' || type === 'both') { + if(args[0] === null) { + throw new Error('Flash local storage not available.'); + } + rval = func.apply(this, args); + done = (type === 'flash'); + } + if(type === 'web' || type === 'both') { + args[0] = localStorage; + rval = func.apply(this, args); + done = true; + } + } catch(ex) { + exception = ex; + } + if(done) { + break; + } + } + + if(!done) { + throw exception; + } + + return rval; + }; + + /** + * Stores an item on local disk. + * + * The available types of local storage include 'flash', 'web', and 'both'. + * + * The type 'flash' refers to flash local storage (SharedObject). In order + * to use flash local storage, the 'api' parameter must be valid. The type + * 'web' refers to WebStorage, if supported by the browser. The type 'both' + * refers to storing using both 'flash' and 'web', not just one or the + * other. + * + * The location array should list the storage types to use in order of + * preference: + * + * ['flash']: flash only storage + * ['web']: web only storage + * ['both']: try to store in both + * ['flash','web']: store in flash first, but if not available, 'web' + * ['web','flash']: store in web first, but if not available, 'flash' + * + * The location array defaults to: ['web', 'flash'] + * + * @param api the flash interface, null to use only WebStorage. + * @param id the storage ID to use. + * @param key the key for the item. + * @param data the data for the item (any javascript object/primitive). + * @param location an array with the preferred types of storage to use. + */ + util.setItem = function(api, id, key, data, location) { + _callStorageFunction(_setItem, arguments, location); + }; + + /** + * Gets an item on local disk. + * + * Set setItem() for details on storage types. + * + * @param api the flash interface, null to use only WebStorage. + * @param id the storage ID to use. + * @param key the key for the item. + * @param location an array with the preferred types of storage to use. + * + * @return the item. + */ + util.getItem = function(api, id, key, location) { + return _callStorageFunction(_getItem, arguments, location); + }; + + /** + * Removes an item on local disk. + * + * Set setItem() for details on storage types. + * + * @param api the flash interface. + * @param id the storage ID to use. + * @param key the key for the item. + * @param location an array with the preferred types of storage to use. + */ + util.removeItem = function(api, id, key, location) { + _callStorageFunction(_removeItem, arguments, location); + }; + + /** + * Clears the local disk storage identified by the given ID. + * + * Set setItem() for details on storage types. + * + * @param api the flash interface if flash is available. + * @param id the storage ID to use. + * @param location an array with the preferred types of storage to use. + */ + util.clearItems = function(api, id, location) { + _callStorageFunction(_clearItems, arguments, location); + }; + + /** + * Parses the scheme, host, and port from an http(s) url. + * + * @param str the url string. + * + * @return the parsed url object or null if the url is invalid. + */ + util.parseUrl = function(str) { + // FIXME: this regex looks a bit broken + var regex = /^(https?):\/\/([^:&^\/]*):?(\d*)(.*)$/g; + regex.lastIndex = 0; + var m = regex.exec(str); + var url = (m === null) ? null : { + full: str, + scheme: m[1], + host: m[2], + port: m[3], + path: m[4] + }; + if(url) { + url.fullHost = url.host; + if(url.port) { + if(url.port !== 80 && url.scheme === 'http') { + url.fullHost += ':' + url.port; + } else if(url.port !== 443 && url.scheme === 'https') { + url.fullHost += ':' + url.port; + } + } else if(url.scheme === 'http') { + url.port = 80; + } else if(url.scheme === 'https') { + url.port = 443; + } + url.full = url.scheme + '://' + url.fullHost; + } + return url; + }; + + /* Storage for query variables */ + var _queryVariables = null; + + /** + * Returns the window location query variables. Query is parsed on the first + * call and the same object is returned on subsequent calls. The mapping + * is from keys to an array of values. Parameters without values will have + * an object key set but no value added to the value array. Values are + * unescaped. + * + * ...?k1=v1&k2=v2: + * { + * "k1": ["v1"], + * "k2": ["v2"] + * } + * + * ...?k1=v1&k1=v2: + * { + * "k1": ["v1", "v2"] + * } + * + * ...?k1=v1&k2: + * { + * "k1": ["v1"], + * "k2": [] + * } + * + * ...?k1=v1&k1: + * { + * "k1": ["v1"] + * } + * + * ...?k1&k1: + * { + * "k1": [] + * } + * + * @param query the query string to parse (optional, default to cached + * results from parsing window location search query). + * + * @return object mapping keys to variables. + */ + util.getQueryVariables = function(query) { + var parse = function(q) { + var rval = {}; + var kvpairs = q.split('&'); + for(var i = 0; i < kvpairs.length; i++) { + var pos = kvpairs[i].indexOf('='); + var key; + var val; + if(pos > 0) { + key = kvpairs[i].substring(0, pos); + val = kvpairs[i].substring(pos + 1); + } else { + key = kvpairs[i]; + val = null; + } + if(!(key in rval)) { + rval[key] = []; + } + // disallow overriding object prototype keys + if(!(key in Object.prototype) && val !== null) { + rval[key].push(unescape(val)); + } + } + return rval; + }; + + var rval; + if(typeof(query) === 'undefined') { + // set cached variables if needed + if(_queryVariables === null) { + if(typeof(window) !== 'undefined' && window.location && window.location.search) { + // parse window search query + _queryVariables = parse(window.location.search.substring(1)); + } else { + // no query variables available + _queryVariables = {}; + } + } + rval = _queryVariables; + } else { + // parse given query + rval = parse(query); + } + return rval; + }; + + /** + * Parses a fragment into a path and query. This method will take a URI + * fragment and break it up as if it were the main URI. For example: + * /bar/baz?a=1&b=2 + * results in: + * { + * path: ["bar", "baz"], + * query: {"k1": ["v1"], "k2": ["v2"]} + * } + * + * @return object with a path array and query object. + */ + util.parseFragment = function(fragment) { + // default to whole fragment + var fp = fragment; + var fq = ''; + // split into path and query if possible at the first '?' + var pos = fragment.indexOf('?'); + if(pos > 0) { + fp = fragment.substring(0, pos); + fq = fragment.substring(pos + 1); + } + // split path based on '/' and ignore first element if empty + var path = fp.split('/'); + if(path.length > 0 && path[0] === '') { + path.shift(); + } + // convert query into object + var query = (fq === '') ? {} : util.getQueryVariables(fq); + + return { + pathString: fp, + queryString: fq, + path: path, + query: query + }; + }; + + /** + * Makes a request out of a URI-like request string. This is intended to + * be used where a fragment id (after a URI '#') is parsed as a URI with + * path and query parts. The string should have a path beginning and + * delimited by '/' and optional query parameters following a '?'. The + * query should be a standard URL set of key value pairs delimited by + * '&'. For backwards compatibility the initial '/' on the path is not + * required. The request object has the following API, (fully described + * in the method code): + * { + * path: . + * query: , + * getPath(i): get part or all of the split path array, + * getQuery(k, i): get part or all of a query key array, + * getQueryLast(k, _default): get last element of a query key array. + * } + * + * @return object with request parameters. + */ + util.makeRequest = function(reqString) { + var frag = util.parseFragment(reqString); + var req = { + // full path string + path: frag.pathString, + // full query string + query: frag.queryString, + /** + * Get path or element in path. + * + * @param i optional path index. + * + * @return path or part of path if i provided. + */ + getPath: function(i) { + return (typeof(i) === 'undefined') ? frag.path : frag.path[i]; + }, + /** + * Get query, values for a key, or value for a key index. + * + * @param k optional query key. + * @param i optional query key index. + * + * @return query, values for a key, or value for a key index. + */ + getQuery: function(k, i) { + var rval; + if(typeof(k) === 'undefined') { + rval = frag.query; + } else { + rval = frag.query[k]; + if(rval && typeof(i) !== 'undefined') { + rval = rval[i]; + } + } + return rval; + }, + getQueryLast: function(k, _default) { + var rval; + var vals = req.getQuery(k); + if(vals) { + rval = vals[vals.length - 1]; + } else { + rval = _default; + } + return rval; + } + }; + return req; + }; + + /** + * Makes a URI out of a path, an object with query parameters, and a + * fragment. Uses jQuery.param() internally for query string creation. + * If the path is an array, it will be joined with '/'. + * + * @param path string path or array of strings. + * @param query object with query parameters. (optional) + * @param fragment fragment string. (optional) + * + * @return string object with request parameters. + */ + util.makeLink = function(path, query, fragment) { + // join path parts if needed + path = jQuery.isArray(path) ? path.join('/') : path; + + var qstr = jQuery.param(query || {}); + fragment = fragment || ''; + return path + + ((qstr.length > 0) ? ('?' + qstr) : '') + + ((fragment.length > 0) ? ('#' + fragment) : ''); + }; + + /** + * Follows a path of keys deep into an object hierarchy and set a value. + * If a key does not exist or it's value is not an object, create an + * object in it's place. This can be destructive to a object tree if + * leaf nodes are given as non-final path keys. + * Used to avoid exceptions from missing parts of the path. + * + * @param object the starting object. + * @param keys an array of string keys. + * @param value the value to set. + */ + util.setPath = function(object, keys, value) { + // need to start at an object + if(typeof(object) === 'object' && object !== null) { + var i = 0; + var len = keys.length; + while(i < len) { + var next = keys[i++]; + if(i == len) { + // last + object[next] = value; + } else { + // more + var hasNext = (next in object); + if(!hasNext || + (hasNext && typeof(object[next]) !== 'object') || + (hasNext && object[next] === null)) { + object[next] = {}; + } + object = object[next]; + } + } + } + }; + + /** + * Follows a path of keys deep into an object hierarchy and return a value. + * If a key does not exist, create an object in it's place. + * Used to avoid exceptions from missing parts of the path. + * + * @param object the starting object. + * @param keys an array of string keys. + * @param _default value to return if path not found. + * + * @return the value at the path if found, else default if given, else + * undefined. + */ + util.getPath = function(object, keys, _default) { + var i = 0; + var len = keys.length; + var hasNext = true; + while(hasNext && i < len && + typeof(object) === 'object' && object !== null) { + var next = keys[i++]; + hasNext = next in object; + if(hasNext) { + object = object[next]; + } + } + return (hasNext ? object : _default); + }; + + /** + * Follow a path of keys deep into an object hierarchy and delete the + * last one. If a key does not exist, do nothing. + * Used to avoid exceptions from missing parts of the path. + * + * @param object the starting object. + * @param keys an array of string keys. + */ + util.deletePath = function(object, keys) { + // need to start at an object + if(typeof(object) === 'object' && object !== null) { + var i = 0; + var len = keys.length; + while(i < len) { + var next = keys[i++]; + if(i == len) { + // last + delete object[next]; + } else { + // more + if(!(next in object) || + (typeof(object[next]) !== 'object') || + (object[next] === null)) { + break; + } + object = object[next]; + } + } + } + }; + + /** + * Check if an object is empty. + * + * Taken from: + * http://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object-from-json/679937#679937 + * + * @param object the object to check. + */ + util.isEmpty = function(obj) { + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { + return false; + } + } + return true; + }; + + /** + * Format with simple printf-style interpolation. + * + * %%: literal '%' + * %s,%o: convert next argument into a string. + * + * @param format the string to format. + * @param ... arguments to interpolate into the format string. + */ + util.format = function(format) { + var re = /%./g; + // current match + var match; + // current part + var part; + // current arg index + var argi = 0; + // collected parts to recombine later + var parts = []; + // last index found + var last = 0; + // loop while matches remain + while((match = re.exec(format))) { + part = format.substring(last, re.lastIndex - 2); + // don't add empty strings (ie, parts between %s%s) + if(part.length > 0) { + parts.push(part); + } + last = re.lastIndex; + // switch on % code + var code = match[0][1]; + switch(code) { + case 's': + case 'o': + // check if enough arguments were given + if(argi < arguments.length) { + parts.push(arguments[argi++ + 1]); + } else { + parts.push(''); + } + break; + // FIXME: do proper formating for numbers, etc + //case 'f': + //case 'd': + case '%': + parts.push('%'); + break; + default: + parts.push('<%' + code + '?>'); + } + } + // add trailing part of format string + parts.push(format.substring(last)); + return parts.join(''); + }; + + /** + * Formats a number. + * + * http://snipplr.com/view/5945/javascript-numberformat--ported-from-php/ + */ + util.formatNumber = function(number, decimals, dec_point, thousands_sep) { + // http://kevin.vanzonneveld.net + // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfix by: Michael White (http://crestidg.com) + // + bugfix by: Benjamin Lupton + // + bugfix by: Allan Jensen (http://www.winternet.no) + // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // * example 1: number_format(1234.5678, 2, '.', ''); + // * returns 1: 1234.57 + + var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals; + var d = dec_point === undefined ? ',' : dec_point; + var t = thousands_sep === undefined ? + '.' : thousands_sep, s = n < 0 ? '-' : ''; + var i = parseInt((n = Math.abs(+n || 0).toFixed(c)), 10) + ''; + var j = (i.length > 3) ? i.length % 3 : 0; + return s + (j ? i.substr(0, j) + t : '') + + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + t) + + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ''); + }; + + /** + * Formats a byte size. + * + * http://snipplr.com/view/5949/format-humanize-file-byte-size-presentation-in-javascript/ + */ + util.formatSize = function(size) { + if(size >= 1073741824) { + size = util.formatNumber(size / 1073741824, 2, '.', '') + ' GiB'; + } else if(size >= 1048576) { + size = util.formatNumber(size / 1048576, 2, '.', '') + ' MiB'; + } else if(size >= 1024) { + size = util.formatNumber(size / 1024, 0) + ' KiB'; + } else { + size = util.formatNumber(size, 0) + ' bytes'; + } + return size; + }; + + /** + * Converts an IPv4 or IPv6 string representation into bytes (in network order). + * + * @param ip the IPv4 or IPv6 address to convert. + * + * @return the 4-byte IPv6 or 16-byte IPv6 address or null if the address can't + * be parsed. + */ + util.bytesFromIP = function(ip) { + if(ip.indexOf('.') !== -1) { + return util.bytesFromIPv4(ip); + } + if(ip.indexOf(':') !== -1) { + return util.bytesFromIPv6(ip); + } + return null; + }; + + /** + * Converts an IPv4 string representation into bytes (in network order). + * + * @param ip the IPv4 address to convert. + * + * @return the 4-byte address or null if the address can't be parsed. + */ + util.bytesFromIPv4 = function(ip) { + ip = ip.split('.'); + if(ip.length !== 4) { + return null; + } + var b = util.createBuffer(); + for(var i = 0; i < ip.length; ++i) { + var num = parseInt(ip[i], 10); + if(isNaN(num)) { + return null; + } + b.putByte(num); + } + return b.getBytes(); + }; + + /** + * Converts an IPv6 string representation into bytes (in network order). + * + * @param ip the IPv6 address to convert. + * + * @return the 16-byte address or null if the address can't be parsed. + */ + util.bytesFromIPv6 = function(ip) { + var blanks = 0; + ip = ip.split(':').filter(function(e) { + if(e.length === 0) ++blanks; + return true; + }); + var zeros = (8 - ip.length + blanks) * 2; + var b = util.createBuffer(); + for(var i = 0; i < 8; ++i) { + if(!ip[i] || ip[i].length === 0) { + b.fillWithByte(0, zeros); + zeros = 0; + continue; + } + var bytes = util.hexToBytes(ip[i]); + if(bytes.length < 2) { + b.putByte(0); + } + b.putBytes(bytes); + } + return b.getBytes(); + }; + + /** + * Converts 4-bytes into an IPv4 string representation or 16-bytes into + * an IPv6 string representation. The bytes must be in network order. + * + * @param bytes the bytes to convert. + * + * @return the IPv4 or IPv6 string representation if 4 or 16 bytes, + * respectively, are given, otherwise null. + */ + util.bytesToIP = function(bytes) { + if(bytes.length === 4) { + return util.bytesToIPv4(bytes); + } + if(bytes.length === 16) { + return util.bytesToIPv6(bytes); + } + return null; + }; + + /** + * Converts 4-bytes into an IPv4 string representation. The bytes must be + * in network order. + * + * @param bytes the bytes to convert. + * + * @return the IPv4 string representation or null for an invalid # of bytes. + */ + util.bytesToIPv4 = function(bytes) { + if(bytes.length !== 4) { + return null; + } + var ip = []; + for(var i = 0; i < bytes.length; ++i) { + ip.push(bytes.charCodeAt(i)); + } + return ip.join('.'); + }; + + /** + * Converts 16-bytes into an IPv16 string representation. The bytes must be + * in network order. + * + * @param bytes the bytes to convert. + * + * @return the IPv16 string representation or null for an invalid # of bytes. + */ + util.bytesToIPv6 = function(bytes) { + if(bytes.length !== 16) { + return null; + } + var ip = []; + var zeroGroups = []; + var zeroMaxGroup = 0; + for(var i = 0; i < bytes.length; i += 2) { + var hex = util.bytesToHex(bytes[i] + bytes[i + 1]); + // canonicalize zero representation + while(hex[0] === '0' && hex !== '0') { + hex = hex.substr(1); + } + if(hex === '0') { + var last = zeroGroups[zeroGroups.length - 1]; + var idx = ip.length; + if(!last || idx !== last.end + 1) { + zeroGroups.push({start: idx, end: idx}); + } else { + last.end = idx; + if((last.end - last.start) > + (zeroGroups[zeroMaxGroup].end - zeroGroups[zeroMaxGroup].start)) { + zeroMaxGroup = zeroGroups.length - 1; + } + } + } + ip.push(hex); + } + if(zeroGroups.length > 0) { + var group = zeroGroups[zeroMaxGroup]; + // only shorten group of length > 0 + if(group.end - group.start > 0) { + ip.splice(group.start, group.end - group.start + 1, ''); + if(group.start === 0) { + ip.unshift(''); + } + if(group.end === 7) { + ip.push(''); + } + } + } + return ip.join(':'); + }; + + /** + * Estimates the number of processes that can be run concurrently. If + * creating Web Workers, keep in mind that the main JavaScript process needs + * its own core. + * + * @param options the options to use: + * update true to force an update (not use the cached value). + * @param callback(err, max) called once the operation completes. + */ + util.estimateCores = function(options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + if('cores' in util && !options.update) { + return callback(null, util.cores); + } + if(typeof navigator !== 'undefined' && + 'hardwareConcurrency' in navigator && + navigator.hardwareConcurrency > 0) { + util.cores = navigator.hardwareConcurrency; + return callback(null, util.cores); + } + if(typeof Worker === 'undefined') { + // workers not available + util.cores = 1; + return callback(null, util.cores); + } + if(typeof Blob === 'undefined') { + // can't estimate, default to 2 + util.cores = 2; + return callback(null, util.cores); + } + + // create worker concurrency estimation code as blob + var blobUrl = URL.createObjectURL(new Blob(['(', + function() { + self.addEventListener('message', function(e) { + // run worker for 4 ms + var st = Date.now(); + var et = st + 4; + self.postMessage({st: st, et: et}); + }); + }.toString(), + ')()'], {type: 'application/javascript'})); + + // take 5 samples using 16 workers + sample([], 5, 16); + + function sample(max, samples, numWorkers) { + if(samples === 0) { + // get overlap average + var avg = Math.floor(max.reduce(function(avg, x) { + return avg + x; + }, 0) / max.length); + util.cores = Math.max(1, avg); + URL.revokeObjectURL(blobUrl); + return callback(null, util.cores); + } + map(numWorkers, function(err, results) { + max.push(reduce(numWorkers, results)); + sample(max, samples - 1, numWorkers); + }); + } + + function map(numWorkers, callback) { + var workers = []; + var results = []; + for(var i = 0; i < numWorkers; ++i) { + var worker = new Worker(blobUrl); + worker.addEventListener('message', function(e) { + results.push(e.data); + if(results.length === numWorkers) { + for(var i = 0; i < numWorkers; ++i) { + workers[i].terminate(); + } + callback(null, results); + } + }); + workers.push(worker); + } + for(var i = 0; i < numWorkers; ++i) { + workers[i].postMessage(i); + } + } + + function reduce(numWorkers, results) { + // find overlapping time windows + var overlaps = []; + for(var n = 0; n < numWorkers; ++n) { + var r1 = results[n]; + var overlap = overlaps[n] = []; + for(var i = 0; i < numWorkers; ++i) { + if(n === i) { + continue; + } + var r2 = results[i]; + if((r1.st > r2.st && r1.st < r2.et) || + (r2.st > r1.st && r2.st < r1.et)) { + overlap.push(i); + } + } + } + // get maximum overlaps ... don't include overlapping worker itself + // as the main JS process was also being scheduled during the work and + // would have to be subtracted from the estimate anyway + return overlaps.reduce(function(max, overlap) { + return Math.max(max, overlap.length); + }, 0); + } + }; + }); + + /** + * Cipher base API. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + + + + var cipher = forge.cipher = forge.cipher || {}; + + // registered algorithms + forge.cipher.algorithms = forge.cipher.algorithms || {}; + + /** + * Creates a cipher object that can be used to encrypt data using the given + * algorithm and key. The algorithm may be provided as a string value for a + * previously registered algorithm or it may be given as a cipher algorithm + * API object. + * + * @param algorithm the algorithm to use, either a string or an algorithm API + * object. + * @param key the key to use, as a binary-encoded string of bytes or a + * byte buffer. + * + * @return the cipher. + */ + forge.cipher.createCipher = function(algorithm, key) { + var api = algorithm; + if(typeof api === 'string') { + api = forge.cipher.getAlgorithm(api); + if(api) { + api = api(); + } + } + if(!api) { + throw new Error('Unsupported algorithm: ' + algorithm); + } + + // assume block cipher + return new forge.cipher.BlockCipher({ + algorithm: api, + key: key, + decrypt: false + }); + }; + + /** + * Creates a decipher object that can be used to decrypt data using the given + * algorithm and key. The algorithm may be provided as a string value for a + * previously registered algorithm or it may be given as a cipher algorithm + * API object. + * + * @param algorithm the algorithm to use, either a string or an algorithm API + * object. + * @param key the key to use, as a binary-encoded string of bytes or a + * byte buffer. + * + * @return the cipher. + */ + forge.cipher.createDecipher = function(algorithm, key) { + var api = algorithm; + if(typeof api === 'string') { + api = forge.cipher.getAlgorithm(api); + if(api) { + api = api(); + } + } + if(!api) { + throw new Error('Unsupported algorithm: ' + algorithm); + } + + // assume block cipher + return new forge.cipher.BlockCipher({ + algorithm: api, + key: key, + decrypt: true + }); + }; + + /** + * Registers an algorithm by name. If the name was already registered, the + * algorithm API object will be overwritten. + * + * @param name the name of the algorithm. + * @param algorithm the algorithm API object. + */ + forge.cipher.registerAlgorithm = function(name, algorithm) { + name = name.toUpperCase(); + forge.cipher.algorithms[name] = algorithm; + }; + + /** + * Gets a registered algorithm by name. + * + * @param name the name of the algorithm. + * + * @return the algorithm, if found, null if not. + */ + forge.cipher.getAlgorithm = function(name) { + name = name.toUpperCase(); + if(name in forge.cipher.algorithms) { + return forge.cipher.algorithms[name]; + } + return null; + }; + + var BlockCipher = forge.cipher.BlockCipher = function(options) { + this.algorithm = options.algorithm; + this.mode = this.algorithm.mode; + this.blockSize = this.mode.blockSize; + this._finish = false; + this._input = null; + this.output = null; + this._op = options.decrypt ? this.mode.decrypt : this.mode.encrypt; + this._decrypt = options.decrypt; + this.algorithm.initialize(options); + }; + + /** + * Starts or restarts the encryption or decryption process, whichever + * was previously configured. + * + * For non-GCM mode, the IV may be a binary-encoded string of bytes, an array + * of bytes, a byte buffer, or an array of 32-bit integers. If the IV is in + * bytes, then it must be Nb (16) bytes in length. If the IV is given in as + * 32-bit integers, then it must be 4 integers long. + * + * Note: an IV is not required or used in ECB mode. + * + * For GCM-mode, the IV must be given as a binary-encoded string of bytes or + * a byte buffer. The number of bytes should be 12 (96 bits) as recommended + * by NIST SP-800-38D but another length may be given. + * + * @param options the options to use: + * iv the initialization vector to use as a binary-encoded string of + * bytes, null to reuse the last ciphered block from a previous + * update() (this "residue" method is for legacy support only). + * additionalData additional authentication data as a binary-encoded + * string of bytes, for 'GCM' mode, (default: none). + * tagLength desired length of authentication tag, in bits, for + * 'GCM' mode (0-128, default: 128). + * tag the authentication tag to check if decrypting, as a + * binary-encoded string of bytes. + * output the output the buffer to write to, null to create one. + */ + BlockCipher.prototype.start = function(options) { + options = options || {}; + var opts = {}; + for(var key in options) { + opts[key] = options[key]; + } + opts.decrypt = this._decrypt; + this._finish = false; + this._input = forge.util.createBuffer(); + this.output = options.output || forge.util.createBuffer(); + this.mode.start(opts); + }; + + /** + * Updates the next block according to the cipher mode. + * + * @param input the buffer to read from. + */ + BlockCipher.prototype.update = function(input) { + if(input) { + // input given, so empty it into the input buffer + this._input.putBuffer(input); + } + + // do cipher operation until it needs more input and not finished + while(!this._op.call(this.mode, this._input, this.output, this._finish) && + !this._finish) {} + + // free consumed memory from input buffer + this._input.compact(); + }; + + /** + * Finishes encrypting or decrypting. + * + * @param pad a padding function to use in CBC mode, null for default, + * signature(blockSize, buffer, decrypt). + * + * @return true if successful, false on error. + */ + BlockCipher.prototype.finish = function(pad) { + // backwards-compatibility w/deprecated padding API + // Note: will overwrite padding functions even after another start() call + if(pad && (this.mode.name === 'ECB' || this.mode.name === 'CBC')) { + this.mode.pad = function(input) { + return pad(this.blockSize, input, false); + }; + this.mode.unpad = function(output) { + return pad(this.blockSize, output, true); + }; + } + + // build options for padding and afterFinish functions + var options = {}; + options.decrypt = this._decrypt; + + // get # of bytes that won't fill a block + options.overflow = this._input.length() % this.blockSize; + + if(!this._decrypt && this.mode.pad) { + if(!this.mode.pad(this._input, options)) { + return false; + } + } + + // do final update + this._finish = true; + this.update(); + + if(this._decrypt && this.mode.unpad) { + if(!this.mode.unpad(this.output, options)) { + return false; + } + } + + if(this.mode.afterFinish) { + if(!this.mode.afterFinish(this.output, options)) { + return false; + } + } + + return true; + }; + + var cipherModes = createCommonjsModule(function (module) { + /** + * Supported cipher modes. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + + + + forge.cipher = forge.cipher || {}; + + // supported cipher modes + var modes = module.exports = forge.cipher.modes = forge.cipher.modes || {}; + + /** Electronic codebook (ECB) (Don't use this; it's not secure) **/ + + modes.ecb = function(options) { + options = options || {}; + this.name = 'ECB'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = new Array(this._ints); + this._outBlock = new Array(this._ints); + }; + + modes.ecb.prototype.start = function(options) {}; + + modes.ecb.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // write output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i]); + } + }; + + modes.ecb.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + } + + // decrypt block + this.cipher.decrypt(this._inBlock, this._outBlock); + + // write output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i]); + } + }; + + modes.ecb.prototype.pad = function(input, options) { + // add PKCS#7 padding to block (each pad byte is the + // value of the number of pad bytes) + var padding = (input.length() === this.blockSize ? + this.blockSize : (this.blockSize - input.length())); + input.fillWithByte(padding, padding); + return true; + }; + + modes.ecb.prototype.unpad = function(output, options) { + // check for error: input data not a multiple of blockSize + if(options.overflow > 0) { + return false; + } + + // ensure padding byte count is valid + var len = output.length(); + var count = output.at(len - 1); + if(count > (this.blockSize << 2)) { + return false; + } + + // trim off padding bytes + output.truncate(count); + return true; + }; + + /** Cipher-block Chaining (CBC) **/ + + modes.cbc = function(options) { + options = options || {}; + this.name = 'CBC'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = new Array(this._ints); + this._outBlock = new Array(this._ints); + }; + + modes.cbc.prototype.start = function(options) { + // Note: legacy support for using IV residue (has security flaws) + // if IV is null, reuse block from previous processing + if(options.iv === null) { + // must have a previous block + if(!this._prev) { + throw new Error('Invalid IV parameter.'); + } + this._iv = this._prev.slice(0); + } else if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } else { + // save IV as "previous" block + this._iv = transformIV(options.iv, this.blockSize); + this._prev = this._iv.slice(0); + } + }; + + modes.cbc.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + // CBC XOR's IV (or previous block) with plaintext + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._prev[i] ^ input.getInt32(); + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // write output, save previous block + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i]); + } + this._prev = this._outBlock; + }; + + modes.cbc.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + } + + // decrypt block + this.cipher.decrypt(this._inBlock, this._outBlock); + + // write output, save previous ciphered block + // CBC XOR's IV (or previous block) with ciphertext + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._prev[i] ^ this._outBlock[i]); + } + this._prev = this._inBlock.slice(0); + }; + + modes.cbc.prototype.pad = function(input, options) { + // add PKCS#7 padding to block (each pad byte is the + // value of the number of pad bytes) + var padding = (input.length() === this.blockSize ? + this.blockSize : (this.blockSize - input.length())); + input.fillWithByte(padding, padding); + return true; + }; + + modes.cbc.prototype.unpad = function(output, options) { + // check for error: input data not a multiple of blockSize + if(options.overflow > 0) { + return false; + } + + // ensure padding byte count is valid + var len = output.length(); + var count = output.at(len - 1); + if(count > (this.blockSize << 2)) { + return false; + } + + // trim off padding bytes + output.truncate(count); + return true; + }; + + /** Cipher feedback (CFB) **/ + + modes.cfb = function(options) { + options = options || {}; + this.name = 'CFB'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = null; + this._outBlock = new Array(this._ints); + this._partialBlock = new Array(this._ints); + this._partialOutput = forge.util.createBuffer(); + this._partialBytes = 0; + }; + + modes.cfb.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // use IV as first input + this._iv = transformIV(options.iv, this.blockSize); + this._inBlock = this._iv.slice(0); + this._partialBytes = 0; + }; + + modes.cfb.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output, write input as output + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32() ^ this._outBlock[i]; + output.putInt32(this._inBlock[i]); + } + return; + } + + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output, write input as partial output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialBlock[i] = input.getInt32() ^ this._outBlock[i]; + this._partialOutput.putInt32(this._partialBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } else { + // block complete, update input block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._partialBlock[i]; + } + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; + }; + + modes.cfb.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block (CFB always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output, write input as output + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + output.putInt32(this._inBlock[i] ^ this._outBlock[i]); + } + return; + } + + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output, write input as partial output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialBlock[i] = input.getInt32(); + this._partialOutput.putInt32(this._partialBlock[i] ^ this._outBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } else { + // block complete, update input block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._partialBlock[i]; + } + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; + }; + + /** Output feedback (OFB) **/ + + modes.ofb = function(options) { + options = options || {}; + this.name = 'OFB'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = null; + this._outBlock = new Array(this._ints); + this._partialOutput = forge.util.createBuffer(); + this._partialBytes = 0; + }; + + modes.ofb.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // use IV as first input + this._iv = transformIV(options.iv, this.blockSize); + this._inBlock = this._iv.slice(0); + this._partialBytes = 0; + }; + + modes.ofb.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(input.length() === 0) { + return true; + } + + // encrypt block (OFB always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output and update next input + for(var i = 0; i < this._ints; ++i) { + output.putInt32(input.getInt32() ^ this._outBlock[i]); + this._inBlock[i] = this._outBlock[i]; + } + return; + } + + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } else { + // block complete, update input block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._outBlock[i]; + } + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; + }; + + modes.ofb.prototype.decrypt = modes.ofb.prototype.encrypt; + + /** Counter (CTR) **/ + + modes.ctr = function(options) { + options = options || {}; + this.name = 'CTR'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = null; + this._outBlock = new Array(this._ints); + this._partialOutput = forge.util.createBuffer(); + this._partialBytes = 0; + }; + + modes.ctr.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // use IV as first input + this._iv = transformIV(options.iv, this.blockSize); + this._inBlock = this._iv.slice(0); + this._partialBytes = 0; + }; + + modes.ctr.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block (CTR always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(input.getInt32() ^ this._outBlock[i]); + } + } else { + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; + } + + // block complete, increment counter (input block) + inc32(this._inBlock); + }; + + modes.ctr.prototype.decrypt = modes.ctr.prototype.encrypt; + + /** Galois/Counter Mode (GCM) **/ + + modes.gcm = function(options) { + options = options || {}; + this.name = 'GCM'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = new Array(this._ints); + this._outBlock = new Array(this._ints); + this._partialOutput = forge.util.createBuffer(); + this._partialBytes = 0; + + // R is actually this value concatenated with 120 more zero bits, but + // we only XOR against R so the other zeros have no effect -- we just + // apply this value to the first integer in a block + this._R = 0xE1000000; + }; + + modes.gcm.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // ensure IV is a byte buffer + var iv = forge.util.createBuffer(options.iv); + + // no ciphered data processed yet + this._cipherLength = 0; + + // default additional data is none + var additionalData; + if('additionalData' in options) { + additionalData = forge.util.createBuffer(options.additionalData); + } else { + additionalData = forge.util.createBuffer(); + } + + // default tag length is 128 bits + if('tagLength' in options) { + this._tagLength = options.tagLength; + } else { + this._tagLength = 128; + } + + // if tag is given, ensure tag matches tag length + this._tag = null; + if(options.decrypt) { + // save tag to check later + this._tag = forge.util.createBuffer(options.tag).getBytes(); + if(this._tag.length !== (this._tagLength / 8)) { + throw new Error('Authentication tag does not match tag length.'); + } + } + + // create tmp storage for hash calculation + this._hashBlock = new Array(this._ints); + + // no tag generated yet + this.tag = null; + + // generate hash subkey + // (apply block cipher to "zero" block) + this._hashSubkey = new Array(this._ints); + this.cipher.encrypt([0, 0, 0, 0], this._hashSubkey); + + // generate table M + // use 4-bit tables (32 component decomposition of a 16 byte value) + // 8-bit tables take more space and are known to have security + // vulnerabilities (in native implementations) + this.componentBits = 4; + this._m = this.generateHashTable(this._hashSubkey, this.componentBits); + + // Note: support IV length different from 96 bits? (only supporting + // 96 bits is recommended by NIST SP-800-38D) + // generate J_0 + var ivLength = iv.length(); + if(ivLength === 12) { + // 96-bit IV + this._j0 = [iv.getInt32(), iv.getInt32(), iv.getInt32(), 1]; + } else { + // IV is NOT 96-bits + this._j0 = [0, 0, 0, 0]; + while(iv.length() > 0) { + this._j0 = this.ghash( + this._hashSubkey, this._j0, + [iv.getInt32(), iv.getInt32(), iv.getInt32(), iv.getInt32()]); + } + this._j0 = this.ghash( + this._hashSubkey, this._j0, [0, 0].concat(from64To32(ivLength * 8))); + } + + // generate ICB (initial counter block) + this._inBlock = this._j0.slice(0); + inc32(this._inBlock); + this._partialBytes = 0; + + // consume authentication data + additionalData = forge.util.createBuffer(additionalData); + // save additional data length as a BE 64-bit number + this._aDataLength = from64To32(additionalData.length() * 8); + // pad additional data to 128 bit (16 byte) block size + var overflow = additionalData.length() % this.blockSize; + if(overflow) { + additionalData.fillWithByte(0, this.blockSize - overflow); + } + this._s = [0, 0, 0, 0]; + while(additionalData.length() > 0) { + this._s = this.ghash(this._hashSubkey, this._s, [ + additionalData.getInt32(), + additionalData.getInt32(), + additionalData.getInt32(), + additionalData.getInt32() + ]); + } + }; + + modes.gcm.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i] ^= input.getInt32()); + } + this._cipherLength += this.blockSize; + } else { + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); + } + + if(partialBytes <= 0 || finish) { + // handle overflow prior to hashing + if(finish) { + // get block overflow + var overflow = inputLength % this.blockSize; + this._cipherLength += overflow; + // truncate for hash function + this._partialOutput.truncate(this.blockSize - overflow); + } else { + this._cipherLength += this.blockSize; + } + + // get output block for hashing + for(var i = 0; i < this._ints; ++i) { + this._outBlock[i] = this._partialOutput.getInt32(); + } + this._partialOutput.read -= this.blockSize; + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + // block still incomplete, restore input buffer, get partial output, + // and return early + input.read -= this.blockSize; + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; + } + + // update hash block S + this._s = this.ghash(this._hashSubkey, this._s, this._outBlock); + + // increment counter (input block) + inc32(this._inBlock); + }; + + modes.gcm.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + var inputLength = input.length(); + if(inputLength < this.blockSize && !(finish && inputLength > 0)) { + return true; + } + + // encrypt block (GCM always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // increment counter (input block) + inc32(this._inBlock); + + // update hash block S + this._hashBlock[0] = input.getInt32(); + this._hashBlock[1] = input.getInt32(); + this._hashBlock[2] = input.getInt32(); + this._hashBlock[3] = input.getInt32(); + this._s = this.ghash(this._hashSubkey, this._s, this._hashBlock); + + // XOR hash input with output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i] ^ this._hashBlock[i]); + } + + // increment cipher data length + if(inputLength < this.blockSize) { + this._cipherLength += inputLength % this.blockSize; + } else { + this._cipherLength += this.blockSize; + } + }; + + modes.gcm.prototype.afterFinish = function(output, options) { + var rval = true; + + // handle overflow + if(options.decrypt && options.overflow) { + output.truncate(this.blockSize - options.overflow); + } + + // handle authentication tag + this.tag = forge.util.createBuffer(); + + // concatenate additional data length with cipher length + var lengths = this._aDataLength.concat(from64To32(this._cipherLength * 8)); + + // include lengths in hash + this._s = this.ghash(this._hashSubkey, this._s, lengths); + + // do GCTR(J_0, S) + var tag = []; + this.cipher.encrypt(this._j0, tag); + for(var i = 0; i < this._ints; ++i) { + this.tag.putInt32(this._s[i] ^ tag[i]); + } + + // trim tag to length + this.tag.truncate(this.tag.length() % (this._tagLength / 8)); + + // check authentication tag + if(options.decrypt && this.tag.bytes() !== this._tag) { + rval = false; + } + + return rval; + }; + + /** + * See NIST SP-800-38D 6.3 (Algorithm 1). This function performs Galois + * field multiplication. The field, GF(2^128), is defined by the polynomial: + * + * x^128 + x^7 + x^2 + x + 1 + * + * Which is represented in little-endian binary form as: 11100001 (0xe1). When + * the value of a coefficient is 1, a bit is set. The value R, is the + * concatenation of this value and 120 zero bits, yielding a 128-bit value + * which matches the block size. + * + * This function will multiply two elements (vectors of bytes), X and Y, in + * the field GF(2^128). The result is initialized to zero. For each bit of + * X (out of 128), x_i, if x_i is set, then the result is multiplied (XOR'd) + * by the current value of Y. For each bit, the value of Y will be raised by + * a power of x (multiplied by the polynomial x). This can be achieved by + * shifting Y once to the right. If the current value of Y, prior to being + * multiplied by x, has 0 as its LSB, then it is a 127th degree polynomial. + * Otherwise, we must divide by R after shifting to find the remainder. + * + * @param x the first block to multiply by the second. + * @param y the second block to multiply by the first. + * + * @return the block result of the multiplication. + */ + modes.gcm.prototype.multiply = function(x, y) { + var z_i = [0, 0, 0, 0]; + var v_i = y.slice(0); + + // calculate Z_128 (block has 128 bits) + for(var i = 0; i < 128; ++i) { + // if x_i is 0, Z_{i+1} = Z_i (unchanged) + // else Z_{i+1} = Z_i ^ V_i + // get x_i by finding 32-bit int position, then left shift 1 by remainder + var x_i = x[(i / 32) | 0] & (1 << (31 - i % 32)); + if(x_i) { + z_i[0] ^= v_i[0]; + z_i[1] ^= v_i[1]; + z_i[2] ^= v_i[2]; + z_i[3] ^= v_i[3]; + } + + // if LSB(V_i) is 1, V_i = V_i >> 1 + // else V_i = (V_i >> 1) ^ R + this.pow(v_i, v_i); + } + + return z_i; + }; + + modes.gcm.prototype.pow = function(x, out) { + // if LSB(x) is 1, x = x >>> 1 + // else x = (x >>> 1) ^ R + var lsb = x[3] & 1; + + // always do x >>> 1: + // starting with the rightmost integer, shift each integer to the right + // one bit, pulling in the bit from the integer to the left as its top + // most bit (do this for the last 3 integers) + for(var i = 3; i > 0; --i) { + out[i] = (x[i] >>> 1) | ((x[i - 1] & 1) << 31); + } + // shift the first integer normally + out[0] = x[0] >>> 1; + + // if lsb was not set, then polynomial had a degree of 127 and doesn't + // need to divided; otherwise, XOR with R to find the remainder; we only + // need to XOR the first integer since R technically ends w/120 zero bits + if(lsb) { + out[0] ^= this._R; + } + }; + + modes.gcm.prototype.tableMultiply = function(x) { + // assumes 4-bit tables are used + var z = [0, 0, 0, 0]; + for(var i = 0; i < 32; ++i) { + var idx = (i / 8) | 0; + var x_i = (x[idx] >>> ((7 - (i % 8)) * 4)) & 0xF; + var ah = this._m[i][x_i]; + z[0] ^= ah[0]; + z[1] ^= ah[1]; + z[2] ^= ah[2]; + z[3] ^= ah[3]; + } + return z; + }; + + /** + * A continuing version of the GHASH algorithm that operates on a single + * block. The hash block, last hash value (Ym) and the new block to hash + * are given. + * + * @param h the hash block. + * @param y the previous value for Ym, use [0, 0, 0, 0] for a new hash. + * @param x the block to hash. + * + * @return the hashed value (Ym). + */ + modes.gcm.prototype.ghash = function(h, y, x) { + y[0] ^= x[0]; + y[1] ^= x[1]; + y[2] ^= x[2]; + y[3] ^= x[3]; + return this.tableMultiply(y); + //return this.multiply(y, h); + }; + + /** + * Precomputes a table for multiplying against the hash subkey. This + * mechanism provides a substantial speed increase over multiplication + * performed without a table. The table-based multiplication this table is + * for solves X * H by multiplying each component of X by H and then + * composing the results together using XOR. + * + * This function can be used to generate tables with different bit sizes + * for the components, however, this implementation assumes there are + * 32 components of X (which is a 16 byte vector), therefore each component + * takes 4-bits (so the table is constructed with bits=4). + * + * @param h the hash subkey. + * @param bits the bit size for a component. + */ + modes.gcm.prototype.generateHashTable = function(h, bits) { + // TODO: There are further optimizations that would use only the + // first table M_0 (or some variant) along with a remainder table; + // this can be explored in the future + var multiplier = 8 / bits; + var perInt = 4 * multiplier; + var size = 16 * multiplier; + var m = new Array(size); + for(var i = 0; i < size; ++i) { + var tmp = [0, 0, 0, 0]; + var idx = (i / perInt) | 0; + var shft = ((perInt - 1 - (i % perInt)) * bits); + tmp[idx] = (1 << (bits - 1)) << shft; + m[i] = this.generateSubHashTable(this.multiply(tmp, h), bits); + } + return m; + }; + + /** + * Generates a table for multiplying against the hash subkey for one + * particular component (out of all possible component values). + * + * @param mid the pre-multiplied value for the middle key of the table. + * @param bits the bit size for a component. + */ + modes.gcm.prototype.generateSubHashTable = function(mid, bits) { + // compute the table quickly by minimizing the number of + // POW operations -- they only need to be performed for powers of 2, + // all other entries can be composed from those powers using XOR + var size = 1 << bits; + var half = size >>> 1; + var m = new Array(size); + m[half] = mid.slice(0); + var i = half >>> 1; + while(i > 0) { + // raise m0[2 * i] and store in m0[i] + this.pow(m[2 * i], m[i] = []); + i >>= 1; + } + i = 2; + while(i < half) { + for(var j = 1; j < i; ++j) { + var m_i = m[i]; + var m_j = m[j]; + m[i + j] = [ + m_i[0] ^ m_j[0], + m_i[1] ^ m_j[1], + m_i[2] ^ m_j[2], + m_i[3] ^ m_j[3] + ]; + } + i *= 2; + } + m[0] = [0, 0, 0, 0]; + /* Note: We could avoid storing these by doing composition during multiply + calculate top half using composition by speed is preferred. */ + for(i = half + 1; i < size; ++i) { + var c = m[i ^ half]; + m[i] = [mid[0] ^ c[0], mid[1] ^ c[1], mid[2] ^ c[2], mid[3] ^ c[3]]; + } + return m; + }; + + /** Utility functions */ + + function transformIV(iv, blockSize) { + if(typeof iv === 'string') { + // convert iv string into byte buffer + iv = forge.util.createBuffer(iv); + } + + if(forge.util.isArray(iv) && iv.length > 4) { + // convert iv byte array into byte buffer + var tmp = iv; + iv = forge.util.createBuffer(); + for(var i = 0; i < tmp.length; ++i) { + iv.putByte(tmp[i]); + } + } + + if(iv.length() < blockSize) { + throw new Error( + 'Invalid IV length; got ' + iv.length() + + ' bytes and expected ' + blockSize + ' bytes.'); + } + + if(!forge.util.isArray(iv)) { + // convert iv byte buffer into 32-bit integer array + var ints = []; + var blocks = blockSize / 4; + for(var i = 0; i < blocks; ++i) { + ints.push(iv.getInt32()); + } + iv = ints; + } + + return iv; + } + + function inc32(block) { + // increment last 32 bits of block only + block[block.length - 1] = (block[block.length - 1] + 1) & 0xFFFFFFFF; + } + + function from64To32(num) { + // convert 64-bit number to two BE Int32s + return [(num / 0x100000000) | 0, num & 0xFFFFFFFF]; + } + }); + + /** + * Advanced Encryption Standard (AES) implementation. + * + * This implementation is based on the public domain library 'jscrypto' which + * was written by: + * + * Emily Stark (estark@stanford.edu) + * Mike Hamburg (mhamburg@stanford.edu) + * Dan Boneh (dabo@cs.stanford.edu) + * + * Parts of this code are based on the OpenSSL implementation of AES: + * http://www.openssl.org + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + + + + + + /* AES API */ + var aes = forge.aes = forge.aes || {}; + + /** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('AES-', key); + * cipher.start({iv: iv}); + * + * Creates an AES cipher object to encrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as a string of bytes, an array of bytes, + * a byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + forge.aes.startEncrypting = function(key, iv, output, mode) { + var cipher = _createCipher({ + key: key, + output: output, + decrypt: false, + mode: mode + }); + cipher.start(iv); + return cipher; + }; + + /** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('AES-', key); + * + * Creates an AES cipher object to encrypt data using the given symmetric key. + * + * The key may be given as a string of bytes, an array of bytes, a + * byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + forge.aes.createEncryptionCipher = function(key, mode) { + return _createCipher({ + key: key, + output: null, + decrypt: false, + mode: mode + }); + }; + + /** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('AES-', key); + * decipher.start({iv: iv}); + * + * Creates an AES cipher object to decrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as a string of bytes, an array of bytes, + * a byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + forge.aes.startDecrypting = function(key, iv, output, mode) { + var cipher = _createCipher({ + key: key, + output: output, + decrypt: true, + mode: mode + }); + cipher.start(iv); + return cipher; + }; + + /** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('AES-', key); + * + * Creates an AES cipher object to decrypt data using the given symmetric key. + * + * The key may be given as a string of bytes, an array of bytes, a + * byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + forge.aes.createDecryptionCipher = function(key, mode) { + return _createCipher({ + key: key, + output: null, + decrypt: true, + mode: mode + }); + }; + + /** + * Creates a new AES cipher algorithm object. + * + * @param name the name of the algorithm. + * @param mode the mode factory function. + * + * @return the AES algorithm object. + */ + forge.aes.Algorithm = function(name, mode) { + if(!init) { + initialize(); + } + var self = this; + self.name = name; + self.mode = new mode({ + blockSize: 16, + cipher: { + encrypt: function(inBlock, outBlock) { + return _updateBlock(self._w, inBlock, outBlock, false); + }, + decrypt: function(inBlock, outBlock) { + return _updateBlock(self._w, inBlock, outBlock, true); + } + } + }); + self._init = false; + }; + + /** + * Initializes this AES algorithm by expanding its key. + * + * @param options the options to use. + * key the key to use with this algorithm. + * decrypt true if the algorithm should be initialized for decryption, + * false for encryption. + */ + forge.aes.Algorithm.prototype.initialize = function(options) { + if(this._init) { + return; + } + + var key = options.key; + var tmp; + + /* Note: The key may be a string of bytes, an array of bytes, a byte + buffer, or an array of 32-bit integers. If the key is in bytes, then + it must be 16, 24, or 32 bytes in length. If it is in 32-bit + integers, it must be 4, 6, or 8 integers long. */ + + if(typeof key === 'string' && + (key.length === 16 || key.length === 24 || key.length === 32)) { + // convert key string into byte buffer + key = forge.util.createBuffer(key); + } else if(forge.util.isArray(key) && + (key.length === 16 || key.length === 24 || key.length === 32)) { + // convert key integer array into byte buffer + tmp = key; + key = forge.util.createBuffer(); + for(var i = 0; i < tmp.length; ++i) { + key.putByte(tmp[i]); + } + } + + // convert key byte buffer into 32-bit integer array + if(!forge.util.isArray(key)) { + tmp = key; + key = []; + + // key lengths of 16, 24, 32 bytes allowed + var len = tmp.length(); + if(len === 16 || len === 24 || len === 32) { + len = len >>> 2; + for(var i = 0; i < len; ++i) { + key.push(tmp.getInt32()); + } + } + } + + // key must be an array of 32-bit integers by now + if(!forge.util.isArray(key) || + !(key.length === 4 || key.length === 6 || key.length === 8)) { + throw new Error('Invalid key parameter.'); + } + + // encryption operation is always used for these modes + var mode = this.mode.name; + var encryptOp = (['CFB', 'OFB', 'CTR', 'GCM'].indexOf(mode) !== -1); + + // do key expansion + this._w = _expandKey(key, options.decrypt && !encryptOp); + this._init = true; + }; + + /** + * Expands a key. Typically only used for testing. + * + * @param key the symmetric key to expand, as an array of 32-bit words. + * @param decrypt true to expand for decryption, false for encryption. + * + * @return the expanded key. + */ + forge.aes._expandKey = function(key, decrypt) { + if(!init) { + initialize(); + } + return _expandKey(key, decrypt); + }; + + /** + * Updates a single block. Typically only used for testing. + * + * @param w the expanded key to use. + * @param input an array of block-size 32-bit words. + * @param output an array of block-size 32-bit words. + * @param decrypt true to decrypt, false to encrypt. + */ + forge.aes._updateBlock = _updateBlock; + + /** Register AES algorithms **/ + + registerAlgorithm('AES-ECB', forge.cipher.modes.ecb); + registerAlgorithm('AES-CBC', forge.cipher.modes.cbc); + registerAlgorithm('AES-CFB', forge.cipher.modes.cfb); + registerAlgorithm('AES-OFB', forge.cipher.modes.ofb); + registerAlgorithm('AES-CTR', forge.cipher.modes.ctr); + registerAlgorithm('AES-GCM', forge.cipher.modes.gcm); + + function registerAlgorithm(name, mode) { + var factory = function() { + return new forge.aes.Algorithm(name, mode); + }; + forge.cipher.registerAlgorithm(name, factory); + } + + /** AES implementation **/ + + var init = false; // not yet initialized + var Nb = 4; // number of words comprising the state (AES = 4) + var sbox; // non-linear substitution table used in key expansion + var isbox; // inversion of sbox + var rcon; // round constant word array + var mix; // mix-columns table + var imix; // inverse mix-columns table + + /** + * Performs initialization, ie: precomputes tables to optimize for speed. + * + * One way to understand how AES works is to imagine that 'addition' and + * 'multiplication' are interfaces that require certain mathematical + * properties to hold true (ie: they are associative) but they might have + * different implementations and produce different kinds of results ... + * provided that their mathematical properties remain true. AES defines + * its own methods of addition and multiplication but keeps some important + * properties the same, ie: associativity and distributivity. The + * explanation below tries to shed some light on how AES defines addition + * and multiplication of bytes and 32-bit words in order to perform its + * encryption and decryption algorithms. + * + * The basics: + * + * The AES algorithm views bytes as binary representations of polynomials + * that have either 1 or 0 as the coefficients. It defines the addition + * or subtraction of two bytes as the XOR operation. It also defines the + * multiplication of two bytes as a finite field referred to as GF(2^8) + * (Note: 'GF' means "Galois Field" which is a field that contains a finite + * number of elements so GF(2^8) has 256 elements). + * + * This means that any two bytes can be represented as binary polynomials; + * when they multiplied together and modularly reduced by an irreducible + * polynomial of the 8th degree, the results are the field GF(2^8). The + * specific irreducible polynomial that AES uses in hexadecimal is 0x11b. + * This multiplication is associative with 0x01 as the identity: + * + * (b * 0x01 = GF(b, 0x01) = b). + * + * The operation GF(b, 0x02) can be performed at the byte level by left + * shifting b once and then XOR'ing it (to perform the modular reduction) + * with 0x11b if b is >= 128. Repeated application of the multiplication + * of 0x02 can be used to implement the multiplication of any two bytes. + * + * For instance, multiplying 0x57 and 0x13, denoted as GF(0x57, 0x13), can + * be performed by factoring 0x13 into 0x01, 0x02, and 0x10. Then these + * factors can each be multiplied by 0x57 and then added together. To do + * the multiplication, values for 0x57 multiplied by each of these 3 factors + * can be precomputed and stored in a table. To add them, the values from + * the table are XOR'd together. + * + * AES also defines addition and multiplication of words, that is 4-byte + * numbers represented as polynomials of 3 degrees where the coefficients + * are the values of the bytes. + * + * The word [a0, a1, a2, a3] is a polynomial a3x^3 + a2x^2 + a1x + a0. + * + * Addition is performed by XOR'ing like powers of x. Multiplication + * is performed in two steps, the first is an algebriac expansion as + * you would do normally (where addition is XOR). But the result is + * a polynomial larger than 3 degrees and thus it cannot fit in a word. So + * next the result is modularly reduced by an AES-specific polynomial of + * degree 4 which will always produce a polynomial of less than 4 degrees + * such that it will fit in a word. In AES, this polynomial is x^4 + 1. + * + * The modular product of two polynomials 'a' and 'b' is thus: + * + * d(x) = d3x^3 + d2x^2 + d1x + d0 + * with + * d0 = GF(a0, b0) ^ GF(a3, b1) ^ GF(a2, b2) ^ GF(a1, b3) + * d1 = GF(a1, b0) ^ GF(a0, b1) ^ GF(a3, b2) ^ GF(a2, b3) + * d2 = GF(a2, b0) ^ GF(a1, b1) ^ GF(a0, b2) ^ GF(a3, b3) + * d3 = GF(a3, b0) ^ GF(a2, b1) ^ GF(a1, b2) ^ GF(a0, b3) + * + * As a matrix: + * + * [d0] = [a0 a3 a2 a1][b0] + * [d1] [a1 a0 a3 a2][b1] + * [d2] [a2 a1 a0 a3][b2] + * [d3] [a3 a2 a1 a0][b3] + * + * Special polynomials defined by AES (0x02 == {02}): + * a(x) = {03}x^3 + {01}x^2 + {01}x + {02} + * a^-1(x) = {0b}x^3 + {0d}x^2 + {09}x + {0e}. + * + * These polynomials are used in the MixColumns() and InverseMixColumns() + * operations, respectively, to cause each element in the state to affect + * the output (referred to as diffusing). + * + * RotWord() uses: a0 = a1 = a2 = {00} and a3 = {01}, which is the + * polynomial x3. + * + * The ShiftRows() method modifies the last 3 rows in the state (where + * the state is 4 words with 4 bytes per word) by shifting bytes cyclically. + * The 1st byte in the second row is moved to the end of the row. The 1st + * and 2nd bytes in the third row are moved to the end of the row. The 1st, + * 2nd, and 3rd bytes are moved in the fourth row. + * + * More details on how AES arithmetic works: + * + * In the polynomial representation of binary numbers, XOR performs addition + * and subtraction and multiplication in GF(2^8) denoted as GF(a, b) + * corresponds with the multiplication of polynomials modulo an irreducible + * polynomial of degree 8. In other words, for AES, GF(a, b) will multiply + * polynomial 'a' with polynomial 'b' and then do a modular reduction by + * an AES-specific irreducible polynomial of degree 8. + * + * A polynomial is irreducible if its only divisors are one and itself. For + * the AES algorithm, this irreducible polynomial is: + * + * m(x) = x^8 + x^4 + x^3 + x + 1, + * + * or {01}{1b} in hexadecimal notation, where each coefficient is a bit: + * 100011011 = 283 = 0x11b. + * + * For example, GF(0x57, 0x83) = 0xc1 because + * + * 0x57 = 87 = 01010111 = x^6 + x^4 + x^2 + x + 1 + * 0x85 = 131 = 10000101 = x^7 + x + 1 + * + * (x^6 + x^4 + x^2 + x + 1) * (x^7 + x + 1) + * = x^13 + x^11 + x^9 + x^8 + x^7 + + * x^7 + x^5 + x^3 + x^2 + x + + * x^6 + x^4 + x^2 + x + 1 + * = x^13 + x^11 + x^9 + x^8 + x^6 + x^5 + x^4 + x^3 + 1 = y + * y modulo (x^8 + x^4 + x^3 + x + 1) + * = x^7 + x^6 + 1. + * + * The modular reduction by m(x) guarantees the result will be a binary + * polynomial of less than degree 8, so that it can fit in a byte. + * + * The operation to multiply a binary polynomial b with x (the polynomial + * x in binary representation is 00000010) is: + * + * b_7x^8 + b_6x^7 + b_5x^6 + b_4x^5 + b_3x^4 + b_2x^3 + b_1x^2 + b_0x^1 + * + * To get GF(b, x) we must reduce that by m(x). If b_7 is 0 (that is the + * most significant bit is 0 in b) then the result is already reduced. If + * it is 1, then we can reduce it by subtracting m(x) via an XOR. + * + * It follows that multiplication by x (00000010 or 0x02) can be implemented + * by performing a left shift followed by a conditional bitwise XOR with + * 0x1b. This operation on bytes is denoted by xtime(). Multiplication by + * higher powers of x can be implemented by repeated application of xtime(). + * + * By adding intermediate results, multiplication by any constant can be + * implemented. For instance: + * + * GF(0x57, 0x13) = 0xfe because: + * + * xtime(b) = (b & 128) ? (b << 1 ^ 0x11b) : (b << 1) + * + * Note: We XOR with 0x11b instead of 0x1b because in javascript our + * datatype for b can be larger than 1 byte, so a left shift will not + * automatically eliminate bits that overflow a byte ... by XOR'ing the + * overflow bit with 1 (the extra one from 0x11b) we zero it out. + * + * GF(0x57, 0x02) = xtime(0x57) = 0xae + * GF(0x57, 0x04) = xtime(0xae) = 0x47 + * GF(0x57, 0x08) = xtime(0x47) = 0x8e + * GF(0x57, 0x10) = xtime(0x8e) = 0x07 + * + * GF(0x57, 0x13) = GF(0x57, (0x01 ^ 0x02 ^ 0x10)) + * + * And by the distributive property (since XOR is addition and GF() is + * multiplication): + * + * = GF(0x57, 0x01) ^ GF(0x57, 0x02) ^ GF(0x57, 0x10) + * = 0x57 ^ 0xae ^ 0x07 + * = 0xfe. + */ + function initialize() { + init = true; + + /* Populate the Rcon table. These are the values given by + [x^(i-1),{00},{00},{00}] where x^(i-1) are powers of x (and x = 0x02) + in the field of GF(2^8), where i starts at 1. + + rcon[0] = [0x00, 0x00, 0x00, 0x00] + rcon[1] = [0x01, 0x00, 0x00, 0x00] 2^(1-1) = 2^0 = 1 + rcon[2] = [0x02, 0x00, 0x00, 0x00] 2^(2-1) = 2^1 = 2 + ... + rcon[9] = [0x1B, 0x00, 0x00, 0x00] 2^(9-1) = 2^8 = 0x1B + rcon[10] = [0x36, 0x00, 0x00, 0x00] 2^(10-1) = 2^9 = 0x36 + + We only store the first byte because it is the only one used. + */ + rcon = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]; + + // compute xtime table which maps i onto GF(i, 0x02) + var xtime = new Array(256); + for(var i = 0; i < 128; ++i) { + xtime[i] = i << 1; + xtime[i + 128] = (i + 128) << 1 ^ 0x11B; + } + + // compute all other tables + sbox = new Array(256); + isbox = new Array(256); + mix = new Array(4); + imix = new Array(4); + for(var i = 0; i < 4; ++i) { + mix[i] = new Array(256); + imix[i] = new Array(256); + } + var e = 0, ei = 0, e2, e4, e8, sx, sx2, me, ime; + for(var i = 0; i < 256; ++i) { + /* We need to generate the SubBytes() sbox and isbox tables so that + we can perform byte substitutions. This requires us to traverse + all of the elements in GF, find their multiplicative inverses, + and apply to each the following affine transformation: + + bi' = bi ^ b(i + 4) mod 8 ^ b(i + 5) mod 8 ^ b(i + 6) mod 8 ^ + b(i + 7) mod 8 ^ ci + for 0 <= i < 8, where bi is the ith bit of the byte, and ci is the + ith bit of a byte c with the value {63} or {01100011}. + + It is possible to traverse every possible value in a Galois field + using what is referred to as a 'generator'. There are many + generators (128 out of 256): 3,5,6,9,11,82 to name a few. To fully + traverse GF we iterate 255 times, multiplying by our generator + each time. + + On each iteration we can determine the multiplicative inverse for + the current element. + + Suppose there is an element in GF 'e'. For a given generator 'g', + e = g^x. The multiplicative inverse of e is g^(255 - x). It turns + out that if use the inverse of a generator as another generator + it will produce all of the corresponding multiplicative inverses + at the same time. For this reason, we choose 5 as our inverse + generator because it only requires 2 multiplies and 1 add and its + inverse, 82, requires relatively few operations as well. + + In order to apply the affine transformation, the multiplicative + inverse 'ei' of 'e' can be repeatedly XOR'd (4 times) with a + bit-cycling of 'ei'. To do this 'ei' is first stored in 's' and + 'x'. Then 's' is left shifted and the high bit of 's' is made the + low bit. The resulting value is stored in 's'. Then 'x' is XOR'd + with 's' and stored in 'x'. On each subsequent iteration the same + operation is performed. When 4 iterations are complete, 'x' is + XOR'd with 'c' (0x63) and the transformed value is stored in 'x'. + For example: + + s = 01000001 + x = 01000001 + + iteration 1: s = 10000010, x ^= s + iteration 2: s = 00000101, x ^= s + iteration 3: s = 00001010, x ^= s + iteration 4: s = 00010100, x ^= s + x ^= 0x63 + + This can be done with a loop where s = (s << 1) | (s >> 7). However, + it can also be done by using a single 16-bit (in this case 32-bit) + number 'sx'. Since XOR is an associative operation, we can set 'sx' + to 'ei' and then XOR it with 'sx' left-shifted 1,2,3, and 4 times. + The most significant bits will flow into the high 8 bit positions + and be correctly XOR'd with one another. All that remains will be + to cycle the high 8 bits by XOR'ing them all with the lower 8 bits + afterwards. + + At the same time we're populating sbox and isbox we can precompute + the multiplication we'll need to do to do MixColumns() later. + */ + + // apply affine transformation + sx = ei ^ (ei << 1) ^ (ei << 2) ^ (ei << 3) ^ (ei << 4); + sx = (sx >> 8) ^ (sx & 255) ^ 0x63; + + // update tables + sbox[e] = sx; + isbox[sx] = e; + + /* Mixing columns is done using matrix multiplication. The columns + that are to be mixed are each a single word in the current state. + The state has Nb columns (4 columns). Therefore each column is a + 4 byte word. So to mix the columns in a single column 'c' where + its rows are r0, r1, r2, and r3, we use the following matrix + multiplication: + + [2 3 1 1]*[r0,c]=[r'0,c] + [1 2 3 1] [r1,c] [r'1,c] + [1 1 2 3] [r2,c] [r'2,c] + [3 1 1 2] [r3,c] [r'3,c] + + r0, r1, r2, and r3 are each 1 byte of one of the words in the + state (a column). To do matrix multiplication for each mixed + column c' we multiply the corresponding row from the left matrix + with the corresponding column from the right matrix. In total, we + get 4 equations: + + r0,c' = 2*r0,c + 3*r1,c + 1*r2,c + 1*r3,c + r1,c' = 1*r0,c + 2*r1,c + 3*r2,c + 1*r3,c + r2,c' = 1*r0,c + 1*r1,c + 2*r2,c + 3*r3,c + r3,c' = 3*r0,c + 1*r1,c + 1*r2,c + 2*r3,c + + As usual, the multiplication is as previously defined and the + addition is XOR. In order to optimize mixing columns we can store + the multiplication results in tables. If you think of the whole + column as a word (it might help to visualize by mentally rotating + the equations above by counterclockwise 90 degrees) then you can + see that it would be useful to map the multiplications performed on + each byte (r0, r1, r2, r3) onto a word as well. For instance, we + could map 2*r0,1*r0,1*r0,3*r0 onto a word by storing 2*r0 in the + highest 8 bits and 3*r0 in the lowest 8 bits (with the other two + respectively in the middle). This means that a table can be + constructed that uses r0 as an index to the word. We can do the + same with r1, r2, and r3, creating a total of 4 tables. + + To construct a full c', we can just look up each byte of c in + their respective tables and XOR the results together. + + Also, to build each table we only have to calculate the word + for 2,1,1,3 for every byte ... which we can do on each iteration + of this loop since we will iterate over every byte. After we have + calculated 2,1,1,3 we can get the results for the other tables + by cycling the byte at the end to the beginning. For instance + we can take the result of table 2,1,1,3 and produce table 3,2,1,1 + by moving the right most byte to the left most position just like + how you can imagine the 3 moved out of 2,1,1,3 and to the front + to produce 3,2,1,1. + + There is another optimization in that the same multiples of + the current element we need in order to advance our generator + to the next iteration can be reused in performing the 2,1,1,3 + calculation. We also calculate the inverse mix column tables, + with e,9,d,b being the inverse of 2,1,1,3. + + When we're done, and we need to actually mix columns, the first + byte of each state word should be put through mix[0] (2,1,1,3), + the second through mix[1] (3,2,1,1) and so forth. Then they should + be XOR'd together to produce the fully mixed column. + */ + + // calculate mix and imix table values + sx2 = xtime[sx]; + e2 = xtime[e]; + e4 = xtime[e2]; + e8 = xtime[e4]; + me = + (sx2 << 24) ^ // 2 + (sx << 16) ^ // 1 + (sx << 8) ^ // 1 + (sx ^ sx2); // 3 + ime = + (e2 ^ e4 ^ e8) << 24 ^ // E (14) + (e ^ e8) << 16 ^ // 9 + (e ^ e4 ^ e8) << 8 ^ // D (13) + (e ^ e2 ^ e8); // B (11) + // produce each of the mix tables by rotating the 2,1,1,3 value + for(var n = 0; n < 4; ++n) { + mix[n][e] = me; + imix[n][sx] = ime; + // cycle the right most byte to the left most position + // ie: 2,1,1,3 becomes 3,2,1,1 + me = me << 24 | me >>> 8; + ime = ime << 24 | ime >>> 8; + } + + // get next element and inverse + if(e === 0) { + // 1 is the inverse of 1 + e = ei = 1; + } else { + // e = 2e + 2*2*2*(10e)) = multiply e by 82 (chosen generator) + // ei = ei + 2*2*ei = multiply ei by 5 (inverse generator) + e = e2 ^ xtime[xtime[xtime[e2 ^ e8]]]; + ei ^= xtime[xtime[ei]]; + } + } + } + + /** + * Generates a key schedule using the AES key expansion algorithm. + * + * The AES algorithm takes the Cipher Key, K, and performs a Key Expansion + * routine to generate a key schedule. The Key Expansion generates a total + * of Nb*(Nr + 1) words: the algorithm requires an initial set of Nb words, + * and each of the Nr rounds requires Nb words of key data. The resulting + * key schedule consists of a linear array of 4-byte words, denoted [wi ], + * with i in the range 0 <= i < Nb(Nr + 1). + * + * KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk) + * AES-128 (Nb=4, Nk=4, Nr=10) + * AES-192 (Nb=4, Nk=6, Nr=12) + * AES-256 (Nb=4, Nk=8, Nr=14) + * Note: Nr=Nk+6. + * + * Nb is the number of columns (32-bit words) comprising the State (or + * number of bytes in a block). For AES, Nb=4. + * + * @param key the key to schedule (as an array of 32-bit words). + * @param decrypt true to modify the key schedule to decrypt, false not to. + * + * @return the generated key schedule. + */ + function _expandKey(key, decrypt) { + // copy the key's words to initialize the key schedule + var w = key.slice(0); + + /* RotWord() will rotate a word, moving the first byte to the last + byte's position (shifting the other bytes left). + + We will be getting the value of Rcon at i / Nk. 'i' will iterate + from Nk to (Nb * Nr+1). Nk = 4 (4 byte key), Nb = 4 (4 words in + a block), Nr = Nk + 6 (10). Therefore 'i' will iterate from + 4 to 44 (exclusive). Each time we iterate 4 times, i / Nk will + increase by 1. We use a counter iNk to keep track of this. + */ + + // go through the rounds expanding the key + var temp, iNk = 1; + var Nk = w.length; + var Nr1 = Nk + 6 + 1; + var end = Nb * Nr1; + for(var i = Nk; i < end; ++i) { + temp = w[i - 1]; + if(i % Nk === 0) { + // temp = SubWord(RotWord(temp)) ^ Rcon[i / Nk] + temp = + sbox[temp >>> 16 & 255] << 24 ^ + sbox[temp >>> 8 & 255] << 16 ^ + sbox[temp & 255] << 8 ^ + sbox[temp >>> 24] ^ (rcon[iNk] << 24); + iNk++; + } else if(Nk > 6 && (i % Nk === 4)) { + // temp = SubWord(temp) + temp = + sbox[temp >>> 24] << 24 ^ + sbox[temp >>> 16 & 255] << 16 ^ + sbox[temp >>> 8 & 255] << 8 ^ + sbox[temp & 255]; + } + w[i] = w[i - Nk] ^ temp; + } + + /* When we are updating a cipher block we always use the code path for + encryption whether we are decrypting or not (to shorten code and + simplify the generation of look up tables). However, because there + are differences in the decryption algorithm, other than just swapping + in different look up tables, we must transform our key schedule to + account for these changes: + + 1. The decryption algorithm gets its key rounds in reverse order. + 2. The decryption algorithm adds the round key before mixing columns + instead of afterwards. + + We don't need to modify our key schedule to handle the first case, + we can just traverse the key schedule in reverse order when decrypting. + + The second case requires a little work. + + The tables we built for performing rounds will take an input and then + perform SubBytes() and MixColumns() or, for the decrypt version, + InvSubBytes() and InvMixColumns(). But the decrypt algorithm requires + us to AddRoundKey() before InvMixColumns(). This means we'll need to + apply some transformations to the round key to inverse-mix its columns + so they'll be correct for moving AddRoundKey() to after the state has + had its columns inverse-mixed. + + To inverse-mix the columns of the state when we're decrypting we use a + lookup table that will apply InvSubBytes() and InvMixColumns() at the + same time. However, the round key's bytes are not inverse-substituted + in the decryption algorithm. To get around this problem, we can first + substitute the bytes in the round key so that when we apply the + transformation via the InvSubBytes()+InvMixColumns() table, it will + undo our substitution leaving us with the original value that we + want -- and then inverse-mix that value. + + This change will correctly alter our key schedule so that we can XOR + each round key with our already transformed decryption state. This + allows us to use the same code path as the encryption algorithm. + + We make one more change to the decryption key. Since the decryption + algorithm runs in reverse from the encryption algorithm, we reverse + the order of the round keys to avoid having to iterate over the key + schedule backwards when running the encryption algorithm later in + decryption mode. In addition to reversing the order of the round keys, + we also swap each round key's 2nd and 4th rows. See the comments + section where rounds are performed for more details about why this is + done. These changes are done inline with the other substitution + described above. + */ + if(decrypt) { + var tmp; + var m0 = imix[0]; + var m1 = imix[1]; + var m2 = imix[2]; + var m3 = imix[3]; + var wnew = w.slice(0); + end = w.length; + for(var i = 0, wi = end - Nb; i < end; i += Nb, wi -= Nb) { + // do not sub the first or last round key (round keys are Nb + // words) as no column mixing is performed before they are added, + // but do change the key order + if(i === 0 || i === (end - Nb)) { + wnew[i] = w[wi]; + wnew[i + 1] = w[wi + 3]; + wnew[i + 2] = w[wi + 2]; + wnew[i + 3] = w[wi + 1]; + } else { + // substitute each round key byte because the inverse-mix + // table will inverse-substitute it (effectively cancel the + // substitution because round key bytes aren't sub'd in + // decryption mode) and swap indexes 3 and 1 + for(var n = 0; n < Nb; ++n) { + tmp = w[wi + n]; + wnew[i + (3&-n)] = + m0[sbox[tmp >>> 24]] ^ + m1[sbox[tmp >>> 16 & 255]] ^ + m2[sbox[tmp >>> 8 & 255]] ^ + m3[sbox[tmp & 255]]; + } + } + } + w = wnew; + } + + return w; + } + + /** + * Updates a single block (16 bytes) using AES. The update will either + * encrypt or decrypt the block. + * + * @param w the key schedule. + * @param input the input block (an array of 32-bit words). + * @param output the updated output block. + * @param decrypt true to decrypt the block, false to encrypt it. + */ + function _updateBlock(w, input, output, decrypt) { + /* + Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) + begin + byte state[4,Nb] + state = in + AddRoundKey(state, w[0, Nb-1]) + for round = 1 step 1 to Nr-1 + SubBytes(state) + ShiftRows(state) + MixColumns(state) + AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + end for + SubBytes(state) + ShiftRows(state) + AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + out = state + end + + InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) + begin + byte state[4,Nb] + state = in + AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for round = Nr-1 step -1 downto 1 + InvShiftRows(state) + InvSubBytes(state) + AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + InvMixColumns(state) + end for + InvShiftRows(state) + InvSubBytes(state) + AddRoundKey(state, w[0, Nb-1]) + out = state + end + */ + + // Encrypt: AddRoundKey(state, w[0, Nb-1]) + // Decrypt: AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + var Nr = w.length / 4 - 1; + var m0, m1, m2, m3, sub; + if(decrypt) { + m0 = imix[0]; + m1 = imix[1]; + m2 = imix[2]; + m3 = imix[3]; + sub = isbox; + } else { + m0 = mix[0]; + m1 = mix[1]; + m2 = mix[2]; + m3 = mix[3]; + sub = sbox; + } + var a, b, c, d, a2, b2, c2; + a = input[0] ^ w[0]; + b = input[decrypt ? 3 : 1] ^ w[1]; + c = input[2] ^ w[2]; + d = input[decrypt ? 1 : 3] ^ w[3]; + var i = 3; + + /* In order to share code we follow the encryption algorithm when both + encrypting and decrypting. To account for the changes required in the + decryption algorithm, we use different lookup tables when decrypting + and use a modified key schedule to account for the difference in the + order of transformations applied when performing rounds. We also get + key rounds in reverse order (relative to encryption). */ + for(var round = 1; round < Nr; ++round) { + /* As described above, we'll be using table lookups to perform the + column mixing. Each column is stored as a word in the state (the + array 'input' has one column as a word at each index). In order to + mix a column, we perform these transformations on each row in c, + which is 1 byte in each word. The new column for c0 is c'0: + + m0 m1 m2 m3 + r0,c'0 = 2*r0,c0 + 3*r1,c0 + 1*r2,c0 + 1*r3,c0 + r1,c'0 = 1*r0,c0 + 2*r1,c0 + 3*r2,c0 + 1*r3,c0 + r2,c'0 = 1*r0,c0 + 1*r1,c0 + 2*r2,c0 + 3*r3,c0 + r3,c'0 = 3*r0,c0 + 1*r1,c0 + 1*r2,c0 + 2*r3,c0 + + So using mix tables where c0 is a word with r0 being its upper + 8 bits and r3 being its lower 8 bits: + + m0[c0 >> 24] will yield this word: [2*r0,1*r0,1*r0,3*r0] + ... + m3[c0 & 255] will yield this word: [1*r3,1*r3,3*r3,2*r3] + + Therefore to mix the columns in each word in the state we + do the following (& 255 omitted for brevity): + c'0,r0 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + c'0,r1 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + c'0,r2 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + c'0,r3 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + + However, before mixing, the algorithm requires us to perform + ShiftRows(). The ShiftRows() transformation cyclically shifts the + last 3 rows of the state over different offsets. The first row + (r = 0) is not shifted. + + s'_r,c = s_r,(c + shift(r, Nb) mod Nb + for 0 < r < 4 and 0 <= c < Nb and + shift(1, 4) = 1 + shift(2, 4) = 2 + shift(3, 4) = 3. + + This causes the first byte in r = 1 to be moved to the end of + the row, the first 2 bytes in r = 2 to be moved to the end of + the row, the first 3 bytes in r = 3 to be moved to the end of + the row: + + r1: [c0 c1 c2 c3] => [c1 c2 c3 c0] + r2: [c0 c1 c2 c3] [c2 c3 c0 c1] + r3: [c0 c1 c2 c3] [c3 c0 c1 c2] + + We can make these substitutions inline with our column mixing to + generate an updated set of equations to produce each word in the + state (note the columns have changed positions): + + c0 c1 c2 c3 => c0 c1 c2 c3 + c0 c1 c2 c3 c1 c2 c3 c0 (cycled 1 byte) + c0 c1 c2 c3 c2 c3 c0 c1 (cycled 2 bytes) + c0 c1 c2 c3 c3 c0 c1 c2 (cycled 3 bytes) + + Therefore: + + c'0 = 2*r0,c0 + 3*r1,c1 + 1*r2,c2 + 1*r3,c3 + c'0 = 1*r0,c0 + 2*r1,c1 + 3*r2,c2 + 1*r3,c3 + c'0 = 1*r0,c0 + 1*r1,c1 + 2*r2,c2 + 3*r3,c3 + c'0 = 3*r0,c0 + 1*r1,c1 + 1*r2,c2 + 2*r3,c3 + + c'1 = 2*r0,c1 + 3*r1,c2 + 1*r2,c3 + 1*r3,c0 + c'1 = 1*r0,c1 + 2*r1,c2 + 3*r2,c3 + 1*r3,c0 + c'1 = 1*r0,c1 + 1*r1,c2 + 2*r2,c3 + 3*r3,c0 + c'1 = 3*r0,c1 + 1*r1,c2 + 1*r2,c3 + 2*r3,c0 + + ... and so forth for c'2 and c'3. The important distinction is + that the columns are cycling, with c0 being used with the m0 + map when calculating c0, but c1 being used with the m0 map when + calculating c1 ... and so forth. + + When performing the inverse we transform the mirror image and + skip the bottom row, instead of the top one, and move upwards: + + c3 c2 c1 c0 => c0 c3 c2 c1 (cycled 3 bytes) *same as encryption + c3 c2 c1 c0 c1 c0 c3 c2 (cycled 2 bytes) + c3 c2 c1 c0 c2 c1 c0 c3 (cycled 1 byte) *same as encryption + c3 c2 c1 c0 c3 c2 c1 c0 + + If you compare the resulting matrices for ShiftRows()+MixColumns() + and for InvShiftRows()+InvMixColumns() the 2nd and 4th columns are + different (in encrypt mode vs. decrypt mode). So in order to use + the same code to handle both encryption and decryption, we will + need to do some mapping. + + If in encryption mode we let a=c0, b=c1, c=c2, d=c3, and r be + a row number in the state, then the resulting matrix in encryption + mode for applying the above transformations would be: + + r1: a b c d + r2: b c d a + r3: c d a b + r4: d a b c + + If we did the same in decryption mode we would get: + + r1: a d c b + r2: b a d c + r3: c b a d + r4: d c b a + + If instead we swap d and b (set b=c3 and d=c1), then we get: + + r1: a b c d + r2: d a b c + r3: c d a b + r4: b c d a + + Now the 1st and 3rd rows are the same as the encryption matrix. All + we need to do then to make the mapping exactly the same is to swap + the 2nd and 4th rows when in decryption mode. To do this without + having to do it on each iteration, we swapped the 2nd and 4th rows + in the decryption key schedule. We also have to do the swap above + when we first pull in the input and when we set the final output. */ + a2 = + m0[a >>> 24] ^ + m1[b >>> 16 & 255] ^ + m2[c >>> 8 & 255] ^ + m3[d & 255] ^ w[++i]; + b2 = + m0[b >>> 24] ^ + m1[c >>> 16 & 255] ^ + m2[d >>> 8 & 255] ^ + m3[a & 255] ^ w[++i]; + c2 = + m0[c >>> 24] ^ + m1[d >>> 16 & 255] ^ + m2[a >>> 8 & 255] ^ + m3[b & 255] ^ w[++i]; + d = + m0[d >>> 24] ^ + m1[a >>> 16 & 255] ^ + m2[b >>> 8 & 255] ^ + m3[c & 255] ^ w[++i]; + a = a2; + b = b2; + c = c2; + } + + /* + Encrypt: + SubBytes(state) + ShiftRows(state) + AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + + Decrypt: + InvShiftRows(state) + InvSubBytes(state) + AddRoundKey(state, w[0, Nb-1]) + */ + // Note: rows are shifted inline + output[0] = + (sub[a >>> 24] << 24) ^ + (sub[b >>> 16 & 255] << 16) ^ + (sub[c >>> 8 & 255] << 8) ^ + (sub[d & 255]) ^ w[++i]; + output[decrypt ? 3 : 1] = + (sub[b >>> 24] << 24) ^ + (sub[c >>> 16 & 255] << 16) ^ + (sub[d >>> 8 & 255] << 8) ^ + (sub[a & 255]) ^ w[++i]; + output[2] = + (sub[c >>> 24] << 24) ^ + (sub[d >>> 16 & 255] << 16) ^ + (sub[a >>> 8 & 255] << 8) ^ + (sub[b & 255]) ^ w[++i]; + output[decrypt ? 1 : 3] = + (sub[d >>> 24] << 24) ^ + (sub[a >>> 16 & 255] << 16) ^ + (sub[b >>> 8 & 255] << 8) ^ + (sub[c & 255]) ^ w[++i]; + } + + /** + * Deprecated. Instead, use: + * + * forge.cipher.createCipher('AES-', key); + * forge.cipher.createDecipher('AES-', key); + * + * Creates a deprecated AES cipher object. This object's mode will default to + * CBC (cipher-block-chaining). + * + * The key and iv may be given as a string of bytes, an array of bytes, a + * byte buffer, or an array of 32-bit words. + * + * @param options the options to use. + * key the symmetric key to use. + * output the buffer to write to. + * decrypt true for decryption, false for encryption. + * mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + function _createCipher(options) { + options = options || {}; + var mode = (options.mode || 'CBC').toUpperCase(); + var algorithm = 'AES-' + mode; + + var cipher; + if(options.decrypt) { + cipher = forge.cipher.createDecipher(algorithm, options.key); + } else { + cipher = forge.cipher.createCipher(algorithm, options.key); + } + + // backwards compatible start API + var start = cipher.start; + cipher.start = function(iv, options) { + // backwards compatibility: support second arg as output buffer + var output = null; + if(options instanceof forge.util.ByteBuffer) { + output = options; + options = {}; + } + options = options || {}; + options.output = output; + options.iv = iv; + start.call(cipher, options); + }; + + return cipher; + } + + var oids_1 = createCommonjsModule(function (module) { + /** + * Object IDs for ASN.1. + * + * @author Dave Longley + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + */ + + + forge.pki = forge.pki || {}; + var oids = module.exports = forge.pki.oids = forge.oids = forge.oids || {}; + + // set id to name mapping and name to id mapping + function _IN(id, name) { + oids[id] = name; + oids[name] = id; + } + // set id to name mapping only + function _I_(id, name) { + oids[id] = name; + } + + // algorithm OIDs + _IN('1.2.840.113549.1.1.1', 'rsaEncryption'); + // Note: md2 & md4 not implemented + //_IN('1.2.840.113549.1.1.2', 'md2WithRSAEncryption'); + //_IN('1.2.840.113549.1.1.3', 'md4WithRSAEncryption'); + _IN('1.2.840.113549.1.1.4', 'md5WithRSAEncryption'); + _IN('1.2.840.113549.1.1.5', 'sha1WithRSAEncryption'); + _IN('1.2.840.113549.1.1.7', 'RSAES-OAEP'); + _IN('1.2.840.113549.1.1.8', 'mgf1'); + _IN('1.2.840.113549.1.1.9', 'pSpecified'); + _IN('1.2.840.113549.1.1.10', 'RSASSA-PSS'); + _IN('1.2.840.113549.1.1.11', 'sha256WithRSAEncryption'); + _IN('1.2.840.113549.1.1.12', 'sha384WithRSAEncryption'); + _IN('1.2.840.113549.1.1.13', 'sha512WithRSAEncryption'); + // Edwards-curve Digital Signature Algorithm (EdDSA) Ed25519 + _IN('1.3.101.112', 'EdDSA25519'); + + _IN('1.2.840.10040.4.3', 'dsa-with-sha1'); + + _IN('1.3.14.3.2.7', 'desCBC'); + + _IN('1.3.14.3.2.26', 'sha1'); + _IN('2.16.840.1.101.3.4.2.1', 'sha256'); + _IN('2.16.840.1.101.3.4.2.2', 'sha384'); + _IN('2.16.840.1.101.3.4.2.3', 'sha512'); + _IN('1.2.840.113549.2.5', 'md5'); + + // pkcs#7 content types + _IN('1.2.840.113549.1.7.1', 'data'); + _IN('1.2.840.113549.1.7.2', 'signedData'); + _IN('1.2.840.113549.1.7.3', 'envelopedData'); + _IN('1.2.840.113549.1.7.4', 'signedAndEnvelopedData'); + _IN('1.2.840.113549.1.7.5', 'digestedData'); + _IN('1.2.840.113549.1.7.6', 'encryptedData'); + + // pkcs#9 oids + _IN('1.2.840.113549.1.9.1', 'emailAddress'); + _IN('1.2.840.113549.1.9.2', 'unstructuredName'); + _IN('1.2.840.113549.1.9.3', 'contentType'); + _IN('1.2.840.113549.1.9.4', 'messageDigest'); + _IN('1.2.840.113549.1.9.5', 'signingTime'); + _IN('1.2.840.113549.1.9.6', 'counterSignature'); + _IN('1.2.840.113549.1.9.7', 'challengePassword'); + _IN('1.2.840.113549.1.9.8', 'unstructuredAddress'); + _IN('1.2.840.113549.1.9.14', 'extensionRequest'); + + _IN('1.2.840.113549.1.9.20', 'friendlyName'); + _IN('1.2.840.113549.1.9.21', 'localKeyId'); + _IN('1.2.840.113549.1.9.22.1', 'x509Certificate'); + + // pkcs#12 safe bags + _IN('1.2.840.113549.1.12.10.1.1', 'keyBag'); + _IN('1.2.840.113549.1.12.10.1.2', 'pkcs8ShroudedKeyBag'); + _IN('1.2.840.113549.1.12.10.1.3', 'certBag'); + _IN('1.2.840.113549.1.12.10.1.4', 'crlBag'); + _IN('1.2.840.113549.1.12.10.1.5', 'secretBag'); + _IN('1.2.840.113549.1.12.10.1.6', 'safeContentsBag'); + + // password-based-encryption for pkcs#12 + _IN('1.2.840.113549.1.5.13', 'pkcs5PBES2'); + _IN('1.2.840.113549.1.5.12', 'pkcs5PBKDF2'); + + _IN('1.2.840.113549.1.12.1.1', 'pbeWithSHAAnd128BitRC4'); + _IN('1.2.840.113549.1.12.1.2', 'pbeWithSHAAnd40BitRC4'); + _IN('1.2.840.113549.1.12.1.3', 'pbeWithSHAAnd3-KeyTripleDES-CBC'); + _IN('1.2.840.113549.1.12.1.4', 'pbeWithSHAAnd2-KeyTripleDES-CBC'); + _IN('1.2.840.113549.1.12.1.5', 'pbeWithSHAAnd128BitRC2-CBC'); + _IN('1.2.840.113549.1.12.1.6', 'pbewithSHAAnd40BitRC2-CBC'); + + // hmac OIDs + _IN('1.2.840.113549.2.7', 'hmacWithSHA1'); + _IN('1.2.840.113549.2.8', 'hmacWithSHA224'); + _IN('1.2.840.113549.2.9', 'hmacWithSHA256'); + _IN('1.2.840.113549.2.10', 'hmacWithSHA384'); + _IN('1.2.840.113549.2.11', 'hmacWithSHA512'); + + // symmetric key algorithm oids + _IN('1.2.840.113549.3.7', 'des-EDE3-CBC'); + _IN('2.16.840.1.101.3.4.1.2', 'aes128-CBC'); + _IN('2.16.840.1.101.3.4.1.22', 'aes192-CBC'); + _IN('2.16.840.1.101.3.4.1.42', 'aes256-CBC'); + + // certificate issuer/subject OIDs + _IN('2.5.4.3', 'commonName'); + _IN('2.5.4.5', 'serialName'); + _IN('2.5.4.6', 'countryName'); + _IN('2.5.4.7', 'localityName'); + _IN('2.5.4.8', 'stateOrProvinceName'); + _IN('2.5.4.9', 'streetAddress'); + _IN('2.5.4.10', 'organizationName'); + _IN('2.5.4.11', 'organizationalUnitName'); + _IN('2.5.4.13', 'description'); + _IN('2.5.4.15', 'businessCategory'); + _IN('2.5.4.17', 'postalCode'); + _IN('1.3.6.1.4.1.311.60.2.1.2', 'jurisdictionOfIncorporationStateOrProvinceName'); + _IN('1.3.6.1.4.1.311.60.2.1.3', 'jurisdictionOfIncorporationCountryName'); + + // X.509 extension OIDs + _IN('2.16.840.1.113730.1.1', 'nsCertType'); + _IN('2.16.840.1.113730.1.13', 'nsComment'); // deprecated in theory; still widely used + _I_('2.5.29.1', 'authorityKeyIdentifier'); // deprecated, use .35 + _I_('2.5.29.2', 'keyAttributes'); // obsolete use .37 or .15 + _I_('2.5.29.3', 'certificatePolicies'); // deprecated, use .32 + _I_('2.5.29.4', 'keyUsageRestriction'); // obsolete use .37 or .15 + _I_('2.5.29.5', 'policyMapping'); // deprecated use .33 + _I_('2.5.29.6', 'subtreesConstraint'); // obsolete use .30 + _I_('2.5.29.7', 'subjectAltName'); // deprecated use .17 + _I_('2.5.29.8', 'issuerAltName'); // deprecated use .18 + _I_('2.5.29.9', 'subjectDirectoryAttributes'); + _I_('2.5.29.10', 'basicConstraints'); // deprecated use .19 + _I_('2.5.29.11', 'nameConstraints'); // deprecated use .30 + _I_('2.5.29.12', 'policyConstraints'); // deprecated use .36 + _I_('2.5.29.13', 'basicConstraints'); // deprecated use .19 + _IN('2.5.29.14', 'subjectKeyIdentifier'); + _IN('2.5.29.15', 'keyUsage'); + _I_('2.5.29.16', 'privateKeyUsagePeriod'); + _IN('2.5.29.17', 'subjectAltName'); + _IN('2.5.29.18', 'issuerAltName'); + _IN('2.5.29.19', 'basicConstraints'); + _I_('2.5.29.20', 'cRLNumber'); + _I_('2.5.29.21', 'cRLReason'); + _I_('2.5.29.22', 'expirationDate'); + _I_('2.5.29.23', 'instructionCode'); + _I_('2.5.29.24', 'invalidityDate'); + _I_('2.5.29.25', 'cRLDistributionPoints'); // deprecated use .31 + _I_('2.5.29.26', 'issuingDistributionPoint'); // deprecated use .28 + _I_('2.5.29.27', 'deltaCRLIndicator'); + _I_('2.5.29.28', 'issuingDistributionPoint'); + _I_('2.5.29.29', 'certificateIssuer'); + _I_('2.5.29.30', 'nameConstraints'); + _IN('2.5.29.31', 'cRLDistributionPoints'); + _IN('2.5.29.32', 'certificatePolicies'); + _I_('2.5.29.33', 'policyMappings'); + _I_('2.5.29.34', 'policyConstraints'); // deprecated use .36 + _IN('2.5.29.35', 'authorityKeyIdentifier'); + _I_('2.5.29.36', 'policyConstraints'); + _IN('2.5.29.37', 'extKeyUsage'); + _I_('2.5.29.46', 'freshestCRL'); + _I_('2.5.29.54', 'inhibitAnyPolicy'); + + // extKeyUsage purposes + _IN('1.3.6.1.4.1.11129.2.4.2', 'timestampList'); + _IN('1.3.6.1.5.5.7.1.1', 'authorityInfoAccess'); + _IN('1.3.6.1.5.5.7.3.1', 'serverAuth'); + _IN('1.3.6.1.5.5.7.3.2', 'clientAuth'); + _IN('1.3.6.1.5.5.7.3.3', 'codeSigning'); + _IN('1.3.6.1.5.5.7.3.4', 'emailProtection'); + _IN('1.3.6.1.5.5.7.3.8', 'timeStamping'); + }); + + var asn1_1 = createCommonjsModule(function (module) { + /** + * Javascript implementation of Abstract Syntax Notation Number One. + * + * @author Dave Longley + * + * Copyright (c) 2010-2015 Digital Bazaar, Inc. + * + * An API for storing data using the Abstract Syntax Notation Number One + * format using DER (Distinguished Encoding Rules) encoding. This encoding is + * commonly used to store data for PKI, i.e. X.509 Certificates, and this + * implementation exists for that purpose. + * + * Abstract Syntax Notation Number One (ASN.1) is used to define the abstract + * syntax of information without restricting the way the information is encoded + * for transmission. It provides a standard that allows for open systems + * communication. ASN.1 defines the syntax of information data and a number of + * simple data types as well as a notation for describing them and specifying + * values for them. + * + * The RSA algorithm creates public and private keys that are often stored in + * X.509 or PKCS#X formats -- which use ASN.1 (encoded in DER format). This + * class provides the most basic functionality required to store and load DSA + * keys that are encoded according to ASN.1. + * + * The most common binary encodings for ASN.1 are BER (Basic Encoding Rules) + * and DER (Distinguished Encoding Rules). DER is just a subset of BER that + * has stricter requirements for how data must be encoded. + * + * Each ASN.1 structure has a tag (a byte identifying the ASN.1 structure type) + * and a byte array for the value of this ASN1 structure which may be data or a + * list of ASN.1 structures. + * + * Each ASN.1 structure using BER is (Tag-Length-Value): + * + * | byte 0 | bytes X | bytes Y | + * |--------|---------|---------- + * | tag | length | value | + * + * ASN.1 allows for tags to be of "High-tag-number form" which allows a tag to + * be two or more octets, but that is not supported by this class. A tag is + * only 1 byte. Bits 1-5 give the tag number (ie the data type within a + * particular 'class'), 6 indicates whether or not the ASN.1 value is + * constructed from other ASN.1 values, and bits 7 and 8 give the 'class'. If + * bits 7 and 8 are both zero, the class is UNIVERSAL. If only bit 7 is set, + * then the class is APPLICATION. If only bit 8 is set, then the class is + * CONTEXT_SPECIFIC. If both bits 7 and 8 are set, then the class is PRIVATE. + * The tag numbers for the data types for the class UNIVERSAL are listed below: + * + * UNIVERSAL 0 Reserved for use by the encoding rules + * UNIVERSAL 1 Boolean type + * UNIVERSAL 2 Integer type + * UNIVERSAL 3 Bitstring type + * UNIVERSAL 4 Octetstring type + * UNIVERSAL 5 Null type + * UNIVERSAL 6 Object identifier type + * UNIVERSAL 7 Object descriptor type + * UNIVERSAL 8 External type and Instance-of type + * UNIVERSAL 9 Real type + * UNIVERSAL 10 Enumerated type + * UNIVERSAL 11 Embedded-pdv type + * UNIVERSAL 12 UTF8String type + * UNIVERSAL 13 Relative object identifier type + * UNIVERSAL 14-15 Reserved for future editions + * UNIVERSAL 16 Sequence and Sequence-of types + * UNIVERSAL 17 Set and Set-of types + * UNIVERSAL 18-22, 25-30 Character string types + * UNIVERSAL 23-24 Time types + * + * The length of an ASN.1 structure is specified after the tag identifier. + * There is a definite form and an indefinite form. The indefinite form may + * be used if the encoding is constructed and not all immediately available. + * The indefinite form is encoded using a length byte with only the 8th bit + * set. The end of the constructed object is marked using end-of-contents + * octets (two zero bytes). + * + * The definite form looks like this: + * + * The length may take up 1 or more bytes, it depends on the length of the + * value of the ASN.1 structure. DER encoding requires that if the ASN.1 + * structure has a value that has a length greater than 127, more than 1 byte + * will be used to store its length, otherwise just one byte will be used. + * This is strict. + * + * In the case that the length of the ASN.1 value is less than 127, 1 octet + * (byte) is used to store the "short form" length. The 8th bit has a value of + * 0 indicating the length is "short form" and not "long form" and bits 7-1 + * give the length of the data. (The 8th bit is the left-most, most significant + * bit: also known as big endian or network format). + * + * In the case that the length of the ASN.1 value is greater than 127, 2 to + * 127 octets (bytes) are used to store the "long form" length. The first + * byte's 8th bit is set to 1 to indicate the length is "long form." Bits 7-1 + * give the number of additional octets. All following octets are in base 256 + * with the most significant digit first (typical big-endian binary unsigned + * integer storage). So, for instance, if the length of a value was 257, the + * first byte would be set to: + * + * 10000010 = 130 = 0x82. + * + * This indicates there are 2 octets (base 256) for the length. The second and + * third bytes (the octets just mentioned) would store the length in base 256: + * + * octet 2: 00000001 = 1 * 256^1 = 256 + * octet 3: 00000001 = 1 * 256^0 = 1 + * total = 257 + * + * The algorithm for converting a js integer value of 257 to base-256 is: + * + * var value = 257; + * var bytes = []; + * bytes[0] = (value >>> 8) & 0xFF; // most significant byte first + * bytes[1] = value & 0xFF; // least significant byte last + * + * On the ASN.1 UNIVERSAL Object Identifier (OID) type: + * + * An OID can be written like: "value1.value2.value3...valueN" + * + * The DER encoding rules: + * + * The first byte has the value 40 * value1 + value2. + * The following bytes, if any, encode the remaining values. Each value is + * encoded in base 128, most significant digit first (big endian), with as + * few digits as possible, and the most significant bit of each byte set + * to 1 except the last in each value's encoding. For example: Given the + * OID "1.2.840.113549", its DER encoding is (remember each byte except the + * last one in each encoding is OR'd with 0x80): + * + * byte 1: 40 * 1 + 2 = 42 = 0x2A. + * bytes 2-3: 128 * 6 + 72 = 840 = 6 72 = 6 72 = 0x0648 = 0x8648 + * bytes 4-6: 16384 * 6 + 128 * 119 + 13 = 6 119 13 = 0x06770D = 0x86F70D + * + * The final value is: 0x2A864886F70D. + * The full OID (including ASN.1 tag and length of 6 bytes) is: + * 0x06062A864886F70D + */ + + + + + /* ASN.1 API */ + var asn1 = module.exports = forge.asn1 = forge.asn1 || {}; + + /** + * ASN.1 classes. + */ + asn1.Class = { + UNIVERSAL: 0x00, + APPLICATION: 0x40, + CONTEXT_SPECIFIC: 0x80, + PRIVATE: 0xC0 + }; + + /** + * ASN.1 types. Not all types are supported by this implementation, only + * those necessary to implement a simple PKI are implemented. + */ + asn1.Type = { + NONE: 0, + BOOLEAN: 1, + INTEGER: 2, + BITSTRING: 3, + OCTETSTRING: 4, + NULL: 5, + OID: 6, + ODESC: 7, + EXTERNAL: 8, + REAL: 9, + ENUMERATED: 10, + EMBEDDED: 11, + UTF8: 12, + ROID: 13, + SEQUENCE: 16, + SET: 17, + PRINTABLESTRING: 19, + IA5STRING: 22, + UTCTIME: 23, + GENERALIZEDTIME: 24, + BMPSTRING: 30 + }; + + /** + * Creates a new asn1 object. + * + * @param tagClass the tag class for the object. + * @param type the data type (tag number) for the object. + * @param constructed true if the asn1 object is in constructed form. + * @param value the value for the object, if it is not constructed. + * @param [options] the options to use: + * [bitStringContents] the plain BIT STRING content including padding + * byte. + * + * @return the asn1 object. + */ + asn1.create = function(tagClass, type, constructed, value, options) { + /* An asn1 object has a tagClass, a type, a constructed flag, and a + value. The value's type depends on the constructed flag. If + constructed, it will contain a list of other asn1 objects. If not, + it will contain the ASN.1 value as an array of bytes formatted + according to the ASN.1 data type. */ + + // remove undefined values + if(forge.util.isArray(value)) { + var tmp = []; + for(var i = 0; i < value.length; ++i) { + if(value[i] !== undefined) { + tmp.push(value[i]); + } + } + value = tmp; + } + + var obj = { + tagClass: tagClass, + type: type, + constructed: constructed, + composed: constructed || forge.util.isArray(value), + value: value + }; + if(options && 'bitStringContents' in options) { + // TODO: copy byte buffer if it's a buffer not a string + obj.bitStringContents = options.bitStringContents; + // TODO: add readonly flag to avoid this overhead + // save copy to detect changes + obj.original = asn1.copy(obj); + } + return obj; + }; + + /** + * Copies an asn1 object. + * + * @param obj the asn1 object. + * @param [options] copy options: + * [excludeBitStringContents] true to not copy bitStringContents + * + * @return the a copy of the asn1 object. + */ + asn1.copy = function(obj, options) { + var copy; + + if(forge.util.isArray(obj)) { + copy = []; + for(var i = 0; i < obj.length; ++i) { + copy.push(asn1.copy(obj[i], options)); + } + return copy; + } + + if(typeof obj === 'string') { + // TODO: copy byte buffer if it's a buffer not a string + return obj; + } + + copy = { + tagClass: obj.tagClass, + type: obj.type, + constructed: obj.constructed, + composed: obj.composed, + value: asn1.copy(obj.value, options) + }; + if(options && !options.excludeBitStringContents) { + // TODO: copy byte buffer if it's a buffer not a string + copy.bitStringContents = obj.bitStringContents; + } + return copy; + }; + + /** + * Compares asn1 objects for equality. + * + * Note this function does not run in constant time. + * + * @param obj1 the first asn1 object. + * @param obj2 the second asn1 object. + * @param [options] compare options: + * [includeBitStringContents] true to compare bitStringContents + * + * @return true if the asn1 objects are equal. + */ + asn1.equals = function(obj1, obj2, options) { + if(forge.util.isArray(obj1)) { + if(!forge.util.isArray(obj2)) { + return false; + } + if(obj1.length !== obj2.length) { + return false; + } + for(var i = 0; i < obj1.length; ++i) { + if(!asn1.equals(obj1[i], obj2[i])) { + return false; + } + } + return true; + } + + if(typeof obj1 !== typeof obj2) { + return false; + } + + if(typeof obj1 === 'string') { + return obj1 === obj2; + } + + var equal = obj1.tagClass === obj2.tagClass && + obj1.type === obj2.type && + obj1.constructed === obj2.constructed && + obj1.composed === obj2.composed && + asn1.equals(obj1.value, obj2.value); + if(options && options.includeBitStringContents) { + equal = equal && (obj1.bitStringContents === obj2.bitStringContents); + } + + return equal; + }; + + /** + * Gets the length of a BER-encoded ASN.1 value. + * + * In case the length is not specified, undefined is returned. + * + * @param b the BER-encoded ASN.1 byte buffer, starting with the first + * length byte. + * + * @return the length of the BER-encoded ASN.1 value or undefined. + */ + asn1.getBerValueLength = function(b) { + // TODO: move this function and related DER/BER functions to a der.js + // file; better abstract ASN.1 away from der/ber. + var b2 = b.getByte(); + if(b2 === 0x80) { + return undefined; + } + + // see if the length is "short form" or "long form" (bit 8 set) + var length; + var longForm = b2 & 0x80; + if(!longForm) { + // length is just the first byte + length = b2; + } else { + // the number of bytes the length is specified in bits 7 through 1 + // and each length byte is in big-endian base-256 + length = b.getInt((b2 & 0x7F) << 3); + } + return length; + }; + + /** + * Check if the byte buffer has enough bytes. Throws an Error if not. + * + * @param bytes the byte buffer to parse from. + * @param remaining the bytes remaining in the current parsing state. + * @param n the number of bytes the buffer must have. + */ + function _checkBufferLength(bytes, remaining, n) { + if(n > remaining) { + var error = new Error('Too few bytes to parse DER.'); + error.available = bytes.length(); + error.remaining = remaining; + error.requested = n; + throw error; + } + } + + /** + * Gets the length of a BER-encoded ASN.1 value. + * + * In case the length is not specified, undefined is returned. + * + * @param bytes the byte buffer to parse from. + * @param remaining the bytes remaining in the current parsing state. + * + * @return the length of the BER-encoded ASN.1 value or undefined. + */ + var _getValueLength = function(bytes, remaining) { + // TODO: move this function and related DER/BER functions to a der.js + // file; better abstract ASN.1 away from der/ber. + // fromDer already checked that this byte exists + var b2 = bytes.getByte(); + remaining--; + if(b2 === 0x80) { + return undefined; + } + + // see if the length is "short form" or "long form" (bit 8 set) + var length; + var longForm = b2 & 0x80; + if(!longForm) { + // length is just the first byte + length = b2; + } else { + // the number of bytes the length is specified in bits 7 through 1 + // and each length byte is in big-endian base-256 + var longFormBytes = b2 & 0x7F; + _checkBufferLength(bytes, remaining, longFormBytes); + length = bytes.getInt(longFormBytes << 3); + } + // FIXME: this will only happen for 32 bit getInt with high bit set + if(length < 0) { + throw new Error('Negative length: ' + length); + } + return length; + }; + + /** + * Parses an asn1 object from a byte buffer in DER format. + * + * @param bytes the byte buffer to parse from. + * @param [strict] true to be strict when checking value lengths, false to + * allow truncated values (default: true). + * @param [options] object with options or boolean strict flag + * [strict] true to be strict when checking value lengths, false to + * allow truncated values (default: true). + * [decodeBitStrings] true to attempt to decode the content of + * BIT STRINGs (not OCTET STRINGs) using strict mode. Note that + * without schema support to understand the data context this can + * erroneously decode values that happen to be valid ASN.1. This + * flag will be deprecated or removed as soon as schema support is + * available. (default: true) + * + * @return the parsed asn1 object. + */ + asn1.fromDer = function(bytes, options) { + if(options === undefined) { + options = { + strict: true, + decodeBitStrings: true + }; + } + if(typeof options === 'boolean') { + options = { + strict: options, + decodeBitStrings: true + }; + } + if(!('strict' in options)) { + options.strict = true; + } + if(!('decodeBitStrings' in options)) { + options.decodeBitStrings = true; + } + + // wrap in buffer if needed + if(typeof bytes === 'string') { + bytes = forge.util.createBuffer(bytes); + } + + return _fromDer(bytes, bytes.length(), 0, options); + }; + + /** + * Internal function to parse an asn1 object from a byte buffer in DER format. + * + * @param bytes the byte buffer to parse from. + * @param remaining the number of bytes remaining for this chunk. + * @param depth the current parsing depth. + * @param options object with same options as fromDer(). + * + * @return the parsed asn1 object. + */ + function _fromDer(bytes, remaining, depth, options) { + // temporary storage for consumption calculations + var start; + + // minimum length for ASN.1 DER structure is 2 + _checkBufferLength(bytes, remaining, 2); + + // get the first byte + var b1 = bytes.getByte(); + // consumed one byte + remaining--; + + // get the tag class + var tagClass = (b1 & 0xC0); + + // get the type (bits 1-5) + var type = b1 & 0x1F; + + // get the variable value length and adjust remaining bytes + start = bytes.length(); + var length = _getValueLength(bytes, remaining); + remaining -= start - bytes.length(); + + // ensure there are enough bytes to get the value + if(length !== undefined && length > remaining) { + if(options.strict) { + var error = new Error('Too few bytes to read ASN.1 value.'); + error.available = bytes.length(); + error.remaining = remaining; + error.requested = length; + throw error; + } + // Note: be lenient with truncated values and use remaining state bytes + length = remaining; + } + + // value storage + var value; + // possible BIT STRING contents storage + var bitStringContents; + + // constructed flag is bit 6 (32 = 0x20) of the first byte + var constructed = ((b1 & 0x20) === 0x20); + if(constructed) { + // parse child asn1 objects from the value + value = []; + if(length === undefined) { + // asn1 object of indefinite length, read until end tag + for(;;) { + _checkBufferLength(bytes, remaining, 2); + if(bytes.bytes(2) === String.fromCharCode(0, 0)) { + bytes.getBytes(2); + remaining -= 2; + break; + } + start = bytes.length(); + value.push(_fromDer(bytes, remaining, depth + 1, options)); + remaining -= start - bytes.length(); + } + } else { + // parsing asn1 object of definite length + while(length > 0) { + start = bytes.length(); + value.push(_fromDer(bytes, length, depth + 1, options)); + remaining -= start - bytes.length(); + length -= start - bytes.length(); + } + } + } + + // if a BIT STRING, save the contents including padding + if(value === undefined && tagClass === asn1.Class.UNIVERSAL && + type === asn1.Type.BITSTRING) { + bitStringContents = bytes.bytes(length); + } + + // determine if a non-constructed value should be decoded as a composed + // value that contains other ASN.1 objects. BIT STRINGs (and OCTET STRINGs) + // can be used this way. + if(value === undefined && options.decodeBitStrings && + tagClass === asn1.Class.UNIVERSAL && + // FIXME: OCTET STRINGs not yet supported here + // .. other parts of forge expect to decode OCTET STRINGs manually + (type === asn1.Type.BITSTRING /*|| type === asn1.Type.OCTETSTRING*/) && + length > 1) { + // save read position + var savedRead = bytes.read; + var savedRemaining = remaining; + var unused = 0; + if(type === asn1.Type.BITSTRING) { + /* The first octet gives the number of bits by which the length of the + bit string is less than the next multiple of eight (this is called + the "number of unused bits"). + + The second and following octets give the value of the bit string + converted to an octet string. */ + _checkBufferLength(bytes, remaining, 1); + unused = bytes.getByte(); + remaining--; + } + // if all bits are used, maybe the BIT/OCTET STRING holds ASN.1 objs + if(unused === 0) { + try { + // attempt to parse child asn1 object from the value + // (stored in array to signal composed value) + start = bytes.length(); + var subOptions = { + // enforce strict mode to avoid parsing ASN.1 from plain data + verbose: options.verbose, + strict: true, + decodeBitStrings: true + }; + var composed = _fromDer(bytes, remaining, depth + 1, subOptions); + var used = start - bytes.length(); + remaining -= used; + if(type == asn1.Type.BITSTRING) { + used++; + } + + // if the data all decoded and the class indicates UNIVERSAL or + // CONTEXT_SPECIFIC then assume we've got an encapsulated ASN.1 object + var tc = composed.tagClass; + if(used === length && + (tc === asn1.Class.UNIVERSAL || tc === asn1.Class.CONTEXT_SPECIFIC)) { + value = [composed]; + } + } catch(ex) { + } + } + if(value === undefined) { + // restore read position + bytes.read = savedRead; + remaining = savedRemaining; + } + } + + if(value === undefined) { + // asn1 not constructed or composed, get raw value + // TODO: do DER to OID conversion and vice-versa in .toDer? + + if(length === undefined) { + if(options.strict) { + throw new Error('Non-constructed ASN.1 object of indefinite length.'); + } + // be lenient and use remaining state bytes + length = remaining; + } + + if(type === asn1.Type.BMPSTRING) { + value = ''; + for(; length > 0; length -= 2) { + _checkBufferLength(bytes, remaining, 2); + value += String.fromCharCode(bytes.getInt16()); + remaining -= 2; + } + } else { + value = bytes.getBytes(length); + } + } + + // add BIT STRING contents if available + var asn1Options = bitStringContents === undefined ? null : { + bitStringContents: bitStringContents + }; + + // create and return asn1 object + return asn1.create(tagClass, type, constructed, value, asn1Options); + } + + /** + * Converts the given asn1 object to a buffer of bytes in DER format. + * + * @param asn1 the asn1 object to convert to bytes. + * + * @return the buffer of bytes. + */ + asn1.toDer = function(obj) { + var bytes = forge.util.createBuffer(); + + // build the first byte + var b1 = obj.tagClass | obj.type; + + // for storing the ASN.1 value + var value = forge.util.createBuffer(); + + // use BIT STRING contents if available and data not changed + var useBitStringContents = false; + if('bitStringContents' in obj) { + useBitStringContents = true; + if(obj.original) { + useBitStringContents = asn1.equals(obj, obj.original); + } + } + + if(useBitStringContents) { + value.putBytes(obj.bitStringContents); + } else if(obj.composed) { + // if composed, use each child asn1 object's DER bytes as value + // turn on 6th bit (0x20 = 32) to indicate asn1 is constructed + // from other asn1 objects + if(obj.constructed) { + b1 |= 0x20; + } else { + // type is a bit string, add unused bits of 0x00 + value.putByte(0x00); + } + + // add all of the child DER bytes together + for(var i = 0; i < obj.value.length; ++i) { + if(obj.value[i] !== undefined) { + value.putBuffer(asn1.toDer(obj.value[i])); + } + } + } else { + // use asn1.value directly + if(obj.type === asn1.Type.BMPSTRING) { + for(var i = 0; i < obj.value.length; ++i) { + value.putInt16(obj.value.charCodeAt(i)); + } + } else { + // ensure integer is minimally-encoded + // TODO: should all leading bytes be stripped vs just one? + // .. ex '00 00 01' => '01'? + if(obj.type === asn1.Type.INTEGER && + obj.value.length > 1 && + // leading 0x00 for positive integer + ((obj.value.charCodeAt(0) === 0 && + (obj.value.charCodeAt(1) & 0x80) === 0) || + // leading 0xFF for negative integer + (obj.value.charCodeAt(0) === 0xFF && + (obj.value.charCodeAt(1) & 0x80) === 0x80))) { + value.putBytes(obj.value.substr(1)); + } else { + value.putBytes(obj.value); + } + } + } + + // add tag byte + bytes.putByte(b1); + + // use "short form" encoding + if(value.length() <= 127) { + // one byte describes the length + // bit 8 = 0 and bits 7-1 = length + bytes.putByte(value.length() & 0x7F); + } else { + // use "long form" encoding + // 2 to 127 bytes describe the length + // first byte: bit 8 = 1 and bits 7-1 = # of additional bytes + // other bytes: length in base 256, big-endian + var len = value.length(); + var lenBytes = ''; + do { + lenBytes += String.fromCharCode(len & 0xFF); + len = len >>> 8; + } while(len > 0); + + // set first byte to # bytes used to store the length and turn on + // bit 8 to indicate long-form length is used + bytes.putByte(lenBytes.length | 0x80); + + // concatenate length bytes in reverse since they were generated + // little endian and we need big endian + for(var i = lenBytes.length - 1; i >= 0; --i) { + bytes.putByte(lenBytes.charCodeAt(i)); + } + } + + // concatenate value bytes + bytes.putBuffer(value); + return bytes; + }; + + /** + * Converts an OID dot-separated string to a byte buffer. The byte buffer + * contains only the DER-encoded value, not any tag or length bytes. + * + * @param oid the OID dot-separated string. + * + * @return the byte buffer. + */ + asn1.oidToDer = function(oid) { + // split OID into individual values + var values = oid.split('.'); + var bytes = forge.util.createBuffer(); + + // first byte is 40 * value1 + value2 + bytes.putByte(40 * parseInt(values[0], 10) + parseInt(values[1], 10)); + // other bytes are each value in base 128 with 8th bit set except for + // the last byte for each value + var last, valueBytes, value, b; + for(var i = 2; i < values.length; ++i) { + // produce value bytes in reverse because we don't know how many + // bytes it will take to store the value + last = true; + valueBytes = []; + value = parseInt(values[i], 10); + do { + b = value & 0x7F; + value = value >>> 7; + // if value is not last, then turn on 8th bit + if(!last) { + b |= 0x80; + } + valueBytes.push(b); + last = false; + } while(value > 0); + + // add value bytes in reverse (needs to be in big endian) + for(var n = valueBytes.length - 1; n >= 0; --n) { + bytes.putByte(valueBytes[n]); + } + } + + return bytes; + }; + + /** + * Converts a DER-encoded byte buffer to an OID dot-separated string. The + * byte buffer should contain only the DER-encoded value, not any tag or + * length bytes. + * + * @param bytes the byte buffer. + * + * @return the OID dot-separated string. + */ + asn1.derToOid = function(bytes) { + var oid; + + // wrap in buffer if needed + if(typeof bytes === 'string') { + bytes = forge.util.createBuffer(bytes); + } + + // first byte is 40 * value1 + value2 + var b = bytes.getByte(); + oid = Math.floor(b / 40) + '.' + (b % 40); + + // other bytes are each value in base 128 with 8th bit set except for + // the last byte for each value + var value = 0; + while(bytes.length() > 0) { + b = bytes.getByte(); + value = value << 7; + // not the last byte for the value + if(b & 0x80) { + value += b & 0x7F; + } else { + // last byte + oid += '.' + (value + b); + value = 0; + } + } + + return oid; + }; + + /** + * Converts a UTCTime value to a date. + * + * Note: GeneralizedTime has 4 digits for the year and is used for X.509 + * dates past 2049. Parsing that structure hasn't been implemented yet. + * + * @param utc the UTCTime value to convert. + * + * @return the date. + */ + asn1.utcTimeToDate = function(utc) { + /* The following formats can be used: + + YYMMDDhhmmZ + YYMMDDhhmm+hh'mm' + YYMMDDhhmm-hh'mm' + YYMMDDhhmmssZ + YYMMDDhhmmss+hh'mm' + YYMMDDhhmmss-hh'mm' + + Where: + + YY is the least significant two digits of the year + MM is the month (01 to 12) + DD is the day (01 to 31) + hh is the hour (00 to 23) + mm are the minutes (00 to 59) + ss are the seconds (00 to 59) + Z indicates that local time is GMT, + indicates that local time is + later than GMT, and - indicates that local time is earlier than GMT + hh' is the absolute value of the offset from GMT in hours + mm' is the absolute value of the offset from GMT in minutes */ + var date = new Date(); + + // if YY >= 50 use 19xx, if YY < 50 use 20xx + var year = parseInt(utc.substr(0, 2), 10); + year = (year >= 50) ? 1900 + year : 2000 + year; + var MM = parseInt(utc.substr(2, 2), 10) - 1; // use 0-11 for month + var DD = parseInt(utc.substr(4, 2), 10); + var hh = parseInt(utc.substr(6, 2), 10); + var mm = parseInt(utc.substr(8, 2), 10); + var ss = 0; + + // not just YYMMDDhhmmZ + if(utc.length > 11) { + // get character after minutes + var c = utc.charAt(10); + var end = 10; + + // see if seconds are present + if(c !== '+' && c !== '-') { + // get seconds + ss = parseInt(utc.substr(10, 2), 10); + end += 2; + } + } + + // update date + date.setUTCFullYear(year, MM, DD); + date.setUTCHours(hh, mm, ss, 0); + + if(end) { + // get +/- after end of time + c = utc.charAt(end); + if(c === '+' || c === '-') { + // get hours+minutes offset + var hhoffset = parseInt(utc.substr(end + 1, 2), 10); + var mmoffset = parseInt(utc.substr(end + 4, 2), 10); + + // calculate offset in milliseconds + var offset = hhoffset * 60 + mmoffset; + offset *= 60000; + + // apply offset + if(c === '+') { + date.setTime(+date - offset); + } else { + date.setTime(+date + offset); + } + } + } + + return date; + }; + + /** + * Converts a GeneralizedTime value to a date. + * + * @param gentime the GeneralizedTime value to convert. + * + * @return the date. + */ + asn1.generalizedTimeToDate = function(gentime) { + /* The following formats can be used: + + YYYYMMDDHHMMSS + YYYYMMDDHHMMSS.fff + YYYYMMDDHHMMSSZ + YYYYMMDDHHMMSS.fffZ + YYYYMMDDHHMMSS+hh'mm' + YYYYMMDDHHMMSS.fff+hh'mm' + YYYYMMDDHHMMSS-hh'mm' + YYYYMMDDHHMMSS.fff-hh'mm' + + Where: + + YYYY is the year + MM is the month (01 to 12) + DD is the day (01 to 31) + hh is the hour (00 to 23) + mm are the minutes (00 to 59) + ss are the seconds (00 to 59) + .fff is the second fraction, accurate to three decimal places + Z indicates that local time is GMT, + indicates that local time is + later than GMT, and - indicates that local time is earlier than GMT + hh' is the absolute value of the offset from GMT in hours + mm' is the absolute value of the offset from GMT in minutes */ + var date = new Date(); + + var YYYY = parseInt(gentime.substr(0, 4), 10); + var MM = parseInt(gentime.substr(4, 2), 10) - 1; // use 0-11 for month + var DD = parseInt(gentime.substr(6, 2), 10); + var hh = parseInt(gentime.substr(8, 2), 10); + var mm = parseInt(gentime.substr(10, 2), 10); + var ss = parseInt(gentime.substr(12, 2), 10); + var fff = 0; + var offset = 0; + var isUTC = false; + + if(gentime.charAt(gentime.length - 1) === 'Z') { + isUTC = true; + } + + var end = gentime.length - 5, c = gentime.charAt(end); + if(c === '+' || c === '-') { + // get hours+minutes offset + var hhoffset = parseInt(gentime.substr(end + 1, 2), 10); + var mmoffset = parseInt(gentime.substr(end + 4, 2), 10); + + // calculate offset in milliseconds + offset = hhoffset * 60 + mmoffset; + offset *= 60000; + + // apply offset + if(c === '+') { + offset *= -1; + } + + isUTC = true; + } + + // check for second fraction + if(gentime.charAt(14) === '.') { + fff = parseFloat(gentime.substr(14), 10) * 1000; + } + + if(isUTC) { + date.setUTCFullYear(YYYY, MM, DD); + date.setUTCHours(hh, mm, ss, fff); + + // apply offset + date.setTime(+date + offset); + } else { + date.setFullYear(YYYY, MM, DD); + date.setHours(hh, mm, ss, fff); + } + + return date; + }; + + /** + * Converts a date to a UTCTime value. + * + * Note: GeneralizedTime has 4 digits for the year and is used for X.509 + * dates past 2049. Converting to a GeneralizedTime hasn't been + * implemented yet. + * + * @param date the date to convert. + * + * @return the UTCTime value. + */ + asn1.dateToUtcTime = function(date) { + // TODO: validate; currently assumes proper format + if(typeof date === 'string') { + return date; + } + + var rval = ''; + + // create format YYMMDDhhmmssZ + var format = []; + format.push(('' + date.getUTCFullYear()).substr(2)); + format.push('' + (date.getUTCMonth() + 1)); + format.push('' + date.getUTCDate()); + format.push('' + date.getUTCHours()); + format.push('' + date.getUTCMinutes()); + format.push('' + date.getUTCSeconds()); + + // ensure 2 digits are used for each format entry + for(var i = 0; i < format.length; ++i) { + if(format[i].length < 2) { + rval += '0'; + } + rval += format[i]; + } + rval += 'Z'; + + return rval; + }; + + /** + * Converts a date to a GeneralizedTime value. + * + * @param date the date to convert. + * + * @return the GeneralizedTime value as a string. + */ + asn1.dateToGeneralizedTime = function(date) { + // TODO: validate; currently assumes proper format + if(typeof date === 'string') { + return date; + } + + var rval = ''; + + // create format YYYYMMDDHHMMSSZ + var format = []; + format.push('' + date.getUTCFullYear()); + format.push('' + (date.getUTCMonth() + 1)); + format.push('' + date.getUTCDate()); + format.push('' + date.getUTCHours()); + format.push('' + date.getUTCMinutes()); + format.push('' + date.getUTCSeconds()); + + // ensure 2 digits are used for each format entry + for(var i = 0; i < format.length; ++i) { + if(format[i].length < 2) { + rval += '0'; + } + rval += format[i]; + } + rval += 'Z'; + + return rval; + }; + + /** + * Converts a javascript integer to a DER-encoded byte buffer to be used + * as the value for an INTEGER type. + * + * @param x the integer. + * + * @return the byte buffer. + */ + asn1.integerToDer = function(x) { + var rval = forge.util.createBuffer(); + if(x >= -0x80 && x < 0x80) { + return rval.putSignedInt(x, 8); + } + if(x >= -0x8000 && x < 0x8000) { + return rval.putSignedInt(x, 16); + } + if(x >= -0x800000 && x < 0x800000) { + return rval.putSignedInt(x, 24); + } + if(x >= -0x80000000 && x < 0x80000000) { + return rval.putSignedInt(x, 32); + } + var error = new Error('Integer too large; max is 32-bits.'); + error.integer = x; + throw error; + }; + + /** + * Converts a DER-encoded byte buffer to a javascript integer. This is + * typically used to decode the value of an INTEGER type. + * + * @param bytes the byte buffer. + * + * @return the integer. + */ + asn1.derToInteger = function(bytes) { + // wrap in buffer if needed + if(typeof bytes === 'string') { + bytes = forge.util.createBuffer(bytes); + } + + var n = bytes.length() * 8; + if(n > 32) { + throw new Error('Integer too large; max is 32-bits.'); + } + return bytes.getSignedInt(n); + }; + + /** + * Validates that the given ASN.1 object is at least a super set of the + * given ASN.1 structure. Only tag classes and types are checked. An + * optional map may also be provided to capture ASN.1 values while the + * structure is checked. + * + * To capture an ASN.1 value, set an object in the validator's 'capture' + * parameter to the key to use in the capture map. To capture the full + * ASN.1 object, specify 'captureAsn1'. To capture BIT STRING bytes, including + * the leading unused bits counter byte, specify 'captureBitStringContents'. + * To capture BIT STRING bytes, without the leading unused bits counter byte, + * specify 'captureBitStringValue'. + * + * Objects in the validator may set a field 'optional' to true to indicate + * that it isn't necessary to pass validation. + * + * @param obj the ASN.1 object to validate. + * @param v the ASN.1 structure validator. + * @param capture an optional map to capture values in. + * @param errors an optional array for storing validation errors. + * + * @return true on success, false on failure. + */ + asn1.validate = function(obj, v, capture, errors) { + var rval = false; + + // ensure tag class and type are the same if specified + if((obj.tagClass === v.tagClass || typeof(v.tagClass) === 'undefined') && + (obj.type === v.type || typeof(v.type) === 'undefined')) { + // ensure constructed flag is the same if specified + if(obj.constructed === v.constructed || + typeof(v.constructed) === 'undefined') { + rval = true; + + // handle sub values + if(v.value && forge.util.isArray(v.value)) { + var j = 0; + for(var i = 0; rval && i < v.value.length; ++i) { + rval = v.value[i].optional || false; + if(obj.value[j]) { + rval = asn1.validate(obj.value[j], v.value[i], capture, errors); + if(rval) { + ++j; + } else if(v.value[i].optional) { + rval = true; + } + } + if(!rval && errors) { + errors.push( + '[' + v.name + '] ' + + 'Tag class "' + v.tagClass + '", type "' + + v.type + '" expected value length "' + + v.value.length + '", got "' + + obj.value.length + '"'); + } + } + } + + if(rval && capture) { + if(v.capture) { + capture[v.capture] = obj.value; + } + if(v.captureAsn1) { + capture[v.captureAsn1] = obj; + } + if(v.captureBitStringContents && 'bitStringContents' in obj) { + capture[v.captureBitStringContents] = obj.bitStringContents; + } + if(v.captureBitStringValue && 'bitStringContents' in obj) { + if(obj.bitStringContents.length < 2) { + capture[v.captureBitStringValue] = ''; + } else { + // FIXME: support unused bits with data shifting + var unused = obj.bitStringContents.charCodeAt(0); + if(unused !== 0) { + throw new Error( + 'captureBitStringValue only supported for zero unused bits'); + } + capture[v.captureBitStringValue] = obj.bitStringContents.slice(1); + } + } + } + } else if(errors) { + errors.push( + '[' + v.name + '] ' + + 'Expected constructed "' + v.constructed + '", got "' + + obj.constructed + '"'); + } + } else if(errors) { + if(obj.tagClass !== v.tagClass) { + errors.push( + '[' + v.name + '] ' + + 'Expected tag class "' + v.tagClass + '", got "' + + obj.tagClass + '"'); + } + if(obj.type !== v.type) { + errors.push( + '[' + v.name + '] ' + + 'Expected type "' + v.type + '", got "' + obj.type + '"'); + } + } + return rval; + }; + + // regex for testing for non-latin characters + var _nonLatinRegex = /[^\\u0000-\\u00ff]/; + + /** + * Pretty prints an ASN.1 object to a string. + * + * @param obj the object to write out. + * @param level the level in the tree. + * @param indentation the indentation to use. + * + * @return the string. + */ + asn1.prettyPrint = function(obj, level, indentation) { + var rval = ''; + + // set default level and indentation + level = level || 0; + indentation = indentation || 2; + + // start new line for deep levels + if(level > 0) { + rval += '\n'; + } + + // create indent + var indent = ''; + for(var i = 0; i < level * indentation; ++i) { + indent += ' '; + } + + // print class:type + rval += indent + 'Tag: '; + switch(obj.tagClass) { + case asn1.Class.UNIVERSAL: + rval += 'Universal:'; + break; + case asn1.Class.APPLICATION: + rval += 'Application:'; + break; + case asn1.Class.CONTEXT_SPECIFIC: + rval += 'Context-Specific:'; + break; + case asn1.Class.PRIVATE: + rval += 'Private:'; + break; + } + + if(obj.tagClass === asn1.Class.UNIVERSAL) { + rval += obj.type; + + // known types + switch(obj.type) { + case asn1.Type.NONE: + rval += ' (None)'; + break; + case asn1.Type.BOOLEAN: + rval += ' (Boolean)'; + break; + case asn1.Type.INTEGER: + rval += ' (Integer)'; + break; + case asn1.Type.BITSTRING: + rval += ' (Bit string)'; + break; + case asn1.Type.OCTETSTRING: + rval += ' (Octet string)'; + break; + case asn1.Type.NULL: + rval += ' (Null)'; + break; + case asn1.Type.OID: + rval += ' (Object Identifier)'; + break; + case asn1.Type.ODESC: + rval += ' (Object Descriptor)'; + break; + case asn1.Type.EXTERNAL: + rval += ' (External or Instance of)'; + break; + case asn1.Type.REAL: + rval += ' (Real)'; + break; + case asn1.Type.ENUMERATED: + rval += ' (Enumerated)'; + break; + case asn1.Type.EMBEDDED: + rval += ' (Embedded PDV)'; + break; + case asn1.Type.UTF8: + rval += ' (UTF8)'; + break; + case asn1.Type.ROID: + rval += ' (Relative Object Identifier)'; + break; + case asn1.Type.SEQUENCE: + rval += ' (Sequence)'; + break; + case asn1.Type.SET: + rval += ' (Set)'; + break; + case asn1.Type.PRINTABLESTRING: + rval += ' (Printable String)'; + break; + case asn1.Type.IA5String: + rval += ' (IA5String (ASCII))'; + break; + case asn1.Type.UTCTIME: + rval += ' (UTC time)'; + break; + case asn1.Type.GENERALIZEDTIME: + rval += ' (Generalized time)'; + break; + case asn1.Type.BMPSTRING: + rval += ' (BMP String)'; + break; + } + } else { + rval += obj.type; + } + + rval += '\n'; + rval += indent + 'Constructed: ' + obj.constructed + '\n'; + + if(obj.composed) { + var subvalues = 0; + var sub = ''; + for(var i = 0; i < obj.value.length; ++i) { + if(obj.value[i] !== undefined) { + subvalues += 1; + sub += asn1.prettyPrint(obj.value[i], level + 1, indentation); + if((i + 1) < obj.value.length) { + sub += ','; + } + } + } + rval += indent + 'Sub values: ' + subvalues + sub; + } else { + rval += indent + 'Value: '; + if(obj.type === asn1.Type.OID) { + var oid = asn1.derToOid(obj.value); + rval += oid; + if(forge.pki && forge.pki.oids) { + if(oid in forge.pki.oids) { + rval += ' (' + forge.pki.oids[oid] + ') '; + } + } + } + if(obj.type === asn1.Type.INTEGER) { + try { + rval += asn1.derToInteger(obj.value); + } catch(ex) { + rval += '0x' + forge.util.bytesToHex(obj.value); + } + } else if(obj.type === asn1.Type.BITSTRING) { + // TODO: shift bits as needed to display without padding + if(obj.value.length > 1) { + // remove unused bits field + rval += '0x' + forge.util.bytesToHex(obj.value.slice(1)); + } else { + rval += '(none)'; + } + // show unused bit count + if(obj.value.length > 0) { + var unused = obj.value.charCodeAt(0); + if(unused == 1) { + rval += ' (1 unused bit shown)'; + } else if(unused > 1) { + rval += ' (' + unused + ' unused bits shown)'; + } + } + } else if(obj.type === asn1.Type.OCTETSTRING) { + if(!_nonLatinRegex.test(obj.value)) { + rval += '(' + obj.value + ') '; + } + rval += '0x' + forge.util.bytesToHex(obj.value); + } else if(obj.type === asn1.Type.UTF8) { + rval += forge.util.decodeUtf8(obj.value); + } else if(obj.type === asn1.Type.PRINTABLESTRING || + obj.type === asn1.Type.IA5String) { + rval += obj.value; + } else if(_nonLatinRegex.test(obj.value)) { + rval += '0x' + forge.util.bytesToHex(obj.value); + } else if(obj.value.length === 0) { + rval += '[null]'; + } else { + rval += obj.value; + } + } + + return rval; + }; + }); + + /** + * Node.js module for Forge message digests. + * + * @author Dave Longley + * + * Copyright 2011-2017 Digital Bazaar, Inc. + */ + + + var md = forge.md = forge.md || {}; + forge.md.algorithms = forge.md.algorithms || {}; + + var hmac_1 = createCommonjsModule(function (module) { + /** + * Hash-based Message Authentication Code implementation. Requires a message + * digest object that can be obtained, for example, from forge.md.sha1 or + * forge.md.md5. + * + * @author Dave Longley + * + * Copyright (c) 2010-2012 Digital Bazaar, Inc. All rights reserved. + */ + + + + + /* HMAC API */ + var hmac = module.exports = forge.hmac = forge.hmac || {}; + + /** + * Creates an HMAC object that uses the given message digest object. + * + * @return an HMAC object. + */ + hmac.create = function() { + // the hmac key to use + var _key = null; + + // the message digest to use + var _md = null; + + // the inner padding + var _ipadding = null; + + // the outer padding + var _opadding = null; + + // hmac context + var ctx = {}; + + /** + * Starts or restarts the HMAC with the given key and message digest. + * + * @param md the message digest to use, null to reuse the previous one, + * a string to use builtin 'sha1', 'md5', 'sha256'. + * @param key the key to use as a string, array of bytes, byte buffer, + * or null to reuse the previous key. + */ + ctx.start = function(md, key) { + if(md !== null) { + if(typeof md === 'string') { + // create builtin message digest + md = md.toLowerCase(); + if(md in forge.md.algorithms) { + _md = forge.md.algorithms[md].create(); + } else { + throw new Error('Unknown hash algorithm "' + md + '"'); + } + } else { + // store message digest + _md = md; + } + } + + if(key === null) { + // reuse previous key + key = _key; + } else { + if(typeof key === 'string') { + // convert string into byte buffer + key = forge.util.createBuffer(key); + } else if(forge.util.isArray(key)) { + // convert byte array into byte buffer + var tmp = key; + key = forge.util.createBuffer(); + for(var i = 0; i < tmp.length; ++i) { + key.putByte(tmp[i]); + } + } + + // if key is longer than blocksize, hash it + var keylen = key.length(); + if(keylen > _md.blockLength) { + _md.start(); + _md.update(key.bytes()); + key = _md.digest(); + } + + // mix key into inner and outer padding + // ipadding = [0x36 * blocksize] ^ key + // opadding = [0x5C * blocksize] ^ key + _ipadding = forge.util.createBuffer(); + _opadding = forge.util.createBuffer(); + keylen = key.length(); + for(var i = 0; i < keylen; ++i) { + var tmp = key.at(i); + _ipadding.putByte(0x36 ^ tmp); + _opadding.putByte(0x5C ^ tmp); + } + + // if key is shorter than blocksize, add additional padding + if(keylen < _md.blockLength) { + var tmp = _md.blockLength - keylen; + for(var i = 0; i < tmp; ++i) { + _ipadding.putByte(0x36); + _opadding.putByte(0x5C); + } + } + _key = key; + _ipadding = _ipadding.bytes(); + _opadding = _opadding.bytes(); + } + + // digest is done like so: hash(opadding | hash(ipadding | message)) + + // prepare to do inner hash + // hash(ipadding | message) + _md.start(); + _md.update(_ipadding); + }; + + /** + * Updates the HMAC with the given message bytes. + * + * @param bytes the bytes to update with. + */ + ctx.update = function(bytes) { + _md.update(bytes); + }; + + /** + * Produces the Message Authentication Code (MAC). + * + * @return a byte buffer containing the digest value. + */ + ctx.getMac = function() { + // digest is done like so: hash(opadding | hash(ipadding | message)) + // here we do the outer hashing + var inner = _md.digest().bytes(); + _md.start(); + _md.update(_opadding); + _md.update(inner); + return _md.digest(); + }; + // alias for getMac + ctx.digest = ctx.getMac; + + return ctx; + }; + }); + + var md5_1 = createCommonjsModule(function (module) { + /** + * Message Digest Algorithm 5 with 128-bit digest (MD5) implementation. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + + + + + var md5 = module.exports = forge.md5 = forge.md5 || {}; + forge.md.md5 = forge.md.algorithms.md5 = md5; + + /** + * Creates an MD5 message digest object. + * + * @return a message digest object. + */ + md5.create = function() { + // do initialization as necessary + if(!_initialized) { + _init(); + } + + // MD5 state contains four 32-bit integers + var _state = null; + + // input buffer + var _input = forge.util.createBuffer(); + + // used for word storage + var _w = new Array(16); + + // message digest object + var md = { + algorithm: 'md5', + blockLength: 64, + digestLength: 16, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 8 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength64 for backwards-compatibility) + md.fullMessageLength = md.messageLength64 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge.util.createBuffer(); + _state = { + h0: 0x67452301, + h1: 0xEFCDAB89, + h2: 0x98BADCFE, + h3: 0x10325476 + }; + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = (len[1] / 0x100000000) >>> 0; + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update(_state, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate MD5 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 448 mod 512. In other words, + the data to be digested must be a multiple of 512 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 8 bytes (64 + bits), that means that the last segment of the data must have 56 bytes + (448 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 448 mod 512 because + 512 - 128 = 448. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 448 mod 512, then 512 padding bits must be added. */ + + var finalBlock = forge.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in little-endian order; since length + // is stored in bytes we multiply by 8 and add carry + var bits, carry = 0; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + bits = md.fullMessageLength[i] * 8 + carry; + carry = (bits / 0x100000000) >>> 0; + finalBlock.putInt32Le(bits >>> 0); + } + + var s2 = { + h0: _state.h0, + h1: _state.h1, + h2: _state.h2, + h3: _state.h3 + }; + _update(s2, _w, finalBlock); + var rval = forge.util.createBuffer(); + rval.putInt32Le(s2.h0); + rval.putInt32Le(s2.h1); + rval.putInt32Le(s2.h2); + rval.putInt32Le(s2.h3); + return rval; + }; + + return md; + }; + + // padding, constant tables for calculating md5 + var _padding = null; + var _g = null; + var _r = null; + var _k = null; + var _initialized = false; + + /** + * Initializes the constant tables. + */ + function _init() { + // create padding + _padding = String.fromCharCode(128); + _padding += forge.util.fillString(String.fromCharCode(0x00), 64); + + // g values + _g = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9]; + + // rounds table + _r = [ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]; + + // get the result of abs(sin(i + 1)) as a 32-bit integer + _k = new Array(64); + for(var i = 0; i < 64; ++i) { + _k[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 0x100000000); + } + + // now initialized + _initialized = true; + } + + /** + * Updates an MD5 state with the given byte buffer. + * + * @param s the MD5 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ + function _update(s, w, bytes) { + // consume 512 bit (64 byte) chunks + var t, a, b, c, d, f, r, i; + var len = bytes.length(); + while(len >= 64) { + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + + // round 1 + for(i = 0; i < 16; ++i) { + w[i] = bytes.getInt32Le(); + f = d ^ (b & (c ^ d)); + t = (a + f + _k[i] + w[i]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + // round 2 + for(; i < 32; ++i) { + f = c ^ (d & (b ^ c)); + t = (a + f + _k[i] + w[_g[i]]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + // round 3 + for(; i < 48; ++i) { + f = b ^ c ^ d; + t = (a + f + _k[i] + w[_g[i]]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + // round 4 + for(; i < 64; ++i) { + f = c ^ (b | ~d); + t = (a + f + _k[i] + w[_g[i]]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + + len -= 64; + } + } + }); + + var pem_1 = createCommonjsModule(function (module) { + /** + * Javascript implementation of basic PEM (Privacy Enhanced Mail) algorithms. + * + * See: RFC 1421. + * + * @author Dave Longley + * + * Copyright (c) 2013-2014 Digital Bazaar, Inc. + * + * A Forge PEM object has the following fields: + * + * type: identifies the type of message (eg: "RSA PRIVATE KEY"). + * + * procType: identifies the type of processing performed on the message, + * it has two subfields: version and type, eg: 4,ENCRYPTED. + * + * contentDomain: identifies the type of content in the message, typically + * only uses the value: "RFC822". + * + * dekInfo: identifies the message encryption algorithm and mode and includes + * any parameters for the algorithm, it has two subfields: algorithm and + * parameters, eg: DES-CBC,F8143EDE5960C597. + * + * headers: contains all other PEM encapsulated headers -- where order is + * significant (for pairing data like recipient ID + key info). + * + * body: the binary-encoded body. + */ + + + + // shortcut for pem API + var pem = module.exports = forge.pem = forge.pem || {}; + + /** + * Encodes (serializes) the given PEM object. + * + * @param msg the PEM message object to encode. + * @param options the options to use: + * maxline the maximum characters per line for the body, (default: 64). + * + * @return the PEM-formatted string. + */ + pem.encode = function(msg, options) { + options = options || {}; + var rval = '-----BEGIN ' + msg.type + '-----\r\n'; + + // encode special headers + var header; + if(msg.procType) { + header = { + name: 'Proc-Type', + values: [String(msg.procType.version), msg.procType.type] + }; + rval += foldHeader(header); + } + if(msg.contentDomain) { + header = {name: 'Content-Domain', values: [msg.contentDomain]}; + rval += foldHeader(header); + } + if(msg.dekInfo) { + header = {name: 'DEK-Info', values: [msg.dekInfo.algorithm]}; + if(msg.dekInfo.parameters) { + header.values.push(msg.dekInfo.parameters); + } + rval += foldHeader(header); + } + + if(msg.headers) { + // encode all other headers + for(var i = 0; i < msg.headers.length; ++i) { + rval += foldHeader(msg.headers[i]); + } + } + + // terminate header + if(msg.procType) { + rval += '\r\n'; + } + + // add body + rval += forge.util.encode64(msg.body, options.maxline || 64) + '\r\n'; + + rval += '-----END ' + msg.type + '-----\r\n'; + return rval; + }; + + /** + * Decodes (deserializes) all PEM messages found in the given string. + * + * @param str the PEM-formatted string to decode. + * + * @return the PEM message objects in an array. + */ + pem.decode = function(str) { + var rval = []; + + // split string into PEM messages (be lenient w/EOF on BEGIN line) + var rMessage = /\s*-----BEGIN ([A-Z0-9- ]+)-----\r?\n?([\x21-\x7e\s]+?(?:\r?\n\r?\n))?([:A-Za-z0-9+\/=\s]+?)-----END \1-----/g; + var rHeader = /([\x21-\x7e]+):\s*([\x21-\x7e\s^:]+)/; + var rCRLF = /\r?\n/; + var match; + while(true) { + match = rMessage.exec(str); + if(!match) { + break; + } + + var msg = { + type: match[1], + procType: null, + contentDomain: null, + dekInfo: null, + headers: [], + body: forge.util.decode64(match[3]) + }; + rval.push(msg); + + // no headers + if(!match[2]) { + continue; + } + + // parse headers + var lines = match[2].split(rCRLF); + var li = 0; + while(match && li < lines.length) { + // get line, trim any rhs whitespace + var line = lines[li].replace(/\s+$/, ''); + + // RFC2822 unfold any following folded lines + for(var nl = li + 1; nl < lines.length; ++nl) { + var next = lines[nl]; + if(!/\s/.test(next[0])) { + break; + } + line += next; + li = nl; + } + + // parse header + match = line.match(rHeader); + if(match) { + var header = {name: match[1], values: []}; + var values = match[2].split(','); + for(var vi = 0; vi < values.length; ++vi) { + header.values.push(ltrim(values[vi])); + } + + // Proc-Type must be the first header + if(!msg.procType) { + if(header.name !== 'Proc-Type') { + throw new Error('Invalid PEM formatted message. The first ' + + 'encapsulated header must be "Proc-Type".'); + } else if(header.values.length !== 2) { + throw new Error('Invalid PEM formatted message. The "Proc-Type" ' + + 'header must have two subfields.'); + } + msg.procType = {version: values[0], type: values[1]}; + } else if(!msg.contentDomain && header.name === 'Content-Domain') { + // special-case Content-Domain + msg.contentDomain = values[0] || ''; + } else if(!msg.dekInfo && header.name === 'DEK-Info') { + // special-case DEK-Info + if(header.values.length === 0) { + throw new Error('Invalid PEM formatted message. The "DEK-Info" ' + + 'header must have at least one subfield.'); + } + msg.dekInfo = {algorithm: values[0], parameters: values[1] || null}; + } else { + msg.headers.push(header); + } + } + + ++li; + } + + if(msg.procType === 'ENCRYPTED' && !msg.dekInfo) { + throw new Error('Invalid PEM formatted message. The "DEK-Info" ' + + 'header must be present if "Proc-Type" is "ENCRYPTED".'); + } + } + + if(rval.length === 0) { + throw new Error('Invalid PEM formatted message.'); + } + + return rval; + }; + + function foldHeader(header) { + var rval = header.name + ': '; + + // ensure values with CRLF are folded + var values = []; + var insertSpace = function(match, $1) { + return ' ' + $1; + }; + for(var i = 0; i < header.values.length; ++i) { + values.push(header.values[i].replace(/^(\S+\r\n)/, insertSpace)); + } + rval += values.join(',') + '\r\n'; + + // do folding + var length = 0; + var candidate = -1; + for(var i = 0; i < rval.length; ++i, ++length) { + if(length > 65 && candidate !== -1) { + var insert = rval[candidate]; + if(insert === ',') { + ++candidate; + rval = rval.substr(0, candidate) + '\r\n ' + rval.substr(candidate); + } else { + rval = rval.substr(0, candidate) + + '\r\n' + insert + rval.substr(candidate + 1); + } + length = (i - candidate - 1); + candidate = -1; + ++i; + } else if(rval[i] === ' ' || rval[i] === '\t' || rval[i] === ',') { + candidate = i; + } + } + + return rval; + } + + function ltrim(str) { + return str.replace(/^\s+/, ''); + } + }); + + /** + * DES (Data Encryption Standard) implementation. + * + * This implementation supports DES as well as 3DES-EDE in ECB and CBC mode. + * It is based on the BSD-licensed implementation by Paul Tero: + * + * Paul Tero, July 2001 + * http://www.tero.co.uk/des/ + * + * Optimised for performance with large blocks by + * Michael Hayworth, November 2001 + * http://www.netdealing.com + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @author Stefan Siegl + * @author Dave Longley + * + * Copyright (c) 2012 Stefan Siegl + * Copyright (c) 2012-2014 Digital Bazaar, Inc. + */ + + + + + + /* DES API */ + var des = forge.des = forge.des || {}; + + /** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('DES-', key); + * cipher.start({iv: iv}); + * + * Creates an DES cipher object to encrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as binary-encoded strings of bytes or + * byte buffers. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC' if IV is + * given, 'ECB' if null). + * + * @return the cipher. + */ + forge.des.startEncrypting = function(key, iv, output, mode) { + var cipher = _createCipher$1({ + key: key, + output: output, + decrypt: false, + mode: mode || (iv === null ? 'ECB' : 'CBC') + }); + cipher.start(iv); + return cipher; + }; + + /** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('DES-', key); + * + * Creates an DES cipher object to encrypt data using the given symmetric key. + * + * The key may be given as a binary-encoded string of bytes or a byte buffer. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + forge.des.createEncryptionCipher = function(key, mode) { + return _createCipher$1({ + key: key, + output: null, + decrypt: false, + mode: mode + }); + }; + + /** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('DES-', key); + * decipher.start({iv: iv}); + * + * Creates an DES cipher object to decrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as binary-encoded strings of bytes or + * byte buffers. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC' if IV is + * given, 'ECB' if null). + * + * @return the cipher. + */ + forge.des.startDecrypting = function(key, iv, output, mode) { + var cipher = _createCipher$1({ + key: key, + output: output, + decrypt: true, + mode: mode || (iv === null ? 'ECB' : 'CBC') + }); + cipher.start(iv); + return cipher; + }; + + /** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('DES-', key); + * + * Creates an DES cipher object to decrypt data using the given symmetric key. + * + * The key may be given as a binary-encoded string of bytes or a byte buffer. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + forge.des.createDecryptionCipher = function(key, mode) { + return _createCipher$1({ + key: key, + output: null, + decrypt: true, + mode: mode + }); + }; + + /** + * Creates a new DES cipher algorithm object. + * + * @param name the name of the algorithm. + * @param mode the mode factory function. + * + * @return the DES algorithm object. + */ + forge.des.Algorithm = function(name, mode) { + var self = this; + self.name = name; + self.mode = new mode({ + blockSize: 8, + cipher: { + encrypt: function(inBlock, outBlock) { + return _updateBlock$1(self._keys, inBlock, outBlock, false); + }, + decrypt: function(inBlock, outBlock) { + return _updateBlock$1(self._keys, inBlock, outBlock, true); + } + } + }); + self._init = false; + }; + + /** + * Initializes this DES algorithm by expanding its key. + * + * @param options the options to use. + * key the key to use with this algorithm. + * decrypt true if the algorithm should be initialized for decryption, + * false for encryption. + */ + forge.des.Algorithm.prototype.initialize = function(options) { + if(this._init) { + return; + } + + var key = forge.util.createBuffer(options.key); + if(this.name.indexOf('3DES') === 0) { + if(key.length() !== 24) { + throw new Error('Invalid Triple-DES key size: ' + key.length() * 8); + } + } + + // do key expansion to 16 or 48 subkeys (single or triple DES) + this._keys = _createKeys(key); + this._init = true; + }; + + /** Register DES algorithms **/ + + registerAlgorithm$1('DES-ECB', forge.cipher.modes.ecb); + registerAlgorithm$1('DES-CBC', forge.cipher.modes.cbc); + registerAlgorithm$1('DES-CFB', forge.cipher.modes.cfb); + registerAlgorithm$1('DES-OFB', forge.cipher.modes.ofb); + registerAlgorithm$1('DES-CTR', forge.cipher.modes.ctr); + + registerAlgorithm$1('3DES-ECB', forge.cipher.modes.ecb); + registerAlgorithm$1('3DES-CBC', forge.cipher.modes.cbc); + registerAlgorithm$1('3DES-CFB', forge.cipher.modes.cfb); + registerAlgorithm$1('3DES-OFB', forge.cipher.modes.ofb); + registerAlgorithm$1('3DES-CTR', forge.cipher.modes.ctr); + + function registerAlgorithm$1(name, mode) { + var factory = function() { + return new forge.des.Algorithm(name, mode); + }; + forge.cipher.registerAlgorithm(name, factory); + } + + /** DES implementation **/ + + var spfunction1 = [0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004]; + var spfunction2 = [-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000]; + var spfunction3 = [0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200]; + var spfunction4 = [0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080]; + var spfunction5 = [0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100]; + var spfunction6 = [0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010]; + var spfunction7 = [0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002]; + var spfunction8 = [0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000]; + + /** + * Create necessary sub keys. + * + * @param key the 64-bit or 192-bit key. + * + * @return the expanded keys. + */ + function _createKeys(key) { + var pc2bytes0 = [0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204], + pc2bytes1 = [0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101], + pc2bytes2 = [0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808], + pc2bytes3 = [0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000], + pc2bytes4 = [0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010], + pc2bytes5 = [0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420], + pc2bytes6 = [0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002], + pc2bytes7 = [0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800], + pc2bytes8 = [0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002], + pc2bytes9 = [0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408], + pc2bytes10 = [0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020], + pc2bytes11 = [0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200], + pc2bytes12 = [0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010], + pc2bytes13 = [0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105]; + + // how many iterations (1 for des, 3 for triple des) + // changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys + var iterations = key.length() > 8 ? 3 : 1; + + // stores the return keys + var keys = []; + + // now define the left shifts which need to be done + var shifts = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]; + + var n = 0, tmp; + for(var j = 0; j < iterations; j++) { + var left = key.getInt32(); + var right = key.getInt32(); + + tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= tmp; + left ^= (tmp << 4); + + tmp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= tmp; + right ^= (tmp << -16); + + tmp = ((left >>> 2) ^ right) & 0x33333333; + right ^= tmp; + left ^= (tmp << 2); + + tmp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= tmp; + right ^= (tmp << -16); + + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + tmp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= tmp; + right ^= (tmp << 8); + + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + // right needs to be shifted and OR'd with last four bits of left + tmp = (left << 8) | ((right >>> 20) & 0x000000f0); + + // left needs to be put upside down + left = ((right << 24) | ((right << 8) & 0xff0000) | + ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0)); + right = tmp; + + // now go through and perform these shifts on the left and right keys + for(var i = 0; i < shifts.length; ++i) { + //shift the keys either one or two bits to the left + if(shifts[i]) { + left = (left << 2) | (left >>> 26); + right = (right << 2) | (right >>> 26); + } else { + left = (left << 1) | (left >>> 27); + right = (right << 1) | (right >>> 27); + } + left &= -0xf; + right &= -0xf; + + // now apply PC-2, in such a way that E is easier when encrypting or + // decrypting this conversion will look like PC-2 except only the last 6 + // bits of each byte are used rather than 48 consecutive bits and the + // order of lines will be according to how the S selection functions will + // be applied: S2, S4, S6, S8, S1, S3, S5, S7 + var lefttmp = ( + pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | + pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf] | + pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | + pc2bytes6[(left >>> 4) & 0xf]); + var righttmp = ( + pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | + pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf] | + pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] | + pc2bytes13[(right >>> 4) & 0xf]); + tmp = ((righttmp >>> 16) ^ lefttmp) & 0x0000ffff; + keys[n++] = lefttmp ^ tmp; + keys[n++] = righttmp ^ (tmp << 16); + } + } + + return keys; + } + + /** + * Updates a single block (1 byte) using DES. The update will either + * encrypt or decrypt the block. + * + * @param keys the expanded keys. + * @param input the input block (an array of 32-bit words). + * @param output the updated output block. + * @param decrypt true to decrypt the block, false to encrypt it. + */ + function _updateBlock$1(keys, input, output, decrypt) { + // set up loops for single or triple DES + var iterations = keys.length === 32 ? 3 : 9; + var looping; + if(iterations === 3) { + looping = decrypt ? [30, -2, -2] : [0, 32, 2]; + } else { + looping = (decrypt ? + [94, 62, -2, 32, 64, 2, 30, -2, -2] : + [0, 32, 2, 62, 30, -2, 64, 96, 2]); + } + + var tmp; + + var left = input[0]; + var right = input[1]; + + // first each 64 bit chunk of the message must be permuted according to IP + tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= tmp; + left ^= (tmp << 4); + + tmp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= tmp; + left ^= (tmp << 16); + + tmp = ((right >>> 2) ^ left) & 0x33333333; + left ^= tmp; + right ^= (tmp << 2); + + tmp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= tmp; + right ^= (tmp << 8); + + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + // rotate left 1 bit + left = ((left << 1) | (left >>> 31)); + right = ((right << 1) | (right >>> 31)); + + for(var j = 0; j < iterations; j += 3) { + var endloop = looping[j + 1]; + var loopinc = looping[j + 2]; + + // now go through and perform the encryption or decryption + for(var i = looping[j]; i != endloop; i += loopinc) { + var right1 = right ^ keys[i]; + var right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1]; + + // passing these bytes through the S selection functions + tmp = left; + left = right; + right = tmp ^ ( + spfunction2[(right1 >>> 24) & 0x3f] | + spfunction4[(right1 >>> 16) & 0x3f] | + spfunction6[(right1 >>> 8) & 0x3f] | + spfunction8[right1 & 0x3f] | + spfunction1[(right2 >>> 24) & 0x3f] | + spfunction3[(right2 >>> 16) & 0x3f] | + spfunction5[(right2 >>> 8) & 0x3f] | + spfunction7[right2 & 0x3f]); + } + // unreverse left and right + tmp = left; + left = right; + right = tmp; + } + + // rotate right 1 bit + left = ((left >>> 1) | (left << 31)); + right = ((right >>> 1) | (right << 31)); + + // now perform IP-1, which is IP in the opposite direction + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + tmp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= tmp; + right ^= (tmp << 8); + + tmp = ((right >>> 2) ^ left) & 0x33333333; + left ^= tmp; + right ^= (tmp << 2); + + tmp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= tmp; + left ^= (tmp << 16); + + tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= tmp; + left ^= (tmp << 4); + + output[0] = left; + output[1] = right; + } + + /** + * Deprecated. Instead, use: + * + * forge.cipher.createCipher('DES-', key); + * forge.cipher.createDecipher('DES-', key); + * + * Creates a deprecated DES cipher object. This object's mode will default to + * CBC (cipher-block-chaining). + * + * The key may be given as a binary-encoded string of bytes or a byte buffer. + * + * @param options the options to use. + * key the symmetric key to use (64 or 192 bits). + * output the buffer to write to. + * decrypt true for decryption, false for encryption. + * mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ + function _createCipher$1(options) { + options = options || {}; + var mode = (options.mode || 'CBC').toUpperCase(); + var algorithm = 'DES-' + mode; + + var cipher; + if(options.decrypt) { + cipher = forge.cipher.createDecipher(algorithm, options.key); + } else { + cipher = forge.cipher.createCipher(algorithm, options.key); + } + + // backwards compatible start API + var start = cipher.start; + cipher.start = function(iv, options) { + // backwards compatibility: support second arg as output buffer + var output = null; + if(options instanceof forge.util.ByteBuffer) { + output = options; + options = {}; + } + options = options || {}; + options.output = output; + options.iv = iv; + start.call(cipher, options); + }; + + return cipher; + } + + /** + * Password-Based Key-Derivation Function #2 implementation. + * + * See RFC 2898 for details. + * + * @author Dave Longley + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + */ + + + + + + var pkcs5 = forge.pkcs5 = forge.pkcs5 || {}; + + var crypto; + if(forge.util.isNodejs && !forge.options.usePureJavaScript) { + crypto = require$$7; + } + + /** + * Derives a key from a password. + * + * @param p the password as a binary-encoded string of bytes. + * @param s the salt as a binary-encoded string of bytes. + * @param c the iteration count, a positive integer. + * @param dkLen the intended length, in bytes, of the derived key, + * (max: 2^32 - 1) * hash length of the PRF. + * @param [md] the message digest (or algorithm identifier as a string) to use + * in the PRF, defaults to SHA-1. + * @param [callback(err, key)] presence triggers asynchronous version, called + * once the operation completes. + * + * @return the derived key, as a binary-encoded string of bytes, for the + * synchronous version (if no callback is specified). + */ + var pbkdf2 = forge.pbkdf2 = pkcs5.pbkdf2 = function( + p, s, c, dkLen, md, callback) { + if(typeof md === 'function') { + callback = md; + md = null; + } + + // use native implementation if possible and not disabled, note that + // some node versions only support SHA-1, others allow digest to be changed + if(forge.util.isNodejs && !forge.options.usePureJavaScript && + crypto.pbkdf2 && (md === null || typeof md !== 'object') && + (crypto.pbkdf2Sync.length > 4 || (!md || md === 'sha1'))) { + if(typeof md !== 'string') { + // default prf to SHA-1 + md = 'sha1'; + } + p = Buffer.from(p, 'binary'); + s = Buffer.from(s, 'binary'); + if(!callback) { + if(crypto.pbkdf2Sync.length === 4) { + return crypto.pbkdf2Sync(p, s, c, dkLen).toString('binary'); + } + return crypto.pbkdf2Sync(p, s, c, dkLen, md).toString('binary'); + } + if(crypto.pbkdf2Sync.length === 4) { + return crypto.pbkdf2(p, s, c, dkLen, function(err, key) { + if(err) { + return callback(err); + } + callback(null, key.toString('binary')); + }); + } + return crypto.pbkdf2(p, s, c, dkLen, md, function(err, key) { + if(err) { + return callback(err); + } + callback(null, key.toString('binary')); + }); + } + + if(typeof md === 'undefined' || md === null) { + // default prf to SHA-1 + md = 'sha1'; + } + if(typeof md === 'string') { + if(!(md in forge.md.algorithms)) { + throw new Error('Unknown hash algorithm: ' + md); + } + md = forge.md[md].create(); + } + + var hLen = md.digestLength; + + /* 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and + stop. */ + if(dkLen > (0xFFFFFFFF * hLen)) { + var err = new Error('Derived key is too long.'); + if(callback) { + return callback(err); + } + throw err; + } + + /* 2. Let len be the number of hLen-octet blocks in the derived key, + rounding up, and let r be the number of octets in the last + block: + + len = CEIL(dkLen / hLen), + r = dkLen - (len - 1) * hLen. */ + var len = Math.ceil(dkLen / hLen); + var r = dkLen - (len - 1) * hLen; + + /* 3. For each block of the derived key apply the function F defined + below to the password P, the salt S, the iteration count c, and + the block index to compute the block: + + T_1 = F(P, S, c, 1), + T_2 = F(P, S, c, 2), + ... + T_len = F(P, S, c, len), + + where the function F is defined as the exclusive-or sum of the + first c iterates of the underlying pseudorandom function PRF + applied to the password P and the concatenation of the salt S + and the block index i: + + F(P, S, c, i) = u_1 XOR u_2 XOR ... XOR u_c + + where + + u_1 = PRF(P, S || INT(i)), + u_2 = PRF(P, u_1), + ... + u_c = PRF(P, u_{c-1}). + + Here, INT(i) is a four-octet encoding of the integer i, most + significant octet first. */ + var prf = forge.hmac.create(); + prf.start(md, p); + var dk = ''; + var xor, u_c, u_c1; + + // sync version + if(!callback) { + for(var i = 1; i <= len; ++i) { + // PRF(P, S || INT(i)) (first iteration) + prf.start(null, null); + prf.update(s); + prf.update(forge.util.int32ToBytes(i)); + xor = u_c1 = prf.digest().getBytes(); + + // PRF(P, u_{c-1}) (other iterations) + for(var j = 2; j <= c; ++j) { + prf.start(null, null); + prf.update(u_c1); + u_c = prf.digest().getBytes(); + // F(p, s, c, i) + xor = forge.util.xorBytes(xor, u_c, hLen); + u_c1 = u_c; + } + + /* 4. Concatenate the blocks and extract the first dkLen octets to + produce a derived key DK: + + DK = T_1 || T_2 || ... || T_len<0..r-1> */ + dk += (i < len) ? xor : xor.substr(0, r); + } + /* 5. Output the derived key DK. */ + return dk; + } + + // async version + var i = 1, j; + function outer() { + if(i > len) { + // done + return callback(null, dk); + } + + // PRF(P, S || INT(i)) (first iteration) + prf.start(null, null); + prf.update(s); + prf.update(forge.util.int32ToBytes(i)); + xor = u_c1 = prf.digest().getBytes(); + + // PRF(P, u_{c-1}) (other iterations) + j = 2; + inner(); + } + + function inner() { + if(j <= c) { + prf.start(null, null); + prf.update(u_c1); + u_c = prf.digest().getBytes(); + // F(p, s, c, i) + xor = forge.util.xorBytes(xor, u_c, hLen); + u_c1 = u_c; + ++j; + return forge.util.setImmediate(inner); + } + + /* 4. Concatenate the blocks and extract the first dkLen octets to + produce a derived key DK: + + DK = T_1 || T_2 || ... || T_len<0..r-1> */ + dk += (i < len) ? xor : xor.substr(0, r); + + ++i; + outer(); + } + + outer(); + }; + + var sha256_1 = createCommonjsModule(function (module) { + /** + * Secure Hash Algorithm with 256-bit digest (SHA-256) implementation. + * + * See FIPS 180-2 for details. + * + * @author Dave Longley + * + * Copyright (c) 2010-2015 Digital Bazaar, Inc. + */ + + + + + var sha256 = module.exports = forge.sha256 = forge.sha256 || {}; + forge.md.sha256 = forge.md.algorithms.sha256 = sha256; + + /** + * Creates a SHA-256 message digest object. + * + * @return a message digest object. + */ + sha256.create = function() { + // do initialization as necessary + if(!_initialized) { + _init(); + } + + // SHA-256 state contains eight 32-bit integers + var _state = null; + + // input buffer + var _input = forge.util.createBuffer(); + + // used for word storage + var _w = new Array(64); + + // message digest object + var md = { + algorithm: 'sha256', + blockLength: 64, + digestLength: 32, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 8 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength64 for backwards-compatibility) + md.fullMessageLength = md.messageLength64 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge.util.createBuffer(); + _state = { + h0: 0x6A09E667, + h1: 0xBB67AE85, + h2: 0x3C6EF372, + h3: 0xA54FF53A, + h4: 0x510E527F, + h5: 0x9B05688C, + h6: 0x1F83D9AB, + h7: 0x5BE0CD19 + }; + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = ((len[1] / 0x100000000) >>> 0); + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update(_state, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate SHA-256 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 448 mod 512. In other words, + the data to be digested must be a multiple of 512 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 8 bytes (64 + bits), that means that the last segment of the data must have 56 bytes + (448 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 448 mod 512 because + 512 - 128 = 448. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 448 mod 512, then 512 padding bits must be added. */ + + var finalBlock = forge.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in big-endian order; since length + // is stored in bytes we multiply by 8 and add carry from next int + var next, carry; + var bits = md.fullMessageLength[0] * 8; + for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { + next = md.fullMessageLength[i + 1] * 8; + carry = (next / 0x100000000) >>> 0; + bits += carry; + finalBlock.putInt32(bits >>> 0); + bits = next >>> 0; + } + finalBlock.putInt32(bits); + + var s2 = { + h0: _state.h0, + h1: _state.h1, + h2: _state.h2, + h3: _state.h3, + h4: _state.h4, + h5: _state.h5, + h6: _state.h6, + h7: _state.h7 + }; + _update(s2, _w, finalBlock); + var rval = forge.util.createBuffer(); + rval.putInt32(s2.h0); + rval.putInt32(s2.h1); + rval.putInt32(s2.h2); + rval.putInt32(s2.h3); + rval.putInt32(s2.h4); + rval.putInt32(s2.h5); + rval.putInt32(s2.h6); + rval.putInt32(s2.h7); + return rval; + }; + + return md; + }; + + // sha-256 padding bytes not initialized yet + var _padding = null; + var _initialized = false; + + // table of constants + var _k = null; + + /** + * Initializes the constant tables. + */ + function _init() { + // create padding + _padding = String.fromCharCode(128); + _padding += forge.util.fillString(String.fromCharCode(0x00), 64); + + // create K table for SHA-256 + _k = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; + + // now initialized + _initialized = true; + } + + /** + * Updates a SHA-256 state with the given byte buffer. + * + * @param s the SHA-256 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ + function _update(s, w, bytes) { + // consume 512 bit (64 byte) chunks + var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h; + var len = bytes.length(); + while(len >= 64) { + // the w array will be populated with sixteen 32-bit big-endian words + // and then extended into 64 32-bit words according to SHA-256 + for(i = 0; i < 16; ++i) { + w[i] = bytes.getInt32(); + } + for(; i < 64; ++i) { + // XOR word 2 words ago rot right 17, rot right 19, shft right 10 + t1 = w[i - 2]; + t1 = + ((t1 >>> 17) | (t1 << 15)) ^ + ((t1 >>> 19) | (t1 << 13)) ^ + (t1 >>> 10); + // XOR word 15 words ago rot right 7, rot right 18, shft right 3 + t2 = w[i - 15]; + t2 = + ((t2 >>> 7) | (t2 << 25)) ^ + ((t2 >>> 18) | (t2 << 14)) ^ + (t2 >>> 3); + // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32 + w[i] = (t1 + w[i - 7] + t2 + w[i - 16]) | 0; + } + + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + e = s.h4; + f = s.h5; + g = s.h6; + h = s.h7; + + // round function + for(i = 0; i < 64; ++i) { + // Sum1(e) + s1 = + ((e >>> 6) | (e << 26)) ^ + ((e >>> 11) | (e << 21)) ^ + ((e >>> 25) | (e << 7)); + // Ch(e, f, g) (optimized the same way as SHA-1) + ch = g ^ (e & (f ^ g)); + // Sum0(a) + s0 = + ((a >>> 2) | (a << 30)) ^ + ((a >>> 13) | (a << 19)) ^ + ((a >>> 22) | (a << 10)); + // Maj(a, b, c) (optimized the same way as SHA-1) + maj = (a & b) | (c & (a ^ b)); + + // main algorithm + t1 = h + s1 + ch + _k[i] + w[i]; + t2 = s0 + maj; + h = g; + g = f; + f = e; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + // can't truncate with `| 0` + e = (d + t1) >>> 0; + d = c; + c = b; + b = a; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + // can't truncate with `| 0` + a = (t1 + t2) >>> 0; + } + + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + s.h4 = (s.h4 + e) | 0; + s.h5 = (s.h5 + f) | 0; + s.h6 = (s.h6 + g) | 0; + s.h7 = (s.h7 + h) | 0; + len -= 64; + } + } + }); + + var prng_1 = createCommonjsModule(function (module) { + /** + * A javascript implementation of a cryptographically-secure + * Pseudo Random Number Generator (PRNG). The Fortuna algorithm is followed + * here though the use of SHA-256 is not enforced; when generating an + * a PRNG context, the hashing algorithm and block cipher used for + * the generator are specified via a plugin. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + + + + var _crypto = null; + if(forge.util.isNodejs && !forge.options.usePureJavaScript && + !process.versions['node-webkit']) { + _crypto = require$$7; + } + + /* PRNG API */ + var prng = module.exports = forge.prng = forge.prng || {}; + + /** + * Creates a new PRNG context. + * + * A PRNG plugin must be passed in that will provide: + * + * 1. A function that initializes the key and seed of a PRNG context. It + * will be given a 16 byte key and a 16 byte seed. Any key expansion + * or transformation of the seed from a byte string into an array of + * integers (or similar) should be performed. + * 2. The cryptographic function used by the generator. It takes a key and + * a seed. + * 3. A seed increment function. It takes the seed and returns seed + 1. + * 4. An api to create a message digest. + * + * For an example, see random.js. + * + * @param plugin the PRNG plugin to use. + */ + prng.create = function(plugin) { + var ctx = { + plugin: plugin, + key: null, + seed: null, + time: null, + // number of reseeds so far + reseeds: 0, + // amount of data generated so far + generated: 0, + // no initial key bytes + keyBytes: '' + }; + + // create 32 entropy pools (each is a message digest) + var md = plugin.md; + var pools = new Array(32); + for(var i = 0; i < 32; ++i) { + pools[i] = md.create(); + } + ctx.pools = pools; + + // entropy pools are written to cyclically, starting at index 0 + ctx.pool = 0; + + /** + * Generates random bytes. The bytes may be generated synchronously or + * asynchronously. Web workers must use the asynchronous interface or + * else the behavior is undefined. + * + * @param count the number of random bytes to generate. + * @param [callback(err, bytes)] called once the operation completes. + * + * @return count random bytes as a string. + */ + ctx.generate = function(count, callback) { + // do synchronously + if(!callback) { + return ctx.generateSync(count); + } + + // simple generator using counter-based CBC + var cipher = ctx.plugin.cipher; + var increment = ctx.plugin.increment; + var formatKey = ctx.plugin.formatKey; + var formatSeed = ctx.plugin.formatSeed; + var b = forge.util.createBuffer(); + + // paranoid deviation from Fortuna: + // reset key for every request to protect previously + // generated random bytes should the key be discovered; + // there is no 100ms based reseeding because of this + // forced reseed for every `generate` call + ctx.key = null; + + generate(); + + function generate(err) { + if(err) { + return callback(err); + } + + // sufficient bytes generated + if(b.length() >= count) { + return callback(null, b.getBytes(count)); + } + + // if amount of data generated is greater than 1 MiB, trigger reseed + if(ctx.generated > 0xfffff) { + ctx.key = null; + } + + if(ctx.key === null) { + // prevent stack overflow + return forge.util.nextTick(function() { + _reseed(generate); + }); + } + + // generate the random bytes + var bytes = cipher(ctx.key, ctx.seed); + ctx.generated += bytes.length; + b.putBytes(bytes); + + // generate bytes for a new key and seed + ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed))); + ctx.seed = formatSeed(cipher(ctx.key, ctx.seed)); + + forge.util.setImmediate(generate); + } + }; + + /** + * Generates random bytes synchronously. + * + * @param count the number of random bytes to generate. + * + * @return count random bytes as a string. + */ + ctx.generateSync = function(count) { + // simple generator using counter-based CBC + var cipher = ctx.plugin.cipher; + var increment = ctx.plugin.increment; + var formatKey = ctx.plugin.formatKey; + var formatSeed = ctx.plugin.formatSeed; + + // paranoid deviation from Fortuna: + // reset key for every request to protect previously + // generated random bytes should the key be discovered; + // there is no 100ms based reseeding because of this + // forced reseed for every `generateSync` call + ctx.key = null; + + var b = forge.util.createBuffer(); + while(b.length() < count) { + // if amount of data generated is greater than 1 MiB, trigger reseed + if(ctx.generated > 0xfffff) { + ctx.key = null; + } + + if(ctx.key === null) { + _reseedSync(); + } + + // generate the random bytes + var bytes = cipher(ctx.key, ctx.seed); + ctx.generated += bytes.length; + b.putBytes(bytes); + + // generate bytes for a new key and seed + ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed))); + ctx.seed = formatSeed(cipher(ctx.key, ctx.seed)); + } + + return b.getBytes(count); + }; + + /** + * Private function that asynchronously reseeds a generator. + * + * @param callback(err) called once the operation completes. + */ + function _reseed(callback) { + if(ctx.pools[0].messageLength >= 32) { + _seed(); + return callback(); + } + // not enough seed data... + var needed = (32 - ctx.pools[0].messageLength) << 5; + ctx.seedFile(needed, function(err, bytes) { + if(err) { + return callback(err); + } + ctx.collect(bytes); + _seed(); + callback(); + }); + } + + /** + * Private function that synchronously reseeds a generator. + */ + function _reseedSync() { + if(ctx.pools[0].messageLength >= 32) { + return _seed(); + } + // not enough seed data... + var needed = (32 - ctx.pools[0].messageLength) << 5; + ctx.collect(ctx.seedFileSync(needed)); + _seed(); + } + + /** + * Private function that seeds a generator once enough bytes are available. + */ + function _seed() { + // update reseed count + ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1; + + // goal is to update `key` via: + // key = hash(key + s) + // where 's' is all collected entropy from selected pools, then... + + // create a plugin-based message digest + var md = ctx.plugin.md.create(); + + // consume current key bytes + md.update(ctx.keyBytes); + + // digest the entropy of pools whose index k meet the + // condition 'n mod 2^k == 0' where n is the number of reseeds + var _2powK = 1; + for(var k = 0; k < 32; ++k) { + if(ctx.reseeds % _2powK === 0) { + md.update(ctx.pools[k].digest().getBytes()); + ctx.pools[k].start(); + } + _2powK = _2powK << 1; + } + + // get digest for key bytes + ctx.keyBytes = md.digest().getBytes(); + + // paranoid deviation from Fortuna: + // update `seed` via `seed = hash(key)` + // instead of initializing to zero once and only + // ever incrementing it + md.start(); + md.update(ctx.keyBytes); + var seedBytes = md.digest().getBytes(); + + // update state + ctx.key = ctx.plugin.formatKey(ctx.keyBytes); + ctx.seed = ctx.plugin.formatSeed(seedBytes); + ctx.generated = 0; + } + + /** + * The built-in default seedFile. This seedFile is used when entropy + * is needed immediately. + * + * @param needed the number of bytes that are needed. + * + * @return the random bytes. + */ + function defaultSeedFile(needed) { + // use window.crypto.getRandomValues strong source of entropy if available + var getRandomValues = null; + var globalScope = forge.util.globalScope; + var _crypto = globalScope.crypto || globalScope.msCrypto; + if(_crypto && _crypto.getRandomValues) { + getRandomValues = function(arr) { + return _crypto.getRandomValues(arr); + }; + } + + var b = forge.util.createBuffer(); + if(getRandomValues) { + while(b.length() < needed) { + // max byte length is 65536 before QuotaExceededError is thrown + // http://www.w3.org/TR/WebCryptoAPI/#RandomSource-method-getRandomValues + var count = Math.max(1, Math.min(needed - b.length(), 65536) / 4); + var entropy = new Uint32Array(Math.floor(count)); + try { + getRandomValues(entropy); + for(var i = 0; i < entropy.length; ++i) { + b.putInt32(entropy[i]); + } + } catch(e) { + /* only ignore QuotaExceededError */ + if(!(typeof QuotaExceededError !== 'undefined' && + e instanceof QuotaExceededError)) { + throw e; + } + } + } + } + + // be sad and add some weak random data + if(b.length() < needed) { + /* Draws from Park-Miller "minimal standard" 31 bit PRNG, + implemented with David G. Carta's optimization: with 32 bit math + and without division (Public Domain). */ + var hi, lo, next; + var seed = Math.floor(Math.random() * 0x010000); + while(b.length() < needed) { + lo = 16807 * (seed & 0xFFFF); + hi = 16807 * (seed >> 16); + lo += (hi & 0x7FFF) << 16; + lo += hi >> 15; + lo = (lo & 0x7FFFFFFF) + (lo >> 31); + seed = lo & 0xFFFFFFFF; + + // consume lower 3 bytes of seed + for(var i = 0; i < 3; ++i) { + // throw in more pseudo random + next = seed >>> (i << 3); + next ^= Math.floor(Math.random() * 0x0100); + b.putByte(String.fromCharCode(next & 0xFF)); + } + } + } + + return b.getBytes(needed); + } + // initialize seed file APIs + if(_crypto) { + // use nodejs async API + ctx.seedFile = function(needed, callback) { + _crypto.randomBytes(needed, function(err, bytes) { + if(err) { + return callback(err); + } + callback(null, bytes.toString()); + }); + }; + // use nodejs sync API + ctx.seedFileSync = function(needed) { + return _crypto.randomBytes(needed).toString(); + }; + } else { + ctx.seedFile = function(needed, callback) { + try { + callback(null, defaultSeedFile(needed)); + } catch(e) { + callback(e); + } + }; + ctx.seedFileSync = defaultSeedFile; + } + + /** + * Adds entropy to a prng ctx's accumulator. + * + * @param bytes the bytes of entropy as a string. + */ + ctx.collect = function(bytes) { + // iterate over pools distributing entropy cyclically + var count = bytes.length; + for(var i = 0; i < count; ++i) { + ctx.pools[ctx.pool].update(bytes.substr(i, 1)); + ctx.pool = (ctx.pool === 31) ? 0 : ctx.pool + 1; + } + }; + + /** + * Collects an integer of n bits. + * + * @param i the integer entropy. + * @param n the number of bits in the integer. + */ + ctx.collectInt = function(i, n) { + var bytes = ''; + for(var x = 0; x < n; x += 8) { + bytes += String.fromCharCode((i >> x) & 0xFF); + } + ctx.collect(bytes); + }; + + /** + * Registers a Web Worker to receive immediate entropy from the main thread. + * This method is required until Web Workers can access the native crypto + * API. This method should be called twice for each created worker, once in + * the main thread, and once in the worker itself. + * + * @param worker the worker to register. + */ + ctx.registerWorker = function(worker) { + // worker receives random bytes + if(worker === self) { + ctx.seedFile = function(needed, callback) { + function listener(e) { + var data = e.data; + if(data.forge && data.forge.prng) { + self.removeEventListener('message', listener); + callback(data.forge.prng.err, data.forge.prng.bytes); + } + } + self.addEventListener('message', listener); + self.postMessage({forge: {prng: {needed: needed}}}); + }; + } else { + // main thread sends random bytes upon request + var listener = function(e) { + var data = e.data; + if(data.forge && data.forge.prng) { + ctx.seedFile(data.forge.prng.needed, function(err, bytes) { + worker.postMessage({forge: {prng: {err: err, bytes: bytes}}}); + }); + } + }; + // TODO: do we need to remove the event listener when the worker dies? + worker.addEventListener('message', listener); + } + }; + + return ctx; + }; + }); + + var random = createCommonjsModule(function (module) { + /** + * An API for getting cryptographically-secure random bytes. The bytes are + * generated using the Fortuna algorithm devised by Bruce Schneier and + * Niels Ferguson. + * + * Getting strong random bytes is not yet easy to do in javascript. The only + * truish random entropy that can be collected is from the mouse, keyboard, or + * from timing with respect to page loads, etc. This generator makes a poor + * attempt at providing random bytes when those sources haven't yet provided + * enough entropy to initially seed or to reseed the PRNG. + * + * @author Dave Longley + * + * Copyright (c) 2009-2014 Digital Bazaar, Inc. + */ + + + + + + + (function() { + + // forge.random already defined + if(forge.random && forge.random.getBytes) { + module.exports = forge.random; + return; + } + + (function(jQuery) { + + // the default prng plugin, uses AES-128 + var prng_aes = {}; + var _prng_aes_output = new Array(4); + var _prng_aes_buffer = forge.util.createBuffer(); + prng_aes.formatKey = function(key) { + // convert the key into 32-bit integers + var tmp = forge.util.createBuffer(key); + key = new Array(4); + key[0] = tmp.getInt32(); + key[1] = tmp.getInt32(); + key[2] = tmp.getInt32(); + key[3] = tmp.getInt32(); + + // return the expanded key + return forge.aes._expandKey(key, false); + }; + prng_aes.formatSeed = function(seed) { + // convert seed into 32-bit integers + var tmp = forge.util.createBuffer(seed); + seed = new Array(4); + seed[0] = tmp.getInt32(); + seed[1] = tmp.getInt32(); + seed[2] = tmp.getInt32(); + seed[3] = tmp.getInt32(); + return seed; + }; + prng_aes.cipher = function(key, seed) { + forge.aes._updateBlock(key, seed, _prng_aes_output, false); + _prng_aes_buffer.putInt32(_prng_aes_output[0]); + _prng_aes_buffer.putInt32(_prng_aes_output[1]); + _prng_aes_buffer.putInt32(_prng_aes_output[2]); + _prng_aes_buffer.putInt32(_prng_aes_output[3]); + return _prng_aes_buffer.getBytes(); + }; + prng_aes.increment = function(seed) { + // FIXME: do we care about carry or signed issues? + ++seed[3]; + return seed; + }; + prng_aes.md = forge.md.sha256; + + /** + * Creates a new PRNG. + */ + function spawnPrng() { + var ctx = forge.prng.create(prng_aes); + + /** + * Gets random bytes. If a native secure crypto API is unavailable, this + * method tries to make the bytes more unpredictable by drawing from data that + * can be collected from the user of the browser, eg: mouse movement. + * + * If a callback is given, this method will be called asynchronously. + * + * @param count the number of random bytes to get. + * @param [callback(err, bytes)] called once the operation completes. + * + * @return the random bytes in a string. + */ + ctx.getBytes = function(count, callback) { + return ctx.generate(count, callback); + }; + + /** + * Gets random bytes asynchronously. If a native secure crypto API is + * unavailable, this method tries to make the bytes more unpredictable by + * drawing from data that can be collected from the user of the browser, + * eg: mouse movement. + * + * @param count the number of random bytes to get. + * + * @return the random bytes in a string. + */ + ctx.getBytesSync = function(count) { + return ctx.generate(count); + }; + + return ctx; + } + + // create default prng context + var _ctx = spawnPrng(); + + // add other sources of entropy only if window.crypto.getRandomValues is not + // available -- otherwise this source will be automatically used by the prng + var getRandomValues = null; + var globalScope = forge.util.globalScope; + var _crypto = globalScope.crypto || globalScope.msCrypto; + if(_crypto && _crypto.getRandomValues) { + getRandomValues = function(arr) { + return _crypto.getRandomValues(arr); + }; + } + + if( + (!forge.util.isNodejs && !getRandomValues)) { + + // get load time entropy + _ctx.collectInt(+new Date(), 32); + + // add some entropy from navigator object + if(typeof(navigator) !== 'undefined') { + var _navBytes = ''; + for(var key in navigator) { + try { + if(typeof(navigator[key]) == 'string') { + _navBytes += navigator[key]; + } + } catch(e) { + /* Some navigator keys might not be accessible, e.g. the geolocation + attribute throws an exception if touched in Mozilla chrome:// + context. + + Silently ignore this and just don't use this as a source of + entropy. */ + } + } + _ctx.collect(_navBytes); + _navBytes = null; + } + + // add mouse and keyboard collectors if jquery is available + if(jQuery) { + // set up mouse entropy capture + jQuery().mousemove(function(e) { + // add mouse coords + _ctx.collectInt(e.clientX, 16); + _ctx.collectInt(e.clientY, 16); + }); + + // set up keyboard entropy capture + jQuery().keypress(function(e) { + _ctx.collectInt(e.charCode, 8); + }); + } + } + + /* Random API */ + if(!forge.random) { + forge.random = _ctx; + } else { + // extend forge.random with _ctx + for(var key in _ctx) { + forge.random[key] = _ctx[key]; + } + } + + // expose spawn PRNG + forge.random.createInstance = spawnPrng; + + module.exports = forge.random; + + })(typeof(jQuery) !== 'undefined' ? jQuery : null); + + })(); + }); + + /** + * RC2 implementation. + * + * @author Stefan Siegl + * + * Copyright (c) 2012 Stefan Siegl + * + * Information on the RC2 cipher is available from RFC #2268, + * http://www.ietf.org/rfc/rfc2268.txt + */ + + + + var piTable = [ + 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, + 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, + 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, + 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, + 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, + 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, + 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, + 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, + 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, + 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, + 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, + 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, + 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, + 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, + 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, + 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad + ]; + + var s = [1, 2, 3, 5]; + + /** + * Rotate a word left by given number of bits. + * + * Bits that are shifted out on the left are put back in on the right + * hand side. + * + * @param word The word to shift left. + * @param bits The number of bits to shift by. + * @return The rotated word. + */ + var rol = function(word, bits) { + return ((word << bits) & 0xffff) | ((word & 0xffff) >> (16 - bits)); + }; + + /** + * Rotate a word right by given number of bits. + * + * Bits that are shifted out on the right are put back in on the left + * hand side. + * + * @param word The word to shift right. + * @param bits The number of bits to shift by. + * @return The rotated word. + */ + var ror = function(word, bits) { + return ((word & 0xffff) >> bits) | ((word << (16 - bits)) & 0xffff); + }; + + /* RC2 API */ + var rc2 = forge.rc2 = forge.rc2 || {}; + + /** + * Perform RC2 key expansion as per RFC #2268, section 2. + * + * @param key variable-length user key (between 1 and 128 bytes) + * @param effKeyBits number of effective key bits (default: 128) + * @return the expanded RC2 key (ByteBuffer of 128 bytes) + */ + forge.rc2.expandKey = function(key, effKeyBits) { + if(typeof key === 'string') { + key = forge.util.createBuffer(key); + } + effKeyBits = effKeyBits || 128; + + /* introduce variables that match the names used in RFC #2268 */ + var L = key; + var T = key.length(); + var T1 = effKeyBits; + var T8 = Math.ceil(T1 / 8); + var TM = 0xff >> (T1 & 0x07); + var i; + + for(i = T; i < 128; i++) { + L.putByte(piTable[(L.at(i - 1) + L.at(i - T)) & 0xff]); + } + + L.setAt(128 - T8, piTable[L.at(128 - T8) & TM]); + + for(i = 127 - T8; i >= 0; i--) { + L.setAt(i, piTable[L.at(i + 1) ^ L.at(i + T8)]); + } + + return L; + }; + + /** + * Creates a RC2 cipher object. + * + * @param key the symmetric key to use (as base for key generation). + * @param bits the number of effective key bits. + * @param encrypt false for decryption, true for encryption. + * + * @return the cipher. + */ + var createCipher = function(key, bits, encrypt) { + var _finish = false, _input = null, _output = null, _iv = null; + var mixRound, mashRound; + var i, j, K = []; + + /* Expand key and fill into K[] Array */ + key = forge.rc2.expandKey(key, bits); + for(i = 0; i < 64; i++) { + K.push(key.getInt16Le()); + } + + if(encrypt) { + /** + * Perform one mixing round "in place". + * + * @param R Array of four words to perform mixing on. + */ + mixRound = function(R) { + for(i = 0; i < 4; i++) { + R[i] += K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) + + ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); + R[i] = rol(R[i], s[i]); + j++; + } + }; + + /** + * Perform one mashing round "in place". + * + * @param R Array of four words to perform mashing on. + */ + mashRound = function(R) { + for(i = 0; i < 4; i++) { + R[i] += K[R[(i + 3) % 4] & 63]; + } + }; + } else { + /** + * Perform one r-mixing round "in place". + * + * @param R Array of four words to perform mixing on. + */ + mixRound = function(R) { + for(i = 3; i >= 0; i--) { + R[i] = ror(R[i], s[i]); + R[i] -= K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) + + ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); + j--; + } + }; + + /** + * Perform one r-mashing round "in place". + * + * @param R Array of four words to perform mashing on. + */ + mashRound = function(R) { + for(i = 3; i >= 0; i--) { + R[i] -= K[R[(i + 3) % 4] & 63]; + } + }; + } + + /** + * Run the specified cipher execution plan. + * + * This function takes four words from the input buffer, applies the IV on + * it (if requested) and runs the provided execution plan. + * + * The plan must be put together in form of a array of arrays. Where the + * outer one is simply a list of steps to perform and the inner one needs + * to have two elements: the first one telling how many rounds to perform, + * the second one telling what to do (i.e. the function to call). + * + * @param {Array} plan The plan to execute. + */ + var runPlan = function(plan) { + var R = []; + + /* Get data from input buffer and fill the four words into R */ + for(i = 0; i < 4; i++) { + var val = _input.getInt16Le(); + + if(_iv !== null) { + if(encrypt) { + /* We're encrypting, apply the IV first. */ + val ^= _iv.getInt16Le(); + } else { + /* We're decryption, keep cipher text for next block. */ + _iv.putInt16Le(val); + } + } + + R.push(val & 0xffff); + } + + /* Reset global "j" variable as per spec. */ + j = encrypt ? 0 : 63; + + /* Run execution plan. */ + for(var ptr = 0; ptr < plan.length; ptr++) { + for(var ctr = 0; ctr < plan[ptr][0]; ctr++) { + plan[ptr][1](R); + } + } + + /* Write back result to output buffer. */ + for(i = 0; i < 4; i++) { + if(_iv !== null) { + if(encrypt) { + /* We're encrypting in CBC-mode, feed back encrypted bytes into + IV buffer to carry it forward to next block. */ + _iv.putInt16Le(R[i]); + } else { + R[i] ^= _iv.getInt16Le(); + } + } + + _output.putInt16Le(R[i]); + } + }; + + /* Create cipher object */ + var cipher = null; + cipher = { + /** + * Starts or restarts the encryption or decryption process, whichever + * was previously configured. + * + * To use the cipher in CBC mode, iv may be given either as a string + * of bytes, or as a byte buffer. For ECB mode, give null as iv. + * + * @param iv the initialization vector to use, null for ECB mode. + * @param output the output the buffer to write to, null to create one. + */ + start: function(iv, output) { + if(iv) { + /* CBC mode */ + if(typeof iv === 'string') { + iv = forge.util.createBuffer(iv); + } + } + + _finish = false; + _input = forge.util.createBuffer(); + _output = output || new forge.util.createBuffer(); + _iv = iv; + + cipher.output = _output; + }, + + /** + * Updates the next block. + * + * @param input the buffer to read from. + */ + update: function(input) { + if(!_finish) { + // not finishing, so fill the input buffer with more input + _input.putBuffer(input); + } + + while(_input.length() >= 8) { + runPlan([ + [ 5, mixRound ], + [ 1, mashRound ], + [ 6, mixRound ], + [ 1, mashRound ], + [ 5, mixRound ] + ]); + } + }, + + /** + * Finishes encrypting or decrypting. + * + * @param pad a padding function to use, null for PKCS#7 padding, + * signature(blockSize, buffer, decrypt). + * + * @return true if successful, false on error. + */ + finish: function(pad) { + var rval = true; + + if(encrypt) { + if(pad) { + rval = pad(8, _input, !encrypt); + } else { + // add PKCS#7 padding to block (each pad byte is the + // value of the number of pad bytes) + var padding = (_input.length() === 8) ? 8 : (8 - _input.length()); + _input.fillWithByte(padding, padding); + } + } + + if(rval) { + // do final update + _finish = true; + cipher.update(); + } + + if(!encrypt) { + // check for error: input data not a multiple of block size + rval = (_input.length() === 0); + if(rval) { + if(pad) { + rval = pad(8, _output, !encrypt); + } else { + // ensure padding byte count is valid + var len = _output.length(); + var count = _output.at(len - 1); + + if(count > len) { + rval = false; + } else { + // trim off padding bytes + _output.truncate(count); + } + } + } + } + + return rval; + } + }; + + return cipher; + }; + + /** + * Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the + * given symmetric key. The output will be stored in the 'output' member + * of the returned cipher. + * + * The key and iv may be given as a string of bytes or a byte buffer. + * The cipher is initialized to use 128 effective key bits. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * + * @return the cipher. + */ + forge.rc2.startEncrypting = function(key, iv, output) { + var cipher = forge.rc2.createEncryptionCipher(key, 128); + cipher.start(iv, output); + return cipher; + }; + + /** + * Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the + * given symmetric key. + * + * The key may be given as a string of bytes or a byte buffer. + * + * To start encrypting call start() on the cipher with an iv and optional + * output buffer. + * + * @param key the symmetric key to use. + * + * @return the cipher. + */ + forge.rc2.createEncryptionCipher = function(key, bits) { + return createCipher(key, bits, true); + }; + + /** + * Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the + * given symmetric key. The output will be stored in the 'output' member + * of the returned cipher. + * + * The key and iv may be given as a string of bytes or a byte buffer. + * The cipher is initialized to use 128 effective key bits. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * + * @return the cipher. + */ + forge.rc2.startDecrypting = function(key, iv, output) { + var cipher = forge.rc2.createDecryptionCipher(key, 128); + cipher.start(iv, output); + return cipher; + }; + + /** + * Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the + * given symmetric key. + * + * The key may be given as a string of bytes or a byte buffer. + * + * To start decrypting call start() on the cipher with an iv and optional + * output buffer. + * + * @param key the symmetric key to use. + * + * @return the cipher. + */ + forge.rc2.createDecryptionCipher = function(key, bits) { + return createCipher(key, bits, false); + }; + + // Copyright (c) 2005 Tom Wu + // All Rights Reserved. + // See "LICENSE" for details. + + // Basic JavaScript BN library - subset useful for RSA encryption. + + /* + Licensing (LICENSE) + ------------------- + + This software is covered under the following copyright: + */ + /* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ + /* + Address all questions regarding this license to: + + Tom Wu + tjw@cs.Stanford.EDU + */ + + + var jsbn = forge.jsbn = forge.jsbn || {}; + + // Bits per digit + var dbits; + + // (public) Constructor + function BigInteger$1(a,b,c) { + this.data = []; + if(a != null) + if("number" == typeof a) this.fromNumber(a,b,c); + else if(b == null && "string" != typeof a) this.fromString(a,256); + else this.fromString(a,b); + } + forge.jsbn.BigInteger = BigInteger$1; + + // return new, unset BigInteger + function nbi() { return new BigInteger$1(null); } + + // am: Compute w_j += (x*this_i), propagate carries, + // c is initial carry, returns final carry. + // c < 3*dvalue, x < 2*dvalue, this_i < dvalue + // We need to select the fastest one that works in this environment. + + // am1: use a single mult and divide to get the high bits, + // max digit bits should be 26 because + // max internal value = 2*dvalue^2-2*dvalue (< 2^53) + function am1(i,x,w,j,c,n) { + while(--n >= 0) { + var v = x*this.data[i++]+w.data[j]+c; + c = Math.floor(v/0x4000000); + w.data[j++] = v&0x3ffffff; + } + return c; + } + // am2 avoids a big mult-and-extract completely. + // Max digit bits should be <= 30 because we do bitwise ops + // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) + function am2(i,x,w,j,c,n) { + var xl = x&0x7fff, xh = x>>15; + while(--n >= 0) { + var l = this.data[i]&0x7fff; + var h = this.data[i++]>>15; + var m = xh*l+h*xl; + l = xl*l+((m&0x7fff)<<15)+w.data[j]+(c&0x3fffffff); + c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); + w.data[j++] = l&0x3fffffff; + } + return c; + } + // Alternately, set max digit bits to 28 since some + // browsers slow down when dealing with 32-bit numbers. + function am3(i,x,w,j,c,n) { + var xl = x&0x3fff, xh = x>>14; + while(--n >= 0) { + var l = this.data[i]&0x3fff; + var h = this.data[i++]>>14; + var m = xh*l+h*xl; + l = xl*l+((m&0x3fff)<<14)+w.data[j]+c; + c = (l>>28)+(m>>14)+xh*h; + w.data[j++] = l&0xfffffff; + } + return c; + } + + // node.js (no browser) + if(typeof(navigator) === 'undefined') + { + BigInteger$1.prototype.am = am3; + dbits = 28; + } else if( (navigator.appName == "Microsoft Internet Explorer")) { + BigInteger$1.prototype.am = am2; + dbits = 30; + } else if( (navigator.appName != "Netscape")) { + BigInteger$1.prototype.am = am1; + dbits = 26; + } else { // Mozilla/Netscape seems to prefer am3 + BigInteger$1.prototype.am = am3; + dbits = 28; + } + + BigInteger$1.prototype.DB = dbits; + BigInteger$1.prototype.DM = ((1<= 0; --i) r.data[i] = this.data[i]; + r.t = this.t; + r.s = this.s; + } + + // (protected) set from integer value x, -DV <= x < DV + function bnpFromInt(x) { + this.t = 1; + this.s = (x<0)?-1:0; + if(x > 0) this.data[0] = x; + else if(x < -1) this.data[0] = x+this.DV; + else this.t = 0; + } + + // return bigint initialized to value + function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + + // (protected) set from string and radix + function bnpFromString(s,b) { + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 256) k = 8; // byte array + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else { this.fromRadix(s,b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while(--i >= 0) { + var x = (k==8)?s[i]&0xff:intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if(sh == 0) + this.data[this.t++] = x; + else if(sh+k > this.DB) { + this.data[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); + } else + this.data[this.t-1] |= x<= this.DB) sh -= this.DB; + } + if(k == 8 && (s[0]&0x80) != 0) { + this.s = -1; + if(sh > 0) this.data[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this.data[this.t-1] == c) --this.t; + } + + // (public) return string representation in given radix + function bnToString(b) { + if(this.s < 0) return "-"+this.negate().toString(b); + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else return this.toRadix(b); + var km = (1< 0) { + if(p < this.DB && (d = this.data[i]>>p) > 0) { m = true; r = int2char(d); } + while(i >= 0) { + if(p < k) { + d = (this.data[i]&((1<>(p+=this.DB-k); + } else { + d = (this.data[i]>>(p-=k))&km; + if(p <= 0) { p += this.DB; --i; } + } + if(d > 0) m = true; + if(m) r += int2char(d); + } + } + return m?r:"0"; + } + + // (public) -this + function bnNegate() { var r = nbi(); BigInteger$1.ZERO.subTo(this,r); return r; } + + // (public) |this| + function bnAbs() { return (this.s<0)?this.negate():this; } + + // (public) return + if this > a, - if this < a, 0 if equal + function bnCompareTo(a) { + var r = this.s-a.s; + if(r != 0) return r; + var i = this.t; + r = i-a.t; + if(r != 0) return (this.s<0)?-r:r; + while(--i >= 0) if((r=this.data[i]-a.data[i]) != 0) return r; + return 0; + } + + // returns bit length of the integer x + function nbits(x) { + var r = 1, t; + if((t=x>>>16) != 0) { x = t; r += 16; } + if((t=x>>8) != 0) { x = t; r += 8; } + if((t=x>>4) != 0) { x = t; r += 4; } + if((t=x>>2) != 0) { x = t; r += 2; } + if((t=x>>1) != 0) { x = t; r += 1; } + return r; + } + + // (public) return the number of bits in "this" + function bnBitLength() { + if(this.t <= 0) return 0; + return this.DB*(this.t-1)+nbits(this.data[this.t-1]^(this.s&this.DM)); + } + + // (protected) r = this << n*DB + function bnpDLShiftTo(n,r) { + var i; + for(i = this.t-1; i >= 0; --i) r.data[i+n] = this.data[i]; + for(i = n-1; i >= 0; --i) r.data[i] = 0; + r.t = this.t+n; + r.s = this.s; + } + + // (protected) r = this >> n*DB + function bnpDRShiftTo(n,r) { + for(var i = n; i < this.t; ++i) r.data[i-n] = this.data[i]; + r.t = Math.max(this.t-n,0); + r.s = this.s; + } + + // (protected) r = this << n + function bnpLShiftTo(n,r) { + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<= 0; --i) { + r.data[i+ds+1] = (this.data[i]>>cbs)|c; + c = (this.data[i]&bm)<= 0; --i) r.data[i] = 0; + r.data[ds] = c; + r.t = this.t+ds+1; + r.s = this.s; + r.clamp(); + } + + // (protected) r = this >> n + function bnpRShiftTo(n,r) { + r.s = this.s; + var ds = Math.floor(n/this.DB); + if(ds >= this.t) { r.t = 0; return; } + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<>bs; + for(var i = ds+1; i < this.t; ++i) { + r.data[i-ds-1] |= (this.data[i]&bm)<>bs; + } + if(bs > 0) r.data[this.t-ds-1] |= (this.s&bm)<>= this.DB; + } + if(a.t < this.t) { + c -= a.s; + while(i < this.t) { + c += this.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while(i < a.t) { + c -= a.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c<0)?-1:0; + if(c < -1) r.data[i++] = this.DV+c; + else if(c > 0) r.data[i++] = c; + r.t = i; + r.clamp(); + } + + // (protected) r = this * a, r != this,a (HAC 14.12) + // "this" should be the larger one if appropriate. + function bnpMultiplyTo(a,r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i+y.t; + while(--i >= 0) r.data[i] = 0; + for(i = 0; i < y.t; ++i) r.data[i+x.t] = x.am(0,y.data[i],r,i,0,x.t); + r.s = 0; + r.clamp(); + if(this.s != a.s) BigInteger$1.ZERO.subTo(r,r); + } + + // (protected) r = this^2, r != this (HAC 14.16) + function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2*x.t; + while(--i >= 0) r.data[i] = 0; + for(i = 0; i < x.t-1; ++i) { + var c = x.am(i,x.data[i],r,2*i,0,1); + if((r.data[i+x.t]+=x.am(i+1,2*x.data[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { + r.data[i+x.t] -= x.DV; + r.data[i+x.t+1] = 1; + } + } + if(r.t > 0) r.data[r.t-1] += x.am(i,x.data[i],r,2*i,0,1); + r.s = 0; + r.clamp(); + } + + // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) + // r != q, this != m. q or r may be null. + function bnpDivRemTo(m,q,r) { + var pm = m.abs(); + if(pm.t <= 0) return; + var pt = this.abs(); + if(pt.t < pm.t) { + if(q != null) q.fromInt(0); + if(r != null) this.copyTo(r); + return; + } + if(r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB-nbits(pm.data[pm.t-1]); // normalize modulus + if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y.data[ys-1]; + if(y0 == 0) return; + var yt = y0*(1<1)?y.data[ys-2]>>this.F2:0); + var d1 = this.FV/yt, d2 = (1<= 0) { + r.data[r.t++] = 1; + r.subTo(t,r); + } + BigInteger$1.ONE.dlShiftTo(ys,t); + t.subTo(y,y); // "negative" y so we can replace sub with am later + while(y.t < ys) y.data[y.t++] = 0; + while(--j >= 0) { + // Estimate quotient digit + var qd = (r.data[--i]==y0)?this.DM:Math.floor(r.data[i]*d1+(r.data[i-1]+e)*d2); + if((r.data[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out + y.dlShiftTo(j,t); + r.subTo(t,r); + while(r.data[i] < --qd) r.subTo(t,r); + } + } + if(q != null) { + r.drShiftTo(ys,q); + if(ts != ms) BigInteger$1.ZERO.subTo(q,q); + } + r.t = ys; + r.clamp(); + if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder + if(ts < 0) BigInteger$1.ZERO.subTo(r,r); + } + + // (public) this mod a + function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a,null,r); + if(this.s < 0 && r.compareTo(BigInteger$1.ZERO) > 0) a.subTo(r,r); + return r; + } + + // Modular reduction using "classic" algorithm + function Classic(m) { this.m = m; } + function cConvert(x) { + if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; + } + function cRevert(x) { return x; } + function cReduce(x) { x.divRemTo(this.m,null,x); } + function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + + Classic.prototype.convert = cConvert; + Classic.prototype.revert = cRevert; + Classic.prototype.reduce = cReduce; + Classic.prototype.mulTo = cMulTo; + Classic.prototype.sqrTo = cSqrTo; + + // (protected) return "-1/this % 2^DB"; useful for Mont. reduction + // justification: + // xy == 1 (mod m) + // xy = 1+km + // xy(2-xy) = (1+km)(1-km) + // x[y(2-xy)] = 1-k^2m^2 + // x[y(2-xy)] == 1 (mod m^2) + // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 + // should reduce x and y(2-xy) by m^2 at each step to keep size bounded. + // JS multiply "overflows" differently from C/C++, so care is needed here. + function bnpInvDigit() { + if(this.t < 1) return 0; + var x = this.data[0]; + if((x&1) == 0) return 0; + var y = x&3; // y == 1/x mod 2^2 + y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 + y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 + y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y>0)?this.DV-y:-y; + } + + // Montgomery reduction + function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp&0x7fff; + this.mph = this.mp>>15; + this.um = (1<<(m.DB-15))-1; + this.mt2 = 2*m.t; + } + + // xR mod m + function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t,r); + r.divRemTo(this.m,null,r); + if(x.s < 0 && r.compareTo(BigInteger$1.ZERO) > 0) this.m.subTo(r,r); + return r; + } + + // x/R mod m + function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; + } + + // x = x/R mod m (HAC 14.32) + function montReduce(x) { + while(x.t <= this.mt2) // pad x so am has enough room later + x.data[x.t++] = 0; + for(var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x.data[i]*mp mod DV + var j = x.data[i]&0x7fff; + var u0 = (j*this.mpl+(((j*this.mph+(x.data[i]>>15)*this.mpl)&this.um)<<15))&x.DM; + // use am to combine the multiply-shift-add into one call + j = i+this.m.t; + x.data[j] += this.m.am(0,u0,x,i,0,this.m.t); + // propagate carry + while(x.data[j] >= x.DV) { x.data[j] -= x.DV; x.data[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t,x); + if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); + } + + // r = "x^2/R mod m"; x != r + function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + + // r = "xy/R mod m"; x,y != r + function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + + Montgomery.prototype.convert = montConvert; + Montgomery.prototype.revert = montRevert; + Montgomery.prototype.reduce = montReduce; + Montgomery.prototype.mulTo = montMulTo; + Montgomery.prototype.sqrTo = montSqrTo; + + // (protected) true iff this is even + function bnpIsEven() { return ((this.t>0)?(this.data[0]&1):this.s) == 0; } + + // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) + function bnpExp(e,z) { + if(e > 0xffffffff || e < 1) return BigInteger$1.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; + g.copyTo(r); + while(--i >= 0) { + z.sqrTo(r,r2); + if((e&(1< 0) z.mulTo(r2,g,r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); + } + + // (public) this^e % m, 0 <= e < 2^32 + function bnModPowInt(e,m) { + var z; + if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e,z); + } + + // protected + BigInteger$1.prototype.copyTo = bnpCopyTo; + BigInteger$1.prototype.fromInt = bnpFromInt; + BigInteger$1.prototype.fromString = bnpFromString; + BigInteger$1.prototype.clamp = bnpClamp; + BigInteger$1.prototype.dlShiftTo = bnpDLShiftTo; + BigInteger$1.prototype.drShiftTo = bnpDRShiftTo; + BigInteger$1.prototype.lShiftTo = bnpLShiftTo; + BigInteger$1.prototype.rShiftTo = bnpRShiftTo; + BigInteger$1.prototype.subTo = bnpSubTo; + BigInteger$1.prototype.multiplyTo = bnpMultiplyTo; + BigInteger$1.prototype.squareTo = bnpSquareTo; + BigInteger$1.prototype.divRemTo = bnpDivRemTo; + BigInteger$1.prototype.invDigit = bnpInvDigit; + BigInteger$1.prototype.isEven = bnpIsEven; + BigInteger$1.prototype.exp = bnpExp; + + // public + BigInteger$1.prototype.toString = bnToString; + BigInteger$1.prototype.negate = bnNegate; + BigInteger$1.prototype.abs = bnAbs; + BigInteger$1.prototype.compareTo = bnCompareTo; + BigInteger$1.prototype.bitLength = bnBitLength; + BigInteger$1.prototype.mod = bnMod; + BigInteger$1.prototype.modPowInt = bnModPowInt; + + // "constants" + BigInteger$1.ZERO = nbv(0); + BigInteger$1.ONE = nbv(1); + + // jsbn2 lib + + //Copyright (c) 2005-2009 Tom Wu + //All Rights Reserved. + //See "LICENSE" for details (See jsbn.js for LICENSE). + + //Extended JavaScript BN functions, required for RSA private ops. + + //Version 1.1: new BigInteger("0", 10) returns "proper" zero + + //(public) + function bnClone() { var r = nbi(); this.copyTo(r); return r; } + + //(public) return value as integer + function bnIntValue() { + if(this.s < 0) { + if(this.t == 1) return this.data[0]-this.DV; + else if(this.t == 0) return -1; + } else if(this.t == 1) return this.data[0]; + else if(this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this.data[1]&((1<<(32-this.DB))-1))<>24; } + + //(public) return value as short (assumes DB>=16) + function bnShortValue() { return (this.t==0)?this.s:(this.data[0]<<16)>>16; } + + //(protected) return x s.t. r^x < DV + function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } + + //(public) 0 if this == 0, 1 if this > 0 + function bnSigNum() { + if(this.s < 0) return -1; + else if(this.t <= 0 || (this.t == 1 && this.data[0] <= 0)) return 0; + else return 1; + } + + //(protected) convert to radix string + function bnpToRadix(b) { + if(b == null) b = 10; + if(this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b,cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d,y,z); + while(y.signum() > 0) { + r = (a+z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d,y,z); + } + return z.intValue().toString(b) + r; + } + + //(protected) convert from radix string + function bnpFromRadix(s,b) { + this.fromInt(0); + if(b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b,cs), mi = false, j = 0, w = 0; + for(var i = 0; i < s.length; ++i) { + var x = intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b*w+x; + if(++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w,0); + j = 0; + w = 0; + } + } + if(j > 0) { + this.dMultiply(Math.pow(b,j)); + this.dAddOffset(w,0); + } + if(mi) BigInteger$1.ZERO.subTo(this,this); + } + + //(protected) alternate constructor + function bnpFromNumber(a,b,c) { + if("number" == typeof b) { + // new BigInteger(int,int,RNG) + if(a < 2) this.fromInt(1); + else { + this.fromNumber(a,c); + if(!this.testBit(a-1)) // force MSB set + this.bitwiseTo(BigInteger$1.ONE.shiftLeft(a-1),op_or,this); + if(this.isEven()) this.dAddOffset(1,0); // force odd + while(!this.isProbablePrime(b)) { + this.dAddOffset(2,0); + if(this.bitLength() > a) this.subTo(BigInteger$1.ONE.shiftLeft(a-1),this); + } + } + } else { + // new BigInteger(int,RNG) + var x = new Array(), t = a&7; + x.length = (a>>3)+1; + b.nextBytes(x); + if(t > 0) x[0] &= ((1< 0) { + if(p < this.DB && (d = this.data[i]>>p) != (this.s&this.DM)>>p) + r[k++] = d|(this.s<<(this.DB-p)); + while(i >= 0) { + if(p < 8) { + d = (this.data[i]&((1<>(p+=this.DB-8); + } else { + d = (this.data[i]>>(p-=8))&0xff; + if(p <= 0) { p += this.DB; --i; } + } + if((d&0x80) != 0) d |= -256; + if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; + if(k > 0 || d != this.s) r[k++] = d; + } + } + return r; + } + + function bnEquals(a) { return(this.compareTo(a)==0); } + function bnMin(a) { return (this.compareTo(a)<0)?this:a; } + function bnMax(a) { return (this.compareTo(a)>0)?this:a; } + + //(protected) r = this op a (bitwise) + function bnpBitwiseTo(a,op,r) { + var i, f, m = Math.min(a.t,this.t); + for(i = 0; i < m; ++i) r.data[i] = op(this.data[i],a.data[i]); + if(a.t < this.t) { + f = a.s&this.DM; + for(i = m; i < this.t; ++i) r.data[i] = op(this.data[i],f); + r.t = this.t; + } else { + f = this.s&this.DM; + for(i = m; i < a.t; ++i) r.data[i] = op(f,a.data[i]); + r.t = a.t; + } + r.s = op(this.s,a.s); + r.clamp(); + } + + //(public) this & a + function op_and(x,y) { return x&y; } + function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } + + //(public) this | a + function op_or(x,y) { return x|y; } + function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } + + //(public) this ^ a + function op_xor(x,y) { return x^y; } + function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } + + //(public) this & ~a + function op_andnot(x,y) { return x&~y; } + function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } + + //(public) ~this + function bnNot() { + var r = nbi(); + for(var i = 0; i < this.t; ++i) r.data[i] = this.DM&~this.data[i]; + r.t = this.t; + r.s = ~this.s; + return r; + } + + //(public) this << n + function bnShiftLeft(n) { + var r = nbi(); + if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); + return r; + } + + //(public) this >> n + function bnShiftRight(n) { + var r = nbi(); + if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); + return r; + } + + //return index of lowest 1-bit in x, x < 2^31 + function lbit(x) { + if(x == 0) return -1; + var r = 0; + if((x&0xffff) == 0) { x >>= 16; r += 16; } + if((x&0xff) == 0) { x >>= 8; r += 8; } + if((x&0xf) == 0) { x >>= 4; r += 4; } + if((x&3) == 0) { x >>= 2; r += 2; } + if((x&1) == 0) ++r; + return r; + } + + //(public) returns index of lowest 1-bit (or -1 if none) + function bnGetLowestSetBit() { + for(var i = 0; i < this.t; ++i) + if(this.data[i] != 0) return i*this.DB+lbit(this.data[i]); + if(this.s < 0) return this.t*this.DB; + return -1; + } + + //return number of 1 bits in x + function cbit(x) { + var r = 0; + while(x != 0) { x &= x-1; ++r; } + return r; + } + + //(public) return number of set bits + function bnBitCount() { + var r = 0, x = this.s&this.DM; + for(var i = 0; i < this.t; ++i) r += cbit(this.data[i]^x); + return r; + } + + //(public) true iff nth bit is set + function bnTestBit(n) { + var j = Math.floor(n/this.DB); + if(j >= this.t) return(this.s!=0); + return((this.data[j]&(1<<(n%this.DB)))!=0); + } + + //(protected) this op (1<>= this.DB; + } + if(a.t < this.t) { + c += a.s; + while(i < this.t) { + c += this.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while(i < a.t) { + c += a.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = (c<0)?-1:0; + if(c > 0) r.data[i++] = c; + else if(c < -1) r.data[i++] = this.DV+c; + r.t = i; + r.clamp(); + } + + //(public) this + a + function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } + + //(public) this - a + function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } + + //(public) this * a + function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } + + //(public) this / a + function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } + + //(public) this % a + function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } + + //(public) [this/a,this%a] + function bnDivideAndRemainder(a) { + var q = nbi(), r = nbi(); + this.divRemTo(a,q,r); + return new Array(q,r); + } + + //(protected) this *= n, this >= 0, 1 < n < DV + function bnpDMultiply(n) { + this.data[this.t] = this.am(0,n-1,this,0,0,this.t); + ++this.t; + this.clamp(); + } + + //(protected) this += n << w words, this >= 0 + function bnpDAddOffset(n,w) { + if(n == 0) return; + while(this.t <= w) this.data[this.t++] = 0; + this.data[w] += n; + while(this.data[w] >= this.DV) { + this.data[w] -= this.DV; + if(++w >= this.t) this.data[this.t++] = 0; + ++this.data[w]; + } + } + + //A "null" reducer + function NullExp() {} + function nNop(x) { return x; } + function nMulTo(x,y,r) { x.multiplyTo(y,r); } + function nSqrTo(x,r) { x.squareTo(r); } + + NullExp.prototype.convert = nNop; + NullExp.prototype.revert = nNop; + NullExp.prototype.mulTo = nMulTo; + NullExp.prototype.sqrTo = nSqrTo; + + //(public) this^e + function bnPow(e) { return this.exp(e,new NullExp()); } + + //(protected) r = lower n words of "this * a", a.t <= n + //"this" should be the larger one if appropriate. + function bnpMultiplyLowerTo(a,n,r) { + var i = Math.min(this.t+a.t,n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while(i > 0) r.data[--i] = 0; + var j; + for(j = r.t-this.t; i < j; ++i) r.data[i+this.t] = this.am(0,a.data[i],r,i,0,this.t); + for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a.data[i],r,i,0,n-i); + r.clamp(); + } + + //(protected) r = "this * a" without lower n words, n > 0 + //"this" should be the larger one if appropriate. + function bnpMultiplyUpperTo(a,n,r) { + --n; + var i = r.t = this.t+a.t-n; + r.s = 0; // assumes a,this >= 0 + while(--i >= 0) r.data[i] = 0; + for(i = Math.max(n-this.t,0); i < a.t; ++i) + r.data[this.t+i-n] = this.am(n-i,a.data[i],r,0,0,this.t+i-n); + r.clamp(); + r.drShiftTo(1,r); + } + + //Barrett modular reduction + function Barrett(m) { + // setup Barrett + this.r2 = nbi(); + this.q3 = nbi(); + BigInteger$1.ONE.dlShiftTo(2*m.t,this.r2); + this.mu = this.r2.divide(m); + this.m = m; + } + + function barrettConvert(x) { + if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); + else if(x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } + } + + function barrettRevert(x) { return x; } + + //x = x mod m (HAC 14.42) + function barrettReduce(x) { + x.drShiftTo(this.m.t-1,this.r2); + if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } + this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); + this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); + while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); + x.subTo(this.r2,x); + while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); + } + + //r = x^2 mod m; x != r + function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + + //r = x*y mod m; x,y != r + function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + + Barrett.prototype.convert = barrettConvert; + Barrett.prototype.revert = barrettRevert; + Barrett.prototype.reduce = barrettReduce; + Barrett.prototype.mulTo = barrettMulTo; + Barrett.prototype.sqrTo = barrettSqrTo; + + //(public) this^e % m (HAC 14.85) + function bnModPow(e,m) { + var i = e.bitLength(), k, r = nbv(1), z; + if(i <= 0) return r; + else if(i < 18) k = 1; + else if(i < 48) k = 3; + else if(i < 144) k = 4; + else if(i < 768) k = 5; + else k = 6; + if(i < 8) + z = new Classic(m); + else if(m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { + var g2 = nbi(); + z.sqrTo(g[1],g2); + while(n <= km) { + g[n] = nbi(); + z.mulTo(g2,g[n-2],g[n]); + n += 2; + } + } + + var j = e.t-1, w, is1 = true, r2 = nbi(), t; + i = nbits(e.data[j])-1; + while(j >= 0) { + if(i >= k1) w = (e.data[j]>>(i-k1))&km; + else { + w = (e.data[j]&((1<<(i+1))-1))<<(k1-i); + if(j > 0) w |= e.data[j-1]>>(this.DB+i-k1); + } + + n = k; + while((w&1) == 0) { w >>= 1; --n; } + if((i -= n) < 0) { i += this.DB; --j; } + if(is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } else { + while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } + if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2,g[w],r); + } + + while(j >= 0 && (e.data[j]&(1< 0) { + x.rShiftTo(g,x); + y.rShiftTo(g,y); + } + while(x.signum() > 0) { + if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); + if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); + if(x.compareTo(y) >= 0) { + x.subTo(y,x); + x.rShiftTo(1,x); + } else { + y.subTo(x,y); + y.rShiftTo(1,y); + } + } + if(g > 0) y.lShiftTo(g,y); + return y; + } + + //(protected) this % n, n < 2^26 + function bnpModInt(n) { + if(n <= 0) return 0; + var d = this.DV%n, r = (this.s<0)?n-1:0; + if(this.t > 0) + if(d == 0) r = this.data[0]%n; + else for(var i = this.t-1; i >= 0; --i) r = (d*r+this.data[i])%n; + return r; + } + + //(public) 1/this % m (HAC 14.61) + function bnModInverse(m) { + var ac = m.isEven(); + if((this.isEven() && ac) || m.signum() == 0) return BigInteger$1.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while(u.signum() != 0) { + while(u.isEven()) { + u.rShiftTo(1,u); + if(ac) { + if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } + a.rShiftTo(1,a); + } else if(!b.isEven()) b.subTo(m,b); + b.rShiftTo(1,b); + } + while(v.isEven()) { + v.rShiftTo(1,v); + if(ac) { + if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } + c.rShiftTo(1,c); + } else if(!d.isEven()) d.subTo(m,d); + d.rShiftTo(1,d); + } + if(u.compareTo(v) >= 0) { + u.subTo(v,u); + if(ac) a.subTo(c,a); + b.subTo(d,b); + } else { + v.subTo(u,v); + if(ac) c.subTo(a,c); + d.subTo(b,d); + } + } + if(v.compareTo(BigInteger$1.ONE) != 0) return BigInteger$1.ZERO; + if(d.compareTo(m) >= 0) return d.subtract(m); + if(d.signum() < 0) d.addTo(m,d); else return d; + if(d.signum() < 0) return d.add(m); else return d; + } + + var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509]; + var lplim = (1<<26)/lowprimes[lowprimes.length-1]; + + //(public) test primality with certainty >= 1-.5^t + function bnIsProbablePrime(t) { + var i, x = this.abs(); + if(x.t == 1 && x.data[0] <= lowprimes[lowprimes.length-1]) { + for(i = 0; i < lowprimes.length; ++i) + if(x.data[0] == lowprimes[i]) return true; + return false; + } + if(x.isEven()) return false; + i = 1; + while(i < lowprimes.length) { + var m = lowprimes[i], j = i+1; + while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while(i < j) if(m%lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); + } + + //(protected) true if probably prime (HAC 4.24, Miller-Rabin) + function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger$1.ONE); + var k = n1.getLowestSetBit(); + if(k <= 0) return false; + var r = n1.shiftRight(k); + var prng = bnGetPrng(); + var a; + for(var i = 0; i < t; ++i) { + // select witness 'a' at random from between 1 and n1 + do { + a = new BigInteger$1(this.bitLength(), prng); + } + while(a.compareTo(BigInteger$1.ONE) <= 0 || a.compareTo(n1) >= 0); + var y = a.modPow(r,this); + if(y.compareTo(BigInteger$1.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while(j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2,this); + if(y.compareTo(BigInteger$1.ONE) == 0) return false; + } + if(y.compareTo(n1) != 0) return false; + } + } + return true; + } + + // get pseudo random number generator + function bnGetPrng() { + // create prng with api that matches BigInteger secure random + return { + // x is an array to fill with bytes + nextBytes: function(x) { + for(var i = 0; i < x.length; ++i) { + x[i] = Math.floor(Math.random() * 0x0100); + } + } + }; + } + + //protected + BigInteger$1.prototype.chunkSize = bnpChunkSize; + BigInteger$1.prototype.toRadix = bnpToRadix; + BigInteger$1.prototype.fromRadix = bnpFromRadix; + BigInteger$1.prototype.fromNumber = bnpFromNumber; + BigInteger$1.prototype.bitwiseTo = bnpBitwiseTo; + BigInteger$1.prototype.changeBit = bnpChangeBit; + BigInteger$1.prototype.addTo = bnpAddTo; + BigInteger$1.prototype.dMultiply = bnpDMultiply; + BigInteger$1.prototype.dAddOffset = bnpDAddOffset; + BigInteger$1.prototype.multiplyLowerTo = bnpMultiplyLowerTo; + BigInteger$1.prototype.multiplyUpperTo = bnpMultiplyUpperTo; + BigInteger$1.prototype.modInt = bnpModInt; + BigInteger$1.prototype.millerRabin = bnpMillerRabin; + + //public + BigInteger$1.prototype.clone = bnClone; + BigInteger$1.prototype.intValue = bnIntValue; + BigInteger$1.prototype.byteValue = bnByteValue; + BigInteger$1.prototype.shortValue = bnShortValue; + BigInteger$1.prototype.signum = bnSigNum; + BigInteger$1.prototype.toByteArray = bnToByteArray; + BigInteger$1.prototype.equals = bnEquals; + BigInteger$1.prototype.min = bnMin; + BigInteger$1.prototype.max = bnMax; + BigInteger$1.prototype.and = bnAnd; + BigInteger$1.prototype.or = bnOr; + BigInteger$1.prototype.xor = bnXor; + BigInteger$1.prototype.andNot = bnAndNot; + BigInteger$1.prototype.not = bnNot; + BigInteger$1.prototype.shiftLeft = bnShiftLeft; + BigInteger$1.prototype.shiftRight = bnShiftRight; + BigInteger$1.prototype.getLowestSetBit = bnGetLowestSetBit; + BigInteger$1.prototype.bitCount = bnBitCount; + BigInteger$1.prototype.testBit = bnTestBit; + BigInteger$1.prototype.setBit = bnSetBit; + BigInteger$1.prototype.clearBit = bnClearBit; + BigInteger$1.prototype.flipBit = bnFlipBit; + BigInteger$1.prototype.add = bnAdd; + BigInteger$1.prototype.subtract = bnSubtract; + BigInteger$1.prototype.multiply = bnMultiply; + BigInteger$1.prototype.divide = bnDivide; + BigInteger$1.prototype.remainder = bnRemainder; + BigInteger$1.prototype.divideAndRemainder = bnDivideAndRemainder; + BigInteger$1.prototype.modPow = bnModPow; + BigInteger$1.prototype.modInverse = bnModInverse; + BigInteger$1.prototype.pow = bnPow; + BigInteger$1.prototype.gcd = bnGCD; + BigInteger$1.prototype.isProbablePrime = bnIsProbablePrime; + + var sha1_1 = createCommonjsModule(function (module) { + /** + * Secure Hash Algorithm with 160-bit digest (SHA-1) implementation. + * + * @author Dave Longley + * + * Copyright (c) 2010-2015 Digital Bazaar, Inc. + */ + + + + + var sha1 = module.exports = forge.sha1 = forge.sha1 || {}; + forge.md.sha1 = forge.md.algorithms.sha1 = sha1; + + /** + * Creates a SHA-1 message digest object. + * + * @return a message digest object. + */ + sha1.create = function() { + // do initialization as necessary + if(!_initialized) { + _init(); + } + + // SHA-1 state contains five 32-bit integers + var _state = null; + + // input buffer + var _input = forge.util.createBuffer(); + + // used for word storage + var _w = new Array(80); + + // message digest object + var md = { + algorithm: 'sha1', + blockLength: 64, + digestLength: 20, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 8 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength64 for backwards-compatibility) + md.fullMessageLength = md.messageLength64 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge.util.createBuffer(); + _state = { + h0: 0x67452301, + h1: 0xEFCDAB89, + h2: 0x98BADCFE, + h3: 0x10325476, + h4: 0xC3D2E1F0 + }; + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = ((len[1] / 0x100000000) >>> 0); + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update(_state, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate SHA-1 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 448 mod 512. In other words, + the data to be digested must be a multiple of 512 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 8 bytes (64 + bits), that means that the last segment of the data must have 56 bytes + (448 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 448 mod 512 because + 512 - 128 = 448. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 448 mod 512, then 512 padding bits must be added. */ + + var finalBlock = forge.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in big-endian order; since length + // is stored in bytes we multiply by 8 and add carry from next int + var next, carry; + var bits = md.fullMessageLength[0] * 8; + for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { + next = md.fullMessageLength[i + 1] * 8; + carry = (next / 0x100000000) >>> 0; + bits += carry; + finalBlock.putInt32(bits >>> 0); + bits = next >>> 0; + } + finalBlock.putInt32(bits); + + var s2 = { + h0: _state.h0, + h1: _state.h1, + h2: _state.h2, + h3: _state.h3, + h4: _state.h4 + }; + _update(s2, _w, finalBlock); + var rval = forge.util.createBuffer(); + rval.putInt32(s2.h0); + rval.putInt32(s2.h1); + rval.putInt32(s2.h2); + rval.putInt32(s2.h3); + rval.putInt32(s2.h4); + return rval; + }; + + return md; + }; + + // sha-1 padding bytes not initialized yet + var _padding = null; + var _initialized = false; + + /** + * Initializes the constant tables. + */ + function _init() { + // create padding + _padding = String.fromCharCode(128); + _padding += forge.util.fillString(String.fromCharCode(0x00), 64); + + // now initialized + _initialized = true; + } + + /** + * Updates a SHA-1 state with the given byte buffer. + * + * @param s the SHA-1 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ + function _update(s, w, bytes) { + // consume 512 bit (64 byte) chunks + var t, a, b, c, d, e, f, i; + var len = bytes.length(); + while(len >= 64) { + // the w array will be populated with sixteen 32-bit big-endian words + // and then extended into 80 32-bit words according to SHA-1 algorithm + // and for 32-79 using Max Locktyukhin's optimization + + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + e = s.h4; + + // round 1 + for(i = 0; i < 16; ++i) { + t = bytes.getInt32(); + w[i] = t; + f = d ^ (b & (c ^ d)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + for(; i < 20; ++i) { + t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]); + t = (t << 1) | (t >>> 31); + w[i] = t; + f = d ^ (b & (c ^ d)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + // round 2 + for(; i < 32; ++i) { + t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]); + t = (t << 1) | (t >>> 31); + w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + for(; i < 40; ++i) { + t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); + t = (t << 2) | (t >>> 30); + w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + // round 3 + for(; i < 60; ++i) { + t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); + t = (t << 2) | (t >>> 30); + w[i] = t; + f = (b & c) | (d & (b ^ c)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x8F1BBCDC + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + // round 4 + for(; i < 80; ++i) { + t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); + t = (t << 2) | (t >>> 30); + w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0xCA62C1D6 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + s.h4 = (s.h4 + e) | 0; + + len -= 64; + } + } + }); + + var pkcs1_1 = createCommonjsModule(function (module) { + /** + * Partial implementation of PKCS#1 v2.2: RSA-OEAP + * + * Modified but based on the following MIT and BSD licensed code: + * + * https://github.com/kjur/jsjws/blob/master/rsa.js: + * + * The 'jsjws'(JSON Web Signature JavaScript Library) License + * + * Copyright (c) 2012 Kenji Urushima + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * http://webrsa.cvs.sourceforge.net/viewvc/webrsa/Client/RSAES-OAEP.js?content-type=text%2Fplain: + * + * RSAES-OAEP.js + * $Id: RSAES-OAEP.js,v 1.1.1.1 2003/03/19 15:37:20 ellispritchard Exp $ + * JavaScript Implementation of PKCS #1 v2.1 RSA CRYPTOGRAPHY STANDARD (RSA Laboratories, June 14, 2002) + * Copyright (C) Ellis Pritchard, Guardian Unlimited 2003. + * Contact: ellis@nukinetics.com + * Distributed under the BSD License. + * + * Official documentation: http://www.rsa.com/rsalabs/node.asp?id=2125 + * + * @author Evan Jones (http://evanjones.ca/) + * @author Dave Longley + * + * Copyright (c) 2013-2014 Digital Bazaar, Inc. + */ + + + + + + // shortcut for PKCS#1 API + var pkcs1 = module.exports = forge.pkcs1 = forge.pkcs1 || {}; + + /** + * Encode the given RSAES-OAEP message (M) using key, with optional label (L) + * and seed. + * + * This method does not perform RSA encryption, it only encodes the message + * using RSAES-OAEP. + * + * @param key the RSA key to use. + * @param message the message to encode. + * @param options the options to use: + * label an optional label to use. + * seed the seed to use. + * md the message digest object to use, undefined for SHA-1. + * mgf1 optional mgf1 parameters: + * md the message digest object to use for MGF1. + * + * @return the encoded message bytes. + */ + pkcs1.encode_rsa_oaep = function(key, message, options) { + // parse arguments + var label; + var seed; + var md; + var mgf1Md; + // legacy args (label, seed, md) + if(typeof options === 'string') { + label = options; + seed = arguments[3] || undefined; + md = arguments[4] || undefined; + } else if(options) { + label = options.label || undefined; + seed = options.seed || undefined; + md = options.md || undefined; + if(options.mgf1 && options.mgf1.md) { + mgf1Md = options.mgf1.md; + } + } + + // default OAEP to SHA-1 message digest + if(!md) { + md = forge.md.sha1.create(); + } else { + md.start(); + } + + // default MGF-1 to same as OAEP + if(!mgf1Md) { + mgf1Md = md; + } + + // compute length in bytes and check output + var keyLength = Math.ceil(key.n.bitLength() / 8); + var maxLength = keyLength - 2 * md.digestLength - 2; + if(message.length > maxLength) { + var error = new Error('RSAES-OAEP input message length is too long.'); + error.length = message.length; + error.maxLength = maxLength; + throw error; + } + + if(!label) { + label = ''; + } + md.update(label, 'raw'); + var lHash = md.digest(); + + var PS = ''; + var PS_length = maxLength - message.length; + for(var i = 0; i < PS_length; i++) { + PS += '\x00'; + } + + var DB = lHash.getBytes() + PS + '\x01' + message; + + if(!seed) { + seed = forge.random.getBytes(md.digestLength); + } else if(seed.length !== md.digestLength) { + var error = new Error('Invalid RSAES-OAEP seed. The seed length must ' + + 'match the digest length.'); + error.seedLength = seed.length; + error.digestLength = md.digestLength; + throw error; + } + + var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md); + var maskedDB = forge.util.xorBytes(DB, dbMask, DB.length); + + var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md); + var maskedSeed = forge.util.xorBytes(seed, seedMask, seed.length); + + // return encoded message + return '\x00' + maskedSeed + maskedDB; + }; + + /** + * Decode the given RSAES-OAEP encoded message (EM) using key, with optional + * label (L). + * + * This method does not perform RSA decryption, it only decodes the message + * using RSAES-OAEP. + * + * @param key the RSA key to use. + * @param em the encoded message to decode. + * @param options the options to use: + * label an optional label to use. + * md the message digest object to use for OAEP, undefined for SHA-1. + * mgf1 optional mgf1 parameters: + * md the message digest object to use for MGF1. + * + * @return the decoded message bytes. + */ + pkcs1.decode_rsa_oaep = function(key, em, options) { + // parse args + var label; + var md; + var mgf1Md; + // legacy args + if(typeof options === 'string') { + label = options; + md = arguments[3] || undefined; + } else if(options) { + label = options.label || undefined; + md = options.md || undefined; + if(options.mgf1 && options.mgf1.md) { + mgf1Md = options.mgf1.md; + } + } + + // compute length in bytes + var keyLength = Math.ceil(key.n.bitLength() / 8); + + if(em.length !== keyLength) { + var error = new Error('RSAES-OAEP encoded message length is invalid.'); + error.length = em.length; + error.expectedLength = keyLength; + throw error; + } + + // default OAEP to SHA-1 message digest + if(md === undefined) { + md = forge.md.sha1.create(); + } else { + md.start(); + } + + // default MGF-1 to same as OAEP + if(!mgf1Md) { + mgf1Md = md; + } + + if(keyLength < 2 * md.digestLength + 2) { + throw new Error('RSAES-OAEP key is too short for the hash function.'); + } + + if(!label) { + label = ''; + } + md.update(label, 'raw'); + var lHash = md.digest().getBytes(); + + // split the message into its parts + var y = em.charAt(0); + var maskedSeed = em.substring(1, md.digestLength + 1); + var maskedDB = em.substring(1 + md.digestLength); + + var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md); + var seed = forge.util.xorBytes(maskedSeed, seedMask, maskedSeed.length); + + var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md); + var db = forge.util.xorBytes(maskedDB, dbMask, maskedDB.length); + + var lHashPrime = db.substring(0, md.digestLength); + + // constant time check that all values match what is expected + var error = (y !== '\x00'); + + // constant time check lHash vs lHashPrime + for(var i = 0; i < md.digestLength; ++i) { + error |= (lHash.charAt(i) !== lHashPrime.charAt(i)); + } + + // "constant time" find the 0x1 byte separating the padding (zeros) from the + // message + // TODO: It must be possible to do this in a better/smarter way? + var in_ps = 1; + var index = md.digestLength; + for(var j = md.digestLength; j < db.length; j++) { + var code = db.charCodeAt(j); + + var is_0 = (code & 0x1) ^ 0x1; + + // non-zero if not 0 or 1 in the ps section + var error_mask = in_ps ? 0xfffe : 0x0000; + error |= (code & error_mask); + + // latch in_ps to zero after we find 0x1 + in_ps = in_ps & is_0; + index += in_ps; + } + + if(error || db.charCodeAt(index) !== 0x1) { + throw new Error('Invalid RSAES-OAEP padding.'); + } + + return db.substring(index + 1); + }; + + function rsa_mgf1(seed, maskLength, hash) { + // default to SHA-1 message digest + if(!hash) { + hash = forge.md.sha1.create(); + } + var t = ''; + var count = Math.ceil(maskLength / hash.digestLength); + for(var i = 0; i < count; ++i) { + var c = String.fromCharCode( + (i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF); + hash.start(); + hash.update(seed + c); + t += hash.digest().getBytes(); + } + return t.substring(0, maskLength); + } + }); + + var prime = createCommonjsModule(function (module) { + /** + * Prime number generation API. + * + * @author Dave Longley + * + * Copyright (c) 2014 Digital Bazaar, Inc. + */ + + + + + + (function() { + + // forge.prime already defined + if(forge.prime) { + module.exports = forge.prime; + return; + } + + /* PRIME API */ + var prime = module.exports = forge.prime = forge.prime || {}; + + var BigInteger = forge.jsbn.BigInteger; + + // primes are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29 + var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2]; + var THIRTY = new BigInteger(null); + THIRTY.fromInt(30); + var op_or = function(x, y) {return x|y;}; + + /** + * Generates a random probable prime with the given number of bits. + * + * Alternative algorithms can be specified by name as a string or as an + * object with custom options like so: + * + * { + * name: 'PRIMEINC', + * options: { + * maxBlockTime: , + * millerRabinTests: , + * workerScript: , + * workers: . + * workLoad: the size of the work load, ie: number of possible prime + * numbers for each web worker to check per work assignment, + * (default: 100). + * } + * } + * + * @param bits the number of bits for the prime number. + * @param options the options to use. + * [algorithm] the algorithm to use (default: 'PRIMEINC'). + * [prng] a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". + * + * @return callback(err, num) called once the operation completes. + */ + prime.generateProbablePrime = function(bits, options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + + // default to PRIMEINC algorithm + var algorithm = options.algorithm || 'PRIMEINC'; + if(typeof algorithm === 'string') { + algorithm = {name: algorithm}; + } + algorithm.options = algorithm.options || {}; + + // create prng with api that matches BigInteger secure random + var prng = options.prng || forge.random; + var rng = { + // x is an array to fill with bytes + nextBytes: function(x) { + var b = prng.getBytesSync(x.length); + for(var i = 0; i < x.length; ++i) { + x[i] = b.charCodeAt(i); + } + } + }; + + if(algorithm.name === 'PRIMEINC') { + return primeincFindPrime(bits, rng, algorithm.options, callback); + } + + throw new Error('Invalid prime generation algorithm: ' + algorithm.name); + }; + + function primeincFindPrime(bits, rng, options, callback) { + if('workers' in options) { + return primeincFindPrimeWithWorkers(bits, rng, options, callback); + } + return primeincFindPrimeWithoutWorkers(bits, rng, options, callback); + } + + function primeincFindPrimeWithoutWorkers(bits, rng, options, callback) { + // initialize random number + var num = generateRandom(bits, rng); + + /* Note: All primes are of the form 30k+i for i < 30 and gcd(30, i)=1. The + number we are given is always aligned at 30k + 1. Each time the number is + determined not to be prime we add to get to the next 'i', eg: if the number + was at 30k + 1 we add 6. */ + var deltaIdx = 0; + + // get required number of MR tests + var mrTests = getMillerRabinTests(num.bitLength()); + if('millerRabinTests' in options) { + mrTests = options.millerRabinTests; + } + + // find prime nearest to 'num' for maxBlockTime ms + // 10 ms gives 5ms of leeway for other calculations before dropping + // below 60fps (1000/60 == 16.67), but in reality, the number will + // likely be higher due to an 'atomic' big int modPow + var maxBlockTime = 10; + if('maxBlockTime' in options) { + maxBlockTime = options.maxBlockTime; + } + + _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback); + } + + function _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback) { + var start = +new Date(); + do { + // overflow, regenerate random number + if(num.bitLength() > bits) { + num = generateRandom(bits, rng); + } + // do primality test + if(num.isProbablePrime(mrTests)) { + return callback(null, num); + } + // get next potential prime + num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0); + } while(maxBlockTime < 0 || (+new Date() - start < maxBlockTime)); + + // keep trying later + forge.util.setImmediate(function() { + _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback); + }); + } + + // NOTE: This algorithm is indeterminate in nature because workers + // run in parallel looking at different segments of numbers. Even if this + // algorithm is run twice with the same input from a predictable RNG, it + // may produce different outputs. + function primeincFindPrimeWithWorkers(bits, rng, options, callback) { + // web workers unavailable + if(typeof Worker === 'undefined') { + return primeincFindPrimeWithoutWorkers(bits, rng, options, callback); + } + + // initialize random number + var num = generateRandom(bits, rng); + + // use web workers to generate keys + var numWorkers = options.workers; + var workLoad = options.workLoad || 100; + var range = workLoad * 30 / 8; + var workerScript = options.workerScript || 'forge/prime.worker.js'; + if(numWorkers === -1) { + return forge.util.estimateCores(function(err, cores) { + if(err) { + // default to 2 + cores = 2; + } + numWorkers = cores - 1; + generate(); + }); + } + generate(); + + function generate() { + // require at least 1 worker + numWorkers = Math.max(1, numWorkers); + + // TODO: consider optimizing by starting workers outside getPrime() ... + // note that in order to clean up they will have to be made internally + // asynchronous which may actually be slower + + // start workers immediately + var workers = []; + for(var i = 0; i < numWorkers; ++i) { + // FIXME: fix path or use blob URLs + workers[i] = new Worker(workerScript); + } + + // listen for requests from workers and assign ranges to find prime + for(var i = 0; i < numWorkers; ++i) { + workers[i].addEventListener('message', workerMessage); + } + + /* Note: The distribution of random numbers is unknown. Therefore, each + web worker is continuously allocated a range of numbers to check for a + random number until one is found. + + Every 30 numbers will be checked just 8 times, because prime numbers + have the form: + + 30k+i, for i < 30 and gcd(30, i)=1 (there are 8 values of i for this) + + Therefore, if we want a web worker to run N checks before asking for + a new range of numbers, each range must contain N*30/8 numbers. + + For 100 checks (workLoad), this is a range of 375. */ + + var found = false; + function workerMessage(e) { + // ignore message, prime already found + if(found) { + return; + } + var data = e.data; + if(data.found) { + // terminate all workers + for(var i = 0; i < workers.length; ++i) { + workers[i].terminate(); + } + found = true; + return callback(null, new BigInteger(data.prime, 16)); + } + + // overflow, regenerate random number + if(num.bitLength() > bits) { + num = generateRandom(bits, rng); + } + + // assign new range to check + var hex = num.toString(16); + + // start prime search + e.target.postMessage({ + hex: hex, + workLoad: workLoad + }); + + num.dAddOffset(range, 0); + } + } + } + + /** + * Generates a random number using the given number of bits and RNG. + * + * @param bits the number of bits for the number. + * @param rng the random number generator to use. + * + * @return the random number. + */ + function generateRandom(bits, rng) { + var num = new BigInteger(bits, rng); + // force MSB set + var bits1 = bits - 1; + if(!num.testBit(bits1)) { + num.bitwiseTo(BigInteger.ONE.shiftLeft(bits1), op_or, num); + } + // align number on 30k+1 boundary + num.dAddOffset(31 - num.mod(THIRTY).byteValue(), 0); + return num; + } + + /** + * Returns the required number of Miller-Rabin tests to generate a + * prime with an error probability of (1/2)^80. + * + * See Handbook of Applied Cryptography Chapter 4, Table 4.4. + * + * @param bits the bit size. + * + * @return the required number of iterations. + */ + function getMillerRabinTests(bits) { + if(bits <= 100) return 27; + if(bits <= 150) return 18; + if(bits <= 200) return 15; + if(bits <= 250) return 12; + if(bits <= 300) return 9; + if(bits <= 350) return 8; + if(bits <= 400) return 7; + if(bits <= 500) return 6; + if(bits <= 600) return 5; + if(bits <= 800) return 4; + if(bits <= 1250) return 3; + return 2; + } + + })(); + }); + + /** + * Javascript implementation of basic RSA algorithms. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + * + * The only algorithm currently supported for PKI is RSA. + * + * An RSA key is often stored in ASN.1 DER format. The SubjectPublicKeyInfo + * ASN.1 structure is composed of an algorithm of type AlgorithmIdentifier + * and a subjectPublicKey of type bit string. + * + * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters + * for the algorithm, if any. In the case of RSA, there aren't any. + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * For an RSA public key, the subjectPublicKey is: + * + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL + * } + * + * Version ::= INTEGER + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * PrivateKey ::= OCTET STRING + * Attributes ::= SET OF Attribute + * + * An RSA private key as the following structure: + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER -- (inverse of q) mod p + * } + * + * Version ::= INTEGER + * + * The OID for the RSA key algorithm is: 1.2.840.113549.1.1.1 + */ + + + + + + + + + + if(typeof BigInteger$2 === 'undefined') { + var BigInteger$2 = forge.jsbn.BigInteger; + } + + var _crypto = forge.util.isNodejs ? require$$7 : null; + + // shortcut for asn.1 API + var asn1 = forge.asn1; + + // shortcut for util API + var util = forge.util; + + /* + * RSA encryption and decryption, see RFC 2313. + */ + forge.pki = forge.pki || {}; + var rsa = forge.pki.rsa = forge.rsa = forge.rsa || {}; + var pki = forge.pki; + + // for finding primes, which are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29 + var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2]; + + // validator for a PrivateKeyInfo structure + var privateKeyValidator = { + // PrivateKeyInfo + name: 'PrivateKeyInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + // Version (INTEGER) + name: 'PrivateKeyInfo.version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyVersion' + }, { + // privateKeyAlgorithm + name: 'PrivateKeyInfo.privateKeyAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'privateKeyOid' + }] + }, { + // PrivateKey + name: 'PrivateKeyInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OCTETSTRING, + constructed: false, + capture: 'privateKey' + }] + }; + + // validator for an RSA private key + var rsaPrivateKeyValidator = { + // RSAPrivateKey + name: 'RSAPrivateKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + // Version (INTEGER) + name: 'RSAPrivateKey.version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyVersion' + }, { + // modulus (n) + name: 'RSAPrivateKey.modulus', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyModulus' + }, { + // publicExponent (e) + name: 'RSAPrivateKey.publicExponent', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyPublicExponent' + }, { + // privateExponent (d) + name: 'RSAPrivateKey.privateExponent', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyPrivateExponent' + }, { + // prime1 (p) + name: 'RSAPrivateKey.prime1', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyPrime1' + }, { + // prime2 (q) + name: 'RSAPrivateKey.prime2', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyPrime2' + }, { + // exponent1 (d mod (p-1)) + name: 'RSAPrivateKey.exponent1', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyExponent1' + }, { + // exponent2 (d mod (q-1)) + name: 'RSAPrivateKey.exponent2', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyExponent2' + }, { + // coefficient ((inverse of q) mod p) + name: 'RSAPrivateKey.coefficient', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'privateKeyCoefficient' + }] + }; + + // validator for an RSA public key + var rsaPublicKeyValidator = { + // RSAPublicKey + name: 'RSAPublicKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + // modulus (n) + name: 'RSAPublicKey.modulus', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'publicKeyModulus' + }, { + // publicExponent (e) + name: 'RSAPublicKey.exponent', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'publicKeyExponent' + }] + }; + + // validator for an SubjectPublicKeyInfo structure + // Note: Currently only works with an RSA public key + var publicKeyValidator = forge.pki.rsa.publicKeyValidator = { + name: 'SubjectPublicKeyInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'subjectPublicKeyInfo', + value: [{ + name: 'SubjectPublicKeyInfo.AlgorithmIdentifier', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'publicKeyOid' + }] + }, { + // subjectPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.BITSTRING, + constructed: false, + value: [{ + // RSAPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + optional: true, + captureAsn1: 'rsaPublicKey' + }] + }] + }; + + /** + * Wrap digest in DigestInfo object. + * + * This function implements EMSA-PKCS1-v1_5-ENCODE as per RFC 3447. + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * Digest ::= OCTET STRING + * + * @param md the message digest object with the hash to sign. + * + * @return the encoded message (ready for RSA encrytion) + */ + var emsaPkcs1v15encode = function(md) { + // get the oid for the algorithm + var oid; + if(md.algorithm in pki.oids) { + oid = pki.oids[md.algorithm]; + } else { + var error = new Error('Unknown message digest algorithm.'); + error.algorithm = md.algorithm; + throw error; + } + var oidBytes = asn1.oidToDer(oid).getBytes(); + + // create the digest info + var digestInfo = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + var digestAlgorithm = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + digestAlgorithm.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OID, false, oidBytes)); + digestAlgorithm.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')); + var digest = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, + false, md.digest().getBytes()); + digestInfo.value.push(digestAlgorithm); + digestInfo.value.push(digest); + + // encode digest info + return asn1.toDer(digestInfo).getBytes(); + }; + + /** + * Performs x^c mod n (RSA encryption or decryption operation). + * + * @param x the number to raise and mod. + * @param key the key to use. + * @param pub true if the key is public, false if private. + * + * @return the result of x^c mod n. + */ + var _modPow = function(x, key, pub) { + if(pub) { + return x.modPow(key.e, key.n); + } + + if(!key.p || !key.q) { + // allow calculation without CRT params (slow) + return x.modPow(key.d, key.n); + } + + // pre-compute dP, dQ, and qInv if necessary + if(!key.dP) { + key.dP = key.d.mod(key.p.subtract(BigInteger$2.ONE)); + } + if(!key.dQ) { + key.dQ = key.d.mod(key.q.subtract(BigInteger$2.ONE)); + } + if(!key.qInv) { + key.qInv = key.q.modInverse(key.p); + } + + /* Chinese remainder theorem (CRT) states: + + Suppose n1, n2, ..., nk are positive integers which are pairwise + coprime (n1 and n2 have no common factors other than 1). For any + integers x1, x2, ..., xk there exists an integer x solving the + system of simultaneous congruences (where ~= means modularly + congruent so a ~= b mod n means a mod n = b mod n): + + x ~= x1 mod n1 + x ~= x2 mod n2 + ... + x ~= xk mod nk + + This system of congruences has a single simultaneous solution x + between 0 and n - 1. Furthermore, each xk solution and x itself + is congruent modulo the product n = n1*n2*...*nk. + So x1 mod n = x2 mod n = xk mod n = x mod n. + + The single simultaneous solution x can be solved with the following + equation: + + x = sum(xi*ri*si) mod n where ri = n/ni and si = ri^-1 mod ni. + + Where x is less than n, xi = x mod ni. + + For RSA we are only concerned with k = 2. The modulus n = pq, where + p and q are coprime. The RSA decryption algorithm is: + + y = x^d mod n + + Given the above: + + x1 = x^d mod p + r1 = n/p = q + s1 = q^-1 mod p + x2 = x^d mod q + r2 = n/q = p + s2 = p^-1 mod q + + So y = (x1r1s1 + x2r2s2) mod n + = ((x^d mod p)q(q^-1 mod p) + (x^d mod q)p(p^-1 mod q)) mod n + + According to Fermat's Little Theorem, if the modulus P is prime, + for any integer A not evenly divisible by P, A^(P-1) ~= 1 mod P. + Since A is not divisible by P it follows that if: + N ~= M mod (P - 1), then A^N mod P = A^M mod P. Therefore: + + A^N mod P = A^(M mod (P - 1)) mod P. (The latter takes less effort + to calculate). In order to calculate x^d mod p more quickly the + exponent d mod (p - 1) is stored in the RSA private key (the same + is done for x^d mod q). These values are referred to as dP and dQ + respectively. Therefore we now have: + + y = ((x^dP mod p)q(q^-1 mod p) + (x^dQ mod q)p(p^-1 mod q)) mod n + + Since we'll be reducing x^dP by modulo p (same for q) we can also + reduce x by p (and q respectively) before hand. Therefore, let + + xp = ((x mod p)^dP mod p), and + xq = ((x mod q)^dQ mod q), yielding: + + y = (xp*q*(q^-1 mod p) + xq*p*(p^-1 mod q)) mod n + + This can be further reduced to a simple algorithm that only + requires 1 inverse (the q inverse is used) to be used and stored. + The algorithm is called Garner's algorithm. If qInv is the + inverse of q, we simply calculate: + + y = (qInv*(xp - xq) mod p) * q + xq + + However, there are two further complications. First, we need to + ensure that xp > xq to prevent signed BigIntegers from being used + so we add p until this is true (since we will be mod'ing with + p anyway). Then, there is a known timing attack on algorithms + using the CRT. To mitigate this risk, "cryptographic blinding" + should be used. This requires simply generating a random number r + between 0 and n-1 and its inverse and multiplying x by r^e before + calculating y and then multiplying y by r^-1 afterwards. Note that + r must be coprime with n (gcd(r, n) === 1) in order to have an + inverse. + */ + + // cryptographic blinding + var r; + do { + r = new BigInteger$2( + forge.util.bytesToHex(forge.random.getBytes(key.n.bitLength() / 8)), + 16); + } while(r.compareTo(key.n) >= 0 || !r.gcd(key.n).equals(BigInteger$2.ONE)); + x = x.multiply(r.modPow(key.e, key.n)).mod(key.n); + + // calculate xp and xq + var xp = x.mod(key.p).modPow(key.dP, key.p); + var xq = x.mod(key.q).modPow(key.dQ, key.q); + + // xp must be larger than xq to avoid signed bit usage + while(xp.compareTo(xq) < 0) { + xp = xp.add(key.p); + } + + // do last step + var y = xp.subtract(xq) + .multiply(key.qInv).mod(key.p) + .multiply(key.q).add(xq); + + // remove effect of random for cryptographic blinding + y = y.multiply(r.modInverse(key.n)).mod(key.n); + + return y; + }; + + /** + * NOTE: THIS METHOD IS DEPRECATED, use 'sign' on a private key object or + * 'encrypt' on a public key object instead. + * + * Performs RSA encryption. + * + * The parameter bt controls whether to put padding bytes before the + * message passed in. Set bt to either true or false to disable padding + * completely (in order to handle e.g. EMSA-PSS encoding seperately before), + * signaling whether the encryption operation is a public key operation + * (i.e. encrypting data) or not, i.e. private key operation (data signing). + * + * For PKCS#1 v1.5 padding pass in the block type to use, i.e. either 0x01 + * (for signing) or 0x02 (for encryption). The key operation mode (private + * or public) is derived from this flag in that case). + * + * @param m the message to encrypt as a byte string. + * @param key the RSA key to use. + * @param bt for PKCS#1 v1.5 padding, the block type to use + * (0x01 for private key, 0x02 for public), + * to disable padding: true = public key, false = private key. + * + * @return the encrypted bytes as a string. + */ + pki.rsa.encrypt = function(m, key, bt) { + var pub = bt; + var eb; + + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + if(bt !== false && bt !== true) { + // legacy, default to PKCS#1 v1.5 padding + pub = (bt === 0x02); + eb = _encodePkcs1_v1_5(m, key, bt); + } else { + eb = forge.util.createBuffer(); + eb.putBytes(m); + } + + // load encryption block as big integer 'x' + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var x = new BigInteger$2(eb.toHex(), 16); + + // do RSA encryption + var y = _modPow(x, key, pub); + + // convert y into the encrypted data byte string, if y is shorter in + // bytes than k, then prepend zero bytes to fill up ed + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var yhex = y.toString(16); + var ed = forge.util.createBuffer(); + var zeros = k - Math.ceil(yhex.length / 2); + while(zeros > 0) { + ed.putByte(0x00); + --zeros; + } + ed.putBytes(forge.util.hexToBytes(yhex)); + return ed.getBytes(); + }; + + /** + * NOTE: THIS METHOD IS DEPRECATED, use 'decrypt' on a private key object or + * 'verify' on a public key object instead. + * + * Performs RSA decryption. + * + * The parameter ml controls whether to apply PKCS#1 v1.5 padding + * or not. Set ml = false to disable padding removal completely + * (in order to handle e.g. EMSA-PSS later on) and simply pass back + * the RSA encryption block. + * + * @param ed the encrypted data to decrypt in as a byte string. + * @param key the RSA key to use. + * @param pub true for a public key operation, false for private. + * @param ml the message length, if known, false to disable padding. + * + * @return the decrypted message as a byte string. + */ + pki.rsa.decrypt = function(ed, key, pub, ml) { + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + // error if the length of the encrypted data ED is not k + if(ed.length !== k) { + var error = new Error('Encrypted message length is invalid.'); + error.length = ed.length; + error.expected = k; + throw error; + } + + // convert encrypted data into a big integer + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var y = new BigInteger$2(forge.util.createBuffer(ed).toHex(), 16); + + // y must be less than the modulus or it wasn't the result of + // a previous mod operation (encryption) using that modulus + if(y.compareTo(key.n) >= 0) { + throw new Error('Encrypted message is invalid.'); + } + + // do RSA decryption + var x = _modPow(y, key, pub); + + // create the encryption block, if x is shorter in bytes than k, then + // prepend zero bytes to fill up eb + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var xhex = x.toString(16); + var eb = forge.util.createBuffer(); + var zeros = k - Math.ceil(xhex.length / 2); + while(zeros > 0) { + eb.putByte(0x00); + --zeros; + } + eb.putBytes(forge.util.hexToBytes(xhex)); + + if(ml !== false) { + // legacy, default to PKCS#1 v1.5 padding + return _decodePkcs1_v1_5(eb.getBytes(), key, pub); + } + + // return message + return eb.getBytes(); + }; + + /** + * Creates an RSA key-pair generation state object. It is used to allow + * key-generation to be performed in steps. It also allows for a UI to + * display progress updates. + * + * @param bits the size for the private key in bits, defaults to 2048. + * @param e the public exponent to use, defaults to 65537 (0x10001). + * @param [options] the options to use. + * prng a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". + * algorithm the algorithm to use (default: 'PRIMEINC'). + * + * @return the state object to use to generate the key-pair. + */ + pki.rsa.createKeyPairGenerationState = function(bits, e, options) { + // TODO: migrate step-based prime generation code to forge.prime + + // set default bits + if(typeof(bits) === 'string') { + bits = parseInt(bits, 10); + } + bits = bits || 2048; + + // create prng with api that matches BigInteger secure random + options = options || {}; + var prng = options.prng || forge.random; + var rng = { + // x is an array to fill with bytes + nextBytes: function(x) { + var b = prng.getBytesSync(x.length); + for(var i = 0; i < x.length; ++i) { + x[i] = b.charCodeAt(i); + } + } + }; + + var algorithm = options.algorithm || 'PRIMEINC'; + + // create PRIMEINC algorithm state + var rval; + if(algorithm === 'PRIMEINC') { + rval = { + algorithm: algorithm, + state: 0, + bits: bits, + rng: rng, + eInt: e || 65537, + e: new BigInteger$2(null), + p: null, + q: null, + qBits: bits >> 1, + pBits: bits - (bits >> 1), + pqState: 0, + num: null, + keys: null + }; + rval.e.fromInt(rval.eInt); + } else { + throw new Error('Invalid key generation algorithm: ' + algorithm); + } + + return rval; + }; + + /** + * Attempts to runs the key-generation algorithm for at most n seconds + * (approximately) using the given state. When key-generation has completed, + * the keys will be stored in state.keys. + * + * To use this function to update a UI while generating a key or to prevent + * causing browser lockups/warnings, set "n" to a value other than 0. A + * simple pattern for generating a key and showing a progress indicator is: + * + * var state = pki.rsa.createKeyPairGenerationState(2048); + * var step = function() { + * // step key-generation, run algorithm for 100 ms, repeat + * if(!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) { + * setTimeout(step, 1); + * } else { + * // key-generation complete + * // TODO: turn off progress indicator here + * // TODO: use the generated key-pair in "state.keys" + * } + * }; + * // TODO: turn on progress indicator here + * setTimeout(step, 0); + * + * @param state the state to use. + * @param n the maximum number of milliseconds to run the algorithm for, 0 + * to run the algorithm to completion. + * + * @return true if the key-generation completed, false if not. + */ + pki.rsa.stepKeyPairGenerationState = function(state, n) { + // set default algorithm if not set + if(!('algorithm' in state)) { + state.algorithm = 'PRIMEINC'; + } + + // TODO: migrate step-based prime generation code to forge.prime + // TODO: abstract as PRIMEINC algorithm + + // do key generation (based on Tom Wu's rsa.js, see jsbn.js license) + // with some minor optimizations and designed to run in steps + + // local state vars + var THIRTY = new BigInteger$2(null); + THIRTY.fromInt(30); + var deltaIdx = 0; + var op_or = function(x, y) {return x | y;}; + + // keep stepping until time limit is reached or done + var t1 = +new Date(); + var t2; + var total = 0; + while(state.keys === null && (n <= 0 || total < n)) { + // generate p or q + if(state.state === 0) { + /* Note: All primes are of the form: + + 30k+i, for i < 30 and gcd(30, i)=1, where there are 8 values for i + + When we generate a random number, we always align it at 30k + 1. Each + time the number is determined not to be prime we add to get to the + next 'i', eg: if the number was at 30k + 1 we add 6. */ + var bits = (state.p === null) ? state.pBits : state.qBits; + var bits1 = bits - 1; + + // get a random number + if(state.pqState === 0) { + state.num = new BigInteger$2(bits, state.rng); + // force MSB set + if(!state.num.testBit(bits1)) { + state.num.bitwiseTo( + BigInteger$2.ONE.shiftLeft(bits1), op_or, state.num); + } + // align number on 30k+1 boundary + state.num.dAddOffset(31 - state.num.mod(THIRTY).byteValue(), 0); + deltaIdx = 0; + + ++state.pqState; + } else if(state.pqState === 1) { + // try to make the number a prime + if(state.num.bitLength() > bits) { + // overflow, try again + state.pqState = 0; + // do primality test + } else if(state.num.isProbablePrime( + _getMillerRabinTests(state.num.bitLength()))) { + ++state.pqState; + } else { + // get next potential prime + state.num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0); + } + } else if(state.pqState === 2) { + // ensure number is coprime with e + state.pqState = + (state.num.subtract(BigInteger$2.ONE).gcd(state.e) + .compareTo(BigInteger$2.ONE) === 0) ? 3 : 0; + } else if(state.pqState === 3) { + // store p or q + state.pqState = 0; + if(state.p === null) { + state.p = state.num; + } else { + state.q = state.num; + } + + // advance state if both p and q are ready + if(state.p !== null && state.q !== null) { + ++state.state; + } + state.num = null; + } + } else if(state.state === 1) { + // ensure p is larger than q (swap them if not) + if(state.p.compareTo(state.q) < 0) { + state.num = state.p; + state.p = state.q; + state.q = state.num; + } + ++state.state; + } else if(state.state === 2) { + // compute phi: (p - 1)(q - 1) (Euler's totient function) + state.p1 = state.p.subtract(BigInteger$2.ONE); + state.q1 = state.q.subtract(BigInteger$2.ONE); + state.phi = state.p1.multiply(state.q1); + ++state.state; + } else if(state.state === 3) { + // ensure e and phi are coprime + if(state.phi.gcd(state.e).compareTo(BigInteger$2.ONE) === 0) { + // phi and e are coprime, advance + ++state.state; + } else { + // phi and e aren't coprime, so generate a new p and q + state.p = null; + state.q = null; + state.state = 0; + } + } else if(state.state === 4) { + // create n, ensure n is has the right number of bits + state.n = state.p.multiply(state.q); + + // ensure n is right number of bits + if(state.n.bitLength() === state.bits) { + // success, advance + ++state.state; + } else { + // failed, get new q + state.q = null; + state.state = 0; + } + } else if(state.state === 5) { + // set keys + var d = state.e.modInverse(state.phi); + state.keys = { + privateKey: pki.rsa.setPrivateKey( + state.n, state.e, d, state.p, state.q, + d.mod(state.p1), d.mod(state.q1), + state.q.modInverse(state.p)), + publicKey: pki.rsa.setPublicKey(state.n, state.e) + }; + } + + // update timing + t2 = +new Date(); + total += t2 - t1; + t1 = t2; + } + + return state.keys !== null; + }; + + /** + * Generates an RSA public-private key pair in a single call. + * + * To generate a key-pair in steps (to allow for progress updates and to + * prevent blocking or warnings in slow browsers) then use the key-pair + * generation state functions. + * + * To generate a key-pair asynchronously (either through web-workers, if + * available, or by breaking up the work on the main thread), pass a + * callback function. + * + * @param [bits] the size for the private key in bits, defaults to 2048. + * @param [e] the public exponent to use, defaults to 65537. + * @param [options] options for key-pair generation, if given then 'bits' + * and 'e' must *not* be given: + * bits the size for the private key in bits, (default: 2048). + * e the public exponent to use, (default: 65537 (0x10001)). + * workerScript the worker script URL. + * workers the number of web workers (if supported) to use, + * (default: 2). + * workLoad the size of the work load, ie: number of possible prime + * numbers for each web worker to check per work assignment, + * (default: 100). + * prng a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". Disables use of native APIs. + * algorithm the algorithm to use (default: 'PRIMEINC'). + * @param [callback(err, keypair)] called once the operation completes. + * + * @return an object with privateKey and publicKey properties. + */ + pki.rsa.generateKeyPair = function(bits, e, options, callback) { + // (bits), (options), (callback) + if(arguments.length === 1) { + if(typeof bits === 'object') { + options = bits; + bits = undefined; + } else if(typeof bits === 'function') { + callback = bits; + bits = undefined; + } + } else if(arguments.length === 2) { + // (bits, e), (bits, options), (bits, callback), (options, callback) + if(typeof bits === 'number') { + if(typeof e === 'function') { + callback = e; + e = undefined; + } else if(typeof e !== 'number') { + options = e; + e = undefined; + } + } else { + options = bits; + callback = e; + bits = undefined; + e = undefined; + } + } else if(arguments.length === 3) { + // (bits, e, options), (bits, e, callback), (bits, options, callback) + if(typeof e === 'number') { + if(typeof options === 'function') { + callback = options; + options = undefined; + } + } else { + callback = options; + options = e; + e = undefined; + } + } + options = options || {}; + if(bits === undefined) { + bits = options.bits || 2048; + } + if(e === undefined) { + e = options.e || 0x10001; + } + + // use native code if permitted, available, and parameters are acceptable + if( !options.prng && + bits >= 256 && bits <= 16384 && (e === 0x10001 || e === 3)) { + if(callback) { + // try native async + if(_detectNodeCrypto('generateKeyPair')) { + return _crypto.generateKeyPair('rsa', { + modulusLength: bits, + publicExponent: e, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }, function(err, pub, priv) { + if(err) { + return callback(err); + } + callback(null, { + privateKey: pki.privateKeyFromPem(priv), + publicKey: pki.publicKeyFromPem(pub) + }); + }); + } + if(_detectSubtleCrypto('generateKey') && + _detectSubtleCrypto('exportKey')) { + // use standard native generateKey + return util.globalScope.crypto.subtle.generateKey({ + name: 'RSASSA-PKCS1-v1_5', + modulusLength: bits, + publicExponent: _intToUint8Array(e), + hash: {name: 'SHA-256'} + }, true /* key can be exported*/, ['sign', 'verify']) + .then(function(pair) { + return util.globalScope.crypto.subtle.exportKey( + 'pkcs8', pair.privateKey); + // avoiding catch(function(err) {...}) to support IE <= 8 + }).then(undefined, function(err) { + callback(err); + }).then(function(pkcs8) { + if(pkcs8) { + var privateKey = pki.privateKeyFromAsn1( + asn1.fromDer(forge.util.createBuffer(pkcs8))); + callback(null, { + privateKey: privateKey, + publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e) + }); + } + }); + } + if(_detectSubtleMsCrypto('generateKey') && + _detectSubtleMsCrypto('exportKey')) { + var genOp = util.globalScope.msCrypto.subtle.generateKey({ + name: 'RSASSA-PKCS1-v1_5', + modulusLength: bits, + publicExponent: _intToUint8Array(e), + hash: {name: 'SHA-256'} + }, true /* key can be exported*/, ['sign', 'verify']); + genOp.oncomplete = function(e) { + var pair = e.target.result; + var exportOp = util.globalScope.msCrypto.subtle.exportKey( + 'pkcs8', pair.privateKey); + exportOp.oncomplete = function(e) { + var pkcs8 = e.target.result; + var privateKey = pki.privateKeyFromAsn1( + asn1.fromDer(forge.util.createBuffer(pkcs8))); + callback(null, { + privateKey: privateKey, + publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e) + }); + }; + exportOp.onerror = function(err) { + callback(err); + }; + }; + genOp.onerror = function(err) { + callback(err); + }; + return; + } + } else { + // try native sync + if(_detectNodeCrypto('generateKeyPairSync')) { + var keypair = _crypto.generateKeyPairSync('rsa', { + modulusLength: bits, + publicExponent: e, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }); + return { + privateKey: pki.privateKeyFromPem(keypair.privateKey), + publicKey: pki.publicKeyFromPem(keypair.publicKey) + }; + } + } + } + + // use JavaScript implementation + var state = pki.rsa.createKeyPairGenerationState(bits, e, options); + if(!callback) { + pki.rsa.stepKeyPairGenerationState(state, 0); + return state.keys; + } + _generateKeyPair(state, options, callback); + }; + + /** + * Sets an RSA public key from BigIntegers modulus and exponent. + * + * @param n the modulus. + * @param e the exponent. + * + * @return the public key. + */ + pki.setRsaPublicKey = pki.rsa.setPublicKey = function(n, e) { + var key = { + n: n, + e: e + }; + + /** + * Encrypts the given data with this public key. Newer applications + * should use the 'RSA-OAEP' decryption scheme, 'RSAES-PKCS1-V1_5' is for + * legacy applications. + * + * @param data the byte string to encrypt. + * @param scheme the encryption scheme to use: + * 'RSAES-PKCS1-V1_5' (default), + * 'RSA-OAEP', + * 'RAW', 'NONE', or null to perform raw RSA encryption, + * an object with an 'encode' property set to a function + * with the signature 'function(data, key)' that returns + * a binary-encoded string representing the encoded data. + * @param schemeOptions any scheme-specific options. + * + * @return the encrypted byte string. + */ + key.encrypt = function(data, scheme, schemeOptions) { + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } else if(scheme === undefined) { + scheme = 'RSAES-PKCS1-V1_5'; + } + + if(scheme === 'RSAES-PKCS1-V1_5') { + scheme = { + encode: function(m, key, pub) { + return _encodePkcs1_v1_5(m, key, 0x02).getBytes(); + } + }; + } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') { + scheme = { + encode: function(m, key) { + return forge.pkcs1.encode_rsa_oaep(key, m, schemeOptions); + } + }; + } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) { + scheme = {encode: function(e) {return e;}}; + } else if(typeof scheme === 'string') { + throw new Error('Unsupported encryption scheme: "' + scheme + '".'); + } + + // do scheme-based encoding then rsa encryption + var e = scheme.encode(data, key, true); + return pki.rsa.encrypt(e, key, true); + }; + + /** + * Verifies the given signature against the given digest. + * + * PKCS#1 supports multiple (currently two) signature schemes: + * RSASSA-PKCS1-V1_5 and RSASSA-PSS. + * + * By default this implementation uses the "old scheme", i.e. + * RSASSA-PKCS1-V1_5, in which case once RSA-decrypted, the + * signature is an OCTET STRING that holds a DigestInfo. + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * Digest ::= OCTET STRING + * + * To perform PSS signature verification, provide an instance + * of Forge PSS object as the scheme parameter. + * + * @param digest the message digest hash to compare against the signature, + * as a binary-encoded string. + * @param signature the signature to verify, as a binary-encoded string. + * @param scheme signature verification scheme to use: + * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5, + * a Forge PSS object for RSASSA-PSS, + * 'NONE' or null for none, DigestInfo will not be expected, but + * PKCS#1 v1.5 padding will still be used. + * + * @return true if the signature was verified, false if not. + */ + key.verify = function(digest, signature, scheme) { + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } else if(scheme === undefined) { + scheme = 'RSASSA-PKCS1-V1_5'; + } + + if(scheme === 'RSASSA-PKCS1-V1_5') { + scheme = { + verify: function(digest, d) { + // remove padding + d = _decodePkcs1_v1_5(d, key, true); + // d is ASN.1 BER-encoded DigestInfo + var obj = asn1.fromDer(d); + // compare the given digest to the decrypted one + return digest === obj.value[1].value; + } + }; + } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) { + scheme = { + verify: function(digest, d) { + // remove padding + d = _decodePkcs1_v1_5(d, key, true); + return digest === d; + } + }; + } + + // do rsa decryption w/o any decoding, then verify -- which does decoding + var d = pki.rsa.decrypt(signature, key, true, false); + return scheme.verify(digest, d, key.n.bitLength()); + }; + + return key; + }; + + /** + * Sets an RSA private key from BigIntegers modulus, exponent, primes, + * prime exponents, and modular multiplicative inverse. + * + * @param n the modulus. + * @param e the public exponent. + * @param d the private exponent ((inverse of e) mod n). + * @param p the first prime. + * @param q the second prime. + * @param dP exponent1 (d mod (p-1)). + * @param dQ exponent2 (d mod (q-1)). + * @param qInv ((inverse of q) mod p) + * + * @return the private key. + */ + pki.setRsaPrivateKey = pki.rsa.setPrivateKey = function( + n, e, d, p, q, dP, dQ, qInv) { + var key = { + n: n, + e: e, + d: d, + p: p, + q: q, + dP: dP, + dQ: dQ, + qInv: qInv + }; + + /** + * Decrypts the given data with this private key. The decryption scheme + * must match the one used to encrypt the data. + * + * @param data the byte string to decrypt. + * @param scheme the decryption scheme to use: + * 'RSAES-PKCS1-V1_5' (default), + * 'RSA-OAEP', + * 'RAW', 'NONE', or null to perform raw RSA decryption. + * @param schemeOptions any scheme-specific options. + * + * @return the decrypted byte string. + */ + key.decrypt = function(data, scheme, schemeOptions) { + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } else if(scheme === undefined) { + scheme = 'RSAES-PKCS1-V1_5'; + } + + // do rsa decryption w/o any decoding + var d = pki.rsa.decrypt(data, key, false, false); + + if(scheme === 'RSAES-PKCS1-V1_5') { + scheme = {decode: _decodePkcs1_v1_5}; + } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') { + scheme = { + decode: function(d, key) { + return forge.pkcs1.decode_rsa_oaep(key, d, schemeOptions); + } + }; + } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) { + scheme = {decode: function(d) {return d;}}; + } else { + throw new Error('Unsupported encryption scheme: "' + scheme + '".'); + } + + // decode according to scheme + return scheme.decode(d, key, false); + }; + + /** + * Signs the given digest, producing a signature. + * + * PKCS#1 supports multiple (currently two) signature schemes: + * RSASSA-PKCS1-V1_5 and RSASSA-PSS. + * + * By default this implementation uses the "old scheme", i.e. + * RSASSA-PKCS1-V1_5. In order to generate a PSS signature, provide + * an instance of Forge PSS object as the scheme parameter. + * + * @param md the message digest object with the hash to sign. + * @param scheme the signature scheme to use: + * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5, + * a Forge PSS object for RSASSA-PSS, + * 'NONE' or null for none, DigestInfo will not be used but + * PKCS#1 v1.5 padding will still be used. + * + * @return the signature as a byte string. + */ + key.sign = function(md, scheme) { + /* Note: The internal implementation of RSA operations is being + transitioned away from a PKCS#1 v1.5 hard-coded scheme. Some legacy + code like the use of an encoding block identifier 'bt' will eventually + be removed. */ + + // private key operation + var bt = false; + + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } + + if(scheme === undefined || scheme === 'RSASSA-PKCS1-V1_5') { + scheme = {encode: emsaPkcs1v15encode}; + bt = 0x01; + } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) { + scheme = {encode: function() {return md;}}; + bt = 0x01; + } + + // encode and then encrypt + var d = scheme.encode(md, key.n.bitLength()); + return pki.rsa.encrypt(d, key, bt); + }; + + return key; + }; + + /** + * Wraps an RSAPrivateKey ASN.1 object in an ASN.1 PrivateKeyInfo object. + * + * @param rsaKey the ASN.1 RSAPrivateKey. + * + * @return the ASN.1 PrivateKeyInfo. + */ + pki.wrapRsaPrivateKey = function(rsaKey) { + // PrivateKeyInfo + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // version (0) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(0).getBytes()), + // privateKeyAlgorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.rsaEncryption).getBytes()), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]), + // PrivateKey + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + asn1.toDer(rsaKey).getBytes()) + ]); + }; + + /** + * Converts a private key from an ASN.1 object. + * + * @param obj the ASN.1 representation of a PrivateKeyInfo containing an + * RSAPrivateKey or an RSAPrivateKey. + * + * @return the private key. + */ + pki.privateKeyFromAsn1 = function(obj) { + // get PrivateKeyInfo + var capture = {}; + var errors = []; + if(asn1.validate(obj, privateKeyValidator, capture, errors)) { + obj = asn1.fromDer(forge.util.createBuffer(capture.privateKey)); + } + + // get RSAPrivateKey + capture = {}; + errors = []; + if(!asn1.validate(obj, rsaPrivateKeyValidator, capture, errors)) { + var error = new Error('Cannot read private key. ' + + 'ASN.1 object does not contain an RSAPrivateKey.'); + error.errors = errors; + throw error; + } + + // Note: Version is currently ignored. + // capture.privateKeyVersion + // FIXME: inefficient, get a BigInteger that uses byte strings + var n, e, d, p, q, dP, dQ, qInv; + n = forge.util.createBuffer(capture.privateKeyModulus).toHex(); + e = forge.util.createBuffer(capture.privateKeyPublicExponent).toHex(); + d = forge.util.createBuffer(capture.privateKeyPrivateExponent).toHex(); + p = forge.util.createBuffer(capture.privateKeyPrime1).toHex(); + q = forge.util.createBuffer(capture.privateKeyPrime2).toHex(); + dP = forge.util.createBuffer(capture.privateKeyExponent1).toHex(); + dQ = forge.util.createBuffer(capture.privateKeyExponent2).toHex(); + qInv = forge.util.createBuffer(capture.privateKeyCoefficient).toHex(); + + // set private key + return pki.setRsaPrivateKey( + new BigInteger$2(n, 16), + new BigInteger$2(e, 16), + new BigInteger$2(d, 16), + new BigInteger$2(p, 16), + new BigInteger$2(q, 16), + new BigInteger$2(dP, 16), + new BigInteger$2(dQ, 16), + new BigInteger$2(qInv, 16)); + }; + + /** + * Converts a private key to an ASN.1 RSAPrivateKey. + * + * @param key the private key. + * + * @return the ASN.1 representation of an RSAPrivateKey. + */ + pki.privateKeyToAsn1 = pki.privateKeyToRSAPrivateKey = function(key) { + // RSAPrivateKey + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // version (0 = only 2 primes, 1 multiple primes) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(0).getBytes()), + // modulus (n) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.n)), + // publicExponent (e) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.e)), + // privateExponent (d) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.d)), + // privateKeyPrime1 (p) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.p)), + // privateKeyPrime2 (q) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.q)), + // privateKeyExponent1 (dP) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.dP)), + // privateKeyExponent2 (dQ) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.dQ)), + // coefficient (qInv) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.qInv)) + ]); + }; + + /** + * Converts a public key from an ASN.1 SubjectPublicKeyInfo or RSAPublicKey. + * + * @param obj the asn1 representation of a SubjectPublicKeyInfo or RSAPublicKey. + * + * @return the public key. + */ + pki.publicKeyFromAsn1 = function(obj) { + // get SubjectPublicKeyInfo + var capture = {}; + var errors = []; + if(asn1.validate(obj, publicKeyValidator, capture, errors)) { + // get oid + var oid = asn1.derToOid(capture.publicKeyOid); + if(oid !== pki.oids.rsaEncryption) { + var error = new Error('Cannot read public key. Unknown OID.'); + error.oid = oid; + throw error; + } + obj = capture.rsaPublicKey; + } + + // get RSA params + errors = []; + if(!asn1.validate(obj, rsaPublicKeyValidator, capture, errors)) { + var error = new Error('Cannot read public key. ' + + 'ASN.1 object does not contain an RSAPublicKey.'); + error.errors = errors; + throw error; + } + + // FIXME: inefficient, get a BigInteger that uses byte strings + var n = forge.util.createBuffer(capture.publicKeyModulus).toHex(); + var e = forge.util.createBuffer(capture.publicKeyExponent).toHex(); + + // set public key + return pki.setRsaPublicKey( + new BigInteger$2(n, 16), + new BigInteger$2(e, 16)); + }; + + /** + * Converts a public key to an ASN.1 SubjectPublicKeyInfo. + * + * @param key the public key. + * + * @return the asn1 representation of a SubjectPublicKeyInfo. + */ + pki.publicKeyToAsn1 = pki.publicKeyToSubjectPublicKeyInfo = function(key) { + // SubjectPublicKeyInfo + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // AlgorithmIdentifier + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.rsaEncryption).getBytes()), + // parameters (null) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]), + // subjectPublicKey + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [ + pki.publicKeyToRSAPublicKey(key) + ]) + ]); + }; + + /** + * Converts a public key to an ASN.1 RSAPublicKey. + * + * @param key the public key. + * + * @return the asn1 representation of a RSAPublicKey. + */ + pki.publicKeyToRSAPublicKey = function(key) { + // RSAPublicKey + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // modulus (n) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.n)), + // publicExponent (e) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + _bnToBytes(key.e)) + ]); + }; + + /** + * Encodes a message using PKCS#1 v1.5 padding. + * + * @param m the message to encode. + * @param key the RSA key to use. + * @param bt the block type to use, i.e. either 0x01 (for signing) or 0x02 + * (for encryption). + * + * @return the padded byte buffer. + */ + function _encodePkcs1_v1_5(m, key, bt) { + var eb = forge.util.createBuffer(); + + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + /* use PKCS#1 v1.5 padding */ + if(m.length > (k - 11)) { + var error = new Error('Message is too long for PKCS#1 v1.5 padding.'); + error.length = m.length; + error.max = k - 11; + throw error; + } + + /* A block type BT, a padding string PS, and the data D shall be + formatted into an octet string EB, the encryption block: + + EB = 00 || BT || PS || 00 || D + + The block type BT shall be a single octet indicating the structure of + the encryption block. For this version of the document it shall have + value 00, 01, or 02. For a private-key operation, the block type + shall be 00 or 01. For a public-key operation, it shall be 02. + + The padding string PS shall consist of k-3-||D|| octets. For block + type 00, the octets shall have value 00; for block type 01, they + shall have value FF; and for block type 02, they shall be + pseudorandomly generated and nonzero. This makes the length of the + encryption block EB equal to k. */ + + // build the encryption block + eb.putByte(0x00); + eb.putByte(bt); + + // create the padding + var padNum = k - 3 - m.length; + var padByte; + // private key op + if(bt === 0x00 || bt === 0x01) { + padByte = (bt === 0x00) ? 0x00 : 0xFF; + for(var i = 0; i < padNum; ++i) { + eb.putByte(padByte); + } + } else { + // public key op + // pad with random non-zero values + while(padNum > 0) { + var numZeros = 0; + var padBytes = forge.random.getBytes(padNum); + for(var i = 0; i < padNum; ++i) { + padByte = padBytes.charCodeAt(i); + if(padByte === 0) { + ++numZeros; + } else { + eb.putByte(padByte); + } + } + padNum = numZeros; + } + } + + // zero followed by message + eb.putByte(0x00); + eb.putBytes(m); + + return eb; + } + + /** + * Decodes a message using PKCS#1 v1.5 padding. + * + * @param em the message to decode. + * @param key the RSA key to use. + * @param pub true if the key is a public key, false if it is private. + * @param ml the message length, if specified. + * + * @return the decoded bytes. + */ + function _decodePkcs1_v1_5(em, key, pub, ml) { + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + /* It is an error if any of the following conditions occurs: + + 1. The encryption block EB cannot be parsed unambiguously. + 2. The padding string PS consists of fewer than eight octets + or is inconsisent with the block type BT. + 3. The decryption process is a public-key operation and the block + type BT is not 00 or 01, or the decryption process is a + private-key operation and the block type is not 02. + */ + + // parse the encryption block + var eb = forge.util.createBuffer(em); + var first = eb.getByte(); + var bt = eb.getByte(); + if(first !== 0x00 || + (pub && bt !== 0x00 && bt !== 0x01) || + (!pub && bt != 0x02) || + (pub && bt === 0x00 && typeof(ml) === 'undefined')) { + throw new Error('Encryption block is invalid.'); + } + + var padNum = 0; + if(bt === 0x00) { + // check all padding bytes for 0x00 + padNum = k - 3 - ml; + for(var i = 0; i < padNum; ++i) { + if(eb.getByte() !== 0x00) { + throw new Error('Encryption block is invalid.'); + } + } + } else if(bt === 0x01) { + // find the first byte that isn't 0xFF, should be after all padding + padNum = 0; + while(eb.length() > 1) { + if(eb.getByte() !== 0xFF) { + --eb.read; + break; + } + ++padNum; + } + } else if(bt === 0x02) { + // look for 0x00 byte + padNum = 0; + while(eb.length() > 1) { + if(eb.getByte() === 0x00) { + --eb.read; + break; + } + ++padNum; + } + } + + // zero must be 0x00 and padNum must be (k - 3 - message length) + var zero = eb.getByte(); + if(zero !== 0x00 || padNum !== (k - 3 - eb.length())) { + throw new Error('Encryption block is invalid.'); + } + + return eb.getBytes(); + } + + /** + * Runs the key-generation algorithm asynchronously, either in the background + * via Web Workers, or using the main thread and setImmediate. + * + * @param state the key-pair generation state. + * @param [options] options for key-pair generation: + * workerScript the worker script URL. + * workers the number of web workers (if supported) to use, + * (default: 2, -1 to use estimated cores minus one). + * workLoad the size of the work load, ie: number of possible prime + * numbers for each web worker to check per work assignment, + * (default: 100). + * @param callback(err, keypair) called once the operation completes. + */ + function _generateKeyPair(state, options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + + var opts = { + algorithm: { + name: options.algorithm || 'PRIMEINC', + options: { + workers: options.workers || 2, + workLoad: options.workLoad || 100, + workerScript: options.workerScript + } + } + }; + if('prng' in options) { + opts.prng = options.prng; + } + + generate(); + + function generate() { + // find p and then q (done in series to simplify) + getPrime(state.pBits, function(err, num) { + if(err) { + return callback(err); + } + state.p = num; + if(state.q !== null) { + return finish(err, state.q); + } + getPrime(state.qBits, finish); + }); + } + + function getPrime(bits, callback) { + forge.prime.generateProbablePrime(bits, opts, callback); + } + + function finish(err, num) { + if(err) { + return callback(err); + } + + // set q + state.q = num; + + // ensure p is larger than q (swap them if not) + if(state.p.compareTo(state.q) < 0) { + var tmp = state.p; + state.p = state.q; + state.q = tmp; + } + + // ensure p is coprime with e + if(state.p.subtract(BigInteger$2.ONE).gcd(state.e) + .compareTo(BigInteger$2.ONE) !== 0) { + state.p = null; + generate(); + return; + } + + // ensure q is coprime with e + if(state.q.subtract(BigInteger$2.ONE).gcd(state.e) + .compareTo(BigInteger$2.ONE) !== 0) { + state.q = null; + getPrime(state.qBits, finish); + return; + } + + // compute phi: (p - 1)(q - 1) (Euler's totient function) + state.p1 = state.p.subtract(BigInteger$2.ONE); + state.q1 = state.q.subtract(BigInteger$2.ONE); + state.phi = state.p1.multiply(state.q1); + + // ensure e and phi are coprime + if(state.phi.gcd(state.e).compareTo(BigInteger$2.ONE) !== 0) { + // phi and e aren't coprime, so generate a new p and q + state.p = state.q = null; + generate(); + return; + } + + // create n, ensure n is has the right number of bits + state.n = state.p.multiply(state.q); + if(state.n.bitLength() !== state.bits) { + // failed, get new q + state.q = null; + getPrime(state.qBits, finish); + return; + } + + // set keys + var d = state.e.modInverse(state.phi); + state.keys = { + privateKey: pki.rsa.setPrivateKey( + state.n, state.e, d, state.p, state.q, + d.mod(state.p1), d.mod(state.q1), + state.q.modInverse(state.p)), + publicKey: pki.rsa.setPublicKey(state.n, state.e) + }; + + callback(null, state.keys); + } + } + + /** + * Converts a positive BigInteger into 2's-complement big-endian bytes. + * + * @param b the big integer to convert. + * + * @return the bytes. + */ + function _bnToBytes(b) { + // prepend 0x00 if first byte >= 0x80 + var hex = b.toString(16); + if(hex[0] >= '8') { + hex = '00' + hex; + } + var bytes = forge.util.hexToBytes(hex); + + // ensure integer is minimally-encoded + if(bytes.length > 1 && + // leading 0x00 for positive integer + ((bytes.charCodeAt(0) === 0 && + (bytes.charCodeAt(1) & 0x80) === 0) || + // leading 0xFF for negative integer + (bytes.charCodeAt(0) === 0xFF && + (bytes.charCodeAt(1) & 0x80) === 0x80))) { + return bytes.substr(1); + } + return bytes; + } + + /** + * Returns the required number of Miller-Rabin tests to generate a + * prime with an error probability of (1/2)^80. + * + * See Handbook of Applied Cryptography Chapter 4, Table 4.4. + * + * @param bits the bit size. + * + * @return the required number of iterations. + */ + function _getMillerRabinTests(bits) { + if(bits <= 100) return 27; + if(bits <= 150) return 18; + if(bits <= 200) return 15; + if(bits <= 250) return 12; + if(bits <= 300) return 9; + if(bits <= 350) return 8; + if(bits <= 400) return 7; + if(bits <= 500) return 6; + if(bits <= 600) return 5; + if(bits <= 800) return 4; + if(bits <= 1250) return 3; + return 2; + } + + /** + * Performs feature detection on the Node crypto interface. + * + * @param fn the feature (function) to detect. + * + * @return true if detected, false if not. + */ + function _detectNodeCrypto(fn) { + return forge.util.isNodejs && typeof _crypto[fn] === 'function'; + } + + /** + * Performs feature detection on the SubtleCrypto interface. + * + * @param fn the feature (function) to detect. + * + * @return true if detected, false if not. + */ + function _detectSubtleCrypto(fn) { + return (typeof util.globalScope !== 'undefined' && + typeof util.globalScope.crypto === 'object' && + typeof util.globalScope.crypto.subtle === 'object' && + typeof util.globalScope.crypto.subtle[fn] === 'function'); + } + + /** + * Performs feature detection on the deprecated Microsoft Internet Explorer + * outdated SubtleCrypto interface. This function should only be used after + * checking for the modern, standard SubtleCrypto interface. + * + * @param fn the feature (function) to detect. + * + * @return true if detected, false if not. + */ + function _detectSubtleMsCrypto(fn) { + return (typeof util.globalScope !== 'undefined' && + typeof util.globalScope.msCrypto === 'object' && + typeof util.globalScope.msCrypto.subtle === 'object' && + typeof util.globalScope.msCrypto.subtle[fn] === 'function'); + } + + function _intToUint8Array(x) { + var bytes = forge.util.hexToBytes(x.toString(16)); + var buffer = new Uint8Array(bytes.length); + for(var i = 0; i < bytes.length; ++i) { + buffer[i] = bytes.charCodeAt(i); + } + return buffer; + } + + /** + * Password-based encryption functions. + * + * @author Dave Longley + * @author Stefan Siegl + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + * Copyright (c) 2012 Stefan Siegl + * + * An EncryptedPrivateKeyInfo: + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData } + * + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedData ::= OCTET STRING + */ + + + + + + + + + + + + + + if(typeof BigInteger$3 === 'undefined') { + var BigInteger$3 = forge.jsbn.BigInteger; + } + + // shortcut for asn.1 API + var asn1$1 = forge.asn1; + + /* Password-based encryption implementation. */ + var pki$1 = forge.pki = forge.pki || {}; + var pbe = pki$1.pbe = forge.pbe = forge.pbe || {}; + var oids = pki$1.oids; + + // validator for an EncryptedPrivateKeyInfo structure + // Note: Currently only works w/algorithm params + var encryptedPrivateKeyValidator = { + name: 'EncryptedPrivateKeyInfo', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedPrivateKeyInfo.encryptionAlgorithm', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OID, + constructed: false, + capture: 'encryptionOid' + }, { + name: 'AlgorithmIdentifier.parameters', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'encryptionParams' + }] + }, { + // encryptedData + name: 'EncryptedPrivateKeyInfo.encryptedData', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OCTETSTRING, + constructed: false, + capture: 'encryptedData' + }] + }; + + // validator for a PBES2Algorithms structure + // Note: Currently only works w/PBKDF2 + AES encryption schemes + var PBES2AlgorithmsValidator = { + name: 'PBES2Algorithms', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.keyDerivationFunc', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.keyDerivationFunc.oid', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OID, + constructed: false, + capture: 'kdfOid' + }, { + name: 'PBES2Algorithms.params', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.params.salt', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OCTETSTRING, + constructed: false, + capture: 'kdfSalt' + }, { + name: 'PBES2Algorithms.params.iterationCount', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.INTEGER, + constructed: false, + capture: 'kdfIterationCount' + }, { + name: 'PBES2Algorithms.params.keyLength', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.INTEGER, + constructed: false, + optional: true, + capture: 'keyLength' + }, { + // prf + name: 'PBES2Algorithms.params.prf', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + optional: true, + value: [{ + name: 'PBES2Algorithms.params.prf.algorithm', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OID, + constructed: false, + capture: 'prfOid' + }] + }] + }] + }, { + name: 'PBES2Algorithms.encryptionScheme', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.encryptionScheme.oid', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OID, + constructed: false, + capture: 'encOid' + }, { + name: 'PBES2Algorithms.encryptionScheme.iv', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OCTETSTRING, + constructed: false, + capture: 'encIv' + }] + }] + }; + + var pkcs12PbeParamsValidator = { + name: 'pkcs-12PbeParams', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'pkcs-12PbeParams.salt', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OCTETSTRING, + constructed: false, + capture: 'salt' + }, { + name: 'pkcs-12PbeParams.iterations', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.INTEGER, + constructed: false, + capture: 'iterations' + }] + }; + + /** + * Encrypts a ASN.1 PrivateKeyInfo object, producing an EncryptedPrivateKeyInfo. + * + * PBES2Algorithms ALGORITHM-IDENTIFIER ::= + * { {PBES2-params IDENTIFIED BY id-PBES2}, ...} + * + * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} + * + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} + * } + * + * PBES2-KDFs ALGORITHM-IDENTIFIER ::= + * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } + * + * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } + * + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} + * }, + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX) OPTIONAL, + * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + * } + * + * @param obj the ASN.1 PrivateKeyInfo object. + * @param password the password to encrypt with. + * @param options: + * algorithm the encryption algorithm to use + * ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'. + * count the iteration count to use. + * saltSize the salt size to use. + * prfAlgorithm the PRF message digest algorithm to use + * ('sha1', 'sha224', 'sha256', 'sha384', 'sha512') + * + * @return the ASN.1 EncryptedPrivateKeyInfo. + */ + pki$1.encryptPrivateKeyInfo = function(obj, password, options) { + // set default options + options = options || {}; + options.saltSize = options.saltSize || 8; + options.count = options.count || 2048; + options.algorithm = options.algorithm || 'aes128'; + options.prfAlgorithm = options.prfAlgorithm || 'sha1'; + + // generate PBE params + var salt = forge.random.getBytesSync(options.saltSize); + var count = options.count; + var countBytes = asn1$1.integerToDer(count); + var dkLen; + var encryptionAlgorithm; + var encryptedData; + if(options.algorithm.indexOf('aes') === 0 || options.algorithm === 'des') { + // do PBES2 + var ivLen, encOid, cipherFn; + switch(options.algorithm) { + case 'aes128': + dkLen = 16; + ivLen = 16; + encOid = oids['aes128-CBC']; + cipherFn = forge.aes.createEncryptionCipher; + break; + case 'aes192': + dkLen = 24; + ivLen = 16; + encOid = oids['aes192-CBC']; + cipherFn = forge.aes.createEncryptionCipher; + break; + case 'aes256': + dkLen = 32; + ivLen = 16; + encOid = oids['aes256-CBC']; + cipherFn = forge.aes.createEncryptionCipher; + break; + case 'des': + dkLen = 8; + ivLen = 8; + encOid = oids['desCBC']; + cipherFn = forge.des.createEncryptionCipher; + break; + default: + var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.'); + error.algorithm = options.algorithm; + throw error; + } + + // get PRF message digest + var prfAlgorithm = 'hmacWith' + options.prfAlgorithm.toUpperCase(); + var md = prfAlgorithmToMessageDigest(prfAlgorithm); + + // encrypt private key using pbe SHA-1 and AES/DES + var dk = forge.pkcs5.pbkdf2(password, salt, count, dkLen, md); + var iv = forge.random.getBytesSync(ivLen); + var cipher = cipherFn(dk); + cipher.start(iv); + cipher.update(asn1$1.toDer(obj)); + cipher.finish(); + encryptedData = cipher.output.getBytes(); + + // get PBKDF2-params + var params = createPbkdf2Params(salt, countBytes, dkLen, prfAlgorithm); + + encryptionAlgorithm = asn1$1.create( + asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, + asn1$1.oidToDer(oids['pkcs5PBES2']).getBytes()), + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + // keyDerivationFunc + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, + asn1$1.oidToDer(oids['pkcs5PBKDF2']).getBytes()), + // PBKDF2-params + params + ]), + // encryptionScheme + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, + asn1$1.oidToDer(encOid).getBytes()), + // iv + asn1$1.create( + asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, iv) + ]) + ]) + ]); + } else if(options.algorithm === '3des') { + // Do PKCS12 PBE + dkLen = 24; + + var saltBytes = new forge.util.ByteBuffer(salt); + var dk = pki$1.pbe.generatePkcs12Key(password, saltBytes, 1, count, dkLen); + var iv = pki$1.pbe.generatePkcs12Key(password, saltBytes, 2, count, dkLen); + var cipher = forge.des.createEncryptionCipher(dk); + cipher.start(iv); + cipher.update(asn1$1.toDer(obj)); + cipher.finish(); + encryptedData = cipher.output.getBytes(); + + encryptionAlgorithm = asn1$1.create( + asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, + asn1$1.oidToDer(oids['pbeWithSHAAnd3-KeyTripleDES-CBC']).getBytes()), + // pkcs-12PbeParams + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + // salt + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, salt), + // iteration count + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.INTEGER, false, + countBytes.getBytes()) + ]) + ]); + } else { + var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.'); + error.algorithm = options.algorithm; + throw error; + } + + // EncryptedPrivateKeyInfo + var rval = asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + // encryptionAlgorithm + encryptionAlgorithm, + // encryptedData + asn1$1.create( + asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, encryptedData) + ]); + return rval; + }; + + /** + * Decrypts a ASN.1 PrivateKeyInfo object. + * + * @param obj the ASN.1 EncryptedPrivateKeyInfo object. + * @param password the password to decrypt with. + * + * @return the ASN.1 PrivateKeyInfo on success, null on failure. + */ + pki$1.decryptPrivateKeyInfo = function(obj, password) { + var rval = null; + + // get PBE params + var capture = {}; + var errors = []; + if(!asn1$1.validate(obj, encryptedPrivateKeyValidator, capture, errors)) { + var error = new Error('Cannot read encrypted private key. ' + + 'ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); + error.errors = errors; + throw error; + } + + // get cipher + var oid = asn1$1.derToOid(capture.encryptionOid); + var cipher = pki$1.pbe.getCipher(oid, capture.encryptionParams, password); + + // get encrypted data + var encrypted = forge.util.createBuffer(capture.encryptedData); + + cipher.update(encrypted); + if(cipher.finish()) { + rval = asn1$1.fromDer(cipher.output); + } + + return rval; + }; + + /** + * Converts a EncryptedPrivateKeyInfo to PEM format. + * + * @param epki the EncryptedPrivateKeyInfo. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted encrypted private key. + */ + pki$1.encryptedPrivateKeyToPem = function(epki, maxline) { + // convert to DER, then PEM-encode + var msg = { + type: 'ENCRYPTED PRIVATE KEY', + body: asn1$1.toDer(epki).getBytes() + }; + return forge.pem.encode(msg, {maxline: maxline}); + }; + + /** + * Converts a PEM-encoded EncryptedPrivateKeyInfo to ASN.1 format. Decryption + * is not performed. + * + * @param pem the EncryptedPrivateKeyInfo in PEM-format. + * + * @return the ASN.1 EncryptedPrivateKeyInfo. + */ + pki$1.encryptedPrivateKeyFromPem = function(pem) { + var msg = forge.pem.decode(pem)[0]; + + if(msg.type !== 'ENCRYPTED PRIVATE KEY') { + var error = new Error('Could not convert encrypted private key from PEM; ' + + 'PEM header type is "ENCRYPTED PRIVATE KEY".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert encrypted private key from PEM; ' + + 'PEM is encrypted.'); + } + + // convert DER to ASN.1 object + return asn1$1.fromDer(msg.body); + }; + + /** + * Encrypts an RSA private key. By default, the key will be wrapped in + * a PrivateKeyInfo and encrypted to produce a PKCS#8 EncryptedPrivateKeyInfo. + * This is the standard, preferred way to encrypt a private key. + * + * To produce a non-standard PEM-encrypted private key that uses encapsulated + * headers to indicate the encryption algorithm (old-style non-PKCS#8 OpenSSL + * private key encryption), set the 'legacy' option to true. Note: Using this + * option will cause the iteration count to be forced to 1. + * + * Note: The 'des' algorithm is supported, but it is not considered to be + * secure because it only uses a single 56-bit key. If possible, it is highly + * recommended that a different algorithm be used. + * + * @param rsaKey the RSA key to encrypt. + * @param password the password to use. + * @param options: + * algorithm: the encryption algorithm to use + * ('aes128', 'aes192', 'aes256', '3des', 'des'). + * count: the iteration count to use. + * saltSize: the salt size to use. + * legacy: output an old non-PKCS#8 PEM-encrypted+encapsulated + * headers (DEK-Info) private key. + * + * @return the PEM-encoded ASN.1 EncryptedPrivateKeyInfo. + */ + pki$1.encryptRsaPrivateKey = function(rsaKey, password, options) { + // standard PKCS#8 + options = options || {}; + if(!options.legacy) { + // encrypt PrivateKeyInfo + var rval = pki$1.wrapRsaPrivateKey(pki$1.privateKeyToAsn1(rsaKey)); + rval = pki$1.encryptPrivateKeyInfo(rval, password, options); + return pki$1.encryptedPrivateKeyToPem(rval); + } + + // legacy non-PKCS#8 + var algorithm; + var iv; + var dkLen; + var cipherFn; + switch(options.algorithm) { + case 'aes128': + algorithm = 'AES-128-CBC'; + dkLen = 16; + iv = forge.random.getBytesSync(16); + cipherFn = forge.aes.createEncryptionCipher; + break; + case 'aes192': + algorithm = 'AES-192-CBC'; + dkLen = 24; + iv = forge.random.getBytesSync(16); + cipherFn = forge.aes.createEncryptionCipher; + break; + case 'aes256': + algorithm = 'AES-256-CBC'; + dkLen = 32; + iv = forge.random.getBytesSync(16); + cipherFn = forge.aes.createEncryptionCipher; + break; + case '3des': + algorithm = 'DES-EDE3-CBC'; + dkLen = 24; + iv = forge.random.getBytesSync(8); + cipherFn = forge.des.createEncryptionCipher; + break; + case 'des': + algorithm = 'DES-CBC'; + dkLen = 8; + iv = forge.random.getBytesSync(8); + cipherFn = forge.des.createEncryptionCipher; + break; + default: + var error = new Error('Could not encrypt RSA private key; unsupported ' + + 'encryption algorithm "' + options.algorithm + '".'); + error.algorithm = options.algorithm; + throw error; + } + + // encrypt private key using OpenSSL legacy key derivation + var dk = forge.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen); + var cipher = cipherFn(dk); + cipher.start(iv); + cipher.update(asn1$1.toDer(pki$1.privateKeyToAsn1(rsaKey))); + cipher.finish(); + + var msg = { + type: 'RSA PRIVATE KEY', + procType: { + version: '4', + type: 'ENCRYPTED' + }, + dekInfo: { + algorithm: algorithm, + parameters: forge.util.bytesToHex(iv).toUpperCase() + }, + body: cipher.output.getBytes() + }; + return forge.pem.encode(msg); + }; + + /** + * Decrypts an RSA private key. + * + * @param pem the PEM-formatted EncryptedPrivateKeyInfo to decrypt. + * @param password the password to use. + * + * @return the RSA key on success, null on failure. + */ + pki$1.decryptRsaPrivateKey = function(pem, password) { + var rval = null; + + var msg = forge.pem.decode(pem)[0]; + + if(msg.type !== 'ENCRYPTED PRIVATE KEY' && + msg.type !== 'PRIVATE KEY' && + msg.type !== 'RSA PRIVATE KEY') { + var error = new Error('Could not convert private key from PEM; PEM header type ' + + 'is not "ENCRYPTED PRIVATE KEY", "PRIVATE KEY", or "RSA PRIVATE KEY".'); + error.headerType = error; + throw error; + } + + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + var dkLen; + var cipherFn; + switch(msg.dekInfo.algorithm) { + case 'DES-CBC': + dkLen = 8; + cipherFn = forge.des.createDecryptionCipher; + break; + case 'DES-EDE3-CBC': + dkLen = 24; + cipherFn = forge.des.createDecryptionCipher; + break; + case 'AES-128-CBC': + dkLen = 16; + cipherFn = forge.aes.createDecryptionCipher; + break; + case 'AES-192-CBC': + dkLen = 24; + cipherFn = forge.aes.createDecryptionCipher; + break; + case 'AES-256-CBC': + dkLen = 32; + cipherFn = forge.aes.createDecryptionCipher; + break; + case 'RC2-40-CBC': + dkLen = 5; + cipherFn = function(key) { + return forge.rc2.createDecryptionCipher(key, 40); + }; + break; + case 'RC2-64-CBC': + dkLen = 8; + cipherFn = function(key) { + return forge.rc2.createDecryptionCipher(key, 64); + }; + break; + case 'RC2-128-CBC': + dkLen = 16; + cipherFn = function(key) { + return forge.rc2.createDecryptionCipher(key, 128); + }; + break; + default: + var error = new Error('Could not decrypt private key; unsupported ' + + 'encryption algorithm "' + msg.dekInfo.algorithm + '".'); + error.algorithm = msg.dekInfo.algorithm; + throw error; + } + + // use OpenSSL legacy key derivation + var iv = forge.util.hexToBytes(msg.dekInfo.parameters); + var dk = forge.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen); + var cipher = cipherFn(dk); + cipher.start(iv); + cipher.update(forge.util.createBuffer(msg.body)); + if(cipher.finish()) { + rval = cipher.output.getBytes(); + } else { + return rval; + } + } else { + rval = msg.body; + } + + if(msg.type === 'ENCRYPTED PRIVATE KEY') { + rval = pki$1.decryptPrivateKeyInfo(asn1$1.fromDer(rval), password); + } else { + // decryption already performed above + rval = asn1$1.fromDer(rval); + } + + if(rval !== null) { + rval = pki$1.privateKeyFromAsn1(rval); + } + + return rval; + }; + + /** + * Derives a PKCS#12 key. + * + * @param password the password to derive the key material from, null or + * undefined for none. + * @param salt the salt, as a ByteBuffer, to use. + * @param id the PKCS#12 ID byte (1 = key material, 2 = IV, 3 = MAC). + * @param iter the iteration count. + * @param n the number of bytes to derive from the password. + * @param md the message digest to use, defaults to SHA-1. + * + * @return a ByteBuffer with the bytes derived from the password. + */ + pki$1.pbe.generatePkcs12Key = function(password, salt, id, iter, n, md) { + var j, l; + + if(typeof md === 'undefined' || md === null) { + if(!('sha1' in forge.md)) { + throw new Error('"sha1" hash algorithm unavailable.'); + } + md = forge.md.sha1.create(); + } + + var u = md.digestLength; + var v = md.blockLength; + var result = new forge.util.ByteBuffer(); + + /* Convert password to Unicode byte buffer + trailing 0-byte. */ + var passBuf = new forge.util.ByteBuffer(); + if(password !== null && password !== undefined) { + for(l = 0; l < password.length; l++) { + passBuf.putInt16(password.charCodeAt(l)); + } + passBuf.putInt16(0); + } + + /* Length of salt and password in BYTES. */ + var p = passBuf.length(); + var s = salt.length(); + + /* 1. Construct a string, D (the "diversifier"), by concatenating + v copies of ID. */ + var D = new forge.util.ByteBuffer(); + D.fillWithByte(id, v); + + /* 2. Concatenate copies of the salt together to create a string S of length + v * ceil(s / v) bytes (the final copy of the salt may be trunacted + to create S). + Note that if the salt is the empty string, then so is S. */ + var Slen = v * Math.ceil(s / v); + var S = new forge.util.ByteBuffer(); + for(l = 0; l < Slen; l++) { + S.putByte(salt.at(l % s)); + } + + /* 3. Concatenate copies of the password together to create a string P of + length v * ceil(p / v) bytes (the final copy of the password may be + truncated to create P). + Note that if the password is the empty string, then so is P. */ + var Plen = v * Math.ceil(p / v); + var P = new forge.util.ByteBuffer(); + for(l = 0; l < Plen; l++) { + P.putByte(passBuf.at(l % p)); + } + + /* 4. Set I=S||P to be the concatenation of S and P. */ + var I = S; + I.putBuffer(P); + + /* 5. Set c=ceil(n / u). */ + var c = Math.ceil(n / u); + + /* 6. For i=1, 2, ..., c, do the following: */ + for(var i = 1; i <= c; i++) { + /* a) Set Ai=H^r(D||I). (l.e. the rth hash of D||I, H(H(H(...H(D||I)))) */ + var buf = new forge.util.ByteBuffer(); + buf.putBytes(D.bytes()); + buf.putBytes(I.bytes()); + for(var round = 0; round < iter; round++) { + md.start(); + md.update(buf.getBytes()); + buf = md.digest(); + } + + /* b) Concatenate copies of Ai to create a string B of length v bytes (the + final copy of Ai may be truncated to create B). */ + var B = new forge.util.ByteBuffer(); + for(l = 0; l < v; l++) { + B.putByte(buf.at(l % u)); + } + + /* c) Treating I as a concatenation I0, I1, ..., Ik-1 of v-byte blocks, + where k=ceil(s / v) + ceil(p / v), modify I by setting + Ij=(Ij+B+1) mod 2v for each j. */ + var k = Math.ceil(s / v) + Math.ceil(p / v); + var Inew = new forge.util.ByteBuffer(); + for(j = 0; j < k; j++) { + var chunk = new forge.util.ByteBuffer(I.getBytes(v)); + var x = 0x1ff; + for(l = B.length() - 1; l >= 0; l--) { + x = x >> 8; + x += B.at(l) + chunk.at(l); + chunk.setAt(l, x & 0xff); + } + Inew.putBuffer(chunk); + } + I = Inew; + + /* Add Ai to A. */ + result.putBuffer(buf); + } + + result.truncate(result.length() - n); + return result; + }; + + /** + * Get new Forge cipher object instance. + * + * @param oid the OID (in string notation). + * @param params the ASN.1 params object. + * @param password the password to decrypt with. + * + * @return new cipher object instance. + */ + pki$1.pbe.getCipher = function(oid, params, password) { + switch(oid) { + case pki$1.oids['pkcs5PBES2']: + return pki$1.pbe.getCipherForPBES2(oid, params, password); + + case pki$1.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']: + case pki$1.oids['pbewithSHAAnd40BitRC2-CBC']: + return pki$1.pbe.getCipherForPKCS12PBE(oid, params, password); + + default: + var error = new Error('Cannot read encrypted PBE data block. Unsupported OID.'); + error.oid = oid; + error.supportedOids = [ + 'pkcs5PBES2', + 'pbeWithSHAAnd3-KeyTripleDES-CBC', + 'pbewithSHAAnd40BitRC2-CBC' + ]; + throw error; + } + }; + + /** + * Get new Forge cipher object instance according to PBES2 params block. + * + * The returned cipher instance is already started using the IV + * from PBES2 parameter block. + * + * @param oid the PKCS#5 PBKDF2 OID (in string notation). + * @param params the ASN.1 PBES2-params object. + * @param password the password to decrypt with. + * + * @return new cipher object instance. + */ + pki$1.pbe.getCipherForPBES2 = function(oid, params, password) { + // get PBE params + var capture = {}; + var errors = []; + if(!asn1$1.validate(params, PBES2AlgorithmsValidator, capture, errors)) { + var error = new Error('Cannot read password-based-encryption algorithm ' + + 'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); + error.errors = errors; + throw error; + } + + // check oids + oid = asn1$1.derToOid(capture.kdfOid); + if(oid !== pki$1.oids['pkcs5PBKDF2']) { + var error = new Error('Cannot read encrypted private key. ' + + 'Unsupported key derivation function OID.'); + error.oid = oid; + error.supportedOids = ['pkcs5PBKDF2']; + throw error; + } + oid = asn1$1.derToOid(capture.encOid); + if(oid !== pki$1.oids['aes128-CBC'] && + oid !== pki$1.oids['aes192-CBC'] && + oid !== pki$1.oids['aes256-CBC'] && + oid !== pki$1.oids['des-EDE3-CBC'] && + oid !== pki$1.oids['desCBC']) { + var error = new Error('Cannot read encrypted private key. ' + + 'Unsupported encryption scheme OID.'); + error.oid = oid; + error.supportedOids = [ + 'aes128-CBC', 'aes192-CBC', 'aes256-CBC', 'des-EDE3-CBC', 'desCBC']; + throw error; + } + + // set PBE params + var salt = capture.kdfSalt; + var count = forge.util.createBuffer(capture.kdfIterationCount); + count = count.getInt(count.length() << 3); + var dkLen; + var cipherFn; + switch(pki$1.oids[oid]) { + case 'aes128-CBC': + dkLen = 16; + cipherFn = forge.aes.createDecryptionCipher; + break; + case 'aes192-CBC': + dkLen = 24; + cipherFn = forge.aes.createDecryptionCipher; + break; + case 'aes256-CBC': + dkLen = 32; + cipherFn = forge.aes.createDecryptionCipher; + break; + case 'des-EDE3-CBC': + dkLen = 24; + cipherFn = forge.des.createDecryptionCipher; + break; + case 'desCBC': + dkLen = 8; + cipherFn = forge.des.createDecryptionCipher; + break; + } + + // get PRF message digest + var md = prfOidToMessageDigest(capture.prfOid); + + // decrypt private key using pbe with chosen PRF and AES/DES + var dk = forge.pkcs5.pbkdf2(password, salt, count, dkLen, md); + var iv = capture.encIv; + var cipher = cipherFn(dk); + cipher.start(iv); + + return cipher; + }; + + /** + * Get new Forge cipher object instance for PKCS#12 PBE. + * + * The returned cipher instance is already started using the key & IV + * derived from the provided password and PKCS#12 PBE salt. + * + * @param oid The PKCS#12 PBE OID (in string notation). + * @param params The ASN.1 PKCS#12 PBE-params object. + * @param password The password to decrypt with. + * + * @return the new cipher object instance. + */ + pki$1.pbe.getCipherForPKCS12PBE = function(oid, params, password) { + // get PBE params + var capture = {}; + var errors = []; + if(!asn1$1.validate(params, pkcs12PbeParamsValidator, capture, errors)) { + var error = new Error('Cannot read password-based-encryption algorithm ' + + 'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); + error.errors = errors; + throw error; + } + + var salt = forge.util.createBuffer(capture.salt); + var count = forge.util.createBuffer(capture.iterations); + count = count.getInt(count.length() << 3); + + var dkLen, dIvLen, cipherFn; + switch(oid) { + case pki$1.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']: + dkLen = 24; + dIvLen = 8; + cipherFn = forge.des.startDecrypting; + break; + + case pki$1.oids['pbewithSHAAnd40BitRC2-CBC']: + dkLen = 5; + dIvLen = 8; + cipherFn = function(key, iv) { + var cipher = forge.rc2.createDecryptionCipher(key, 40); + cipher.start(iv, null); + return cipher; + }; + break; + + default: + var error = new Error('Cannot read PKCS #12 PBE data block. Unsupported OID.'); + error.oid = oid; + throw error; + } + + // get PRF message digest + var md = prfOidToMessageDigest(capture.prfOid); + var key = pki$1.pbe.generatePkcs12Key(password, salt, 1, count, dkLen, md); + md.start(); + var iv = pki$1.pbe.generatePkcs12Key(password, salt, 2, count, dIvLen, md); + + return cipherFn(key, iv); + }; + + /** + * OpenSSL's legacy key derivation function. + * + * See: http://www.openssl.org/docs/crypto/EVP_BytesToKey.html + * + * @param password the password to derive the key from. + * @param salt the salt to use, null for none. + * @param dkLen the number of bytes needed for the derived key. + * @param [options] the options to use: + * [md] an optional message digest object to use. + */ + pki$1.pbe.opensslDeriveBytes = function(password, salt, dkLen, md) { + if(typeof md === 'undefined' || md === null) { + if(!('md5' in forge.md)) { + throw new Error('"md5" hash algorithm unavailable.'); + } + md = forge.md.md5.create(); + } + if(salt === null) { + salt = ''; + } + var digests = [hash(md, password + salt)]; + for(var length = 16, i = 1; length < dkLen; ++i, length += 16) { + digests.push(hash(md, digests[i - 1] + password + salt)); + } + return digests.join('').substr(0, dkLen); + }; + + function hash(md, bytes) { + return md.start().update(bytes).digest().getBytes(); + } + + function prfOidToMessageDigest(prfOid) { + // get PRF algorithm, default to SHA-1 + var prfAlgorithm; + if(!prfOid) { + prfAlgorithm = 'hmacWithSHA1'; + } else { + prfAlgorithm = pki$1.oids[asn1$1.derToOid(prfOid)]; + if(!prfAlgorithm) { + var error = new Error('Unsupported PRF OID.'); + error.oid = prfOid; + error.supported = [ + 'hmacWithSHA1', 'hmacWithSHA224', 'hmacWithSHA256', 'hmacWithSHA384', + 'hmacWithSHA512']; + throw error; + } + } + return prfAlgorithmToMessageDigest(prfAlgorithm); + } + + function prfAlgorithmToMessageDigest(prfAlgorithm) { + var factory = forge.md; + switch(prfAlgorithm) { + case 'hmacWithSHA224': + factory = forge.md.sha512; + case 'hmacWithSHA1': + case 'hmacWithSHA256': + case 'hmacWithSHA384': + case 'hmacWithSHA512': + prfAlgorithm = prfAlgorithm.substr(8).toLowerCase(); + break; + default: + var error = new Error('Unsupported PRF algorithm.'); + error.algorithm = prfAlgorithm; + error.supported = [ + 'hmacWithSHA1', 'hmacWithSHA224', 'hmacWithSHA256', 'hmacWithSHA384', + 'hmacWithSHA512']; + throw error; + } + if(!factory || !(prfAlgorithm in factory)) { + throw new Error('Unknown hash algorithm: ' + prfAlgorithm); + } + return factory[prfAlgorithm].create(); + } + + function createPbkdf2Params(salt, countBytes, dkLen, prfAlgorithm) { + var params = asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + // salt + asn1$1.create( + asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, salt), + // iteration count + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.INTEGER, false, + countBytes.getBytes()) + ]); + // when PRF algorithm is not SHA-1 default, add key length and PRF algorithm + if(prfAlgorithm !== 'hmacWithSHA1') { + params.value.push( + // key length + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.INTEGER, false, + forge.util.hexToBytes(dkLen.toString(16))), + // AlgorithmIdentifier + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ + // algorithm + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, + asn1$1.oidToDer(pki$1.oids[prfAlgorithm]).getBytes()), + // parameters (null) + asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.NULL, false, '') + ])); + } + return params; + } + + var pkcs7asn1 = createCommonjsModule(function (module) { + /** + * Javascript implementation of ASN.1 validators for PKCS#7 v1.5. + * + * @author Dave Longley + * @author Stefan Siegl + * + * Copyright (c) 2012-2015 Digital Bazaar, Inc. + * Copyright (c) 2012 Stefan Siegl + * + * The ASN.1 representation of PKCS#7 is as follows + * (see RFC #2315 for details, http://www.ietf.org/rfc/rfc2315.txt): + * + * A PKCS#7 message consists of a ContentInfo on root level, which may + * contain any number of further ContentInfo nested into it. + * + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL + * } + * + * ContentType ::= OBJECT IDENTIFIER + * + * EnvelopedData ::= SEQUENCE { + * version Version, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo + * } + * + * EncryptedData ::= SEQUENCE { + * version Version, + * encryptedContentInfo EncryptedContentInfo + * } + * + * id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) + * us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 } + * + * SignedData ::= SEQUENCE { + * version INTEGER, + * digestAlgorithms DigestAlgorithmIdentifiers, + * contentInfo ContentInfo, + * certificates [0] IMPLICIT Certificates OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos + * } + * + * SignerInfos ::= SET OF SignerInfo + * + * SignerInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * + * Attributes ::= SET OF Attribute + * + * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + * + * AttributeValue ::= ANY + * + * Version ::= INTEGER + * + * RecipientInfos ::= SET OF RecipientInfo + * + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + * + * ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters + * for the algorithm, if any. In the case of AES and DES3, there is only one, + * the IV. + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * EncryptedContent ::= OCTET STRING + * + * RecipientInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey + * } + * + * IssuerAndSerialNumber ::= SEQUENCE { + * issuer Name, + * serialNumber CertificateSerialNumber + * } + * + * CertificateSerialNumber ::= INTEGER + * + * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedKey ::= OCTET STRING + */ + + + + + // shortcut for ASN.1 API + var asn1 = forge.asn1; + + // shortcut for PKCS#7 API + var p7v = module.exports = forge.pkcs7asn1 = forge.pkcs7asn1 || {}; + forge.pkcs7 = forge.pkcs7 || {}; + forge.pkcs7.asn1 = p7v; + + var contentInfoValidator = { + name: 'ContentInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'ContentInfo.ContentType', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'contentType' + }, { + name: 'ContentInfo.content', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + captureAsn1: 'content' + }] + }; + p7v.contentInfoValidator = contentInfoValidator; + + var encryptedContentInfoValidator = { + name: 'EncryptedContentInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedContentInfo.contentType', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'contentType' + }, { + name: 'EncryptedContentInfo.contentEncryptionAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedContentInfo.contentEncryptionAlgorithm.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'encAlgorithm' + }, { + name: 'EncryptedContentInfo.contentEncryptionAlgorithm.parameter', + tagClass: asn1.Class.UNIVERSAL, + captureAsn1: 'encParameter' + }] + }, { + name: 'EncryptedContentInfo.encryptedContent', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 0, + /* The PKCS#7 structure output by OpenSSL somewhat differs from what + * other implementations do generate. + * + * OpenSSL generates a structure like this: + * SEQUENCE { + * ... + * [0] + * 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38 + * C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45 + * ... + * } + * + * Whereas other implementations (and this PKCS#7 module) generate: + * SEQUENCE { + * ... + * [0] { + * OCTET STRING + * 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38 + * C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45 + * ... + * } + * } + * + * In order to support both, we just capture the context specific + * field here. The OCTET STRING bit is removed below. + */ + capture: 'encryptedContent', + captureAsn1: 'encryptedContentAsn1' + }] + }; + + p7v.envelopedDataValidator = { + name: 'EnvelopedData', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EnvelopedData.Version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'version' + }, { + name: 'EnvelopedData.RecipientInfos', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SET, + constructed: true, + captureAsn1: 'recipientInfos' + }].concat(encryptedContentInfoValidator) + }; + + p7v.encryptedDataValidator = { + name: 'EncryptedData', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedData.Version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'version' + }].concat(encryptedContentInfoValidator) + }; + + var signerValidator = { + name: 'SignerInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignerInfo.version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false + }, { + name: 'SignerInfo.issuerAndSerialNumber', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignerInfo.issuerAndSerialNumber.issuer', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'issuer' + }, { + name: 'SignerInfo.issuerAndSerialNumber.serialNumber', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'serial' + }] + }, { + name: 'SignerInfo.digestAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignerInfo.digestAlgorithm.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'digestAlgorithm' + }, { + name: 'SignerInfo.digestAlgorithm.parameter', + tagClass: asn1.Class.UNIVERSAL, + constructed: false, + captureAsn1: 'digestParameter', + optional: true + }] + }, { + name: 'SignerInfo.authenticatedAttributes', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + capture: 'authenticatedAttributes' + }, { + name: 'SignerInfo.digestEncryptionAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + capture: 'signatureAlgorithm' + }, { + name: 'SignerInfo.encryptedDigest', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OCTETSTRING, + constructed: false, + capture: 'signature' + }, { + name: 'SignerInfo.unauthenticatedAttributes', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 1, + constructed: true, + optional: true, + capture: 'unauthenticatedAttributes' + }] + }; + + p7v.signedDataValidator = { + name: 'SignedData', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignedData.Version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'version' + }, { + name: 'SignedData.DigestAlgorithms', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SET, + constructed: true, + captureAsn1: 'digestAlgorithms' + }, + contentInfoValidator, + { + name: 'SignedData.Certificates', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 0, + optional: true, + captureAsn1: 'certificates' + }, { + name: 'SignedData.CertificateRevocationLists', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 1, + optional: true, + captureAsn1: 'crls' + }, { + name: 'SignedData.SignerInfos', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SET, + capture: 'signerInfos', + optional: true, + value: [signerValidator] + }] + }; + + p7v.recipientInfoValidator = { + name: 'RecipientInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'RecipientInfo.version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'version' + }, { + name: 'RecipientInfo.issuerAndSerial', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'RecipientInfo.issuerAndSerial.issuer', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'issuer' + }, { + name: 'RecipientInfo.issuerAndSerial.serialNumber', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'serial' + }] + }, { + name: 'RecipientInfo.keyEncryptionAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'RecipientInfo.keyEncryptionAlgorithm.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'encAlgorithm' + }, { + name: 'RecipientInfo.keyEncryptionAlgorithm.parameter', + tagClass: asn1.Class.UNIVERSAL, + constructed: false, + captureAsn1: 'encParameter' + }] + }, { + name: 'RecipientInfo.encryptedKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OCTETSTRING, + constructed: false, + capture: 'encKey' + }] + }; + }); + + var mgf1_1 = createCommonjsModule(function (module) { + /** + * Javascript implementation of mask generation function MGF1. + * + * @author Stefan Siegl + * @author Dave Longley + * + * Copyright (c) 2012 Stefan Siegl + * Copyright (c) 2014 Digital Bazaar, Inc. + */ + + + + forge.mgf = forge.mgf || {}; + var mgf1 = module.exports = forge.mgf.mgf1 = forge.mgf1 = forge.mgf1 || {}; + + /** + * Creates a MGF1 mask generation function object. + * + * @param md the message digest API to use (eg: forge.md.sha1.create()). + * + * @return a mask generation function object. + */ + mgf1.create = function(md) { + var mgf = { + /** + * Generate mask of specified length. + * + * @param {String} seed The seed for mask generation. + * @param maskLen Number of bytes to generate. + * @return {String} The generated mask. + */ + generate: function(seed, maskLen) { + /* 2. Let T be the empty octet string. */ + var t = new forge.util.ByteBuffer(); + + /* 3. For counter from 0 to ceil(maskLen / hLen), do the following: */ + var len = Math.ceil(maskLen / md.digestLength); + for(var i = 0; i < len; i++) { + /* a. Convert counter to an octet string C of length 4 octets */ + var c = new forge.util.ByteBuffer(); + c.putInt32(i); + + /* b. Concatenate the hash of the seed mgfSeed and C to the octet + * string T: */ + md.start(); + md.update(seed + c.getBytes()); + t.putBuffer(md.digest()); + } + + /* Output the leading maskLen octets of T as the octet string mask. */ + t.truncate(t.length() - maskLen); + return t.getBytes(); + } + }; + + return mgf; + }; + }); + + /** + * Node.js module for Forge mask generation functions. + * + * @author Stefan Siegl + * + * Copyright 2012 Stefan Siegl + */ + + + + var mgf = forge.mgf = forge.mgf || {}; + forge.mgf.mgf1 = forge.mgf1; + + var pss_1 = createCommonjsModule(function (module) { + /** + * Javascript implementation of PKCS#1 PSS signature padding. + * + * @author Stefan Siegl + * + * Copyright (c) 2012 Stefan Siegl + */ + + + + + // shortcut for PSS API + var pss = module.exports = forge.pss = forge.pss || {}; + + /** + * Creates a PSS signature scheme object. + * + * There are several ways to provide a salt for encoding: + * + * 1. Specify the saltLength only and the built-in PRNG will generate it. + * 2. Specify the saltLength and a custom PRNG with 'getBytesSync' defined that + * will be used. + * 3. Specify the salt itself as a forge.util.ByteBuffer. + * + * @param options the options to use: + * md the message digest object to use, a forge md instance. + * mgf the mask generation function to use, a forge mgf instance. + * [saltLength] the length of the salt in octets. + * [prng] the pseudo-random number generator to use to produce a salt. + * [salt] the salt to use when encoding. + * + * @return a signature scheme object. + */ + pss.create = function(options) { + // backwards compatibility w/legacy args: hash, mgf, sLen + if(arguments.length === 3) { + options = { + md: arguments[0], + mgf: arguments[1], + saltLength: arguments[2] + }; + } + + var hash = options.md; + var mgf = options.mgf; + var hLen = hash.digestLength; + + var salt_ = options.salt || null; + if(typeof salt_ === 'string') { + // assume binary-encoded string + salt_ = forge.util.createBuffer(salt_); + } + + var sLen; + if('saltLength' in options) { + sLen = options.saltLength; + } else if(salt_ !== null) { + sLen = salt_.length(); + } else { + throw new Error('Salt length not specified or specific salt not given.'); + } + + if(salt_ !== null && salt_.length() !== sLen) { + throw new Error('Given salt length does not match length of given salt.'); + } + + var prng = options.prng || forge.random; + + var pssobj = {}; + + /** + * Encodes a PSS signature. + * + * This function implements EMSA-PSS-ENCODE as per RFC 3447, section 9.1.1. + * + * @param md the message digest object with the hash to sign. + * @param modsBits the length of the RSA modulus in bits. + * + * @return the encoded message as a binary-encoded string of length + * ceil((modBits - 1) / 8). + */ + pssobj.encode = function(md, modBits) { + var i; + var emBits = modBits - 1; + var emLen = Math.ceil(emBits / 8); + + /* 2. Let mHash = Hash(M), an octet string of length hLen. */ + var mHash = md.digest().getBytes(); + + /* 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. */ + if(emLen < hLen + sLen + 2) { + throw new Error('Message is too long to encrypt.'); + } + + /* 4. Generate a random octet string salt of length sLen; if sLen = 0, + * then salt is the empty string. */ + var salt; + if(salt_ === null) { + salt = prng.getBytesSync(sLen); + } else { + salt = salt_.bytes(); + } + + /* 5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; */ + var m_ = new forge.util.ByteBuffer(); + m_.fillWithByte(0, 8); + m_.putBytes(mHash); + m_.putBytes(salt); + + /* 6. Let H = Hash(M'), an octet string of length hLen. */ + hash.start(); + hash.update(m_.getBytes()); + var h = hash.digest().getBytes(); + + /* 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 + * zero octets. The length of PS may be 0. */ + var ps = new forge.util.ByteBuffer(); + ps.fillWithByte(0, emLen - sLen - hLen - 2); + + /* 8. Let DB = PS || 0x01 || salt; DB is an octet string of length + * emLen - hLen - 1. */ + ps.putByte(0x01); + ps.putBytes(salt); + var db = ps.getBytes(); + + /* 9. Let dbMask = MGF(H, emLen - hLen - 1). */ + var maskLen = emLen - hLen - 1; + var dbMask = mgf.generate(h, maskLen); + + /* 10. Let maskedDB = DB \xor dbMask. */ + var maskedDB = ''; + for(i = 0; i < maskLen; i++) { + maskedDB += String.fromCharCode(db.charCodeAt(i) ^ dbMask.charCodeAt(i)); + } + + /* 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in + * maskedDB to zero. */ + var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF; + maskedDB = String.fromCharCode(maskedDB.charCodeAt(0) & ~mask) + + maskedDB.substr(1); + + /* 12. Let EM = maskedDB || H || 0xbc. + * 13. Output EM. */ + return maskedDB + h + String.fromCharCode(0xbc); + }; + + /** + * Verifies a PSS signature. + * + * This function implements EMSA-PSS-VERIFY as per RFC 3447, section 9.1.2. + * + * @param mHash the message digest hash, as a binary-encoded string, to + * compare against the signature. + * @param em the encoded message, as a binary-encoded string + * (RSA decryption result). + * @param modsBits the length of the RSA modulus in bits. + * + * @return true if the signature was verified, false if not. + */ + pssobj.verify = function(mHash, em, modBits) { + var i; + var emBits = modBits - 1; + var emLen = Math.ceil(emBits / 8); + + /* c. Convert the message representative m to an encoded message EM + * of length emLen = ceil((modBits - 1) / 8) octets, where modBits + * is the length in bits of the RSA modulus n */ + em = em.substr(-emLen); + + /* 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. */ + if(emLen < hLen + sLen + 2) { + throw new Error('Inconsistent parameters to PSS signature verification.'); + } + + /* 4. If the rightmost octet of EM does not have hexadecimal value + * 0xbc, output "inconsistent" and stop. */ + if(em.charCodeAt(emLen - 1) !== 0xbc) { + throw new Error('Encoded message does not end in 0xBC.'); + } + + /* 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and + * let H be the next hLen octets. */ + var maskLen = emLen - hLen - 1; + var maskedDB = em.substr(0, maskLen); + var h = em.substr(maskLen, hLen); + + /* 6. If the leftmost 8emLen - emBits bits of the leftmost octet in + * maskedDB are not all equal to zero, output "inconsistent" and stop. */ + var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF; + if((maskedDB.charCodeAt(0) & mask) !== 0) { + throw new Error('Bits beyond keysize not zero as expected.'); + } + + /* 7. Let dbMask = MGF(H, emLen - hLen - 1). */ + var dbMask = mgf.generate(h, maskLen); + + /* 8. Let DB = maskedDB \xor dbMask. */ + var db = ''; + for(i = 0; i < maskLen; i++) { + db += String.fromCharCode(maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i)); + } + + /* 9. Set the leftmost 8emLen - emBits bits of the leftmost octet + * in DB to zero. */ + db = String.fromCharCode(db.charCodeAt(0) & ~mask) + db.substr(1); + + /* 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero + * or if the octet at position emLen - hLen - sLen - 1 (the leftmost + * position is "position 1") does not have hexadecimal value 0x01, + * output "inconsistent" and stop. */ + var checkLen = emLen - hLen - sLen - 2; + for(i = 0; i < checkLen; i++) { + if(db.charCodeAt(i) !== 0x00) { + throw new Error('Leftmost octets not zero as expected'); + } + } + + if(db.charCodeAt(checkLen) !== 0x01) { + throw new Error('Inconsistent PSS signature, 0x01 marker not found'); + } + + /* 11. Let salt be the last sLen octets of DB. */ + var salt = db.substr(-sLen); + + /* 12. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */ + var m_ = new forge.util.ByteBuffer(); + m_.fillWithByte(0, 8); + m_.putBytes(mHash); + m_.putBytes(salt); + + /* 13. Let H' = Hash(M'), an octet string of length hLen. */ + hash.start(); + hash.update(m_.getBytes()); + var h_ = hash.digest().getBytes(); + + /* 14. If H = H', output "consistent." Otherwise, output "inconsistent." */ + return h === h_; + }; + + return pssobj; + }; + }); + + var x509 = createCommonjsModule(function (module) { + /** + * Javascript implementation of X.509 and related components (such as + * Certification Signing Requests) of a Public Key Infrastructure. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + * + * The ASN.1 representation of an X.509v3 certificate is as follows + * (see RFC 2459): + * + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * + * TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + * } + * + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * CertificateSerialNumber ::= INTEGER + * + * Name ::= CHOICE { + * // only one possible choice for now + * RDNSequence + * } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue + * } + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + * + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time + * } + * + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime + * } + * + * UniqueIdentifier ::= BIT STRING + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * } + * + * The only key algorithm currently supported for PKI is RSA. + * + * RSASSA-PSS signatures are described in RFC 3447 and RFC 4055. + * + * PKCS#10 v1.7 describes certificate signing requests: + * + * CertificationRequestInfo: + * + * CertificationRequestInfo ::= SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + * + * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} + * + * CRIAttributes ATTRIBUTE ::= { + * ... -- add any locally defined attributes here -- } + * + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) + * } + * + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + */ + + + + + + + + + + + + + // shortcut for asn.1 API + var asn1 = forge.asn1; + + /* Public Key Infrastructure (PKI) implementation. */ + var pki = module.exports = forge.pki = forge.pki || {}; + var oids = pki.oids; + + // short name OID mappings + var _shortNames = {}; + _shortNames['CN'] = oids['commonName']; + _shortNames['commonName'] = 'CN'; + _shortNames['C'] = oids['countryName']; + _shortNames['countryName'] = 'C'; + _shortNames['L'] = oids['localityName']; + _shortNames['localityName'] = 'L'; + _shortNames['ST'] = oids['stateOrProvinceName']; + _shortNames['stateOrProvinceName'] = 'ST'; + _shortNames['O'] = oids['organizationName']; + _shortNames['organizationName'] = 'O'; + _shortNames['OU'] = oids['organizationalUnitName']; + _shortNames['organizationalUnitName'] = 'OU'; + _shortNames['E'] = oids['emailAddress']; + _shortNames['emailAddress'] = 'E'; + + // validator for an SubjectPublicKeyInfo structure + // Note: Currently only works with an RSA public key + var publicKeyValidator = forge.pki.rsa.publicKeyValidator; + + // validator for an X.509v3 certificate + var x509CertificateValidator = { + name: 'Certificate', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'Certificate.TBSCertificate', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'tbsCertificate', + value: [{ + name: 'Certificate.TBSCertificate.version', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + value: [{ + name: 'Certificate.TBSCertificate.version.integer', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'certVersion' + }] + }, { + name: 'Certificate.TBSCertificate.serialNumber', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'certSerialNumber' + }, { + name: 'Certificate.TBSCertificate.signature', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'Certificate.TBSCertificate.signature.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'certinfoSignatureOid' + }, { + name: 'Certificate.TBSCertificate.signature.parameters', + tagClass: asn1.Class.UNIVERSAL, + optional: true, + captureAsn1: 'certinfoSignatureParams' + }] + }, { + name: 'Certificate.TBSCertificate.issuer', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certIssuer' + }, { + name: 'Certificate.TBSCertificate.validity', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + // Note: UTC and generalized times may both appear so the capture + // names are based on their detected order, the names used below + // are only for the common case, which validity time really means + // "notBefore" and which means "notAfter" will be determined by order + value: [{ + // notBefore (Time) (UTC time case) + name: 'Certificate.TBSCertificate.validity.notBefore (utc)', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.UTCTIME, + constructed: false, + optional: true, + capture: 'certValidity1UTCTime' + }, { + // notBefore (Time) (generalized time case) + name: 'Certificate.TBSCertificate.validity.notBefore (generalized)', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.GENERALIZEDTIME, + constructed: false, + optional: true, + capture: 'certValidity2GeneralizedTime' + }, { + // notAfter (Time) (only UTC time is supported) + name: 'Certificate.TBSCertificate.validity.notAfter (utc)', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.UTCTIME, + constructed: false, + optional: true, + capture: 'certValidity3UTCTime' + }, { + // notAfter (Time) (only UTC time is supported) + name: 'Certificate.TBSCertificate.validity.notAfter (generalized)', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.GENERALIZEDTIME, + constructed: false, + optional: true, + capture: 'certValidity4GeneralizedTime' + }] + }, { + // Name (subject) (RDNSequence) + name: 'Certificate.TBSCertificate.subject', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certSubject' + }, + // SubjectPublicKeyInfo + publicKeyValidator, + { + // issuerUniqueID (optional) + name: 'Certificate.TBSCertificate.issuerUniqueID', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 1, + constructed: true, + optional: true, + value: [{ + name: 'Certificate.TBSCertificate.issuerUniqueID.id', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.BITSTRING, + constructed: false, + // TODO: support arbitrary bit length ids + captureBitStringValue: 'certIssuerUniqueId' + }] + }, { + // subjectUniqueID (optional) + name: 'Certificate.TBSCertificate.subjectUniqueID', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 2, + constructed: true, + optional: true, + value: [{ + name: 'Certificate.TBSCertificate.subjectUniqueID.id', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.BITSTRING, + constructed: false, + // TODO: support arbitrary bit length ids + captureBitStringValue: 'certSubjectUniqueId' + }] + }, { + // Extensions (optional) + name: 'Certificate.TBSCertificate.extensions', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 3, + constructed: true, + captureAsn1: 'certExtensions', + optional: true + }] + }, { + // AlgorithmIdentifier (signature algorithm) + name: 'Certificate.signatureAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + // algorithm + name: 'Certificate.signatureAlgorithm.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'certSignatureOid' + }, { + name: 'Certificate.TBSCertificate.signature.parameters', + tagClass: asn1.Class.UNIVERSAL, + optional: true, + captureAsn1: 'certSignatureParams' + }] + }, { + // SignatureValue + name: 'Certificate.signatureValue', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.BITSTRING, + constructed: false, + captureBitStringValue: 'certSignature' + }] + }; + + var rsassaPssParameterValidator = { + name: 'rsapss', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'rsapss.hashAlgorithm', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + value: [{ + name: 'rsapss.hashAlgorithm.AlgorithmIdentifier', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Class.SEQUENCE, + constructed: true, + optional: true, + value: [{ + name: 'rsapss.hashAlgorithm.AlgorithmIdentifier.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'hashOid' + /* parameter block omitted, for SHA1 NULL anyhow. */ + }] + }] + }, { + name: 'rsapss.maskGenAlgorithm', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 1, + constructed: true, + value: [{ + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Class.SEQUENCE, + constructed: true, + optional: true, + value: [{ + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'maskGenOid' + }, { + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'maskGenHashOid' + /* parameter block omitted, for SHA1 NULL anyhow. */ + }] + }] + }] + }, { + name: 'rsapss.saltLength', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 2, + optional: true, + value: [{ + name: 'rsapss.saltLength.saltLength', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Class.INTEGER, + constructed: false, + capture: 'saltLength' + }] + }, { + name: 'rsapss.trailerField', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 3, + optional: true, + value: [{ + name: 'rsapss.trailer.trailer', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Class.INTEGER, + constructed: false, + capture: 'trailer' + }] + }] + }; + + // validator for a CertificationRequestInfo structure + var certificationRequestInfoValidator = { + name: 'CertificationRequestInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certificationRequestInfo', + value: [{ + name: 'CertificationRequestInfo.integer', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'certificationRequestInfoVersion' + }, { + // Name (subject) (RDNSequence) + name: 'CertificationRequestInfo.subject', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certificationRequestInfoSubject' + }, + // SubjectPublicKeyInfo + publicKeyValidator, + { + name: 'CertificationRequestInfo.attributes', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + capture: 'certificationRequestInfoAttributes', + value: [{ + name: 'CertificationRequestInfo.attributes', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'CertificationRequestInfo.attributes.type', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false + }, { + name: 'CertificationRequestInfo.attributes.value', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SET, + constructed: true + }] + }] + }] + }; + + // validator for a CertificationRequest structure + var certificationRequestValidator = { + name: 'CertificationRequest', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'csr', + value: [ + certificationRequestInfoValidator, { + // AlgorithmIdentifier (signature algorithm) + name: 'CertificationRequest.signatureAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + // algorithm + name: 'CertificationRequest.signatureAlgorithm.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'csrSignatureOid' + }, { + name: 'CertificationRequest.signatureAlgorithm.parameters', + tagClass: asn1.Class.UNIVERSAL, + optional: true, + captureAsn1: 'csrSignatureParams' + }] + }, { + // signature + name: 'CertificationRequest.signature', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.BITSTRING, + constructed: false, + captureBitStringValue: 'csrSignature' + } + ] + }; + + /** + * Converts an RDNSequence of ASN.1 DER-encoded RelativeDistinguishedName + * sets into an array with objects that have type and value properties. + * + * @param rdn the RDNSequence to convert. + * @param md a message digest to append type and value to if provided. + */ + pki.RDNAttributesAsArray = function(rdn, md) { + var rval = []; + + // each value in 'rdn' in is a SET of RelativeDistinguishedName + var set, attr, obj; + for(var si = 0; si < rdn.value.length; ++si) { + // get the RelativeDistinguishedName set + set = rdn.value[si]; + + // each value in the SET is an AttributeTypeAndValue sequence + // containing first a type (an OID) and second a value (defined by + // the OID) + for(var i = 0; i < set.value.length; ++i) { + obj = {}; + attr = set.value[i]; + obj.type = asn1.derToOid(attr.value[0].value); + obj.value = attr.value[1].value; + obj.valueTagClass = attr.value[1].type; + // if the OID is known, get its name and short name + if(obj.type in oids) { + obj.name = oids[obj.type]; + if(obj.name in _shortNames) { + obj.shortName = _shortNames[obj.name]; + } + } + if(md) { + md.update(obj.type); + md.update(obj.value); + } + rval.push(obj); + } + } + + return rval; + }; + + /** + * Converts ASN.1 CRIAttributes into an array with objects that have type and + * value properties. + * + * @param attributes the CRIAttributes to convert. + */ + pki.CRIAttributesAsArray = function(attributes) { + var rval = []; + + // each value in 'attributes' in is a SEQUENCE with an OID and a SET + for(var si = 0; si < attributes.length; ++si) { + // get the attribute sequence + var seq = attributes[si]; + + // each value in the SEQUENCE containing first a type (an OID) and + // second a set of values (defined by the OID) + var type = asn1.derToOid(seq.value[0].value); + var values = seq.value[1].value; + for(var vi = 0; vi < values.length; ++vi) { + var obj = {}; + obj.type = type; + obj.value = values[vi].value; + obj.valueTagClass = values[vi].type; + // if the OID is known, get its name and short name + if(obj.type in oids) { + obj.name = oids[obj.type]; + if(obj.name in _shortNames) { + obj.shortName = _shortNames[obj.name]; + } + } + // parse extensions + if(obj.type === oids.extensionRequest) { + obj.extensions = []; + for(var ei = 0; ei < obj.value.length; ++ei) { + obj.extensions.push(pki.certificateExtensionFromAsn1(obj.value[ei])); + } + } + rval.push(obj); + } + } + + return rval; + }; + + /** + * Gets an issuer or subject attribute from its name, type, or short name. + * + * @param obj the issuer or subject object. + * @param options a short name string or an object with: + * shortName the short name for the attribute. + * name the name for the attribute. + * type the type for the attribute. + * + * @return the attribute. + */ + function _getAttribute(obj, options) { + if(typeof options === 'string') { + options = {shortName: options}; + } + + var rval = null; + var attr; + for(var i = 0; rval === null && i < obj.attributes.length; ++i) { + attr = obj.attributes[i]; + if(options.type && options.type === attr.type) { + rval = attr; + } else if(options.name && options.name === attr.name) { + rval = attr; + } else if(options.shortName && options.shortName === attr.shortName) { + rval = attr; + } + } + return rval; + } + + /** + * Converts signature parameters from ASN.1 structure. + * + * Currently only RSASSA-PSS supported. The PKCS#1 v1.5 signature scheme had + * no parameters. + * + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT + * sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT + * mgf1SHA1Identifier, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] INTEGER DEFAULT 1 + * } + * + * HashAlgorithm ::= AlgorithmIdentifier + * + * MaskGenAlgorithm ::= AlgorithmIdentifier + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * @param oid The OID specifying the signature algorithm + * @param obj The ASN.1 structure holding the parameters + * @param fillDefaults Whether to use return default values where omitted + * @return signature parameter object + */ + var _readSignatureParameters = function(oid, obj, fillDefaults) { + var params = {}; + + if(oid !== oids['RSASSA-PSS']) { + return params; + } + + if(fillDefaults) { + params = { + hash: { + algorithmOid: oids['sha1'] + }, + mgf: { + algorithmOid: oids['mgf1'], + hash: { + algorithmOid: oids['sha1'] + } + }, + saltLength: 20 + }; + } + + var capture = {}; + var errors = []; + if(!asn1.validate(obj, rsassaPssParameterValidator, capture, errors)) { + var error = new Error('Cannot read RSASSA-PSS parameter block.'); + error.errors = errors; + throw error; + } + + if(capture.hashOid !== undefined) { + params.hash = params.hash || {}; + params.hash.algorithmOid = asn1.derToOid(capture.hashOid); + } + + if(capture.maskGenOid !== undefined) { + params.mgf = params.mgf || {}; + params.mgf.algorithmOid = asn1.derToOid(capture.maskGenOid); + params.mgf.hash = params.mgf.hash || {}; + params.mgf.hash.algorithmOid = asn1.derToOid(capture.maskGenHashOid); + } + + if(capture.saltLength !== undefined) { + params.saltLength = capture.saltLength.charCodeAt(0); + } + + return params; + }; + + /** + * Converts an X.509 certificate from PEM format. + * + * Note: If the certificate is to be verified then compute hash should + * be set to true. This will scan the TBSCertificate part of the ASN.1 + * object while it is converted so it doesn't need to be converted back + * to ASN.1-DER-encoding later. + * + * @param pem the PEM-formatted certificate. + * @param computeHash true to compute the hash for verification. + * @param strict true to be strict when checking ASN.1 value lengths, false to + * allow truncated values (default: true). + * + * @return the certificate. + */ + pki.certificateFromPem = function(pem, computeHash, strict) { + var msg = forge.pem.decode(pem)[0]; + + if(msg.type !== 'CERTIFICATE' && + msg.type !== 'X509 CERTIFICATE' && + msg.type !== 'TRUSTED CERTIFICATE') { + var error = new Error( + 'Could not convert certificate from PEM; PEM header type ' + + 'is not "CERTIFICATE", "X509 CERTIFICATE", or "TRUSTED CERTIFICATE".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error( + 'Could not convert certificate from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1.fromDer(msg.body, strict); + + return pki.certificateFromAsn1(obj, computeHash); + }; + + /** + * Converts an X.509 certificate to PEM format. + * + * @param cert the certificate. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted certificate. + */ + pki.certificateToPem = function(cert, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'CERTIFICATE', + body: asn1.toDer(pki.certificateToAsn1(cert)).getBytes() + }; + return forge.pem.encode(msg, {maxline: maxline}); + }; + + /** + * Converts an RSA public key from PEM format. + * + * @param pem the PEM-formatted public key. + * + * @return the public key. + */ + pki.publicKeyFromPem = function(pem) { + var msg = forge.pem.decode(pem)[0]; + + if(msg.type !== 'PUBLIC KEY' && msg.type !== 'RSA PUBLIC KEY') { + var error = new Error('Could not convert public key from PEM; PEM header ' + + 'type is not "PUBLIC KEY" or "RSA PUBLIC KEY".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert public key from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1.fromDer(msg.body); + + return pki.publicKeyFromAsn1(obj); + }; + + /** + * Converts an RSA public key to PEM format (using a SubjectPublicKeyInfo). + * + * @param key the public key. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted public key. + */ + pki.publicKeyToPem = function(key, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'PUBLIC KEY', + body: asn1.toDer(pki.publicKeyToAsn1(key)).getBytes() + }; + return forge.pem.encode(msg, {maxline: maxline}); + }; + + /** + * Converts an RSA public key to PEM format (using an RSAPublicKey). + * + * @param key the public key. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted public key. + */ + pki.publicKeyToRSAPublicKeyPem = function(key, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'RSA PUBLIC KEY', + body: asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes() + }; + return forge.pem.encode(msg, {maxline: maxline}); + }; + + /** + * Gets a fingerprint for the given public key. + * + * @param options the options to use. + * [md] the message digest object to use (defaults to forge.md.sha1). + * [type] the type of fingerprint, such as 'RSAPublicKey', + * 'SubjectPublicKeyInfo' (defaults to 'RSAPublicKey'). + * [encoding] an alternative output encoding, such as 'hex' + * (defaults to none, outputs a byte buffer). + * [delimiter] the delimiter to use between bytes for 'hex' encoded + * output, eg: ':' (defaults to none). + * + * @return the fingerprint as a byte buffer or other encoding based on options. + */ + pki.getPublicKeyFingerprint = function(key, options) { + options = options || {}; + var md = options.md || forge.md.sha1.create(); + var type = options.type || 'RSAPublicKey'; + + var bytes; + switch(type) { + case 'RSAPublicKey': + bytes = asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes(); + break; + case 'SubjectPublicKeyInfo': + bytes = asn1.toDer(pki.publicKeyToAsn1(key)).getBytes(); + break; + default: + throw new Error('Unknown fingerprint type "' + options.type + '".'); + } + + // hash public key bytes + md.start(); + md.update(bytes); + var digest = md.digest(); + if(options.encoding === 'hex') { + var hex = digest.toHex(); + if(options.delimiter) { + return hex.match(/.{2}/g).join(options.delimiter); + } + return hex; + } else if(options.encoding === 'binary') { + return digest.getBytes(); + } else if(options.encoding) { + throw new Error('Unknown encoding "' + options.encoding + '".'); + } + return digest; + }; + + /** + * Converts a PKCS#10 certification request (CSR) from PEM format. + * + * Note: If the certification request is to be verified then compute hash + * should be set to true. This will scan the CertificationRequestInfo part of + * the ASN.1 object while it is converted so it doesn't need to be converted + * back to ASN.1-DER-encoding later. + * + * @param pem the PEM-formatted certificate. + * @param computeHash true to compute the hash for verification. + * @param strict true to be strict when checking ASN.1 value lengths, false to + * allow truncated values (default: true). + * + * @return the certification request (CSR). + */ + pki.certificationRequestFromPem = function(pem, computeHash, strict) { + var msg = forge.pem.decode(pem)[0]; + + if(msg.type !== 'CERTIFICATE REQUEST') { + var error = new Error('Could not convert certification request from PEM; ' + + 'PEM header type is not "CERTIFICATE REQUEST".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert certification request from PEM; ' + + 'PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1.fromDer(msg.body, strict); + + return pki.certificationRequestFromAsn1(obj, computeHash); + }; + + /** + * Converts a PKCS#10 certification request (CSR) to PEM format. + * + * @param csr the certification request. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted certification request. + */ + pki.certificationRequestToPem = function(csr, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'CERTIFICATE REQUEST', + body: asn1.toDer(pki.certificationRequestToAsn1(csr)).getBytes() + }; + return forge.pem.encode(msg, {maxline: maxline}); + }; + + /** + * Creates an empty X.509v3 RSA certificate. + * + * @return the certificate. + */ + pki.createCertificate = function() { + var cert = {}; + cert.version = 0x02; + cert.serialNumber = '00'; + cert.signatureOid = null; + cert.signature = null; + cert.siginfo = {}; + cert.siginfo.algorithmOid = null; + cert.validity = {}; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + + cert.issuer = {}; + cert.issuer.getField = function(sn) { + return _getAttribute(cert.issuer, sn); + }; + cert.issuer.addField = function(attr) { + _fillMissingFields([attr]); + cert.issuer.attributes.push(attr); + }; + cert.issuer.attributes = []; + cert.issuer.hash = null; + + cert.subject = {}; + cert.subject.getField = function(sn) { + return _getAttribute(cert.subject, sn); + }; + cert.subject.addField = function(attr) { + _fillMissingFields([attr]); + cert.subject.attributes.push(attr); + }; + cert.subject.attributes = []; + cert.subject.hash = null; + + cert.extensions = []; + cert.publicKey = null; + cert.md = null; + + /** + * Sets the subject of this certificate. + * + * @param attrs the array of subject attributes to use. + * @param uniqueId an optional a unique ID to use. + */ + cert.setSubject = function(attrs, uniqueId) { + // set new attributes, clear hash + _fillMissingFields(attrs); + cert.subject.attributes = attrs; + delete cert.subject.uniqueId; + if(uniqueId) { + // TODO: support arbitrary bit length ids + cert.subject.uniqueId = uniqueId; + } + cert.subject.hash = null; + }; + + /** + * Sets the issuer of this certificate. + * + * @param attrs the array of issuer attributes to use. + * @param uniqueId an optional a unique ID to use. + */ + cert.setIssuer = function(attrs, uniqueId) { + // set new attributes, clear hash + _fillMissingFields(attrs); + cert.issuer.attributes = attrs; + delete cert.issuer.uniqueId; + if(uniqueId) { + // TODO: support arbitrary bit length ids + cert.issuer.uniqueId = uniqueId; + } + cert.issuer.hash = null; + }; + + /** + * Sets the extensions of this certificate. + * + * @param exts the array of extensions to use. + */ + cert.setExtensions = function(exts) { + for(var i = 0; i < exts.length; ++i) { + _fillMissingExtensionFields(exts[i], {cert: cert}); + } + // set new extensions + cert.extensions = exts; + }; + + /** + * Gets an extension by its name or id. + * + * @param options the name to use or an object with: + * name the name to use. + * id the id to use. + * + * @return the extension or null if not found. + */ + cert.getExtension = function(options) { + if(typeof options === 'string') { + options = {name: options}; + } + + var rval = null; + var ext; + for(var i = 0; rval === null && i < cert.extensions.length; ++i) { + ext = cert.extensions[i]; + if(options.id && ext.id === options.id) { + rval = ext; + } else if(options.name && ext.name === options.name) { + rval = ext; + } + } + return rval; + }; + + /** + * Signs this certificate using the given private key. + * + * @param key the private key to sign with. + * @param md the message digest object to use (defaults to forge.md.sha1). + */ + cert.sign = function(key, md) { + // TODO: get signature OID from private key + cert.md = md || forge.md.sha1.create(); + var algorithmOid = oids[cert.md.algorithm + 'WithRSAEncryption']; + if(!algorithmOid) { + var error = new Error('Could not compute certificate digest. ' + + 'Unknown message digest algorithm OID.'); + error.algorithm = cert.md.algorithm; + throw error; + } + cert.signatureOid = cert.siginfo.algorithmOid = algorithmOid; + + // get TBSCertificate, convert to DER + cert.tbsCertificate = pki.getTBSCertificate(cert); + var bytes = asn1.toDer(cert.tbsCertificate); + + // digest and sign + cert.md.update(bytes.getBytes()); + cert.signature = key.sign(cert.md); + }; + + /** + * Attempts verify the signature on the passed certificate using this + * certificate's public key. + * + * @param child the certificate to verify. + * + * @return true if verified, false if not. + */ + cert.verify = function(child) { + var rval = false; + + if(!cert.issued(child)) { + var issuer = child.issuer; + var subject = cert.subject; + var error = new Error( + 'The parent certificate did not issue the given child ' + + 'certificate; the child certificate\'s issuer does not match the ' + + 'parent\'s subject.'); + error.expectedIssuer = issuer.attributes; + error.actualIssuer = subject.attributes; + throw error; + } + + var md = child.md; + if(md === null) { + // check signature OID for supported signature types + if(child.signatureOid in oids) { + var oid = oids[child.signatureOid]; + switch(oid) { + case 'sha1WithRSAEncryption': + md = forge.md.sha1.create(); + break; + case 'md5WithRSAEncryption': + md = forge.md.md5.create(); + break; + case 'sha256WithRSAEncryption': + md = forge.md.sha256.create(); + break; + case 'sha384WithRSAEncryption': + md = forge.md.sha384.create(); + break; + case 'sha512WithRSAEncryption': + md = forge.md.sha512.create(); + break; + case 'RSASSA-PSS': + md = forge.md.sha256.create(); + break; + } + } + if(md === null) { + var error = new Error('Could not compute certificate digest. ' + + 'Unknown signature OID.'); + error.signatureOid = child.signatureOid; + throw error; + } + + // produce DER formatted TBSCertificate and digest it + var tbsCertificate = child.tbsCertificate || pki.getTBSCertificate(child); + var bytes = asn1.toDer(tbsCertificate); + md.update(bytes.getBytes()); + } + + if(md !== null) { + var scheme; + + switch(child.signatureOid) { + case oids.sha1WithRSAEncryption: + scheme = undefined; /* use PKCS#1 v1.5 padding scheme */ + break; + case oids['RSASSA-PSS']: + var hash, mgf; + + /* initialize mgf */ + hash = oids[child.signatureParameters.mgf.hash.algorithmOid]; + if(hash === undefined || forge.md[hash] === undefined) { + var error = new Error('Unsupported MGF hash function.'); + error.oid = child.signatureParameters.mgf.hash.algorithmOid; + error.name = hash; + throw error; + } + + mgf = oids[child.signatureParameters.mgf.algorithmOid]; + if(mgf === undefined || forge.mgf[mgf] === undefined) { + var error = new Error('Unsupported MGF function.'); + error.oid = child.signatureParameters.mgf.algorithmOid; + error.name = mgf; + throw error; + } + + mgf = forge.mgf[mgf].create(forge.md[hash].create()); + + /* initialize hash function */ + hash = oids[child.signatureParameters.hash.algorithmOid]; + if(hash === undefined || forge.md[hash] === undefined) { + throw { + message: 'Unsupported RSASSA-PSS hash function.', + oid: child.signatureParameters.hash.algorithmOid, + name: hash + }; + } + + scheme = forge.pss.create(forge.md[hash].create(), mgf, + child.signatureParameters.saltLength); + break; + } + + // verify signature on cert using public key + rval = cert.publicKey.verify( + md.digest().getBytes(), child.signature, scheme); + } + + return rval; + }; + + /** + * Returns true if this certificate's issuer matches the passed + * certificate's subject. Note that no signature check is performed. + * + * @param parent the certificate to check. + * + * @return true if this certificate's issuer matches the passed certificate's + * subject. + */ + cert.isIssuer = function(parent) { + var rval = false; + + var i = cert.issuer; + var s = parent.subject; + + // compare hashes if present + if(i.hash && s.hash) { + rval = (i.hash === s.hash); + } else if(i.attributes.length === s.attributes.length) { + // all attributes are the same so issuer matches subject + rval = true; + var iattr, sattr; + for(var n = 0; rval && n < i.attributes.length; ++n) { + iattr = i.attributes[n]; + sattr = s.attributes[n]; + if(iattr.type !== sattr.type || iattr.value !== sattr.value) { + // attribute mismatch + rval = false; + } + } + } + + return rval; + }; + + /** + * Returns true if this certificate's subject matches the issuer of the + * given certificate). Note that not signature check is performed. + * + * @param child the certificate to check. + * + * @return true if this certificate's subject matches the passed + * certificate's issuer. + */ + cert.issued = function(child) { + return child.isIssuer(cert); + }; + + /** + * Generates the subjectKeyIdentifier for this certificate as byte buffer. + * + * @return the subjectKeyIdentifier for this certificate as byte buffer. + */ + cert.generateSubjectKeyIdentifier = function() { + /* See: 4.2.1.2 section of the the RFC3280, keyIdentifier is either: + + (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + value of the BIT STRING subjectPublicKey (excluding the tag, + length, and number of unused bits). + + (2) The keyIdentifier is composed of a four bit type field with + the value 0100 followed by the least significant 60 bits of the + SHA-1 hash of the value of the BIT STRING subjectPublicKey + (excluding the tag, length, and number of unused bit string bits). + */ + + // skipping the tag, length, and number of unused bits is the same + // as just using the RSAPublicKey (for RSA keys, which are the + // only ones supported) + return pki.getPublicKeyFingerprint(cert.publicKey, {type: 'RSAPublicKey'}); + }; + + /** + * Verifies the subjectKeyIdentifier extension value for this certificate + * against its public key. If no extension is found, false will be + * returned. + * + * @return true if verified, false if not. + */ + cert.verifySubjectKeyIdentifier = function() { + var oid = oids['subjectKeyIdentifier']; + for(var i = 0; i < cert.extensions.length; ++i) { + var ext = cert.extensions[i]; + if(ext.id === oid) { + var ski = cert.generateSubjectKeyIdentifier().getBytes(); + return (forge.util.hexToBytes(ext.subjectKeyIdentifier) === ski); + } + } + return false; + }; + + return cert; + }; + + /** + * Converts an X.509v3 RSA certificate from an ASN.1 object. + * + * Note: If the certificate is to be verified then compute hash should + * be set to true. There is currently no implementation for converting + * a certificate back to ASN.1 so the TBSCertificate part of the ASN.1 + * object needs to be scanned before the cert object is created. + * + * @param obj the asn1 representation of an X.509v3 RSA certificate. + * @param computeHash true to compute the hash for verification. + * + * @return the certificate. + */ + pki.certificateFromAsn1 = function(obj, computeHash) { + // validate certificate and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(obj, x509CertificateValidator, capture, errors)) { + var error = new Error('Cannot read X.509 certificate. ' + + 'ASN.1 object is not an X509v3 Certificate.'); + error.errors = errors; + throw error; + } + + // get oid + var oid = asn1.derToOid(capture.publicKeyOid); + if(oid !== pki.oids.rsaEncryption) { + throw new Error('Cannot read public key. OID is not RSA.'); + } + + // create certificate + var cert = pki.createCertificate(); + cert.version = capture.certVersion ? + capture.certVersion.charCodeAt(0) : 0; + var serial = forge.util.createBuffer(capture.certSerialNumber); + cert.serialNumber = serial.toHex(); + cert.signatureOid = forge.asn1.derToOid(capture.certSignatureOid); + cert.signatureParameters = _readSignatureParameters( + cert.signatureOid, capture.certSignatureParams, true); + cert.siginfo.algorithmOid = forge.asn1.derToOid(capture.certinfoSignatureOid); + cert.siginfo.parameters = _readSignatureParameters(cert.siginfo.algorithmOid, + capture.certinfoSignatureParams, false); + cert.signature = capture.certSignature; + + var validity = []; + if(capture.certValidity1UTCTime !== undefined) { + validity.push(asn1.utcTimeToDate(capture.certValidity1UTCTime)); + } + if(capture.certValidity2GeneralizedTime !== undefined) { + validity.push(asn1.generalizedTimeToDate( + capture.certValidity2GeneralizedTime)); + } + if(capture.certValidity3UTCTime !== undefined) { + validity.push(asn1.utcTimeToDate(capture.certValidity3UTCTime)); + } + if(capture.certValidity4GeneralizedTime !== undefined) { + validity.push(asn1.generalizedTimeToDate( + capture.certValidity4GeneralizedTime)); + } + if(validity.length > 2) { + throw new Error('Cannot read notBefore/notAfter validity times; more ' + + 'than two times were provided in the certificate.'); + } + if(validity.length < 2) { + throw new Error('Cannot read notBefore/notAfter validity times; they ' + + 'were not provided as either UTCTime or GeneralizedTime.'); + } + cert.validity.notBefore = validity[0]; + cert.validity.notAfter = validity[1]; + + // keep TBSCertificate to preserve signature when exporting + cert.tbsCertificate = capture.tbsCertificate; + + if(computeHash) { + // check signature OID for supported signature types + cert.md = null; + if(cert.signatureOid in oids) { + var oid = oids[cert.signatureOid]; + switch(oid) { + case 'sha1WithRSAEncryption': + cert.md = forge.md.sha1.create(); + break; + case 'md5WithRSAEncryption': + cert.md = forge.md.md5.create(); + break; + case 'sha256WithRSAEncryption': + cert.md = forge.md.sha256.create(); + break; + case 'sha384WithRSAEncryption': + cert.md = forge.md.sha384.create(); + break; + case 'sha512WithRSAEncryption': + cert.md = forge.md.sha512.create(); + break; + case 'RSASSA-PSS': + cert.md = forge.md.sha256.create(); + break; + } + } + if(cert.md === null) { + var error = new Error('Could not compute certificate digest. ' + + 'Unknown signature OID.'); + error.signatureOid = cert.signatureOid; + throw error; + } + + // produce DER formatted TBSCertificate and digest it + var bytes = asn1.toDer(cert.tbsCertificate); + cert.md.update(bytes.getBytes()); + } + + // handle issuer, build issuer message digest + var imd = forge.md.sha1.create(); + cert.issuer.getField = function(sn) { + return _getAttribute(cert.issuer, sn); + }; + cert.issuer.addField = function(attr) { + _fillMissingFields([attr]); + cert.issuer.attributes.push(attr); + }; + cert.issuer.attributes = pki.RDNAttributesAsArray(capture.certIssuer, imd); + if(capture.certIssuerUniqueId) { + cert.issuer.uniqueId = capture.certIssuerUniqueId; + } + cert.issuer.hash = imd.digest().toHex(); + + // handle subject, build subject message digest + var smd = forge.md.sha1.create(); + cert.subject.getField = function(sn) { + return _getAttribute(cert.subject, sn); + }; + cert.subject.addField = function(attr) { + _fillMissingFields([attr]); + cert.subject.attributes.push(attr); + }; + cert.subject.attributes = pki.RDNAttributesAsArray(capture.certSubject, smd); + if(capture.certSubjectUniqueId) { + cert.subject.uniqueId = capture.certSubjectUniqueId; + } + cert.subject.hash = smd.digest().toHex(); + + // handle extensions + if(capture.certExtensions) { + cert.extensions = pki.certificateExtensionsFromAsn1(capture.certExtensions); + } else { + cert.extensions = []; + } + + // convert RSA public key from ASN.1 + cert.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo); + + return cert; + }; + + /** + * Converts an ASN.1 extensions object (with extension sequences as its + * values) into an array of extension objects with types and values. + * + * Supported extensions: + * + * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } + * KeyUsage ::= BIT STRING { + * digitalSignature (0), + * nonRepudiation (1), + * keyEncipherment (2), + * dataEncipherment (3), + * keyAgreement (4), + * keyCertSign (5), + * cRLSign (6), + * encipherOnly (7), + * decipherOnly (8) + * } + * + * id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL + * } + * + * subjectAltName EXTENSION ::= { + * SYNTAX GeneralNames + * IDENTIFIED BY id-ce-subjectAltName + * } + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] INSTANCE OF OTHER-NAME, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * IPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER + * } + * + * OTHER-NAME ::= TYPE-IDENTIFIER + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString {ub-name} OPTIONAL, + * partyName [1] DirectoryString {ub-name} + * } + * + * @param exts the extensions ASN.1 with extension sequences to parse. + * + * @return the array. + */ + pki.certificateExtensionsFromAsn1 = function(exts) { + var rval = []; + for(var i = 0; i < exts.value.length; ++i) { + // get extension sequence + var extseq = exts.value[i]; + for(var ei = 0; ei < extseq.value.length; ++ei) { + rval.push(pki.certificateExtensionFromAsn1(extseq.value[ei])); + } + } + + return rval; + }; + + /** + * Parses a single certificate extension from ASN.1. + * + * @param ext the extension in ASN.1 format. + * + * @return the parsed extension as an object. + */ + pki.certificateExtensionFromAsn1 = function(ext) { + // an extension has: + // [0] extnID OBJECT IDENTIFIER + // [1] critical BOOLEAN DEFAULT FALSE + // [2] extnValue OCTET STRING + var e = {}; + e.id = asn1.derToOid(ext.value[0].value); + e.critical = false; + if(ext.value[1].type === asn1.Type.BOOLEAN) { + e.critical = (ext.value[1].value.charCodeAt(0) !== 0x00); + e.value = ext.value[2].value; + } else { + e.value = ext.value[1].value; + } + // if the oid is known, get its name + if(e.id in oids) { + e.name = oids[e.id]; + + // handle key usage + if(e.name === 'keyUsage') { + // get value as BIT STRING + var ev = asn1.fromDer(e.value); + var b2 = 0x00; + var b3 = 0x00; + if(ev.value.length > 1) { + // skip first byte, just indicates unused bits which + // will be padded with 0s anyway + // get bytes with flag bits + b2 = ev.value.charCodeAt(1); + b3 = ev.value.length > 2 ? ev.value.charCodeAt(2) : 0; + } + // set flags + e.digitalSignature = (b2 & 0x80) === 0x80; + e.nonRepudiation = (b2 & 0x40) === 0x40; + e.keyEncipherment = (b2 & 0x20) === 0x20; + e.dataEncipherment = (b2 & 0x10) === 0x10; + e.keyAgreement = (b2 & 0x08) === 0x08; + e.keyCertSign = (b2 & 0x04) === 0x04; + e.cRLSign = (b2 & 0x02) === 0x02; + e.encipherOnly = (b2 & 0x01) === 0x01; + e.decipherOnly = (b3 & 0x80) === 0x80; + } else if(e.name === 'basicConstraints') { + // handle basic constraints + // get value as SEQUENCE + var ev = asn1.fromDer(e.value); + // get cA BOOLEAN flag (defaults to false) + if(ev.value.length > 0 && ev.value[0].type === asn1.Type.BOOLEAN) { + e.cA = (ev.value[0].value.charCodeAt(0) !== 0x00); + } else { + e.cA = false; + } + // get path length constraint + var value = null; + if(ev.value.length > 0 && ev.value[0].type === asn1.Type.INTEGER) { + value = ev.value[0].value; + } else if(ev.value.length > 1) { + value = ev.value[1].value; + } + if(value !== null) { + e.pathLenConstraint = asn1.derToInteger(value); + } + } else if(e.name === 'extKeyUsage') { + // handle extKeyUsage + // value is a SEQUENCE of OIDs + var ev = asn1.fromDer(e.value); + for(var vi = 0; vi < ev.value.length; ++vi) { + var oid = asn1.derToOid(ev.value[vi].value); + if(oid in oids) { + e[oids[oid]] = true; + } else { + e[oid] = true; + } + } + } else if(e.name === 'nsCertType') { + // handle nsCertType + // get value as BIT STRING + var ev = asn1.fromDer(e.value); + var b2 = 0x00; + if(ev.value.length > 1) { + // skip first byte, just indicates unused bits which + // will be padded with 0s anyway + // get bytes with flag bits + b2 = ev.value.charCodeAt(1); + } + // set flags + e.client = (b2 & 0x80) === 0x80; + e.server = (b2 & 0x40) === 0x40; + e.email = (b2 & 0x20) === 0x20; + e.objsign = (b2 & 0x10) === 0x10; + e.reserved = (b2 & 0x08) === 0x08; + e.sslCA = (b2 & 0x04) === 0x04; + e.emailCA = (b2 & 0x02) === 0x02; + e.objCA = (b2 & 0x01) === 0x01; + } else if( + e.name === 'subjectAltName' || + e.name === 'issuerAltName') { + // handle subjectAltName/issuerAltName + e.altNames = []; + + // ev is a SYNTAX SEQUENCE + var gn; + var ev = asn1.fromDer(e.value); + for(var n = 0; n < ev.value.length; ++n) { + // get GeneralName + gn = ev.value[n]; + + var altName = { + type: gn.type, + value: gn.value + }; + e.altNames.push(altName); + + // Note: Support for types 1,2,6,7,8 + switch(gn.type) { + // rfc822Name + case 1: + // dNSName + case 2: + // uniformResourceIdentifier (URI) + case 6: + break; + // IPAddress + case 7: + // convert to IPv4/IPv6 string representation + altName.ip = forge.util.bytesToIP(gn.value); + break; + // registeredID + case 8: + altName.oid = asn1.derToOid(gn.value); + break; + // unsupported + } + } + } else if(e.name === 'subjectKeyIdentifier') { + // value is an OCTETSTRING w/the hash of the key-type specific + // public key structure (eg: RSAPublicKey) + var ev = asn1.fromDer(e.value); + e.subjectKeyIdentifier = forge.util.bytesToHex(ev.value); + } + } + return e; + }; + + /** + * Converts a PKCS#10 certification request (CSR) from an ASN.1 object. + * + * Note: If the certification request is to be verified then compute hash + * should be set to true. There is currently no implementation for converting + * a certificate back to ASN.1 so the CertificationRequestInfo part of the + * ASN.1 object needs to be scanned before the csr object is created. + * + * @param obj the asn1 representation of a PKCS#10 certification request (CSR). + * @param computeHash true to compute the hash for verification. + * + * @return the certification request (CSR). + */ + pki.certificationRequestFromAsn1 = function(obj, computeHash) { + // validate certification request and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(obj, certificationRequestValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#10 certificate request. ' + + 'ASN.1 object is not a PKCS#10 CertificationRequest.'); + error.errors = errors; + throw error; + } + + // get oid + var oid = asn1.derToOid(capture.publicKeyOid); + if(oid !== pki.oids.rsaEncryption) { + throw new Error('Cannot read public key. OID is not RSA.'); + } + + // create certification request + var csr = pki.createCertificationRequest(); + csr.version = capture.csrVersion ? capture.csrVersion.charCodeAt(0) : 0; + csr.signatureOid = forge.asn1.derToOid(capture.csrSignatureOid); + csr.signatureParameters = _readSignatureParameters( + csr.signatureOid, capture.csrSignatureParams, true); + csr.siginfo.algorithmOid = forge.asn1.derToOid(capture.csrSignatureOid); + csr.siginfo.parameters = _readSignatureParameters( + csr.siginfo.algorithmOid, capture.csrSignatureParams, false); + csr.signature = capture.csrSignature; + + // keep CertificationRequestInfo to preserve signature when exporting + csr.certificationRequestInfo = capture.certificationRequestInfo; + + if(computeHash) { + // check signature OID for supported signature types + csr.md = null; + if(csr.signatureOid in oids) { + var oid = oids[csr.signatureOid]; + switch(oid) { + case 'sha1WithRSAEncryption': + csr.md = forge.md.sha1.create(); + break; + case 'md5WithRSAEncryption': + csr.md = forge.md.md5.create(); + break; + case 'sha256WithRSAEncryption': + csr.md = forge.md.sha256.create(); + break; + case 'sha384WithRSAEncryption': + csr.md = forge.md.sha384.create(); + break; + case 'sha512WithRSAEncryption': + csr.md = forge.md.sha512.create(); + break; + case 'RSASSA-PSS': + csr.md = forge.md.sha256.create(); + break; + } + } + if(csr.md === null) { + var error = new Error('Could not compute certification request digest. ' + + 'Unknown signature OID.'); + error.signatureOid = csr.signatureOid; + throw error; + } + + // produce DER formatted CertificationRequestInfo and digest it + var bytes = asn1.toDer(csr.certificationRequestInfo); + csr.md.update(bytes.getBytes()); + } + + // handle subject, build subject message digest + var smd = forge.md.sha1.create(); + csr.subject.getField = function(sn) { + return _getAttribute(csr.subject, sn); + }; + csr.subject.addField = function(attr) { + _fillMissingFields([attr]); + csr.subject.attributes.push(attr); + }; + csr.subject.attributes = pki.RDNAttributesAsArray( + capture.certificationRequestInfoSubject, smd); + csr.subject.hash = smd.digest().toHex(); + + // convert RSA public key from ASN.1 + csr.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo); + + // convert attributes from ASN.1 + csr.getAttribute = function(sn) { + return _getAttribute(csr, sn); + }; + csr.addAttribute = function(attr) { + _fillMissingFields([attr]); + csr.attributes.push(attr); + }; + csr.attributes = pki.CRIAttributesAsArray( + capture.certificationRequestInfoAttributes || []); + + return csr; + }; + + /** + * Creates an empty certification request (a CSR or certificate signing + * request). Once created, its public key and attributes can be set and then + * it can be signed. + * + * @return the empty certification request. + */ + pki.createCertificationRequest = function() { + var csr = {}; + csr.version = 0x00; + csr.signatureOid = null; + csr.signature = null; + csr.siginfo = {}; + csr.siginfo.algorithmOid = null; + + csr.subject = {}; + csr.subject.getField = function(sn) { + return _getAttribute(csr.subject, sn); + }; + csr.subject.addField = function(attr) { + _fillMissingFields([attr]); + csr.subject.attributes.push(attr); + }; + csr.subject.attributes = []; + csr.subject.hash = null; + + csr.publicKey = null; + csr.attributes = []; + csr.getAttribute = function(sn) { + return _getAttribute(csr, sn); + }; + csr.addAttribute = function(attr) { + _fillMissingFields([attr]); + csr.attributes.push(attr); + }; + csr.md = null; + + /** + * Sets the subject of this certification request. + * + * @param attrs the array of subject attributes to use. + */ + csr.setSubject = function(attrs) { + // set new attributes + _fillMissingFields(attrs); + csr.subject.attributes = attrs; + csr.subject.hash = null; + }; + + /** + * Sets the attributes of this certification request. + * + * @param attrs the array of attributes to use. + */ + csr.setAttributes = function(attrs) { + // set new attributes + _fillMissingFields(attrs); + csr.attributes = attrs; + }; + + /** + * Signs this certification request using the given private key. + * + * @param key the private key to sign with. + * @param md the message digest object to use (defaults to forge.md.sha1). + */ + csr.sign = function(key, md) { + // TODO: get signature OID from private key + csr.md = md || forge.md.sha1.create(); + var algorithmOid = oids[csr.md.algorithm + 'WithRSAEncryption']; + if(!algorithmOid) { + var error = new Error('Could not compute certification request digest. ' + + 'Unknown message digest algorithm OID.'); + error.algorithm = csr.md.algorithm; + throw error; + } + csr.signatureOid = csr.siginfo.algorithmOid = algorithmOid; + + // get CertificationRequestInfo, convert to DER + csr.certificationRequestInfo = pki.getCertificationRequestInfo(csr); + var bytes = asn1.toDer(csr.certificationRequestInfo); + + // digest and sign + csr.md.update(bytes.getBytes()); + csr.signature = key.sign(csr.md); + }; + + /** + * Attempts verify the signature on the passed certification request using + * its public key. + * + * A CSR that has been exported to a file in PEM format can be verified using + * OpenSSL using this command: + * + * openssl req -in -verify -noout -text + * + * @return true if verified, false if not. + */ + csr.verify = function() { + var rval = false; + + var md = csr.md; + if(md === null) { + // check signature OID for supported signature types + if(csr.signatureOid in oids) { + // TODO: create DRY `OID to md` function + var oid = oids[csr.signatureOid]; + switch(oid) { + case 'sha1WithRSAEncryption': + md = forge.md.sha1.create(); + break; + case 'md5WithRSAEncryption': + md = forge.md.md5.create(); + break; + case 'sha256WithRSAEncryption': + md = forge.md.sha256.create(); + break; + case 'sha384WithRSAEncryption': + md = forge.md.sha384.create(); + break; + case 'sha512WithRSAEncryption': + md = forge.md.sha512.create(); + break; + case 'RSASSA-PSS': + md = forge.md.sha256.create(); + break; + } + } + if(md === null) { + var error = new Error( + 'Could not compute certification request digest. ' + + 'Unknown signature OID.'); + error.signatureOid = csr.signatureOid; + throw error; + } + + // produce DER formatted CertificationRequestInfo and digest it + var cri = csr.certificationRequestInfo || + pki.getCertificationRequestInfo(csr); + var bytes = asn1.toDer(cri); + md.update(bytes.getBytes()); + } + + if(md !== null) { + var scheme; + + switch(csr.signatureOid) { + case oids.sha1WithRSAEncryption: + /* use PKCS#1 v1.5 padding scheme */ + break; + case oids['RSASSA-PSS']: + var hash, mgf; + + /* initialize mgf */ + hash = oids[csr.signatureParameters.mgf.hash.algorithmOid]; + if(hash === undefined || forge.md[hash] === undefined) { + var error = new Error('Unsupported MGF hash function.'); + error.oid = csr.signatureParameters.mgf.hash.algorithmOid; + error.name = hash; + throw error; + } + + mgf = oids[csr.signatureParameters.mgf.algorithmOid]; + if(mgf === undefined || forge.mgf[mgf] === undefined) { + var error = new Error('Unsupported MGF function.'); + error.oid = csr.signatureParameters.mgf.algorithmOid; + error.name = mgf; + throw error; + } + + mgf = forge.mgf[mgf].create(forge.md[hash].create()); + + /* initialize hash function */ + hash = oids[csr.signatureParameters.hash.algorithmOid]; + if(hash === undefined || forge.md[hash] === undefined) { + var error = new Error('Unsupported RSASSA-PSS hash function.'); + error.oid = csr.signatureParameters.hash.algorithmOid; + error.name = hash; + throw error; + } + + scheme = forge.pss.create(forge.md[hash].create(), mgf, + csr.signatureParameters.saltLength); + break; + } + + // verify signature on csr using its public key + rval = csr.publicKey.verify( + md.digest().getBytes(), csr.signature, scheme); + } + + return rval; + }; + + return csr; + }; + + /** + * Converts an X.509 subject or issuer to an ASN.1 RDNSequence. + * + * @param obj the subject or issuer (distinguished name). + * + * @return the ASN.1 RDNSequence. + */ + function _dnToAsn1(obj) { + // create an empty RDNSequence + var rval = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + + // iterate over attributes + var attr, set; + var attrs = obj.attributes; + for(var i = 0; i < attrs.length; ++i) { + attr = attrs[i]; + var value = attr.value; + + // reuse tag class for attribute value if available + var valueTagClass = asn1.Type.PRINTABLESTRING; + if('valueTagClass' in attr) { + valueTagClass = attr.valueTagClass; + + if(valueTagClass === asn1.Type.UTF8) { + value = forge.util.encodeUtf8(value); + } + // FIXME: handle more encodings + } + + // create a RelativeDistinguishedName set + // each value in the set is an AttributeTypeAndValue first + // containing the type (an OID) and second the value + set = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // AttributeType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(attr.type).getBytes()), + // AttributeValue + asn1.create(asn1.Class.UNIVERSAL, valueTagClass, false, value) + ]) + ]); + rval.value.push(set); + } + + return rval; + } + + /** + * Fills in missing fields in attributes. + * + * @param attrs the attributes to fill missing fields in. + */ + function _fillMissingFields(attrs) { + var attr; + for(var i = 0; i < attrs.length; ++i) { + attr = attrs[i]; + + // populate missing name + if(typeof attr.name === 'undefined') { + if(attr.type && attr.type in pki.oids) { + attr.name = pki.oids[attr.type]; + } else if(attr.shortName && attr.shortName in _shortNames) { + attr.name = pki.oids[_shortNames[attr.shortName]]; + } + } + + // populate missing type (OID) + if(typeof attr.type === 'undefined') { + if(attr.name && attr.name in pki.oids) { + attr.type = pki.oids[attr.name]; + } else { + var error = new Error('Attribute type not specified.'); + error.attribute = attr; + throw error; + } + } + + // populate missing shortname + if(typeof attr.shortName === 'undefined') { + if(attr.name && attr.name in _shortNames) { + attr.shortName = _shortNames[attr.name]; + } + } + + // convert extensions to value + if(attr.type === oids.extensionRequest) { + attr.valueConstructed = true; + attr.valueTagClass = asn1.Type.SEQUENCE; + if(!attr.value && attr.extensions) { + attr.value = []; + for(var ei = 0; ei < attr.extensions.length; ++ei) { + attr.value.push(pki.certificateExtensionToAsn1( + _fillMissingExtensionFields(attr.extensions[ei]))); + } + } + } + + if(typeof attr.value === 'undefined') { + var error = new Error('Attribute value not specified.'); + error.attribute = attr; + throw error; + } + } + } + + /** + * Fills in missing fields in certificate extensions. + * + * @param e the extension. + * @param [options] the options to use. + * [cert] the certificate the extensions are for. + * + * @return the extension. + */ + function _fillMissingExtensionFields(e, options) { + options = options || {}; + + // populate missing name + if(typeof e.name === 'undefined') { + if(e.id && e.id in pki.oids) { + e.name = pki.oids[e.id]; + } + } + + // populate missing id + if(typeof e.id === 'undefined') { + if(e.name && e.name in pki.oids) { + e.id = pki.oids[e.name]; + } else { + var error = new Error('Extension ID not specified.'); + error.extension = e; + throw error; + } + } + + if(typeof e.value !== 'undefined') { + return e; + } + + // handle missing value: + + // value is a BIT STRING + if(e.name === 'keyUsage') { + // build flags + var unused = 0; + var b2 = 0x00; + var b3 = 0x00; + if(e.digitalSignature) { + b2 |= 0x80; + unused = 7; + } + if(e.nonRepudiation) { + b2 |= 0x40; + unused = 6; + } + if(e.keyEncipherment) { + b2 |= 0x20; + unused = 5; + } + if(e.dataEncipherment) { + b2 |= 0x10; + unused = 4; + } + if(e.keyAgreement) { + b2 |= 0x08; + unused = 3; + } + if(e.keyCertSign) { + b2 |= 0x04; + unused = 2; + } + if(e.cRLSign) { + b2 |= 0x02; + unused = 1; + } + if(e.encipherOnly) { + b2 |= 0x01; + unused = 0; + } + if(e.decipherOnly) { + b3 |= 0x80; + unused = 7; + } + + // create bit string + var value = String.fromCharCode(unused); + if(b3 !== 0) { + value += String.fromCharCode(b2) + String.fromCharCode(b3); + } else if(b2 !== 0) { + value += String.fromCharCode(b2); + } + e.value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value); + } else if(e.name === 'basicConstraints') { + // basicConstraints is a SEQUENCE + e.value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + // cA BOOLEAN flag defaults to false + if(e.cA) { + e.value.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false, + String.fromCharCode(0xFF))); + } + if('pathLenConstraint' in e) { + e.value.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(e.pathLenConstraint).getBytes())); + } + } else if(e.name === 'extKeyUsage') { + // extKeyUsage is a SEQUENCE of OIDs + e.value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + var seq = e.value.value; + for(var key in e) { + if(e[key] !== true) { + continue; + } + // key is name in OID map + if(key in oids) { + seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, + false, asn1.oidToDer(oids[key]).getBytes())); + } else if(key.indexOf('.') !== -1) { + // assume key is an OID + seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, + false, asn1.oidToDer(key).getBytes())); + } + } + } else if(e.name === 'nsCertType') { + // nsCertType is a BIT STRING + // build flags + var unused = 0; + var b2 = 0x00; + + if(e.client) { + b2 |= 0x80; + unused = 7; + } + if(e.server) { + b2 |= 0x40; + unused = 6; + } + if(e.email) { + b2 |= 0x20; + unused = 5; + } + if(e.objsign) { + b2 |= 0x10; + unused = 4; + } + if(e.reserved) { + b2 |= 0x08; + unused = 3; + } + if(e.sslCA) { + b2 |= 0x04; + unused = 2; + } + if(e.emailCA) { + b2 |= 0x02; + unused = 1; + } + if(e.objCA) { + b2 |= 0x01; + unused = 0; + } + + // create bit string + var value = String.fromCharCode(unused); + if(b2 !== 0) { + value += String.fromCharCode(b2); + } + e.value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value); + } else if(e.name === 'subjectAltName' || e.name === 'issuerAltName') { + // SYNTAX SEQUENCE + e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + + var altName; + for(var n = 0; n < e.altNames.length; ++n) { + altName = e.altNames[n]; + var value = altName.value; + // handle IP + if(altName.type === 7 && altName.ip) { + value = forge.util.bytesFromIP(altName.ip); + if(value === null) { + var error = new Error( + 'Extension "ip" value is not a valid IPv4 or IPv6 address.'); + error.extension = e; + throw error; + } + } else if(altName.type === 8) { + // handle OID + if(altName.oid) { + value = asn1.oidToDer(asn1.oidToDer(altName.oid)); + } else { + // deprecated ... convert value to OID + value = asn1.oidToDer(value); + } + } + e.value.value.push(asn1.create( + asn1.Class.CONTEXT_SPECIFIC, altName.type, false, + value)); + } + } else if(e.name === 'nsComment' && options.cert) { + // sanity check value is ASCII (req'd) and not too big + if(!(/^[\x00-\x7F]*$/.test(e.comment)) || + (e.comment.length < 1) || (e.comment.length > 128)) { + throw new Error('Invalid "nsComment" content.'); + } + // IA5STRING opaque comment + e.value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.IA5STRING, false, e.comment); + } else if(e.name === 'subjectKeyIdentifier' && options.cert) { + var ski = options.cert.generateSubjectKeyIdentifier(); + e.subjectKeyIdentifier = ski.toHex(); + // OCTETSTRING w/digest + e.value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, ski.getBytes()); + } else if(e.name === 'authorityKeyIdentifier' && options.cert) { + // SYNTAX SEQUENCE + e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + var seq = e.value.value; + + if(e.keyIdentifier) { + var keyIdentifier = (e.keyIdentifier === true ? + options.cert.generateSubjectKeyIdentifier().getBytes() : + e.keyIdentifier); + seq.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, false, keyIdentifier)); + } + + if(e.authorityCertIssuer) { + var authorityCertIssuer = [ + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 4, true, [ + _dnToAsn1(e.authorityCertIssuer === true ? + options.cert.issuer : e.authorityCertIssuer) + ]) + ]; + seq.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, authorityCertIssuer)); + } + + if(e.serialNumber) { + var serialNumber = forge.util.hexToBytes(e.serialNumber === true ? + options.cert.serialNumber : e.serialNumber); + seq.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, false, serialNumber)); + } + } else if(e.name === 'cRLDistributionPoints') { + e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + var seq = e.value.value; + + // Create sub SEQUENCE of DistributionPointName + var subSeq = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + + // Create fullName CHOICE + var fullNameGeneralNames = asn1.create( + asn1.Class.CONTEXT_SPECIFIC, 0, true, []); + var altName; + for(var n = 0; n < e.altNames.length; ++n) { + altName = e.altNames[n]; + var value = altName.value; + // handle IP + if(altName.type === 7 && altName.ip) { + value = forge.util.bytesFromIP(altName.ip); + if(value === null) { + var error = new Error( + 'Extension "ip" value is not a valid IPv4 or IPv6 address.'); + error.extension = e; + throw error; + } + } else if(altName.type === 8) { + // handle OID + if(altName.oid) { + value = asn1.oidToDer(asn1.oidToDer(altName.oid)); + } else { + // deprecated ... convert value to OID + value = asn1.oidToDer(value); + } + } + fullNameGeneralNames.value.push(asn1.create( + asn1.Class.CONTEXT_SPECIFIC, altName.type, false, + value)); + } + + // Add to the parent SEQUENCE + subSeq.value.push(asn1.create( + asn1.Class.CONTEXT_SPECIFIC, 0, true, [fullNameGeneralNames])); + seq.push(subSeq); + } + + // ensure value has been defined by now + if(typeof e.value === 'undefined') { + var error = new Error('Extension value not specified.'); + error.extension = e; + throw error; + } + + return e; + } + + /** + * Convert signature parameters object to ASN.1 + * + * @param {String} oid Signature algorithm OID + * @param params The signature parametrs object + * @return ASN.1 object representing signature parameters + */ + function _signatureParametersToAsn1(oid, params) { + switch(oid) { + case oids['RSASSA-PSS']: + var parts = []; + + if(params.hash.algorithmOid !== undefined) { + parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(params.hash.algorithmOid).getBytes()), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]) + ])); + } + + if(params.mgf.algorithmOid !== undefined) { + parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(params.mgf.algorithmOid).getBytes()), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(params.mgf.hash.algorithmOid).getBytes()), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]) + ]) + ])); + } + + if(params.saltLength !== undefined) { + parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(params.saltLength).getBytes()) + ])); + } + + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, parts); + + default: + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, ''); + } + } + + /** + * Converts a certification request's attributes to an ASN.1 set of + * CRIAttributes. + * + * @param csr certification request. + * + * @return the ASN.1 set of CRIAttributes. + */ + function _CRIAttributesToAsn1(csr) { + // create an empty context-specific container + var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, []); + + // no attributes, return empty container + if(csr.attributes.length === 0) { + return rval; + } + + // each attribute has a sequence with a type and a set of values + var attrs = csr.attributes; + for(var i = 0; i < attrs.length; ++i) { + var attr = attrs[i]; + var value = attr.value; + + // reuse tag class for attribute value if available + var valueTagClass = asn1.Type.UTF8; + if('valueTagClass' in attr) { + valueTagClass = attr.valueTagClass; + } + if(valueTagClass === asn1.Type.UTF8) { + value = forge.util.encodeUtf8(value); + } + var valueConstructed = false; + if('valueConstructed' in attr) { + valueConstructed = attr.valueConstructed; + } + // FIXME: handle more encodings + + // create a RelativeDistinguishedName set + // each value in the set is an AttributeTypeAndValue first + // containing the type (an OID) and second the value + var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // AttributeType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(attr.type).getBytes()), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ + // AttributeValue + asn1.create( + asn1.Class.UNIVERSAL, valueTagClass, valueConstructed, value) + ]) + ]); + rval.value.push(seq); + } + + return rval; + } + + var jan_1_1950 = new Date('1950-01-01T00:00:00Z'); + var jan_1_2050 = new Date('2050-01-01T00:00:00Z'); + + /** + * Converts a Date object to ASN.1 + * Handles the different format before and after 1st January 2050 + * + * @param date date object. + * + * @return the ASN.1 object representing the date. + */ + function _dateToAsn1(date) { + if(date >= jan_1_1950 && date < jan_1_2050) { + return asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false, + asn1.dateToUtcTime(date)); + } else { + return asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false, + asn1.dateToGeneralizedTime(date)); + } + } + + /** + * Gets the ASN.1 TBSCertificate part of an X.509v3 certificate. + * + * @param cert the certificate. + * + * @return the asn1 TBSCertificate. + */ + pki.getTBSCertificate = function(cert) { + // TBSCertificate + var notBefore = _dateToAsn1(cert.validity.notBefore); + var notAfter = _dateToAsn1(cert.validity.notAfter); + var tbs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // version + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + // integer + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(cert.version).getBytes()) + ]), + // serialNumber + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + forge.util.hexToBytes(cert.serialNumber)), + // signature + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(cert.siginfo.algorithmOid).getBytes()), + // parameters + _signatureParametersToAsn1( + cert.siginfo.algorithmOid, cert.siginfo.parameters) + ]), + // issuer + _dnToAsn1(cert.issuer), + // validity + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + notBefore, + notAfter + ]), + // subject + _dnToAsn1(cert.subject), + // SubjectPublicKeyInfo + pki.publicKeyToAsn1(cert.publicKey) + ]); + + if(cert.issuer.uniqueId) { + // issuerUniqueID (optional) + tbs.value.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, + // TODO: support arbitrary bit length ids + String.fromCharCode(0x00) + + cert.issuer.uniqueId + ) + ]) + ); + } + if(cert.subject.uniqueId) { + // subjectUniqueID (optional) + tbs.value.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, + // TODO: support arbitrary bit length ids + String.fromCharCode(0x00) + + cert.subject.uniqueId + ) + ]) + ); + } + + if(cert.extensions.length > 0) { + // extensions (optional) + tbs.value.push(pki.certificateExtensionsToAsn1(cert.extensions)); + } + + return tbs; + }; + + /** + * Gets the ASN.1 CertificationRequestInfo part of a + * PKCS#10 CertificationRequest. + * + * @param csr the certification request. + * + * @return the asn1 CertificationRequestInfo. + */ + pki.getCertificationRequestInfo = function(csr) { + // CertificationRequestInfo + var cri = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(csr.version).getBytes()), + // subject + _dnToAsn1(csr.subject), + // SubjectPublicKeyInfo + pki.publicKeyToAsn1(csr.publicKey), + // attributes + _CRIAttributesToAsn1(csr) + ]); + + return cri; + }; + + /** + * Converts a DistinguishedName (subject or issuer) to an ASN.1 object. + * + * @param dn the DistinguishedName. + * + * @return the asn1 representation of a DistinguishedName. + */ + pki.distinguishedNameToAsn1 = function(dn) { + return _dnToAsn1(dn); + }; + + /** + * Converts an X.509v3 RSA certificate to an ASN.1 object. + * + * @param cert the certificate. + * + * @return the asn1 representation of an X.509v3 RSA certificate. + */ + pki.certificateToAsn1 = function(cert) { + // prefer cached TBSCertificate over generating one + var tbsCertificate = cert.tbsCertificate || pki.getTBSCertificate(cert); + + // Certificate + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // TBSCertificate + tbsCertificate, + // AlgorithmIdentifier (signature algorithm) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(cert.signatureOid).getBytes()), + // parameters + _signatureParametersToAsn1(cert.signatureOid, cert.signatureParameters) + ]), + // SignatureValue + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, + String.fromCharCode(0x00) + cert.signature) + ]); + }; + + /** + * Converts X.509v3 certificate extensions to ASN.1. + * + * @param exts the extensions to convert. + * + * @return the extensions in ASN.1 format. + */ + pki.certificateExtensionsToAsn1 = function(exts) { + // create top-level extension container + var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 3, true, []); + + // create extension sequence (stores a sequence for each extension) + var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + rval.value.push(seq); + + for(var i = 0; i < exts.length; ++i) { + seq.value.push(pki.certificateExtensionToAsn1(exts[i])); + } + + return rval; + }; + + /** + * Converts a single certificate extension to ASN.1. + * + * @param ext the extension to convert. + * + * @return the extension in ASN.1 format. + */ + pki.certificateExtensionToAsn1 = function(ext) { + // create a sequence for each extension + var extseq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); + + // extnID (OID) + extseq.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(ext.id).getBytes())); + + // critical defaults to false + if(ext.critical) { + // critical BOOLEAN DEFAULT FALSE + extseq.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false, + String.fromCharCode(0xFF))); + } + + var value = ext.value; + if(typeof ext.value !== 'string') { + // value is asn.1 + value = asn1.toDer(value).getBytes(); + } + + // extnValue (OCTET STRING) + extseq.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, value)); + + return extseq; + }; + + /** + * Converts a PKCS#10 certification request to an ASN.1 object. + * + * @param csr the certification request. + * + * @return the asn1 representation of a certification request. + */ + pki.certificationRequestToAsn1 = function(csr) { + // prefer cached CertificationRequestInfo over generating one + var cri = csr.certificationRequestInfo || + pki.getCertificationRequestInfo(csr); + + // Certificate + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // CertificationRequestInfo + cri, + // AlgorithmIdentifier (signature algorithm) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(csr.signatureOid).getBytes()), + // parameters + _signatureParametersToAsn1(csr.signatureOid, csr.signatureParameters) + ]), + // signature + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, + String.fromCharCode(0x00) + csr.signature) + ]); + }; + + /** + * Creates a CA store. + * + * @param certs an optional array of certificate objects or PEM-formatted + * certificate strings to add to the CA store. + * + * @return the CA store. + */ + pki.createCaStore = function(certs) { + // create CA store + var caStore = { + // stored certificates + certs: {} + }; + + /** + * Gets the certificate that issued the passed certificate or its + * 'parent'. + * + * @param cert the certificate to get the parent for. + * + * @return the parent certificate or null if none was found. + */ + caStore.getIssuer = function(cert) { + var rval = getBySubject(cert.issuer); + + // see if there are multiple matches + /*if(forge.util.isArray(rval)) { + // TODO: resolve multiple matches by checking + // authorityKey/subjectKey/issuerUniqueID/other identifiers, etc. + // FIXME: or alternatively do authority key mapping + // if possible (X.509v1 certs can't work?) + throw new Error('Resolving multiple issuer matches not implemented yet.'); + }*/ + + return rval; + }; + + /** + * Adds a trusted certificate to the store. + * + * @param cert the certificate to add as a trusted certificate (either a + * pki.certificate object or a PEM-formatted certificate). + */ + caStore.addCertificate = function(cert) { + // convert from pem if necessary + if(typeof cert === 'string') { + cert = forge.pki.certificateFromPem(cert); + } + + ensureSubjectHasHash(cert.subject); + + if(!caStore.hasCertificate(cert)) { // avoid duplicate certificates in store + if(cert.subject.hash in caStore.certs) { + // subject hash already exists, append to array + var tmp = caStore.certs[cert.subject.hash]; + if(!forge.util.isArray(tmp)) { + tmp = [tmp]; + } + tmp.push(cert); + caStore.certs[cert.subject.hash] = tmp; + } else { + caStore.certs[cert.subject.hash] = cert; + } + } + }; + + /** + * Checks to see if the given certificate is in the store. + * + * @param cert the certificate to check (either a pki.certificate or a + * PEM-formatted certificate). + * + * @return true if the certificate is in the store, false if not. + */ + caStore.hasCertificate = function(cert) { + // convert from pem if necessary + if(typeof cert === 'string') { + cert = forge.pki.certificateFromPem(cert); + } + + var match = getBySubject(cert.subject); + if(!match) { + return false; + } + if(!forge.util.isArray(match)) { + match = [match]; + } + // compare DER-encoding of certificates + var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes(); + for(var i = 0; i < match.length; ++i) { + var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes(); + if(der1 === der2) { + return true; + } + } + return false; + }; + + /** + * Lists all of the certificates kept in the store. + * + * @return an array of all of the pki.certificate objects in the store. + */ + caStore.listAllCertificates = function() { + var certList = []; + + for(var hash in caStore.certs) { + if(caStore.certs.hasOwnProperty(hash)) { + var value = caStore.certs[hash]; + if(!forge.util.isArray(value)) { + certList.push(value); + } else { + for(var i = 0; i < value.length; ++i) { + certList.push(value[i]); + } + } + } + } + + return certList; + }; + + /** + * Removes a certificate from the store. + * + * @param cert the certificate to remove (either a pki.certificate or a + * PEM-formatted certificate). + * + * @return the certificate that was removed or null if the certificate + * wasn't in store. + */ + caStore.removeCertificate = function(cert) { + var result; + + // convert from pem if necessary + if(typeof cert === 'string') { + cert = forge.pki.certificateFromPem(cert); + } + ensureSubjectHasHash(cert.subject); + if(!caStore.hasCertificate(cert)) { + return null; + } + + var match = getBySubject(cert.subject); + + if(!forge.util.isArray(match)) { + result = caStore.certs[cert.subject.hash]; + delete caStore.certs[cert.subject.hash]; + return result; + } + + // compare DER-encoding of certificates + var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes(); + for(var i = 0; i < match.length; ++i) { + var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes(); + if(der1 === der2) { + result = match[i]; + match.splice(i, 1); + } + } + if(match.length === 0) { + delete caStore.certs[cert.subject.hash]; + } + + return result; + }; + + function getBySubject(subject) { + ensureSubjectHasHash(subject); + return caStore.certs[subject.hash] || null; + } + + function ensureSubjectHasHash(subject) { + // produce subject hash if it doesn't exist + if(!subject.hash) { + var md = forge.md.sha1.create(); + subject.attributes = pki.RDNAttributesAsArray(_dnToAsn1(subject), md); + subject.hash = md.digest().toHex(); + } + } + + // auto-add passed in certs + if(certs) { + // parse PEM-formatted certificates as necessary + for(var i = 0; i < certs.length; ++i) { + var cert = certs[i]; + caStore.addCertificate(cert); + } + } + + return caStore; + }; + + /** + * Certificate verification errors, based on TLS. + */ + pki.certificateError = { + bad_certificate: 'forge.pki.BadCertificate', + unsupported_certificate: 'forge.pki.UnsupportedCertificate', + certificate_revoked: 'forge.pki.CertificateRevoked', + certificate_expired: 'forge.pki.CertificateExpired', + certificate_unknown: 'forge.pki.CertificateUnknown', + unknown_ca: 'forge.pki.UnknownCertificateAuthority' + }; + + /** + * Verifies a certificate chain against the given Certificate Authority store + * with an optional custom verify callback. + * + * @param caStore a certificate store to verify against. + * @param chain the certificate chain to verify, with the root or highest + * authority at the end (an array of certificates). + * @param options a callback to be called for every certificate in the chain or + * an object with: + * verify a callback to be called for every certificate in the + * chain + * validityCheckDate the date against which the certificate + * validity period should be checked. Pass null to not check + * the validity period. By default, the current date is used. + * + * The verify callback has the following signature: + * + * verified - Set to true if certificate was verified, otherwise the + * pki.certificateError for why the certificate failed. + * depth - The current index in the chain, where 0 is the end point's cert. + * certs - The certificate chain, *NOTE* an empty chain indicates an anonymous + * end point. + * + * The function returns true on success and on failure either the appropriate + * pki.certificateError or an object with 'error' set to the appropriate + * pki.certificateError and 'message' set to a custom error message. + * + * @return true if successful, error thrown if not. + */ + pki.verifyCertificateChain = function(caStore, chain, options) { + /* From: RFC3280 - Internet X.509 Public Key Infrastructure Certificate + Section 6: Certification Path Validation + See inline parentheticals related to this particular implementation. + + The primary goal of path validation is to verify the binding between + a subject distinguished name or a subject alternative name and subject + public key, as represented in the end entity certificate, based on the + public key of the trust anchor. This requires obtaining a sequence of + certificates that support that binding. That sequence should be provided + in the passed 'chain'. The trust anchor should be in the given CA + store. The 'end entity' certificate is the certificate provided by the + end point (typically a server) and is the first in the chain. + + To meet this goal, the path validation process verifies, among other + things, that a prospective certification path (a sequence of n + certificates or a 'chain') satisfies the following conditions: + + (a) for all x in {1, ..., n-1}, the subject of certificate x is + the issuer of certificate x+1; + + (b) certificate 1 is issued by the trust anchor; + + (c) certificate n is the certificate to be validated; and + + (d) for all x in {1, ..., n}, the certificate was valid at the + time in question. + + Note that here 'n' is index 0 in the chain and 1 is the last certificate + in the chain and it must be signed by a certificate in the connection's + CA store. + + The path validation process also determines the set of certificate + policies that are valid for this path, based on the certificate policies + extension, policy mapping extension, policy constraints extension, and + inhibit any-policy extension. + + Note: Policy mapping extension not supported (Not Required). + + Note: If the certificate has an unsupported critical extension, then it + must be rejected. + + Note: A certificate is self-issued if the DNs that appear in the subject + and issuer fields are identical and are not empty. + + The path validation algorithm assumes the following seven inputs are + provided to the path processing logic. What this specific implementation + will use is provided parenthetically: + + (a) a prospective certification path of length n (the 'chain') + (b) the current date/time: ('now'). + (c) user-initial-policy-set: A set of certificate policy identifiers + naming the policies that are acceptable to the certificate user. + The user-initial-policy-set contains the special value any-policy + if the user is not concerned about certificate policy + (Not implemented. Any policy is accepted). + (d) trust anchor information, describing a CA that serves as a trust + anchor for the certification path. The trust anchor information + includes: + + (1) the trusted issuer name, + (2) the trusted public key algorithm, + (3) the trusted public key, and + (4) optionally, the trusted public key parameters associated + with the public key. + + (Trust anchors are provided via certificates in the CA store). + + The trust anchor information may be provided to the path processing + procedure in the form of a self-signed certificate. The trusted anchor + information is trusted because it was delivered to the path processing + procedure by some trustworthy out-of-band procedure. If the trusted + public key algorithm requires parameters, then the parameters are + provided along with the trusted public key (No parameters used in this + implementation). + + (e) initial-policy-mapping-inhibit, which indicates if policy mapping is + allowed in the certification path. + (Not implemented, no policy checking) + + (f) initial-explicit-policy, which indicates if the path must be valid + for at least one of the certificate policies in the user-initial- + policy-set. + (Not implemented, no policy checking) + + (g) initial-any-policy-inhibit, which indicates whether the + anyPolicy OID should be processed if it is included in a + certificate. + (Not implemented, so any policy is valid provided that it is + not marked as critical) */ + + /* Basic Path Processing: + + For each certificate in the 'chain', the following is checked: + + 1. The certificate validity period includes the current time. + 2. The certificate was signed by its parent (where the parent is either + the next in the chain or from the CA store). Allow processing to + continue to the next step if no parent is found but the certificate is + in the CA store. + 3. TODO: The certificate has not been revoked. + 4. The certificate issuer name matches the parent's subject name. + 5. TODO: If the certificate is self-issued and not the final certificate + in the chain, skip this step, otherwise verify that the subject name + is within one of the permitted subtrees of X.500 distinguished names + and that each of the alternative names in the subjectAltName extension + (critical or non-critical) is within one of the permitted subtrees for + that name type. + 6. TODO: If the certificate is self-issued and not the final certificate + in the chain, skip this step, otherwise verify that the subject name + is not within one of the excluded subtrees for X.500 distinguished + names and none of the subjectAltName extension names are excluded for + that name type. + 7. The other steps in the algorithm for basic path processing involve + handling the policy extension which is not presently supported in this + implementation. Instead, if a critical policy extension is found, the + certificate is rejected as not supported. + 8. If the certificate is not the first or if its the only certificate in + the chain (having no parent from the CA store or is self-signed) and it + has a critical key usage extension, verify that the keyCertSign bit is + set. If the key usage extension exists, verify that the basic + constraints extension exists. If the basic constraints extension exists, + verify that the cA flag is set. If pathLenConstraint is set, ensure that + the number of certificates that precede in the chain (come earlier + in the chain as implemented below), excluding the very first in the + chain (typically the end-entity one), isn't greater than the + pathLenConstraint. This constraint limits the number of intermediate + CAs that may appear below a CA before only end-entity certificates + may be issued. */ + + // if a verify callback is passed as the third parameter, package it within + // the options object. This is to support a legacy function signature that + // expected the verify callback as the third parameter. + if(typeof options === 'function') { + options = {verify: options}; + } + options = options || {}; + + // copy cert chain references to another array to protect against changes + // in verify callback + chain = chain.slice(0); + var certs = chain.slice(0); + + var validityCheckDate = options.validityCheckDate; + // if no validityCheckDate is specified, default to the current date. Make + // sure to maintain the value null because it indicates that the validity + // period should not be checked. + if(typeof validityCheckDate === 'undefined') { + validityCheckDate = new Date(); + } + + // verify each cert in the chain using its parent, where the parent + // is either the next in the chain or from the CA store + var first = true; + var error = null; + var depth = 0; + do { + var cert = chain.shift(); + var parent = null; + var selfSigned = false; + + if(validityCheckDate) { + // 1. check valid time + if(validityCheckDate < cert.validity.notBefore || + validityCheckDate > cert.validity.notAfter) { + error = { + message: 'Certificate is not valid yet or has expired.', + error: pki.certificateError.certificate_expired, + notBefore: cert.validity.notBefore, + notAfter: cert.validity.notAfter, + // TODO: we might want to reconsider renaming 'now' to + // 'validityCheckDate' should this API be changed in the future. + now: validityCheckDate + }; + } + } + + // 2. verify with parent from chain or CA store + if(error === null) { + parent = chain[0] || caStore.getIssuer(cert); + if(parent === null) { + // check for self-signed cert + if(cert.isIssuer(cert)) { + selfSigned = true; + parent = cert; + } + } + + if(parent) { + // FIXME: current CA store implementation might have multiple + // certificates where the issuer can't be determined from the + // certificate (happens rarely with, eg: old certificates) so normalize + // by always putting parents into an array + // TODO: there's may be an extreme degenerate case currently uncovered + // where an old intermediate certificate seems to have a matching parent + // but none of the parents actually verify ... but the intermediate + // is in the CA and it should pass this check; needs investigation + var parents = parent; + if(!forge.util.isArray(parents)) { + parents = [parents]; + } + + // try to verify with each possible parent (typically only one) + var verified = false; + while(!verified && parents.length > 0) { + parent = parents.shift(); + try { + verified = parent.verify(cert); + } catch(ex) { + // failure to verify, don't care why, try next one + } + } + + if(!verified) { + error = { + message: 'Certificate signature is invalid.', + error: pki.certificateError.bad_certificate + }; + } + } + + if(error === null && (!parent || selfSigned) && + !caStore.hasCertificate(cert)) { + // no parent issuer and certificate itself is not trusted + error = { + message: 'Certificate is not trusted.', + error: pki.certificateError.unknown_ca + }; + } + } + + // TODO: 3. check revoked + + // 4. check for matching issuer/subject + if(error === null && parent && !cert.isIssuer(parent)) { + // parent is not issuer + error = { + message: 'Certificate issuer is invalid.', + error: pki.certificateError.bad_certificate + }; + } + + // 5. TODO: check names with permitted names tree + + // 6. TODO: check names against excluded names tree + + // 7. check for unsupported critical extensions + if(error === null) { + // supported extensions + var se = { + keyUsage: true, + basicConstraints: true + }; + for(var i = 0; error === null && i < cert.extensions.length; ++i) { + var ext = cert.extensions[i]; + if(ext.critical && !(ext.name in se)) { + error = { + message: + 'Certificate has an unsupported critical extension.', + error: pki.certificateError.unsupported_certificate + }; + } + } + } + + // 8. check for CA if cert is not first or is the only certificate + // remaining in chain with no parent or is self-signed + if(error === null && + (!first || (chain.length === 0 && (!parent || selfSigned)))) { + // first check keyUsage extension and then basic constraints + var bcExt = cert.getExtension('basicConstraints'); + var keyUsageExt = cert.getExtension('keyUsage'); + if(keyUsageExt !== null) { + // keyCertSign must be true and there must be a basic + // constraints extension + if(!keyUsageExt.keyCertSign || bcExt === null) { + // bad certificate + error = { + message: + 'Certificate keyUsage or basicConstraints conflict ' + + 'or indicate that the certificate is not a CA. ' + + 'If the certificate is the only one in the chain or ' + + 'isn\'t the first then the certificate must be a ' + + 'valid CA.', + error: pki.certificateError.bad_certificate + }; + } + } + // basic constraints cA flag must be set + if(error === null && bcExt !== null && !bcExt.cA) { + // bad certificate + error = { + message: + 'Certificate basicConstraints indicates the certificate ' + + 'is not a CA.', + error: pki.certificateError.bad_certificate + }; + } + // if error is not null and keyUsage is available, then we know it + // has keyCertSign and there is a basic constraints extension too, + // which means we can check pathLenConstraint (if it exists) + if(error === null && keyUsageExt !== null && + 'pathLenConstraint' in bcExt) { + // pathLen is the maximum # of intermediate CA certs that can be + // found between the current certificate and the end-entity (depth 0) + // certificate; this number does not include the end-entity (depth 0, + // last in the chain) even if it happens to be a CA certificate itself + var pathLen = depth - 1; + if(pathLen > bcExt.pathLenConstraint) { + // pathLenConstraint violated, bad certificate + error = { + message: + 'Certificate basicConstraints pathLenConstraint violated.', + error: pki.certificateError.bad_certificate + }; + } + } + } + + // call application callback + var vfd = (error === null) ? true : error.error; + var ret = options.verify ? options.verify(vfd, depth, certs) : vfd; + if(ret === true) { + // clear any set error + error = null; + } else { + // if passed basic tests, set default message and alert + if(vfd === true) { + error = { + message: 'The application rejected the certificate.', + error: pki.certificateError.bad_certificate + }; + } + + // check for custom error info + if(ret || ret === 0) { + // set custom message and error + if(typeof ret === 'object' && !forge.util.isArray(ret)) { + if(ret.message) { + error.message = ret.message; + } + if(ret.error) { + error.error = ret.error; + } + } else if(typeof ret === 'string') { + // set custom error + error.error = ret; + } + } + + // throw error + throw error; + } + + // no longer first cert in chain + first = false; + ++depth; + } while(chain.length > 0); + + return true; + }; + }); + + var pkcs12 = createCommonjsModule(function (module) { + /** + * Javascript implementation of PKCS#12. + * + * @author Dave Longley + * @author Stefan Siegl + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + * Copyright (c) 2012 Stefan Siegl + * + * The ASN.1 representation of PKCS#12 is as follows + * (see ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12-tc1.pdf for details) + * + * PFX ::= SEQUENCE { + * version INTEGER {v3(3)}(v3,...), + * authSafe ContentInfo, + * macData MacData OPTIONAL + * } + * + * MacData ::= SEQUENCE { + * mac DigestInfo, + * macSalt OCTET STRING, + * iterations INTEGER DEFAULT 1 + * } + * Note: The iterations default is for historical reasons and its use is + * deprecated. A higher value, like 1024, is recommended. + * + * DigestInfo is defined in PKCS#7 as follows: + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters + * for the algorithm, if any. In the case of SHA1 there is none. + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * Digest ::= OCTET STRING + * + * + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL + * } + * + * ContentType ::= OBJECT IDENTIFIER + * + * AuthenticatedSafe ::= SEQUENCE OF ContentInfo + * -- Data if unencrypted + * -- EncryptedData if password-encrypted + * -- EnvelopedData if public key-encrypted + * + * + * SafeContents ::= SEQUENCE OF SafeBag + * + * SafeBag ::= SEQUENCE { + * bagId BAG-TYPE.&id ({PKCS12BagSet}) + * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), + * bagAttributes SET OF PKCS12Attribute OPTIONAL + * } + * + * PKCS12Attribute ::= SEQUENCE { + * attrId ATTRIBUTE.&id ({PKCS12AttrSet}), + * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId}) + * } -- This type is compatible with the X.500 type 'Attribute' + * + * PKCS12AttrSet ATTRIBUTE ::= { + * friendlyName | -- from PKCS #9 + * localKeyId, -- from PKCS #9 + * ... -- Other attributes are allowed + * } + * + * CertBag ::= SEQUENCE { + * certId BAG-TYPE.&id ({CertTypes}), + * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId}) + * } + * + * x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}} + * -- DER-encoded X.509 certificate stored in OCTET STRING + * + * sdsiCertificate BAG-TYPE ::= {IA5String IDENTIFIED BY {certTypes 2}} + * -- Base64-encoded SDSI certificate stored in IA5String + * + * CertTypes BAG-TYPE ::= { + * x509Certificate | + * sdsiCertificate, + * ... -- For future extensions + * } + */ + + + + + + + + + + + + + // shortcut for asn.1 & PKI API + var asn1 = forge.asn1; + var pki = forge.pki; + + // shortcut for PKCS#12 API + var p12 = module.exports = forge.pkcs12 = forge.pkcs12 || {}; + + var contentInfoValidator = { + name: 'ContentInfo', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, // a ContentInfo + constructed: true, + value: [{ + name: 'ContentInfo.contentType', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'contentType' + }, { + name: 'ContentInfo.content', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + constructed: true, + captureAsn1: 'content' + }] + }; + + var pfxValidator = { + name: 'PFX', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PFX.version', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + capture: 'version' + }, + contentInfoValidator, { + name: 'PFX.macData', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + optional: true, + captureAsn1: 'mac', + value: [{ + name: 'PFX.macData.mac', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, // DigestInfo + constructed: true, + value: [{ + name: 'PFX.macData.mac.digestAlgorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, // DigestAlgorithmIdentifier + constructed: true, + value: [{ + name: 'PFX.macData.mac.digestAlgorithm.algorithm', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'macAlgorithm' + }, { + name: 'PFX.macData.mac.digestAlgorithm.parameters', + tagClass: asn1.Class.UNIVERSAL, + captureAsn1: 'macAlgorithmParameters' + }] + }, { + name: 'PFX.macData.mac.digest', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OCTETSTRING, + constructed: false, + capture: 'macDigest' + }] + }, { + name: 'PFX.macData.macSalt', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OCTETSTRING, + constructed: false, + capture: 'macSalt' + }, { + name: 'PFX.macData.iterations', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.INTEGER, + constructed: false, + optional: true, + capture: 'macIterations' + }] + }] + }; + + var safeBagValidator = { + name: 'SafeBag', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SafeBag.bagId', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'bagId' + }, { + name: 'SafeBag.bagValue', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + constructed: true, + captureAsn1: 'bagValue' + }, { + name: 'SafeBag.bagAttributes', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SET, + constructed: true, + optional: true, + capture: 'bagAttributes' + }] + }; + + var attributeValidator = { + name: 'Attribute', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'Attribute.attrId', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'oid' + }, { + name: 'Attribute.attrValues', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SET, + constructed: true, + capture: 'values' + }] + }; + + var certBagValidator = { + name: 'CertBag', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'CertBag.certId', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.OID, + constructed: false, + capture: 'certId' + }, { + name: 'CertBag.certValue', + tagClass: asn1.Class.CONTEXT_SPECIFIC, + constructed: true, + /* So far we only support X.509 certificates (which are wrapped in + an OCTET STRING, hence hard code that here). */ + value: [{ + name: 'CertBag.certValue[0]', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Class.OCTETSTRING, + constructed: false, + capture: 'cert' + }] + }] + }; + + /** + * Search SafeContents structure for bags with matching attributes. + * + * The search can optionally be narrowed by a certain bag type. + * + * @param safeContents the SafeContents structure to search in. + * @param attrName the name of the attribute to compare against. + * @param attrValue the attribute value to search for. + * @param [bagType] bag type to narrow search by. + * + * @return an array of matching bags. + */ + function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) { + var result = []; + + for(var i = 0; i < safeContents.length; i++) { + for(var j = 0; j < safeContents[i].safeBags.length; j++) { + var bag = safeContents[i].safeBags[j]; + if(bagType !== undefined && bag.type !== bagType) { + continue; + } + // only filter by bag type, no attribute specified + if(attrName === null) { + result.push(bag); + continue; + } + if(bag.attributes[attrName] !== undefined && + bag.attributes[attrName].indexOf(attrValue) >= 0) { + result.push(bag); + } + } + } + + return result; + } + + /** + * Converts a PKCS#12 PFX in ASN.1 notation into a PFX object. + * + * @param obj The PKCS#12 PFX in ASN.1 notation. + * @param strict true to use strict DER decoding, false not to (default: true). + * @param {String} password Password to decrypt with (optional). + * + * @return PKCS#12 PFX object. + */ + p12.pkcs12FromAsn1 = function(obj, strict, password) { + // handle args + if(typeof strict === 'string') { + password = strict; + strict = true; + } else if(strict === undefined) { + strict = true; + } + + // validate PFX and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(obj, pfxValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#12 PFX. ' + + 'ASN.1 object is not an PKCS#12 PFX.'); + error.errors = error; + throw error; + } + + var pfx = { + version: capture.version.charCodeAt(0), + safeContents: [], + + /** + * Gets bags with matching attributes. + * + * @param filter the attributes to filter by: + * [localKeyId] the localKeyId to search for. + * [localKeyIdHex] the localKeyId in hex to search for. + * [friendlyName] the friendly name to search for. + * [bagType] bag type to narrow each attribute search by. + * + * @return a map of attribute type to an array of matching bags or, if no + * attribute was given but a bag type, the map key will be the + * bag type. + */ + getBags: function(filter) { + var rval = {}; + + var localKeyId; + if('localKeyId' in filter) { + localKeyId = filter.localKeyId; + } else if('localKeyIdHex' in filter) { + localKeyId = forge.util.hexToBytes(filter.localKeyIdHex); + } + + // filter on bagType only + if(localKeyId === undefined && !('friendlyName' in filter) && + 'bagType' in filter) { + rval[filter.bagType] = _getBagsByAttribute( + pfx.safeContents, null, null, filter.bagType); + } + + if(localKeyId !== undefined) { + rval.localKeyId = _getBagsByAttribute( + pfx.safeContents, 'localKeyId', + localKeyId, filter.bagType); + } + if('friendlyName' in filter) { + rval.friendlyName = _getBagsByAttribute( + pfx.safeContents, 'friendlyName', + filter.friendlyName, filter.bagType); + } + + return rval; + }, + + /** + * DEPRECATED: use getBags() instead. + * + * Get bags with matching friendlyName attribute. + * + * @param friendlyName the friendly name to search for. + * @param [bagType] bag type to narrow search by. + * + * @return an array of bags with matching friendlyName attribute. + */ + getBagsByFriendlyName: function(friendlyName, bagType) { + return _getBagsByAttribute( + pfx.safeContents, 'friendlyName', friendlyName, bagType); + }, + + /** + * DEPRECATED: use getBags() instead. + * + * Get bags with matching localKeyId attribute. + * + * @param localKeyId the localKeyId to search for. + * @param [bagType] bag type to narrow search by. + * + * @return an array of bags with matching localKeyId attribute. + */ + getBagsByLocalKeyId: function(localKeyId, bagType) { + return _getBagsByAttribute( + pfx.safeContents, 'localKeyId', localKeyId, bagType); + } + }; + + if(capture.version.charCodeAt(0) !== 3) { + var error = new Error('PKCS#12 PFX of version other than 3 not supported.'); + error.version = capture.version.charCodeAt(0); + throw error; + } + + if(asn1.derToOid(capture.contentType) !== pki.oids.data) { + var error = new Error('Only PKCS#12 PFX in password integrity mode supported.'); + error.oid = asn1.derToOid(capture.contentType); + throw error; + } + + var data = capture.content.value[0]; + if(data.tagClass !== asn1.Class.UNIVERSAL || + data.type !== asn1.Type.OCTETSTRING) { + throw new Error('PKCS#12 authSafe content data is not an OCTET STRING.'); + } + data = _decodePkcs7Data(data); + + // check for MAC + if(capture.mac) { + var md = null; + var macKeyBytes = 0; + var macAlgorithm = asn1.derToOid(capture.macAlgorithm); + switch(macAlgorithm) { + case pki.oids.sha1: + md = forge.md.sha1.create(); + macKeyBytes = 20; + break; + case pki.oids.sha256: + md = forge.md.sha256.create(); + macKeyBytes = 32; + break; + case pki.oids.sha384: + md = forge.md.sha384.create(); + macKeyBytes = 48; + break; + case pki.oids.sha512: + md = forge.md.sha512.create(); + macKeyBytes = 64; + break; + case pki.oids.md5: + md = forge.md.md5.create(); + macKeyBytes = 16; + break; + } + if(md === null) { + throw new Error('PKCS#12 uses unsupported MAC algorithm: ' + macAlgorithm); + } + + // verify MAC (iterations default to 1) + var macSalt = new forge.util.ByteBuffer(capture.macSalt); + var macIterations = (('macIterations' in capture) ? + parseInt(forge.util.bytesToHex(capture.macIterations), 16) : 1); + var macKey = p12.generateKey( + password, macSalt, 3, macIterations, macKeyBytes, md); + var mac = forge.hmac.create(); + mac.start(md, macKey); + mac.update(data.value); + var macValue = mac.getMac(); + if(macValue.getBytes() !== capture.macDigest) { + throw new Error('PKCS#12 MAC could not be verified. Invalid password?'); + } + } + + _decodeAuthenticatedSafe(pfx, data.value, strict, password); + return pfx; + }; + + /** + * Decodes PKCS#7 Data. PKCS#7 (RFC 2315) defines "Data" as an OCTET STRING, + * but it is sometimes an OCTET STRING that is composed/constructed of chunks, + * each its own OCTET STRING. This is BER-encoding vs. DER-encoding. This + * function transforms this corner-case into the usual simple, + * non-composed/constructed OCTET STRING. + * + * This function may be moved to ASN.1 at some point to better deal with + * more BER-encoding issues, should they arise. + * + * @param data the ASN.1 Data object to transform. + */ + function _decodePkcs7Data(data) { + // handle special case of "chunked" data content: an octet string composed + // of other octet strings + if(data.composed || data.constructed) { + var value = forge.util.createBuffer(); + for(var i = 0; i < data.value.length; ++i) { + value.putBytes(data.value[i].value); + } + data.composed = data.constructed = false; + data.value = value.getBytes(); + } + return data; + } + + /** + * Decode PKCS#12 AuthenticatedSafe (BER encoded) into PFX object. + * + * The AuthenticatedSafe is a BER-encoded SEQUENCE OF ContentInfo. + * + * @param pfx The PKCS#12 PFX object to fill. + * @param {String} authSafe BER-encoded AuthenticatedSafe. + * @param strict true to use strict DER decoding, false not to. + * @param {String} password Password to decrypt with (optional). + */ + function _decodeAuthenticatedSafe(pfx, authSafe, strict, password) { + authSafe = asn1.fromDer(authSafe, strict); /* actually it's BER encoded */ + + if(authSafe.tagClass !== asn1.Class.UNIVERSAL || + authSafe.type !== asn1.Type.SEQUENCE || + authSafe.constructed !== true) { + throw new Error('PKCS#12 AuthenticatedSafe expected to be a ' + + 'SEQUENCE OF ContentInfo'); + } + + for(var i = 0; i < authSafe.value.length; i++) { + var contentInfo = authSafe.value[i]; + + // validate contentInfo and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(contentInfo, contentInfoValidator, capture, errors)) { + var error = new Error('Cannot read ContentInfo.'); + error.errors = errors; + throw error; + } + + var obj = { + encrypted: false + }; + var safeContents = null; + var data = capture.content.value[0]; + switch(asn1.derToOid(capture.contentType)) { + case pki.oids.data: + if(data.tagClass !== asn1.Class.UNIVERSAL || + data.type !== asn1.Type.OCTETSTRING) { + throw new Error('PKCS#12 SafeContents Data is not an OCTET STRING.'); + } + safeContents = _decodePkcs7Data(data).value; + break; + case pki.oids.encryptedData: + safeContents = _decryptSafeContents(data, password); + obj.encrypted = true; + break; + default: + var error = new Error('Unsupported PKCS#12 contentType.'); + error.contentType = asn1.derToOid(capture.contentType); + throw error; + } + + obj.safeBags = _decodeSafeContents(safeContents, strict, password); + pfx.safeContents.push(obj); + } + } + + /** + * Decrypt PKCS#7 EncryptedData structure. + * + * @param data ASN.1 encoded EncryptedContentInfo object. + * @param password The user-provided password. + * + * @return The decrypted SafeContents (ASN.1 object). + */ + function _decryptSafeContents(data, password) { + var capture = {}; + var errors = []; + if(!asn1.validate( + data, forge.pkcs7.asn1.encryptedDataValidator, capture, errors)) { + var error = new Error('Cannot read EncryptedContentInfo.'); + error.errors = errors; + throw error; + } + + var oid = asn1.derToOid(capture.contentType); + if(oid !== pki.oids.data) { + var error = new Error( + 'PKCS#12 EncryptedContentInfo ContentType is not Data.'); + error.oid = oid; + throw error; + } + + // get cipher + oid = asn1.derToOid(capture.encAlgorithm); + var cipher = pki.pbe.getCipher(oid, capture.encParameter, password); + + // get encrypted data + var encryptedContentAsn1 = _decodePkcs7Data(capture.encryptedContentAsn1); + var encrypted = forge.util.createBuffer(encryptedContentAsn1.value); + + cipher.update(encrypted); + if(!cipher.finish()) { + throw new Error('Failed to decrypt PKCS#12 SafeContents.'); + } + + return cipher.output.getBytes(); + } + + /** + * Decode PKCS#12 SafeContents (BER-encoded) into array of Bag objects. + * + * The safeContents is a BER-encoded SEQUENCE OF SafeBag. + * + * @param {String} safeContents BER-encoded safeContents. + * @param strict true to use strict DER decoding, false not to. + * @param {String} password Password to decrypt with (optional). + * + * @return {Array} Array of Bag objects. + */ + function _decodeSafeContents(safeContents, strict, password) { + // if strict and no safe contents, return empty safes + if(!strict && safeContents.length === 0) { + return []; + } + + // actually it's BER-encoded + safeContents = asn1.fromDer(safeContents, strict); + + if(safeContents.tagClass !== asn1.Class.UNIVERSAL || + safeContents.type !== asn1.Type.SEQUENCE || + safeContents.constructed !== true) { + throw new Error( + 'PKCS#12 SafeContents expected to be a SEQUENCE OF SafeBag.'); + } + + var res = []; + for(var i = 0; i < safeContents.value.length; i++) { + var safeBag = safeContents.value[i]; + + // validate SafeBag and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(safeBag, safeBagValidator, capture, errors)) { + var error = new Error('Cannot read SafeBag.'); + error.errors = errors; + throw error; + } + + /* Create bag object and push to result array. */ + var bag = { + type: asn1.derToOid(capture.bagId), + attributes: _decodeBagAttributes(capture.bagAttributes) + }; + res.push(bag); + + var validator, decoder; + var bagAsn1 = capture.bagValue.value[0]; + switch(bag.type) { + case pki.oids.pkcs8ShroudedKeyBag: + /* bagAsn1 has a EncryptedPrivateKeyInfo, which we need to decrypt. + Afterwards we can handle it like a keyBag, + which is a PrivateKeyInfo. */ + bagAsn1 = pki.decryptPrivateKeyInfo(bagAsn1, password); + if(bagAsn1 === null) { + throw new Error( + 'Unable to decrypt PKCS#8 ShroudedKeyBag, wrong password?'); + } + + /* fall through */ + case pki.oids.keyBag: + /* A PKCS#12 keyBag is a simple PrivateKeyInfo as understood by our + PKI module, hence we don't have to do validation/capturing here, + just pass what we already got. */ + try { + bag.key = pki.privateKeyFromAsn1(bagAsn1); + } catch(e) { + // ignore unknown key type, pass asn1 value + bag.key = null; + bag.asn1 = bagAsn1; + } + continue; /* Nothing more to do. */ + + case pki.oids.certBag: + /* A PKCS#12 certBag can wrap both X.509 and sdsi certificates. + Therefore put the SafeBag content through another validator to + capture the fields. Afterwards check & store the results. */ + validator = certBagValidator; + decoder = function() { + if(asn1.derToOid(capture.certId) !== pki.oids.x509Certificate) { + var error = new Error( + 'Unsupported certificate type, only X.509 supported.'); + error.oid = asn1.derToOid(capture.certId); + throw error; + } + + // true=produce cert hash + var certAsn1 = asn1.fromDer(capture.cert, strict); + try { + bag.cert = pki.certificateFromAsn1(certAsn1, true); + } catch(e) { + // ignore unknown cert type, pass asn1 value + bag.cert = null; + bag.asn1 = certAsn1; + } + }; + break; + + default: + var error = new Error('Unsupported PKCS#12 SafeBag type.'); + error.oid = bag.type; + throw error; + } + + /* Validate SafeBag value (i.e. CertBag, etc.) and capture data if needed. */ + if(validator !== undefined && + !asn1.validate(bagAsn1, validator, capture, errors)) { + var error = new Error('Cannot read PKCS#12 ' + validator.name); + error.errors = errors; + throw error; + } + + /* Call decoder function from above to store the results. */ + decoder(); + } + + return res; + } + + /** + * Decode PKCS#12 SET OF PKCS12Attribute into JavaScript object. + * + * @param attributes SET OF PKCS12Attribute (ASN.1 object). + * + * @return the decoded attributes. + */ + function _decodeBagAttributes(attributes) { + var decodedAttrs = {}; + + if(attributes !== undefined) { + for(var i = 0; i < attributes.length; ++i) { + var capture = {}; + var errors = []; + if(!asn1.validate(attributes[i], attributeValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#12 BagAttribute.'); + error.errors = errors; + throw error; + } + + var oid = asn1.derToOid(capture.oid); + if(pki.oids[oid] === undefined) { + // unsupported attribute type, ignore. + continue; + } + + decodedAttrs[pki.oids[oid]] = []; + for(var j = 0; j < capture.values.length; ++j) { + decodedAttrs[pki.oids[oid]].push(capture.values[j].value); + } + } + } + + return decodedAttrs; + } + + /** + * Wraps a private key and certificate in a PKCS#12 PFX wrapper. If a + * password is provided then the private key will be encrypted. + * + * An entire certificate chain may also be included. To do this, pass + * an array for the "cert" parameter where the first certificate is + * the one that is paired with the private key and each subsequent one + * verifies the previous one. The certificates may be in PEM format or + * have been already parsed by Forge. + * + * @todo implement password-based-encryption for the whole package + * + * @param key the private key. + * @param cert the certificate (may be an array of certificates in order + * to specify a certificate chain). + * @param password the password to use, null for none. + * @param options: + * algorithm the encryption algorithm to use + * ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'. + * count the iteration count to use. + * saltSize the salt size to use. + * useMac true to include a MAC, false not to, defaults to true. + * localKeyId the local key ID to use, in hex. + * friendlyName the friendly name to use. + * generateLocalKeyId true to generate a random local key ID, + * false not to, defaults to true. + * + * @return the PKCS#12 PFX ASN.1 object. + */ + p12.toPkcs12Asn1 = function(key, cert, password, options) { + // set default options + options = options || {}; + options.saltSize = options.saltSize || 8; + options.count = options.count || 2048; + options.algorithm = options.algorithm || options.encAlgorithm || 'aes128'; + if(!('useMac' in options)) { + options.useMac = true; + } + if(!('localKeyId' in options)) { + options.localKeyId = null; + } + if(!('generateLocalKeyId' in options)) { + options.generateLocalKeyId = true; + } + + var localKeyId = options.localKeyId; + var bagAttrs; + if(localKeyId !== null) { + localKeyId = forge.util.hexToBytes(localKeyId); + } else if(options.generateLocalKeyId) { + // use SHA-1 of paired cert, if available + if(cert) { + var pairedCert = forge.util.isArray(cert) ? cert[0] : cert; + if(typeof pairedCert === 'string') { + pairedCert = pki.certificateFromPem(pairedCert); + } + var sha1 = forge.md.sha1.create(); + sha1.update(asn1.toDer(pki.certificateToAsn1(pairedCert)).getBytes()); + localKeyId = sha1.digest().getBytes(); + } else { + // FIXME: consider using SHA-1 of public key (which can be generated + // from private key components), see: cert.generateSubjectKeyIdentifier + // generate random bytes + localKeyId = forge.random.getBytes(20); + } + } + + var attrs = []; + if(localKeyId !== null) { + attrs.push( + // localKeyID + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // attrId + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.localKeyId).getBytes()), + // attrValues + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + localKeyId) + ]) + ])); + } + if('friendlyName' in options) { + attrs.push( + // friendlyName + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // attrId + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.friendlyName).getBytes()), + // attrValues + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BMPSTRING, false, + options.friendlyName) + ]) + ])); + } + + if(attrs.length > 0) { + bagAttrs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, attrs); + } + + // collect contents for AuthenticatedSafe + var contents = []; + + // create safe bag(s) for certificate chain + var chain = []; + if(cert !== null) { + if(forge.util.isArray(cert)) { + chain = cert; + } else { + chain = [cert]; + } + } + + var certSafeBags = []; + for(var i = 0; i < chain.length; ++i) { + // convert cert from PEM as necessary + cert = chain[i]; + if(typeof cert === 'string') { + cert = pki.certificateFromPem(cert); + } + + // SafeBag + var certBagAttrs = (i === 0) ? bagAttrs : undefined; + var certAsn1 = pki.certificateToAsn1(cert); + var certSafeBag = + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // bagId + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.certBag).getBytes()), + // bagValue + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + // CertBag + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // certId + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.x509Certificate).getBytes()), + // certValue (x509Certificate) + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + asn1.toDer(certAsn1).getBytes()) + ])])]), + // bagAttributes (OPTIONAL) + certBagAttrs + ]); + certSafeBags.push(certSafeBag); + } + + if(certSafeBags.length > 0) { + // SafeContents + var certSafeContents = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, certSafeBags); + + // ContentInfo + var certCI = + // PKCS#7 ContentInfo + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // contentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + // OID for the content type is 'data' + asn1.oidToDer(pki.oids.data).getBytes()), + // content + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + asn1.toDer(certSafeContents).getBytes()) + ]) + ]); + contents.push(certCI); + } + + // create safe contents for private key + var keyBag = null; + if(key !== null) { + // SafeBag + var pkAsn1 = pki.wrapRsaPrivateKey(pki.privateKeyToAsn1(key)); + if(password === null) { + // no encryption + keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // bagId + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.keyBag).getBytes()), + // bagValue + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + // PrivateKeyInfo + pkAsn1 + ]), + // bagAttributes (OPTIONAL) + bagAttrs + ]); + } else { + // encrypted PrivateKeyInfo + keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // bagId + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.pkcs8ShroudedKeyBag).getBytes()), + // bagValue + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + // EncryptedPrivateKeyInfo + pki.encryptPrivateKeyInfo(pkAsn1, password, options) + ]), + // bagAttributes (OPTIONAL) + bagAttrs + ]); + } + + // SafeContents + var keySafeContents = + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [keyBag]); + + // ContentInfo + var keyCI = + // PKCS#7 ContentInfo + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // contentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + // OID for the content type is 'data' + asn1.oidToDer(pki.oids.data).getBytes()), + // content + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + asn1.toDer(keySafeContents).getBytes()) + ]) + ]); + contents.push(keyCI); + } + + // create AuthenticatedSafe by stringing together the contents + var safe = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, contents); + + var macData; + if(options.useMac) { + // MacData + var sha1 = forge.md.sha1.create(); + var macSalt = new forge.util.ByteBuffer( + forge.random.getBytes(options.saltSize)); + var count = options.count; + // 160-bit key + var key = p12.generateKey(password, macSalt, 3, count, 20); + var mac = forge.hmac.create(); + mac.start(sha1, key); + mac.update(asn1.toDer(safe).getBytes()); + var macValue = mac.getMac(); + macData = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // mac DigestInfo + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // digestAlgorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm = SHA-1 + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(pki.oids.sha1).getBytes()), + // parameters = Null + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]), + // digest + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, + false, macValue.getBytes()) + ]), + // macSalt OCTET STRING + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, macSalt.getBytes()), + // iterations INTEGER (XXX: Only support count < 65536) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(count).getBytes() + ) + ]); + } + + // PFX + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // version (3) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(3).getBytes()), + // PKCS#7 ContentInfo + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // contentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + // OID for the content type is 'data' + asn1.oidToDer(pki.oids.data).getBytes()), + // content + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + asn1.toDer(safe).getBytes()) + ]) + ]), + macData + ]); + }; + + /** + * Derives a PKCS#12 key. + * + * @param password the password to derive the key material from, null or + * undefined for none. + * @param salt the salt, as a ByteBuffer, to use. + * @param id the PKCS#12 ID byte (1 = key material, 2 = IV, 3 = MAC). + * @param iter the iteration count. + * @param n the number of bytes to derive from the password. + * @param md the message digest to use, defaults to SHA-1. + * + * @return a ByteBuffer with the bytes derived from the password. + */ + p12.generateKey = forge.pbe.generatePkcs12Key; + }); + + var pki_1 = createCommonjsModule(function (module) { + /** + * Javascript implementation of a basic Public Key Infrastructure, including + * support for RSA public and private keys. + * + * @author Dave Longley + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + */ + + + + + + + + + + + + + // shortcut for asn.1 API + var asn1 = forge.asn1; + + /* Public Key Infrastructure (PKI) implementation. */ + var pki = module.exports = forge.pki = forge.pki || {}; + + /** + * NOTE: THIS METHOD IS DEPRECATED. Use pem.decode() instead. + * + * Converts PEM-formatted data to DER. + * + * @param pem the PEM-formatted data. + * + * @return the DER-formatted data. + */ + pki.pemToDer = function(pem) { + var msg = forge.pem.decode(pem)[0]; + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert PEM to DER; PEM is encrypted.'); + } + return forge.util.createBuffer(msg.body); + }; + + /** + * Converts an RSA private key from PEM format. + * + * @param pem the PEM-formatted private key. + * + * @return the private key. + */ + pki.privateKeyFromPem = function(pem) { + var msg = forge.pem.decode(pem)[0]; + + if(msg.type !== 'PRIVATE KEY' && msg.type !== 'RSA PRIVATE KEY') { + var error = new Error('Could not convert private key from PEM; PEM ' + + 'header type is not "PRIVATE KEY" or "RSA PRIVATE KEY".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert private key from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1.fromDer(msg.body); + + return pki.privateKeyFromAsn1(obj); + }; + + /** + * Converts an RSA private key to PEM format. + * + * @param key the private key. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted private key. + */ + pki.privateKeyToPem = function(key, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'RSA PRIVATE KEY', + body: asn1.toDer(pki.privateKeyToAsn1(key)).getBytes() + }; + return forge.pem.encode(msg, {maxline: maxline}); + }; + + /** + * Converts a PrivateKeyInfo to PEM format. + * + * @param pki the PrivateKeyInfo. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted private key. + */ + pki.privateKeyInfoToPem = function(pki, maxline) { + // convert to DER, then PEM-encode + var msg = { + type: 'PRIVATE KEY', + body: asn1.toDer(pki).getBytes() + }; + return forge.pem.encode(msg, {maxline: maxline}); + }; + }); + + /** + * A Javascript implementation of Transport Layer Security (TLS). + * + * @author Dave Longley + * + * Copyright (c) 2009-2014 Digital Bazaar, Inc. + * + * The TLS Handshake Protocol involves the following steps: + * + * - Exchange hello messages to agree on algorithms, exchange random values, + * and check for session resumption. + * + * - Exchange the necessary cryptographic parameters to allow the client and + * server to agree on a premaster secret. + * + * - Exchange certificates and cryptographic information to allow the client + * and server to authenticate themselves. + * + * - Generate a master secret from the premaster secret and exchanged random + * values. + * + * - Provide security parameters to the record layer. + * + * - Allow the client and server to verify that their peer has calculated the + * same security parameters and that the handshake occurred without tampering + * by an attacker. + * + * Up to 4 different messages may be sent during a key exchange. The server + * certificate, the server key exchange, the client certificate, and the + * client key exchange. + * + * A typical handshake (from the client's perspective). + * + * 1. Client sends ClientHello. + * 2. Client receives ServerHello. + * 3. Client receives optional Certificate. + * 4. Client receives optional ServerKeyExchange. + * 5. Client receives ServerHelloDone. + * 6. Client sends optional Certificate. + * 7. Client sends ClientKeyExchange. + * 8. Client sends optional CertificateVerify. + * 9. Client sends ChangeCipherSpec. + * 10. Client sends Finished. + * 11. Client receives ChangeCipherSpec. + * 12. Client receives Finished. + * 13. Client sends/receives application data. + * + * To reuse an existing session: + * + * 1. Client sends ClientHello with session ID for reuse. + * 2. Client receives ServerHello with same session ID if reusing. + * 3. Client receives ChangeCipherSpec message if reusing. + * 4. Client receives Finished. + * 5. Client sends ChangeCipherSpec. + * 6. Client sends Finished. + * + * Note: Client ignores HelloRequest if in the middle of a handshake. + * + * Record Layer: + * + * The record layer fragments information blocks into TLSPlaintext records + * carrying data in chunks of 2^14 bytes or less. Client message boundaries are + * not preserved in the record layer (i.e., multiple client messages of the + * same ContentType MAY be coalesced into a single TLSPlaintext record, or a + * single message MAY be fragmented across several records). + * + * struct { + * uint8 major; + * uint8 minor; + * } ProtocolVersion; + * + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * opaque fragment[TLSPlaintext.length]; + * } TLSPlaintext; + * + * type: + * The higher-level protocol used to process the enclosed fragment. + * + * version: + * The version of the protocol being employed. TLS Version 1.2 uses version + * {3, 3}. TLS Version 1.0 uses version {3, 1}. Note that a client that + * supports multiple versions of TLS may not know what version will be + * employed before it receives the ServerHello. + * + * length: + * The length (in bytes) of the following TLSPlaintext.fragment. The length + * MUST NOT exceed 2^14 = 16384 bytes. + * + * fragment: + * The application data. This data is transparent and treated as an + * independent block to be dealt with by the higher-level protocol specified + * by the type field. + * + * Implementations MUST NOT send zero-length fragments of Handshake, Alert, or + * ChangeCipherSpec content types. Zero-length fragments of Application data + * MAY be sent as they are potentially useful as a traffic analysis + * countermeasure. + * + * Note: Data of different TLS record layer content types MAY be interleaved. + * Application data is generally of lower precedence for transmission than + * other content types. However, records MUST be delivered to the network in + * the same order as they are protected by the record layer. Recipients MUST + * receive and process interleaved application layer traffic during handshakes + * subsequent to the first one on a connection. + * + * struct { + * ContentType type; // same as TLSPlaintext.type + * ProtocolVersion version;// same as TLSPlaintext.version + * uint16 length; + * opaque fragment[TLSCompressed.length]; + * } TLSCompressed; + * + * length: + * The length (in bytes) of the following TLSCompressed.fragment. + * The length MUST NOT exceed 2^14 + 1024. + * + * fragment: + * The compressed form of TLSPlaintext.fragment. + * + * Note: A CompressionMethod.null operation is an identity operation; no fields + * are altered. In this implementation, since no compression is supported, + * uncompressed records are always the same as compressed records. + * + * Encryption Information: + * + * The encryption and MAC functions translate a TLSCompressed structure into a + * TLSCiphertext. The decryption functions reverse the process. The MAC of the + * record also includes a sequence number so that missing, extra, or repeated + * messages are detectable. + * + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * select (SecurityParameters.cipher_type) { + * case stream: GenericStreamCipher; + * case block: GenericBlockCipher; + * case aead: GenericAEADCipher; + * } fragment; + * } TLSCiphertext; + * + * type: + * The type field is identical to TLSCompressed.type. + * + * version: + * The version field is identical to TLSCompressed.version. + * + * length: + * The length (in bytes) of the following TLSCiphertext.fragment. + * The length MUST NOT exceed 2^14 + 2048. + * + * fragment: + * The encrypted form of TLSCompressed.fragment, with the MAC. + * + * Note: Only CBC Block Ciphers are supported by this implementation. + * + * The TLSCompressed.fragment structures are converted to/from block + * TLSCiphertext.fragment structures. + * + * struct { + * opaque IV[SecurityParameters.record_iv_length]; + * block-ciphered struct { + * opaque content[TLSCompressed.length]; + * opaque MAC[SecurityParameters.mac_length]; + * uint8 padding[GenericBlockCipher.padding_length]; + * uint8 padding_length; + * }; + * } GenericBlockCipher; + * + * The MAC is generated as described in Section 6.2.3.1. + * + * IV: + * The Initialization Vector (IV) SHOULD be chosen at random, and MUST be + * unpredictable. Note that in versions of TLS prior to 1.1, there was no + * IV field, and the last ciphertext block of the previous record (the "CBC + * residue") was used as the IV. This was changed to prevent the attacks + * described in [CBCATT]. For block ciphers, the IV length is of length + * SecurityParameters.record_iv_length, which is equal to the + * SecurityParameters.block_size. + * + * padding: + * Padding that is added to force the length of the plaintext to be an + * integral multiple of the block cipher's block length. The padding MAY be + * any length up to 255 bytes, as long as it results in the + * TLSCiphertext.length being an integral multiple of the block length. + * Lengths longer than necessary might be desirable to frustrate attacks on + * a protocol that are based on analysis of the lengths of exchanged + * messages. Each uint8 in the padding data vector MUST be filled with the + * padding length value. The receiver MUST check this padding and MUST use + * the bad_record_mac alert to indicate padding errors. + * + * padding_length: + * The padding length MUST be such that the total size of the + * GenericBlockCipher structure is a multiple of the cipher's block length. + * Legal values range from zero to 255, inclusive. This length specifies the + * length of the padding field exclusive of the padding_length field itself. + * + * The encrypted data length (TLSCiphertext.length) is one more than the sum of + * SecurityParameters.block_length, TLSCompressed.length, + * SecurityParameters.mac_length, and padding_length. + * + * Example: If the block length is 8 bytes, the content length + * (TLSCompressed.length) is 61 bytes, and the MAC length is 20 bytes, then the + * length before padding is 82 bytes (this does not include the IV. Thus, the + * padding length modulo 8 must be equal to 6 in order to make the total length + * an even multiple of 8 bytes (the block length). The padding length can be + * 6, 14, 22, and so on, through 254. If the padding length were the minimum + * necessary, 6, the padding would be 6 bytes, each containing the value 6. + * Thus, the last 8 octets of the GenericBlockCipher before block encryption + * would be xx 06 06 06 06 06 06 06, where xx is the last octet of the MAC. + * + * Note: With block ciphers in CBC mode (Cipher Block Chaining), it is critical + * that the entire plaintext of the record be known before any ciphertext is + * transmitted. Otherwise, it is possible for the attacker to mount the attack + * described in [CBCATT]. + * + * Implementation note: Canvel et al. [CBCTIME] have demonstrated a timing + * attack on CBC padding based on the time required to compute the MAC. In + * order to defend against this attack, implementations MUST ensure that + * record processing time is essentially the same whether or not the padding + * is correct. In general, the best way to do this is to compute the MAC even + * if the padding is incorrect, and only then reject the packet. For instance, + * if the pad appears to be incorrect, the implementation might assume a + * zero-length pad and then compute the MAC. This leaves a small timing + * channel, since MAC performance depends, to some extent, on the size of the + * data fragment, but it is not believed to be large enough to be exploitable, + * due to the large block size of existing MACs and the small size of the + * timing signal. + */ + + + + + + + + + + + /** + * Generates pseudo random bytes by mixing the result of two hash functions, + * MD5 and SHA-1. + * + * prf_TLS1(secret, label, seed) = + * P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed); + * + * Each P_hash function functions as follows: + * + * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + + * HMAC_hash(secret, A(2) + seed) + + * HMAC_hash(secret, A(3) + seed) + ... + * A() is defined as: + * A(0) = seed + * A(i) = HMAC_hash(secret, A(i-1)) + * + * The '+' operator denotes concatenation. + * + * As many iterations A(N) as are needed are performed to generate enough + * pseudo random byte output. If an iteration creates more data than is + * necessary, then it is truncated. + * + * Therefore: + * A(1) = HMAC_hash(secret, A(0)) + * = HMAC_hash(secret, seed) + * A(2) = HMAC_hash(secret, A(1)) + * = HMAC_hash(secret, HMAC_hash(secret, seed)) + * + * Therefore: + * P_hash(secret, seed) = + * HMAC_hash(secret, HMAC_hash(secret, A(0)) + seed) + + * HMAC_hash(secret, HMAC_hash(secret, A(1)) + seed) + + * ... + * + * Therefore: + * P_hash(secret, seed) = + * HMAC_hash(secret, HMAC_hash(secret, seed) + seed) + + * HMAC_hash(secret, HMAC_hash(secret, HMAC_hash(secret, seed)) + seed) + + * ... + * + * @param secret the secret to use. + * @param label the label to use. + * @param seed the seed value to use. + * @param length the number of bytes to generate. + * + * @return the pseudo random bytes in a byte buffer. + */ + var prf_TLS1 = function(secret, label, seed, length) { + var rval = forge.util.createBuffer(); + + /* For TLS 1.0, the secret is split in half, into two secrets of equal + length. If the secret has an odd length then the last byte of the first + half will be the same as the first byte of the second. The length of the + two secrets is half of the secret rounded up. */ + var idx = (secret.length >> 1); + var slen = idx + (secret.length & 1); + var s1 = secret.substr(0, slen); + var s2 = secret.substr(idx, slen); + var ai = forge.util.createBuffer(); + var hmac = forge.hmac.create(); + seed = label + seed; + + // determine the number of iterations that must be performed to generate + // enough output bytes, md5 creates 16 byte hashes, sha1 creates 20 + var md5itr = Math.ceil(length / 16); + var sha1itr = Math.ceil(length / 20); + + // do md5 iterations + hmac.start('MD5', s1); + var md5bytes = forge.util.createBuffer(); + ai.putBytes(seed); + for(var i = 0; i < md5itr; ++i) { + // HMAC_hash(secret, A(i-1)) + hmac.start(null, null); + hmac.update(ai.getBytes()); + ai.putBuffer(hmac.digest()); + + // HMAC_hash(secret, A(i) + seed) + hmac.start(null, null); + hmac.update(ai.bytes() + seed); + md5bytes.putBuffer(hmac.digest()); + } + + // do sha1 iterations + hmac.start('SHA1', s2); + var sha1bytes = forge.util.createBuffer(); + ai.clear(); + ai.putBytes(seed); + for(var i = 0; i < sha1itr; ++i) { + // HMAC_hash(secret, A(i-1)) + hmac.start(null, null); + hmac.update(ai.getBytes()); + ai.putBuffer(hmac.digest()); + + // HMAC_hash(secret, A(i) + seed) + hmac.start(null, null); + hmac.update(ai.bytes() + seed); + sha1bytes.putBuffer(hmac.digest()); + } + + // XOR the md5 bytes with the sha1 bytes + rval.putBytes(forge.util.xorBytes( + md5bytes.getBytes(), sha1bytes.getBytes(), length)); + + return rval; + }; + + /** + * Gets a MAC for a record using the SHA-1 hash algorithm. + * + * @param key the mac key. + * @param state the sequence number (array of two 32-bit integers). + * @param record the record. + * + * @return the sha-1 hash (20 bytes) for the given record. + */ + var hmac_sha1 = function(key, seqNum, record) { + /* MAC is computed like so: + HMAC_hash( + key, seqNum + + TLSCompressed.type + + TLSCompressed.version + + TLSCompressed.length + + TLSCompressed.fragment) + */ + var hmac = forge.hmac.create(); + hmac.start('SHA1', key); + var b = forge.util.createBuffer(); + b.putInt32(seqNum[0]); + b.putInt32(seqNum[1]); + b.putByte(record.type); + b.putByte(record.version.major); + b.putByte(record.version.minor); + b.putInt16(record.length); + b.putBytes(record.fragment.bytes()); + hmac.update(b.getBytes()); + return hmac.digest().getBytes(); + }; + + /** + * Compresses the TLSPlaintext record into a TLSCompressed record using the + * deflate algorithm. + * + * @param c the TLS connection. + * @param record the TLSPlaintext record to compress. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ + var deflate = function(c, record, s) { + var rval = false; + + try { + var bytes = c.deflate(record.fragment.getBytes()); + record.fragment = forge.util.createBuffer(bytes); + record.length = bytes.length; + rval = true; + } catch(ex) { + // deflate error, fail out + } + + return rval; + }; + + /** + * Decompresses the TLSCompressed record into a TLSPlaintext record using the + * deflate algorithm. + * + * @param c the TLS connection. + * @param record the TLSCompressed record to decompress. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ + var inflate = function(c, record, s) { + var rval = false; + + try { + var bytes = c.inflate(record.fragment.getBytes()); + record.fragment = forge.util.createBuffer(bytes); + record.length = bytes.length; + rval = true; + } catch(ex) { + // inflate error, fail out + } + + return rval; + }; + + /** + * Reads a TLS variable-length vector from a byte buffer. + * + * Variable-length vectors are defined by specifying a subrange of legal + * lengths, inclusively, using the notation . When these are + * encoded, the actual length precedes the vector's contents in the byte + * stream. The length will be in the form of a number consuming as many bytes + * as required to hold the vector's specified maximum (ceiling) length. A + * variable-length vector with an actual length field of zero is referred to + * as an empty vector. + * + * @param b the byte buffer. + * @param lenBytes the number of bytes required to store the length. + * + * @return the resulting byte buffer. + */ + var readVector = function(b, lenBytes) { + var len = 0; + switch(lenBytes) { + case 1: + len = b.getByte(); + break; + case 2: + len = b.getInt16(); + break; + case 3: + len = b.getInt24(); + break; + case 4: + len = b.getInt32(); + break; + } + + // read vector bytes into a new buffer + return forge.util.createBuffer(b.getBytes(len)); + }; + + /** + * Writes a TLS variable-length vector to a byte buffer. + * + * @param b the byte buffer. + * @param lenBytes the number of bytes required to store the length. + * @param v the byte buffer vector. + */ + var writeVector = function(b, lenBytes, v) { + // encode length at the start of the vector, where the number of bytes for + // the length is the maximum number of bytes it would take to encode the + // vector's ceiling + b.putInt(v.length(), lenBytes << 3); + b.putBuffer(v); + }; + + /** + * The tls implementation. + */ + var tls = {}; + + /** + * Version: TLS 1.2 = 3.3, TLS 1.1 = 3.2, TLS 1.0 = 3.1. Both TLS 1.1 and + * TLS 1.2 were still too new (ie: openSSL didn't implement them) at the time + * of this implementation so TLS 1.0 was implemented instead. + */ + tls.Versions = { + TLS_1_0: {major: 3, minor: 1}, + TLS_1_1: {major: 3, minor: 2}, + TLS_1_2: {major: 3, minor: 3} + }; + tls.SupportedVersions = [ + tls.Versions.TLS_1_1, + tls.Versions.TLS_1_0 + ]; + tls.Version = tls.SupportedVersions[0]; + + /** + * Maximum fragment size. True maximum is 16384, but we fragment before that + * to allow for unusual small increases during compression. + */ + tls.MaxFragment = 16384 - 1024; + + /** + * Whether this entity is considered the "client" or "server". + * enum { server, client } ConnectionEnd; + */ + tls.ConnectionEnd = { + server: 0, + client: 1 + }; + + /** + * Pseudo-random function algorithm used to generate keys from the master + * secret. + * enum { tls_prf_sha256 } PRFAlgorithm; + */ + tls.PRFAlgorithm = { + tls_prf_sha256: 0 + }; + + /** + * Bulk encryption algorithms. + * enum { null, rc4, des3, aes } BulkCipherAlgorithm; + */ + tls.BulkCipherAlgorithm = { + none: null, + rc4: 0, + des3: 1, + aes: 2 + }; + + /** + * Cipher types. + * enum { stream, block, aead } CipherType; + */ + tls.CipherType = { + stream: 0, + block: 1, + aead: 2 + }; + + /** + * MAC (Message Authentication Code) algorithms. + * enum { null, hmac_md5, hmac_sha1, hmac_sha256, + * hmac_sha384, hmac_sha512} MACAlgorithm; + */ + tls.MACAlgorithm = { + none: null, + hmac_md5: 0, + hmac_sha1: 1, + hmac_sha256: 2, + hmac_sha384: 3, + hmac_sha512: 4 + }; + + /** + * Compression algorithms. + * enum { null(0), deflate(1), (255) } CompressionMethod; + */ + tls.CompressionMethod = { + none: 0, + deflate: 1 + }; + + /** + * TLS record content types. + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + */ + tls.ContentType = { + change_cipher_spec: 20, + alert: 21, + handshake: 22, + application_data: 23, + heartbeat: 24 + }; + + /** + * TLS handshake types. + * enum { + * hello_request(0), client_hello(1), server_hello(2), + * certificate(11), server_key_exchange (12), + * certificate_request(13), server_hello_done(14), + * certificate_verify(15), client_key_exchange(16), + * finished(20), (255) + * } HandshakeType; + */ + tls.HandshakeType = { + hello_request: 0, + client_hello: 1, + server_hello: 2, + certificate: 11, + server_key_exchange: 12, + certificate_request: 13, + server_hello_done: 14, + certificate_verify: 15, + client_key_exchange: 16, + finished: 20 + }; + + /** + * TLS Alert Protocol. + * + * enum { warning(1), fatal(2), (255) } AlertLevel; + * + * enum { + * close_notify(0), + * unexpected_message(10), + * bad_record_mac(20), + * decryption_failed(21), + * record_overflow(22), + * decompression_failure(30), + * handshake_failure(40), + * bad_certificate(42), + * unsupported_certificate(43), + * certificate_revoked(44), + * certificate_expired(45), + * certificate_unknown(46), + * illegal_parameter(47), + * unknown_ca(48), + * access_denied(49), + * decode_error(50), + * decrypt_error(51), + * export_restriction(60), + * protocol_version(70), + * insufficient_security(71), + * internal_error(80), + * user_canceled(90), + * no_renegotiation(100), + * (255) + * } AlertDescription; + * + * struct { + * AlertLevel level; + * AlertDescription description; + * } Alert; + */ + tls.Alert = {}; + tls.Alert.Level = { + warning: 1, + fatal: 2 + }; + tls.Alert.Description = { + close_notify: 0, + unexpected_message: 10, + bad_record_mac: 20, + decryption_failed: 21, + record_overflow: 22, + decompression_failure: 30, + handshake_failure: 40, + bad_certificate: 42, + unsupported_certificate: 43, + certificate_revoked: 44, + certificate_expired: 45, + certificate_unknown: 46, + illegal_parameter: 47, + unknown_ca: 48, + access_denied: 49, + decode_error: 50, + decrypt_error: 51, + export_restriction: 60, + protocol_version: 70, + insufficient_security: 71, + internal_error: 80, + user_canceled: 90, + no_renegotiation: 100 + }; + + /** + * TLS Heartbeat Message types. + * enum { + * heartbeat_request(1), + * heartbeat_response(2), + * (255) + * } HeartbeatMessageType; + */ + tls.HeartbeatMessageType = { + heartbeat_request: 1, + heartbeat_response: 2 + }; + + /** + * Supported cipher suites. + */ + tls.CipherSuites = {}; + + /** + * Gets a supported cipher suite from its 2 byte ID. + * + * @param twoBytes two bytes in a string. + * + * @return the matching supported cipher suite or null. + */ + tls.getCipherSuite = function(twoBytes) { + var rval = null; + for(var key in tls.CipherSuites) { + var cs = tls.CipherSuites[key]; + if(cs.id[0] === twoBytes.charCodeAt(0) && + cs.id[1] === twoBytes.charCodeAt(1)) { + rval = cs; + break; + } + } + return rval; + }; + + /** + * Called when an unexpected record is encountered. + * + * @param c the connection. + * @param record the record. + */ + tls.handleUnexpected = function(c, record) { + // if connection is client and closed, ignore unexpected messages + var ignore = (!c.open && c.entity === tls.ConnectionEnd.client); + if(!ignore) { + c.error(c, { + message: 'Unexpected message. Received TLS record out of order.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.unexpected_message + } + }); + } + }; + + /** + * Called when a client receives a HelloRequest record. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleHelloRequest = function(c, record, length) { + // ignore renegotiation requests from the server during a handshake, but + // if handshaking, send a warning alert that renegotation is denied + if(!c.handshaking && c.handshakes > 0) { + // send alert warning + tls.queue(c, tls.createAlert(c, { + level: tls.Alert.Level.warning, + description: tls.Alert.Description.no_renegotiation + })); + tls.flush(c); + } + + // continue + c.process(); + }; + + /** + * Parses a hello message from a ClientHello or ServerHello record. + * + * @param record the record to parse. + * + * @return the parsed message. + */ + tls.parseHelloMessage = function(c, record, length) { + var msg = null; + + var client = (c.entity === tls.ConnectionEnd.client); + + // minimum of 38 bytes in message + if(length < 38) { + c.error(c, { + message: client ? + 'Invalid ServerHello message. Message too short.' : + 'Invalid ClientHello message. Message too short.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.illegal_parameter + } + }); + } else { + // use 'remaining' to calculate # of remaining bytes in the message + var b = record.fragment; + var remaining = b.length(); + msg = { + version: { + major: b.getByte(), + minor: b.getByte() + }, + random: forge.util.createBuffer(b.getBytes(32)), + session_id: readVector(b, 1), + extensions: [] + }; + if(client) { + msg.cipher_suite = b.getBytes(2); + msg.compression_method = b.getByte(); + } else { + msg.cipher_suites = readVector(b, 2); + msg.compression_methods = readVector(b, 1); + } + + // read extensions if there are any bytes left in the message + remaining = length - (remaining - b.length()); + if(remaining > 0) { + // parse extensions + var exts = readVector(b, 2); + while(exts.length() > 0) { + msg.extensions.push({ + type: [exts.getByte(), exts.getByte()], + data: readVector(exts, 2) + }); + } + + // TODO: make extension support modular + if(!client) { + for(var i = 0; i < msg.extensions.length; ++i) { + var ext = msg.extensions[i]; + + // support SNI extension + if(ext.type[0] === 0x00 && ext.type[1] === 0x00) { + // get server name list + var snl = readVector(ext.data, 2); + while(snl.length() > 0) { + // read server name type + var snType = snl.getByte(); + + // only HostName type (0x00) is known, break out if + // another type is detected + if(snType !== 0x00) { + break; + } + + // add host name to server name list + c.session.extensions.server_name.serverNameList.push( + readVector(snl, 2).getBytes()); + } + } + } + } + } + + // version already set, do not allow version change + if(c.session.version) { + if(msg.version.major !== c.session.version.major || + msg.version.minor !== c.session.version.minor) { + return c.error(c, { + message: 'TLS version change is disallowed during renegotiation.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.protocol_version + } + }); + } + } + + // get the chosen (ServerHello) cipher suite + if(client) { + // FIXME: should be checking configured acceptable cipher suites + c.session.cipherSuite = tls.getCipherSuite(msg.cipher_suite); + } else { + // get a supported preferred (ClientHello) cipher suite + // choose the first supported cipher suite + var tmp = forge.util.createBuffer(msg.cipher_suites.bytes()); + while(tmp.length() > 0) { + // FIXME: should be checking configured acceptable suites + // cipher suites take up 2 bytes + c.session.cipherSuite = tls.getCipherSuite(tmp.getBytes(2)); + if(c.session.cipherSuite !== null) { + break; + } + } + } + + // cipher suite not supported + if(c.session.cipherSuite === null) { + return c.error(c, { + message: 'No cipher suites in common.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.handshake_failure + }, + cipherSuite: forge.util.bytesToHex(msg.cipher_suite) + }); + } + + // TODO: handle compression methods + if(client) { + c.session.compressionMethod = msg.compression_method; + } else { + // no compression + c.session.compressionMethod = tls.CompressionMethod.none; + } + } + + return msg; + }; + + /** + * Creates security parameters for the given connection based on the given + * hello message. + * + * @param c the TLS connection. + * @param msg the hello message. + */ + tls.createSecurityParameters = function(c, msg) { + /* Note: security params are from TLS 1.2, some values like prf_algorithm + are ignored for TLS 1.0/1.1 and the builtin as specified in the spec is + used. */ + + // TODO: handle other options from server when more supported + + // get client and server randoms + var client = (c.entity === tls.ConnectionEnd.client); + var msgRandom = msg.random.bytes(); + var cRandom = client ? c.session.sp.client_random : msgRandom; + var sRandom = client ? msgRandom : tls.createRandom().getBytes(); + + // create new security parameters + c.session.sp = { + entity: c.entity, + prf_algorithm: tls.PRFAlgorithm.tls_prf_sha256, + bulk_cipher_algorithm: null, + cipher_type: null, + enc_key_length: null, + block_length: null, + fixed_iv_length: null, + record_iv_length: null, + mac_algorithm: null, + mac_length: null, + mac_key_length: null, + compression_algorithm: c.session.compressionMethod, + pre_master_secret: null, + master_secret: null, + client_random: cRandom, + server_random: sRandom + }; + }; + + /** + * Called when a client receives a ServerHello record. + * + * When a ServerHello message will be sent: + * The server will send this message in response to a client hello message + * when it was able to find an acceptable set of algorithms. If it cannot + * find such a match, it will respond with a handshake failure alert. + * + * uint24 length; + * struct { + * ProtocolVersion server_version; + * Random random; + * SessionID session_id; + * CipherSuite cipher_suite; + * CompressionMethod compression_method; + * select(extensions_present) { + * case false: + * struct {}; + * case true: + * Extension extensions<0..2^16-1>; + * }; + * } ServerHello; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleServerHello = function(c, record, length) { + var msg = tls.parseHelloMessage(c, record, length); + if(c.fail) { + return; + } + + // ensure server version is compatible + if(msg.version.minor <= c.version.minor) { + c.version.minor = msg.version.minor; + } else { + return c.error(c, { + message: 'Incompatible TLS version.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.protocol_version + } + }); + } + + // indicate session version has been set + c.session.version = c.version; + + // get the session ID from the message + var sessionId = msg.session_id.bytes(); + + // if the session ID is not blank and matches the cached one, resume + // the session + if(sessionId.length > 0 && sessionId === c.session.id) { + // resuming session, expect a ChangeCipherSpec next + c.expect = SCC; + c.session.resuming = true; + + // get new server random + c.session.sp.server_random = msg.random.bytes(); + } else { + // not resuming, expect a server Certificate message next + c.expect = SCE; + c.session.resuming = false; + + // create new security parameters + tls.createSecurityParameters(c, msg); + } + + // set new session ID + c.session.id = sessionId; + + // continue + c.process(); + }; + + /** + * Called when a server receives a ClientHello record. + * + * When a ClientHello message will be sent: + * When a client first connects to a server it is required to send the + * client hello as its first message. The client can also send a client + * hello in response to a hello request or on its own initiative in order + * to renegotiate the security parameters in an existing connection. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleClientHello = function(c, record, length) { + var msg = tls.parseHelloMessage(c, record, length); + if(c.fail) { + return; + } + + // get the session ID from the message + var sessionId = msg.session_id.bytes(); + + // see if the given session ID is in the cache + var session = null; + if(c.sessionCache) { + session = c.sessionCache.getSession(sessionId); + if(session === null) { + // session ID not found + sessionId = ''; + } else if(session.version.major !== msg.version.major || + session.version.minor > msg.version.minor) { + // if session version is incompatible with client version, do not resume + session = null; + sessionId = ''; + } + } + + // no session found to resume, generate a new session ID + if(sessionId.length === 0) { + sessionId = forge.random.getBytes(32); + } + + // update session + c.session.id = sessionId; + c.session.clientHelloVersion = msg.version; + c.session.sp = {}; + if(session) { + // use version and security parameters from resumed session + c.version = c.session.version = session.version; + c.session.sp = session.sp; + } else { + // use highest compatible minor version + var version; + for(var i = 1; i < tls.SupportedVersions.length; ++i) { + version = tls.SupportedVersions[i]; + if(version.minor <= msg.version.minor) { + break; + } + } + c.version = {major: version.major, minor: version.minor}; + c.session.version = c.version; + } + + // if a session is set, resume it + if(session !== null) { + // resuming session, expect a ChangeCipherSpec next + c.expect = CCC; + c.session.resuming = true; + + // get new client random + c.session.sp.client_random = msg.random.bytes(); + } else { + // not resuming, expect a Certificate or ClientKeyExchange + c.expect = (c.verifyClient !== false) ? CCE : CKE; + c.session.resuming = false; + + // create new security parameters + tls.createSecurityParameters(c, msg); + } + + // connection now open + c.open = true; + + // queue server hello + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createServerHello(c) + })); + + if(c.session.resuming) { + // queue change cipher spec message + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.change_cipher_spec, + data: tls.createChangeCipherSpec() + })); + + // create pending state + c.state.pending = tls.createConnectionState(c); + + // change current write state to pending write state + c.state.current.write = c.state.pending.write; + + // queue finished + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createFinished(c) + })); + } else { + // queue server certificate + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createCertificate(c) + })); + + if(!c.fail) { + // queue server key exchange + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createServerKeyExchange(c) + })); + + // request client certificate if set + if(c.verifyClient !== false) { + // queue certificate request + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createCertificateRequest(c) + })); + } + + // queue server hello done + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createServerHelloDone(c) + })); + } + } + + // send records + tls.flush(c); + + // continue + c.process(); + }; + + /** + * Called when a client receives a Certificate record. + * + * When this message will be sent: + * The server must send a certificate whenever the agreed-upon key exchange + * method is not an anonymous one. This message will always immediately + * follow the server hello message. + * + * Meaning of this message: + * The certificate type must be appropriate for the selected cipher suite's + * key exchange algorithm, and is generally an X.509v3 certificate. It must + * contain a key which matches the key exchange method, as follows. Unless + * otherwise specified, the signing algorithm for the certificate must be + * the same as the algorithm for the certificate key. Unless otherwise + * specified, the public key may be of any length. + * + * opaque ASN.1Cert<1..2^24-1>; + * struct { + * ASN.1Cert certificate_list<1..2^24-1>; + * } Certificate; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleCertificate = function(c, record, length) { + // minimum of 3 bytes in message + if(length < 3) { + return c.error(c, { + message: 'Invalid Certificate message. Message too short.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.illegal_parameter + } + }); + } + + var b = record.fragment; + var msg = { + certificate_list: readVector(b, 3) + }; + + /* The sender's certificate will be first in the list (chain), each + subsequent one that follows will certify the previous one, but root + certificates (self-signed) that specify the certificate authority may + be omitted under the assumption that clients must already possess it. */ + var cert, asn1; + var certs = []; + try { + while(msg.certificate_list.length() > 0) { + // each entry in msg.certificate_list is a vector with 3 len bytes + cert = readVector(msg.certificate_list, 3); + asn1 = forge.asn1.fromDer(cert); + cert = forge.pki.certificateFromAsn1(asn1, true); + certs.push(cert); + } + } catch(ex) { + return c.error(c, { + message: 'Could not parse certificate list.', + cause: ex, + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.bad_certificate + } + }); + } + + // ensure at least 1 certificate was provided if in client-mode + // or if verifyClient was set to true to require a certificate + // (as opposed to 'optional') + var client = (c.entity === tls.ConnectionEnd.client); + if((client || c.verifyClient === true) && certs.length === 0) { + // error, no certificate + c.error(c, { + message: client ? + 'No server certificate provided.' : + 'No client certificate provided.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.illegal_parameter + } + }); + } else if(certs.length === 0) { + // no certs to verify + // expect a ServerKeyExchange or ClientKeyExchange message next + c.expect = client ? SKE : CKE; + } else { + // save certificate in session + if(client) { + c.session.serverCertificate = certs[0]; + } else { + c.session.clientCertificate = certs[0]; + } + + if(tls.verifyCertificateChain(c, certs)) { + // expect a ServerKeyExchange or ClientKeyExchange message next + c.expect = client ? SKE : CKE; + } + } + + // continue + c.process(); + }; + + /** + * Called when a client receives a ServerKeyExchange record. + * + * When this message will be sent: + * This message will be sent immediately after the server certificate + * message (or the server hello message, if this is an anonymous + * negotiation). + * + * The server key exchange message is sent by the server only when the + * server certificate message (if sent) does not contain enough data to + * allow the client to exchange a premaster secret. + * + * Meaning of this message: + * This message conveys cryptographic information to allow the client to + * communicate the premaster secret: either an RSA public key to encrypt + * the premaster secret with, or a Diffie-Hellman public key with which the + * client can complete a key exchange (with the result being the premaster + * secret.) + * + * enum { + * dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa + * } KeyExchangeAlgorithm; + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + * + * struct { + * select(KeyExchangeAlgorithm) { + * case dh_anon: + * ServerDHParams params; + * case dhe_dss: + * case dhe_rsa: + * ServerDHParams params; + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * } signed_params; + * case rsa: + * case dh_dss: + * case dh_rsa: + * struct {}; + * }; + * } ServerKeyExchange; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleServerKeyExchange = function(c, record, length) { + // this implementation only supports RSA, no Diffie-Hellman support + // so any length > 0 is invalid + if(length > 0) { + return c.error(c, { + message: 'Invalid key parameters. Only RSA is supported.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.unsupported_certificate + } + }); + } + + // expect an optional CertificateRequest message next + c.expect = SCR; + + // continue + c.process(); + }; + + /** + * Called when a client receives a ClientKeyExchange record. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleClientKeyExchange = function(c, record, length) { + // this implementation only supports RSA, no Diffie-Hellman support + // so any length < 48 is invalid + if(length < 48) { + return c.error(c, { + message: 'Invalid key parameters. Only RSA is supported.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.unsupported_certificate + } + }); + } + + var b = record.fragment; + var msg = { + enc_pre_master_secret: readVector(b, 2).getBytes() + }; + + // do rsa decryption + var privateKey = null; + if(c.getPrivateKey) { + try { + privateKey = c.getPrivateKey(c, c.session.serverCertificate); + privateKey = forge.pki.privateKeyFromPem(privateKey); + } catch(ex) { + c.error(c, { + message: 'Could not get private key.', + cause: ex, + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.internal_error + } + }); + } + } + + if(privateKey === null) { + return c.error(c, { + message: 'No private key set.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.internal_error + } + }); + } + + try { + // decrypt 48-byte pre-master secret + var sp = c.session.sp; + sp.pre_master_secret = privateKey.decrypt(msg.enc_pre_master_secret); + + // ensure client hello version matches first 2 bytes + var version = c.session.clientHelloVersion; + if(version.major !== sp.pre_master_secret.charCodeAt(0) || + version.minor !== sp.pre_master_secret.charCodeAt(1)) { + // error, do not send alert (see BLEI attack below) + throw new Error('TLS version rollback attack detected.'); + } + } catch(ex) { + /* Note: Daniel Bleichenbacher [BLEI] can be used to attack a + TLS server which is using PKCS#1 encoded RSA, so instead of + failing here, we generate 48 random bytes and use that as + the pre-master secret. */ + sp.pre_master_secret = forge.random.getBytes(48); + } + + // expect a CertificateVerify message if a Certificate was received that + // does not have fixed Diffie-Hellman params, otherwise expect + // ChangeCipherSpec + c.expect = CCC; + if(c.session.clientCertificate !== null) { + // only RSA support, so expect CertificateVerify + // TODO: support Diffie-Hellman + c.expect = CCV; + } + + // continue + c.process(); + }; + + /** + * Called when a client receives a CertificateRequest record. + * + * When this message will be sent: + * A non-anonymous server can optionally request a certificate from the + * client, if appropriate for the selected cipher suite. This message, if + * sent, will immediately follow the Server Key Exchange message (if it is + * sent; otherwise, the Server Certificate message). + * + * enum { + * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), + * rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6), + * fortezza_dms_RESERVED(20), (255) + * } ClientCertificateType; + * + * opaque DistinguishedName<1..2^16-1>; + * + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>; + * DistinguishedName certificate_authorities<0..2^16-1>; + * } CertificateRequest; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleCertificateRequest = function(c, record, length) { + // minimum of 3 bytes in message + if(length < 3) { + return c.error(c, { + message: 'Invalid CertificateRequest. Message too short.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.illegal_parameter + } + }); + } + + // TODO: TLS 1.2+ has different format including + // SignatureAndHashAlgorithm after cert types + var b = record.fragment; + var msg = { + certificate_types: readVector(b, 1), + certificate_authorities: readVector(b, 2) + }; + + // save certificate request in session + c.session.certificateRequest = msg; + + // expect a ServerHelloDone message next + c.expect = SHD; + + // continue + c.process(); + }; + + /** + * Called when a server receives a CertificateVerify record. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleCertificateVerify = function(c, record, length) { + if(length < 2) { + return c.error(c, { + message: 'Invalid CertificateVerify. Message too short.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.illegal_parameter + } + }); + } + + // rewind to get full bytes for message so it can be manually + // digested below (special case for CertificateVerify messages because + // they must be digested *after* handling as opposed to all others) + var b = record.fragment; + b.read -= 4; + var msgBytes = b.bytes(); + b.read += 4; + + var msg = { + signature: readVector(b, 2).getBytes() + }; + + // TODO: add support for DSA + + // generate data to verify + var verify = forge.util.createBuffer(); + verify.putBuffer(c.session.md5.digest()); + verify.putBuffer(c.session.sha1.digest()); + verify = verify.getBytes(); + + try { + var cert = c.session.clientCertificate; + /*b = forge.pki.rsa.decrypt( + msg.signature, cert.publicKey, true, verify.length); + if(b !== verify) {*/ + if(!cert.publicKey.verify(verify, msg.signature, 'NONE')) { + throw new Error('CertificateVerify signature does not match.'); + } + + // digest message now that it has been handled + c.session.md5.update(msgBytes); + c.session.sha1.update(msgBytes); + } catch(ex) { + return c.error(c, { + message: 'Bad signature in CertificateVerify.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.handshake_failure + } + }); + } + + // expect ChangeCipherSpec + c.expect = CCC; + + // continue + c.process(); + }; + + /** + * Called when a client receives a ServerHelloDone record. + * + * When this message will be sent: + * The server hello done message is sent by the server to indicate the end + * of the server hello and associated messages. After sending this message + * the server will wait for a client response. + * + * Meaning of this message: + * This message means that the server is done sending messages to support + * the key exchange, and the client can proceed with its phase of the key + * exchange. + * + * Upon receipt of the server hello done message the client should verify + * that the server provided a valid certificate if required and check that + * the server hello parameters are acceptable. + * + * struct {} ServerHelloDone; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleServerHelloDone = function(c, record, length) { + // len must be 0 bytes + if(length > 0) { + return c.error(c, { + message: 'Invalid ServerHelloDone message. Invalid length.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.record_overflow + } + }); + } + + if(c.serverCertificate === null) { + // no server certificate was provided + var error = { + message: 'No server certificate provided. Not enough security.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.insufficient_security + } + }; + + // call application callback + var depth = 0; + var ret = c.verify(c, error.alert.description, depth, []); + if(ret !== true) { + // check for custom alert info + if(ret || ret === 0) { + // set custom message and alert description + if(typeof ret === 'object' && !forge.util.isArray(ret)) { + if(ret.message) { + error.message = ret.message; + } + if(ret.alert) { + error.alert.description = ret.alert; + } + } else if(typeof ret === 'number') { + // set custom alert description + error.alert.description = ret; + } + } + + // send error + return c.error(c, error); + } + } + + // create client certificate message if requested + if(c.session.certificateRequest !== null) { + record = tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createCertificate(c) + }); + tls.queue(c, record); + } + + // create client key exchange message + record = tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createClientKeyExchange(c) + }); + tls.queue(c, record); + + // expect no messages until the following callback has been called + c.expect = SER; + + // create callback to handle client signature (for client-certs) + var callback = function(c, signature) { + if(c.session.certificateRequest !== null && + c.session.clientCertificate !== null) { + // create certificate verify message + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createCertificateVerify(c, signature) + })); + } + + // create change cipher spec message + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.change_cipher_spec, + data: tls.createChangeCipherSpec() + })); + + // create pending state + c.state.pending = tls.createConnectionState(c); + + // change current write state to pending write state + c.state.current.write = c.state.pending.write; + + // create finished message + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createFinished(c) + })); + + // expect a server ChangeCipherSpec message next + c.expect = SCC; + + // send records + tls.flush(c); + + // continue + c.process(); + }; + + // if there is no certificate request or no client certificate, do + // callback immediately + if(c.session.certificateRequest === null || + c.session.clientCertificate === null) { + return callback(c, null); + } + + // otherwise get the client signature + tls.getClientSignature(c, callback); + }; + + /** + * Called when a ChangeCipherSpec record is received. + * + * @param c the connection. + * @param record the record. + */ + tls.handleChangeCipherSpec = function(c, record) { + if(record.fragment.getByte() !== 0x01) { + return c.error(c, { + message: 'Invalid ChangeCipherSpec message received.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.illegal_parameter + } + }); + } + + // create pending state if: + // 1. Resuming session in client mode OR + // 2. NOT resuming session in server mode + var client = (c.entity === tls.ConnectionEnd.client); + if((c.session.resuming && client) || (!c.session.resuming && !client)) { + c.state.pending = tls.createConnectionState(c); + } + + // change current read state to pending read state + c.state.current.read = c.state.pending.read; + + // clear pending state if: + // 1. NOT resuming session in client mode OR + // 2. resuming a session in server mode + if((!c.session.resuming && client) || (c.session.resuming && !client)) { + c.state.pending = null; + } + + // expect a Finished record next + c.expect = client ? SFI : CFI; + + // continue + c.process(); + }; + + /** + * Called when a Finished record is received. + * + * When this message will be sent: + * A finished message is always sent immediately after a change + * cipher spec message to verify that the key exchange and + * authentication processes were successful. It is essential that a + * change cipher spec message be received between the other + * handshake messages and the Finished message. + * + * Meaning of this message: + * The finished message is the first protected with the just- + * negotiated algorithms, keys, and secrets. Recipients of finished + * messages must verify that the contents are correct. Once a side + * has sent its Finished message and received and validated the + * Finished message from its peer, it may begin to send and receive + * application data over the connection. + * + * struct { + * opaque verify_data[verify_data_length]; + * } Finished; + * + * verify_data + * PRF(master_secret, finished_label, Hash(handshake_messages)) + * [0..verify_data_length-1]; + * + * finished_label + * For Finished messages sent by the client, the string + * "client finished". For Finished messages sent by the server, the + * string "server finished". + * + * verify_data_length depends on the cipher suite. If it is not specified + * by the cipher suite, then it is 12. Versions of TLS < 1.2 always used + * 12 bytes. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ + tls.handleFinished = function(c, record, length) { + // rewind to get full bytes for message so it can be manually + // digested below (special case for Finished messages because they + // must be digested *after* handling as opposed to all others) + var b = record.fragment; + b.read -= 4; + var msgBytes = b.bytes(); + b.read += 4; + + // message contains only verify_data + var vd = record.fragment.getBytes(); + + // ensure verify data is correct + b = forge.util.createBuffer(); + b.putBuffer(c.session.md5.digest()); + b.putBuffer(c.session.sha1.digest()); + + // set label based on entity type + var client = (c.entity === tls.ConnectionEnd.client); + var label = client ? 'server finished' : 'client finished'; + + // TODO: determine prf function and verify length for TLS 1.2 + var sp = c.session.sp; + var vdl = 12; + var prf = prf_TLS1; + b = prf(sp.master_secret, label, b.getBytes(), vdl); + if(b.getBytes() !== vd) { + return c.error(c, { + message: 'Invalid verify_data in Finished message.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.decrypt_error + } + }); + } + + // digest finished message now that it has been handled + c.session.md5.update(msgBytes); + c.session.sha1.update(msgBytes); + + // resuming session as client or NOT resuming session as server + if((c.session.resuming && client) || (!c.session.resuming && !client)) { + // create change cipher spec message + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.change_cipher_spec, + data: tls.createChangeCipherSpec() + })); + + // change current write state to pending write state, clear pending + c.state.current.write = c.state.pending.write; + c.state.pending = null; + + // create finished message + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createFinished(c) + })); + } + + // expect application data next + c.expect = client ? SAD : CAD; + + // handshake complete + c.handshaking = false; + ++c.handshakes; + + // save access to peer certificate + c.peerCertificate = client ? + c.session.serverCertificate : c.session.clientCertificate; + + // send records + tls.flush(c); + + // now connected + c.isConnected = true; + c.connected(c); + + // continue + c.process(); + }; + + /** + * Called when an Alert record is received. + * + * @param c the connection. + * @param record the record. + */ + tls.handleAlert = function(c, record) { + // read alert + var b = record.fragment; + var alert = { + level: b.getByte(), + description: b.getByte() + }; + + // TODO: consider using a table? + // get appropriate message + var msg; + switch(alert.description) { + case tls.Alert.Description.close_notify: + msg = 'Connection closed.'; + break; + case tls.Alert.Description.unexpected_message: + msg = 'Unexpected message.'; + break; + case tls.Alert.Description.bad_record_mac: + msg = 'Bad record MAC.'; + break; + case tls.Alert.Description.decryption_failed: + msg = 'Decryption failed.'; + break; + case tls.Alert.Description.record_overflow: + msg = 'Record overflow.'; + break; + case tls.Alert.Description.decompression_failure: + msg = 'Decompression failed.'; + break; + case tls.Alert.Description.handshake_failure: + msg = 'Handshake failure.'; + break; + case tls.Alert.Description.bad_certificate: + msg = 'Bad certificate.'; + break; + case tls.Alert.Description.unsupported_certificate: + msg = 'Unsupported certificate.'; + break; + case tls.Alert.Description.certificate_revoked: + msg = 'Certificate revoked.'; + break; + case tls.Alert.Description.certificate_expired: + msg = 'Certificate expired.'; + break; + case tls.Alert.Description.certificate_unknown: + msg = 'Certificate unknown.'; + break; + case tls.Alert.Description.illegal_parameter: + msg = 'Illegal parameter.'; + break; + case tls.Alert.Description.unknown_ca: + msg = 'Unknown certificate authority.'; + break; + case tls.Alert.Description.access_denied: + msg = 'Access denied.'; + break; + case tls.Alert.Description.decode_error: + msg = 'Decode error.'; + break; + case tls.Alert.Description.decrypt_error: + msg = 'Decrypt error.'; + break; + case tls.Alert.Description.export_restriction: + msg = 'Export restriction.'; + break; + case tls.Alert.Description.protocol_version: + msg = 'Unsupported protocol version.'; + break; + case tls.Alert.Description.insufficient_security: + msg = 'Insufficient security.'; + break; + case tls.Alert.Description.internal_error: + msg = 'Internal error.'; + break; + case tls.Alert.Description.user_canceled: + msg = 'User canceled.'; + break; + case tls.Alert.Description.no_renegotiation: + msg = 'Renegotiation not supported.'; + break; + default: + msg = 'Unknown error.'; + break; + } + + // close connection on close_notify, not an error + if(alert.description === tls.Alert.Description.close_notify) { + return c.close(); + } + + // call error handler + c.error(c, { + message: msg, + send: false, + // origin is the opposite end + origin: (c.entity === tls.ConnectionEnd.client) ? 'server' : 'client', + alert: alert + }); + + // continue + c.process(); + }; + + /** + * Called when a Handshake record is received. + * + * @param c the connection. + * @param record the record. + */ + tls.handleHandshake = function(c, record) { + // get the handshake type and message length + var b = record.fragment; + var type = b.getByte(); + var length = b.getInt24(); + + // see if the record fragment doesn't yet contain the full message + if(length > b.length()) { + // cache the record, clear its fragment, and reset the buffer read + // pointer before the type and length were read + c.fragmented = record; + record.fragment = forge.util.createBuffer(); + b.read -= 4; + + // continue + return c.process(); + } + + // full message now available, clear cache, reset read pointer to + // before type and length + c.fragmented = null; + b.read -= 4; + + // save the handshake bytes for digestion after handler is found + // (include type and length of handshake msg) + var bytes = b.bytes(length + 4); + + // restore read pointer + b.read += 4; + + // handle expected message + if(type in hsTable[c.entity][c.expect]) { + // initialize server session + if(c.entity === tls.ConnectionEnd.server && !c.open && !c.fail) { + c.handshaking = true; + c.session = { + version: null, + extensions: { + server_name: { + serverNameList: [] + } + }, + cipherSuite: null, + compressionMethod: null, + serverCertificate: null, + clientCertificate: null, + md5: forge.md.md5.create(), + sha1: forge.md.sha1.create() + }; + } + + /* Update handshake messages digest. Finished and CertificateVerify + messages are not digested here. They can't be digested as part of + the verify_data that they contain. These messages are manually + digested in their handlers. HelloRequest messages are simply never + included in the handshake message digest according to spec. */ + if(type !== tls.HandshakeType.hello_request && + type !== tls.HandshakeType.certificate_verify && + type !== tls.HandshakeType.finished) { + c.session.md5.update(bytes); + c.session.sha1.update(bytes); + } + + // handle specific handshake type record + hsTable[c.entity][c.expect][type](c, record, length); + } else { + // unexpected record + tls.handleUnexpected(c, record); + } + }; + + /** + * Called when an ApplicationData record is received. + * + * @param c the connection. + * @param record the record. + */ + tls.handleApplicationData = function(c, record) { + // buffer data, notify that its ready + c.data.putBuffer(record.fragment); + c.dataReady(c); + + // continue + c.process(); + }; + + /** + * Called when a Heartbeat record is received. + * + * @param c the connection. + * @param record the record. + */ + tls.handleHeartbeat = function(c, record) { + // get the heartbeat type and payload + var b = record.fragment; + var type = b.getByte(); + var length = b.getInt16(); + var payload = b.getBytes(length); + + if(type === tls.HeartbeatMessageType.heartbeat_request) { + // discard request during handshake or if length is too large + if(c.handshaking || length > payload.length) { + // continue + return c.process(); + } + // retransmit payload + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.heartbeat, + data: tls.createHeartbeat( + tls.HeartbeatMessageType.heartbeat_response, payload) + })); + tls.flush(c); + } else if(type === tls.HeartbeatMessageType.heartbeat_response) { + // check payload against expected payload, discard heartbeat if no match + if(payload !== c.expectedHeartbeatPayload) { + // continue + return c.process(); + } + + // notify that a valid heartbeat was received + if(c.heartbeatReceived) { + c.heartbeatReceived(c, forge.util.createBuffer(payload)); + } + } + + // continue + c.process(); + }; + + /** + * The transistional state tables for receiving TLS records. It maps the + * current TLS engine state and a received record to a function to handle the + * record and update the state. + * + * For instance, if the current state is SHE, then the TLS engine is expecting + * a ServerHello record. Once a record is received, the handler function is + * looked up using the state SHE and the record's content type. + * + * The resulting function will either be an error handler or a record handler. + * The function will take whatever action is appropriate and update the state + * for the next record. + * + * The states are all based on possible server record types. Note that the + * client will never specifically expect to receive a HelloRequest or an alert + * from the server so there is no state that reflects this. These messages may + * occur at any time. + * + * There are two tables for mapping states because there is a second tier of + * types for handshake messages. Once a record with a content type of handshake + * is received, the handshake record handler will look up the handshake type in + * the secondary map to get its appropriate handler. + * + * Valid message orders are as follows: + * + * =======================FULL HANDSHAKE====================== + * Client Server + * + * ClientHello --------> + * ServerHello + * Certificate* + * ServerKeyExchange* + * CertificateRequest* + * <-------- ServerHelloDone + * Certificate* + * ClientKeyExchange + * CertificateVerify* + * [ChangeCipherSpec] + * Finished --------> + * [ChangeCipherSpec] + * <-------- Finished + * Application Data <-------> Application Data + * + * =====================SESSION RESUMPTION===================== + * Client Server + * + * ClientHello --------> + * ServerHello + * [ChangeCipherSpec] + * <-------- Finished + * [ChangeCipherSpec] + * Finished --------> + * Application Data <-------> Application Data + */ + // client expect states (indicate which records are expected to be received) + var SHE = 0; // rcv server hello + var SCE = 1; // rcv server certificate + var SKE = 2; // rcv server key exchange + var SCR = 3; // rcv certificate request + var SHD = 4; // rcv server hello done + var SCC = 5; // rcv change cipher spec + var SFI = 6; // rcv finished + var SAD = 7; // rcv application data + var SER = 8; // not expecting any messages at this point + + // server expect states + var CHE = 0; // rcv client hello + var CCE = 1; // rcv client certificate + var CKE = 2; // rcv client key exchange + var CCV = 3; // rcv certificate verify + var CCC = 4; // rcv change cipher spec + var CFI = 5; // rcv finished + var CAD = 6; // rcv application data + + // map client current expect state and content type to function + var __ = tls.handleUnexpected; + var R0 = tls.handleChangeCipherSpec; + var R1 = tls.handleAlert; + var R2 = tls.handleHandshake; + var R3 = tls.handleApplicationData; + var R4 = tls.handleHeartbeat; + var ctTable = []; + ctTable[tls.ConnectionEnd.client] = [ + // CC,AL,HS,AD,HB + /*SHE*/[__,R1,R2,__,R4], + /*SCE*/[__,R1,R2,__,R4], + /*SKE*/[__,R1,R2,__,R4], + /*SCR*/[__,R1,R2,__,R4], + /*SHD*/[__,R1,R2,__,R4], + /*SCC*/[R0,R1,__,__,R4], + /*SFI*/[__,R1,R2,__,R4], + /*SAD*/[__,R1,R2,R3,R4], + /*SER*/[__,R1,R2,__,R4] + ]; + + // map server current expect state and content type to function + ctTable[tls.ConnectionEnd.server] = [ + // CC,AL,HS,AD + /*CHE*/[__,R1,R2,__,R4], + /*CCE*/[__,R1,R2,__,R4], + /*CKE*/[__,R1,R2,__,R4], + /*CCV*/[__,R1,R2,__,R4], + /*CCC*/[R0,R1,__,__,R4], + /*CFI*/[__,R1,R2,__,R4], + /*CAD*/[__,R1,R2,R3,R4], + /*CER*/[__,R1,R2,__,R4] + ]; + + // map client current expect state and handshake type to function + var H0 = tls.handleHelloRequest; + var H1 = tls.handleServerHello; + var H2 = tls.handleCertificate; + var H3 = tls.handleServerKeyExchange; + var H4 = tls.handleCertificateRequest; + var H5 = tls.handleServerHelloDone; + var H6 = tls.handleFinished; + var hsTable = []; + hsTable[tls.ConnectionEnd.client] = [ + // HR,01,SH,03,04,05,06,07,08,09,10,SC,SK,CR,HD,15,CK,17,18,19,FI + /*SHE*/[__,__,H1,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], + /*SCE*/[H0,__,__,__,__,__,__,__,__,__,__,H2,H3,H4,H5,__,__,__,__,__,__], + /*SKE*/[H0,__,__,__,__,__,__,__,__,__,__,__,H3,H4,H5,__,__,__,__,__,__], + /*SCR*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,H4,H5,__,__,__,__,__,__], + /*SHD*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,H5,__,__,__,__,__,__], + /*SCC*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], + /*SFI*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H6], + /*SAD*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], + /*SER*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__] + ]; + + // map server current expect state and handshake type to function + // Note: CAD[CH] does not map to FB because renegotation is prohibited + var H7 = tls.handleClientHello; + var H8 = tls.handleClientKeyExchange; + var H9 = tls.handleCertificateVerify; + hsTable[tls.ConnectionEnd.server] = [ + // 01,CH,02,03,04,05,06,07,08,09,10,CC,12,13,14,CV,CK,17,18,19,FI + /*CHE*/[__,H7,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], + /*CCE*/[__,__,__,__,__,__,__,__,__,__,__,H2,__,__,__,__,__,__,__,__,__], + /*CKE*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H8,__,__,__,__], + /*CCV*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H9,__,__,__,__,__], + /*CCC*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], + /*CFI*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H6], + /*CAD*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], + /*CER*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__] + ]; + + /** + * Generates the master_secret and keys using the given security parameters. + * + * The security parameters for a TLS connection state are defined as such: + * + * struct { + * ConnectionEnd entity; + * PRFAlgorithm prf_algorithm; + * BulkCipherAlgorithm bulk_cipher_algorithm; + * CipherType cipher_type; + * uint8 enc_key_length; + * uint8 block_length; + * uint8 fixed_iv_length; + * uint8 record_iv_length; + * MACAlgorithm mac_algorithm; + * uint8 mac_length; + * uint8 mac_key_length; + * CompressionMethod compression_algorithm; + * opaque master_secret[48]; + * opaque client_random[32]; + * opaque server_random[32]; + * } SecurityParameters; + * + * Note that this definition is from TLS 1.2. In TLS 1.0 some of these + * parameters are ignored because, for instance, the PRFAlgorithm is a + * builtin-fixed algorithm combining iterations of MD5 and SHA-1 in TLS 1.0. + * + * The Record Protocol requires an algorithm to generate keys required by the + * current connection state. + * + * The master secret is expanded into a sequence of secure bytes, which is then + * split to a client write MAC key, a server write MAC key, a client write + * encryption key, and a server write encryption key. In TLS 1.0 a client write + * IV and server write IV are also generated. Each of these is generated from + * the byte sequence in that order. Unused values are empty. In TLS 1.2, some + * AEAD ciphers may additionally require a client write IV and a server write + * IV (see Section 6.2.3.3). + * + * When keys, MAC keys, and IVs are generated, the master secret is used as an + * entropy source. + * + * To generate the key material, compute: + * + * master_secret = PRF(pre_master_secret, "master secret", + * ClientHello.random + ServerHello.random) + * + * key_block = PRF(SecurityParameters.master_secret, + * "key expansion", + * SecurityParameters.server_random + + * SecurityParameters.client_random); + * + * until enough output has been generated. Then, the key_block is + * partitioned as follows: + * + * client_write_MAC_key[SecurityParameters.mac_key_length] + * server_write_MAC_key[SecurityParameters.mac_key_length] + * client_write_key[SecurityParameters.enc_key_length] + * server_write_key[SecurityParameters.enc_key_length] + * client_write_IV[SecurityParameters.fixed_iv_length] + * server_write_IV[SecurityParameters.fixed_iv_length] + * + * In TLS 1.2, the client_write_IV and server_write_IV are only generated for + * implicit nonce techniques as described in Section 3.2.1 of [AEAD]. This + * implementation uses TLS 1.0 so IVs are generated. + * + * Implementation note: The currently defined cipher suite which requires the + * most material is AES_256_CBC_SHA256. It requires 2 x 32 byte keys and 2 x 32 + * byte MAC keys, for a total 128 bytes of key material. In TLS 1.0 it also + * requires 2 x 16 byte IVs, so it actually takes 160 bytes of key material. + * + * @param c the connection. + * @param sp the security parameters to use. + * + * @return the security keys. + */ + tls.generateKeys = function(c, sp) { + // TLS_RSA_WITH_AES_128_CBC_SHA (required to be compliant with TLS 1.2) & + // TLS_RSA_WITH_AES_256_CBC_SHA are the only cipher suites implemented + // at present + + // TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA is required to be compliant with + // TLS 1.0 but we don't care right now because AES is better and we have + // an implementation for it + + // TODO: TLS 1.2 implementation + /* + // determine the PRF + var prf; + switch(sp.prf_algorithm) { + case tls.PRFAlgorithm.tls_prf_sha256: + prf = prf_sha256; + break; + default: + // should never happen + throw new Error('Invalid PRF'); + } + */ + + // TLS 1.0/1.1 implementation + var prf = prf_TLS1; + + // concatenate server and client random + var random = sp.client_random + sp.server_random; + + // only create master secret if session is new + if(!c.session.resuming) { + // create master secret, clean up pre-master secret + sp.master_secret = prf( + sp.pre_master_secret, 'master secret', random, 48).bytes(); + sp.pre_master_secret = null; + } + + // generate the amount of key material needed + random = sp.server_random + sp.client_random; + var length = 2 * sp.mac_key_length + 2 * sp.enc_key_length; + + // include IV for TLS/1.0 + var tls10 = (c.version.major === tls.Versions.TLS_1_0.major && + c.version.minor === tls.Versions.TLS_1_0.minor); + if(tls10) { + length += 2 * sp.fixed_iv_length; + } + var km = prf(sp.master_secret, 'key expansion', random, length); + + // split the key material into the MAC and encryption keys + var rval = { + client_write_MAC_key: km.getBytes(sp.mac_key_length), + server_write_MAC_key: km.getBytes(sp.mac_key_length), + client_write_key: km.getBytes(sp.enc_key_length), + server_write_key: km.getBytes(sp.enc_key_length) + }; + + // include TLS 1.0 IVs + if(tls10) { + rval.client_write_IV = km.getBytes(sp.fixed_iv_length); + rval.server_write_IV = km.getBytes(sp.fixed_iv_length); + } + + return rval; + }; + + /** + * Creates a new initialized TLS connection state. A connection state has + * a read mode and a write mode. + * + * compression state: + * The current state of the compression algorithm. + * + * cipher state: + * The current state of the encryption algorithm. This will consist of the + * scheduled key for that connection. For stream ciphers, this will also + * contain whatever state information is necessary to allow the stream to + * continue to encrypt or decrypt data. + * + * MAC key: + * The MAC key for the connection. + * + * sequence number: + * Each connection state contains a sequence number, which is maintained + * separately for read and write states. The sequence number MUST be set to + * zero whenever a connection state is made the active state. Sequence + * numbers are of type uint64 and may not exceed 2^64-1. Sequence numbers do + * not wrap. If a TLS implementation would need to wrap a sequence number, + * it must renegotiate instead. A sequence number is incremented after each + * record: specifically, the first record transmitted under a particular + * connection state MUST use sequence number 0. + * + * @param c the connection. + * + * @return the new initialized TLS connection state. + */ + tls.createConnectionState = function(c) { + var client = (c.entity === tls.ConnectionEnd.client); + + var createMode = function() { + var mode = { + // two 32-bit numbers, first is most significant + sequenceNumber: [0, 0], + macKey: null, + macLength: 0, + macFunction: null, + cipherState: null, + cipherFunction: function(record) {return true;}, + compressionState: null, + compressFunction: function(record) {return true;}, + updateSequenceNumber: function() { + if(mode.sequenceNumber[1] === 0xFFFFFFFF) { + mode.sequenceNumber[1] = 0; + ++mode.sequenceNumber[0]; + } else { + ++mode.sequenceNumber[1]; + } + } + }; + return mode; + }; + var state = { + read: createMode(), + write: createMode() + }; + + // update function in read mode will decrypt then decompress a record + state.read.update = function(c, record) { + if(!state.read.cipherFunction(record, state.read)) { + c.error(c, { + message: 'Could not decrypt record or bad MAC.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + // doesn't matter if decryption failed or MAC was + // invalid, return the same error so as not to reveal + // which one occurred + description: tls.Alert.Description.bad_record_mac + } + }); + } else if(!state.read.compressFunction(c, record, state.read)) { + c.error(c, { + message: 'Could not decompress record.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.decompression_failure + } + }); + } + return !c.fail; + }; + + // update function in write mode will compress then encrypt a record + state.write.update = function(c, record) { + if(!state.write.compressFunction(c, record, state.write)) { + // error, but do not send alert since it would require + // compression as well + c.error(c, { + message: 'Could not compress record.', + send: false, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.internal_error + } + }); + } else if(!state.write.cipherFunction(record, state.write)) { + // error, but do not send alert since it would require + // encryption as well + c.error(c, { + message: 'Could not encrypt record.', + send: false, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.internal_error + } + }); + } + return !c.fail; + }; + + // handle security parameters + if(c.session) { + var sp = c.session.sp; + c.session.cipherSuite.initSecurityParameters(sp); + + // generate keys + sp.keys = tls.generateKeys(c, sp); + state.read.macKey = client ? + sp.keys.server_write_MAC_key : sp.keys.client_write_MAC_key; + state.write.macKey = client ? + sp.keys.client_write_MAC_key : sp.keys.server_write_MAC_key; + + // cipher suite setup + c.session.cipherSuite.initConnectionState(state, c, sp); + + // compression setup + switch(sp.compression_algorithm) { + case tls.CompressionMethod.none: + break; + case tls.CompressionMethod.deflate: + state.read.compressFunction = inflate; + state.write.compressFunction = deflate; + break; + default: + throw new Error('Unsupported compression algorithm.'); + } + } + + return state; + }; + + /** + * Creates a Random structure. + * + * struct { + * uint32 gmt_unix_time; + * opaque random_bytes[28]; + * } Random; + * + * gmt_unix_time: + * The current time and date in standard UNIX 32-bit format (seconds since + * the midnight starting Jan 1, 1970, UTC, ignoring leap seconds) according + * to the sender's internal clock. Clocks are not required to be set + * correctly by the basic TLS protocol; higher-level or application + * protocols may define additional requirements. Note that, for historical + * reasons, the data element is named using GMT, the predecessor of the + * current worldwide time base, UTC. + * random_bytes: + * 28 bytes generated by a secure random number generator. + * + * @return the Random structure as a byte array. + */ + tls.createRandom = function() { + // get UTC milliseconds + var d = new Date(); + var utc = +d + d.getTimezoneOffset() * 60000; + var rval = forge.util.createBuffer(); + rval.putInt32(utc); + rval.putBytes(forge.random.getBytes(28)); + return rval; + }; + + /** + * Creates a TLS record with the given type and data. + * + * @param c the connection. + * @param options: + * type: the record type. + * data: the plain text data in a byte buffer. + * + * @return the created record. + */ + tls.createRecord = function(c, options) { + if(!options.data) { + return null; + } + var record = { + type: options.type, + version: { + major: c.version.major, + minor: c.version.minor + }, + length: options.data.length(), + fragment: options.data + }; + return record; + }; + + /** + * Creates a TLS alert record. + * + * @param c the connection. + * @param alert: + * level: the TLS alert level. + * description: the TLS alert description. + * + * @return the created alert record. + */ + tls.createAlert = function(c, alert) { + var b = forge.util.createBuffer(); + b.putByte(alert.level); + b.putByte(alert.description); + return tls.createRecord(c, { + type: tls.ContentType.alert, + data: b + }); + }; + + /* The structure of a TLS handshake message. + * + * struct { + * HandshakeType msg_type; // handshake type + * uint24 length; // bytes in message + * select(HandshakeType) { + * case hello_request: HelloRequest; + * case client_hello: ClientHello; + * case server_hello: ServerHello; + * case certificate: Certificate; + * case server_key_exchange: ServerKeyExchange; + * case certificate_request: CertificateRequest; + * case server_hello_done: ServerHelloDone; + * case certificate_verify: CertificateVerify; + * case client_key_exchange: ClientKeyExchange; + * case finished: Finished; + * } body; + * } Handshake; + */ + + /** + * Creates a ClientHello message. + * + * opaque SessionID<0..32>; + * enum { null(0), deflate(1), (255) } CompressionMethod; + * uint8 CipherSuite[2]; + * + * struct { + * ProtocolVersion client_version; + * Random random; + * SessionID session_id; + * CipherSuite cipher_suites<2..2^16-2>; + * CompressionMethod compression_methods<1..2^8-1>; + * select(extensions_present) { + * case false: + * struct {}; + * case true: + * Extension extensions<0..2^16-1>; + * }; + * } ClientHello; + * + * The extension format for extended client hellos and server hellos is: + * + * struct { + * ExtensionType extension_type; + * opaque extension_data<0..2^16-1>; + * } Extension; + * + * Here: + * + * - "extension_type" identifies the particular extension type. + * - "extension_data" contains information specific to the particular + * extension type. + * + * The extension types defined in this document are: + * + * enum { + * server_name(0), max_fragment_length(1), + * client_certificate_url(2), trusted_ca_keys(3), + * truncated_hmac(4), status_request(5), (65535) + * } ExtensionType; + * + * @param c the connection. + * + * @return the ClientHello byte buffer. + */ + tls.createClientHello = function(c) { + // save hello version + c.session.clientHelloVersion = { + major: c.version.major, + minor: c.version.minor + }; + + // create supported cipher suites + var cipherSuites = forge.util.createBuffer(); + for(var i = 0; i < c.cipherSuites.length; ++i) { + var cs = c.cipherSuites[i]; + cipherSuites.putByte(cs.id[0]); + cipherSuites.putByte(cs.id[1]); + } + var cSuites = cipherSuites.length(); + + // create supported compression methods, null always supported, but + // also support deflate if connection has inflate and deflate methods + var compressionMethods = forge.util.createBuffer(); + compressionMethods.putByte(tls.CompressionMethod.none); + // FIXME: deflate support disabled until issues with raw deflate data + // without zlib headers are resolved + /* + if(c.inflate !== null && c.deflate !== null) { + compressionMethods.putByte(tls.CompressionMethod.deflate); + } + */ + var cMethods = compressionMethods.length(); + + // create TLS SNI (server name indication) extension if virtual host + // has been specified, see RFC 3546 + var extensions = forge.util.createBuffer(); + if(c.virtualHost) { + // create extension struct + var ext = forge.util.createBuffer(); + ext.putByte(0x00); // type server_name (ExtensionType is 2 bytes) + ext.putByte(0x00); + + /* In order to provide the server name, clients MAY include an + * extension of type "server_name" in the (extended) client hello. + * The "extension_data" field of this extension SHALL contain + * "ServerNameList" where: + * + * struct { + * NameType name_type; + * select(name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + var serverName = forge.util.createBuffer(); + serverName.putByte(0x00); // type host_name + writeVector(serverName, 2, forge.util.createBuffer(c.virtualHost)); + + // ServerNameList is in extension_data + var snList = forge.util.createBuffer(); + writeVector(snList, 2, serverName); + writeVector(ext, 2, snList); + extensions.putBuffer(ext); + } + var extLength = extensions.length(); + if(extLength > 0) { + // add extension vector length + extLength += 2; + } + + // determine length of the handshake message + // cipher suites and compression methods size will need to be + // updated if more get added to the list + var sessionId = c.session.id; + var length = + sessionId.length + 1 + // session ID vector + 2 + // version (major + minor) + 4 + 28 + // random time and random bytes + 2 + cSuites + // cipher suites vector + 1 + cMethods + // compression methods vector + extLength; // extensions vector + + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.client_hello); + rval.putInt24(length); // handshake length + rval.putByte(c.version.major); // major version + rval.putByte(c.version.minor); // minor version + rval.putBytes(c.session.sp.client_random); // random time + bytes + writeVector(rval, 1, forge.util.createBuffer(sessionId)); + writeVector(rval, 2, cipherSuites); + writeVector(rval, 1, compressionMethods); + if(extLength > 0) { + writeVector(rval, 2, extensions); + } + return rval; + }; + + /** + * Creates a ServerHello message. + * + * @param c the connection. + * + * @return the ServerHello byte buffer. + */ + tls.createServerHello = function(c) { + // determine length of the handshake message + var sessionId = c.session.id; + var length = + sessionId.length + 1 + // session ID vector + 2 + // version (major + minor) + 4 + 28 + // random time and random bytes + 2 + // chosen cipher suite + 1; // chosen compression method + + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.server_hello); + rval.putInt24(length); // handshake length + rval.putByte(c.version.major); // major version + rval.putByte(c.version.minor); // minor version + rval.putBytes(c.session.sp.server_random); // random time + bytes + writeVector(rval, 1, forge.util.createBuffer(sessionId)); + rval.putByte(c.session.cipherSuite.id[0]); + rval.putByte(c.session.cipherSuite.id[1]); + rval.putByte(c.session.compressionMethod); + return rval; + }; + + /** + * Creates a Certificate message. + * + * When this message will be sent: + * This is the first message the client can send after receiving a server + * hello done message and the first message the server can send after + * sending a ServerHello. This client message is only sent if the server + * requests a certificate. If no suitable certificate is available, the + * client should send a certificate message containing no certificates. If + * client authentication is required by the server for the handshake to + * continue, it may respond with a fatal handshake failure alert. + * + * opaque ASN.1Cert<1..2^24-1>; + * + * struct { + * ASN.1Cert certificate_list<0..2^24-1>; + * } Certificate; + * + * @param c the connection. + * + * @return the Certificate byte buffer. + */ + tls.createCertificate = function(c) { + // TODO: check certificate request to ensure types are supported + + // get a certificate (a certificate as a PEM string) + var client = (c.entity === tls.ConnectionEnd.client); + var cert = null; + if(c.getCertificate) { + var hint; + if(client) { + hint = c.session.certificateRequest; + } else { + hint = c.session.extensions.server_name.serverNameList; + } + cert = c.getCertificate(c, hint); + } + + // buffer to hold certificate list + var certList = forge.util.createBuffer(); + if(cert !== null) { + try { + // normalize cert to a chain of certificates + if(!forge.util.isArray(cert)) { + cert = [cert]; + } + var asn1 = null; + for(var i = 0; i < cert.length; ++i) { + var msg = forge.pem.decode(cert[i])[0]; + if(msg.type !== 'CERTIFICATE' && + msg.type !== 'X509 CERTIFICATE' && + msg.type !== 'TRUSTED CERTIFICATE') { + var error = new Error('Could not convert certificate from PEM; PEM ' + + 'header type is not "CERTIFICATE", "X509 CERTIFICATE", or ' + + '"TRUSTED CERTIFICATE".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert certificate from PEM; PEM is encrypted.'); + } + + var der = forge.util.createBuffer(msg.body); + if(asn1 === null) { + asn1 = forge.asn1.fromDer(der.bytes(), false); + } + + // certificate entry is itself a vector with 3 length bytes + var certBuffer = forge.util.createBuffer(); + writeVector(certBuffer, 3, der); + + // add cert vector to cert list vector + certList.putBuffer(certBuffer); + } + + // save certificate + cert = forge.pki.certificateFromAsn1(asn1); + if(client) { + c.session.clientCertificate = cert; + } else { + c.session.serverCertificate = cert; + } + } catch(ex) { + return c.error(c, { + message: 'Could not send certificate list.', + cause: ex, + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.bad_certificate + } + }); + } + } + + // determine length of the handshake message + var length = 3 + certList.length(); // cert list vector + + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.certificate); + rval.putInt24(length); + writeVector(rval, 3, certList); + return rval; + }; + + /** + * Creates a ClientKeyExchange message. + * + * When this message will be sent: + * This message is always sent by the client. It will immediately follow the + * client certificate message, if it is sent. Otherwise it will be the first + * message sent by the client after it receives the server hello done + * message. + * + * Meaning of this message: + * With this message, the premaster secret is set, either though direct + * transmission of the RSA-encrypted secret, or by the transmission of + * Diffie-Hellman parameters which will allow each side to agree upon the + * same premaster secret. When the key exchange method is DH_RSA or DH_DSS, + * client certification has been requested, and the client was able to + * respond with a certificate which contained a Diffie-Hellman public key + * whose parameters (group and generator) matched those specified by the + * server in its certificate, this message will not contain any data. + * + * Meaning of this message: + * If RSA is being used for key agreement and authentication, the client + * generates a 48-byte premaster secret, encrypts it using the public key + * from the server's certificate or the temporary RSA key provided in a + * server key exchange message, and sends the result in an encrypted + * premaster secret message. This structure is a variant of the client + * key exchange message, not a message in itself. + * + * struct { + * select(KeyExchangeAlgorithm) { + * case rsa: EncryptedPreMasterSecret; + * case diffie_hellman: ClientDiffieHellmanPublic; + * } exchange_keys; + * } ClientKeyExchange; + * + * struct { + * ProtocolVersion client_version; + * opaque random[46]; + * } PreMasterSecret; + * + * struct { + * public-key-encrypted PreMasterSecret pre_master_secret; + * } EncryptedPreMasterSecret; + * + * A public-key-encrypted element is encoded as a vector <0..2^16-1>. + * + * @param c the connection. + * + * @return the ClientKeyExchange byte buffer. + */ + tls.createClientKeyExchange = function(c) { + // create buffer to encrypt + var b = forge.util.createBuffer(); + + // add highest client-supported protocol to help server avoid version + // rollback attacks + b.putByte(c.session.clientHelloVersion.major); + b.putByte(c.session.clientHelloVersion.minor); + + // generate and add 46 random bytes + b.putBytes(forge.random.getBytes(46)); + + // save pre-master secret + var sp = c.session.sp; + sp.pre_master_secret = b.getBytes(); + + // RSA-encrypt the pre-master secret + var key = c.session.serverCertificate.publicKey; + b = key.encrypt(sp.pre_master_secret); + + /* Note: The encrypted pre-master secret will be stored in a + public-key-encrypted opaque vector that has the length prefixed using + 2 bytes, so include those 2 bytes in the handshake message length. This + is done as a minor optimization instead of calling writeVector(). */ + + // determine length of the handshake message + var length = b.length + 2; + + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.client_key_exchange); + rval.putInt24(length); + // add vector length bytes + rval.putInt16(b.length); + rval.putBytes(b); + return rval; + }; + + /** + * Creates a ServerKeyExchange message. + * + * @param c the connection. + * + * @return the ServerKeyExchange byte buffer. + */ + tls.createServerKeyExchange = function(c) { + + // build record fragment + var rval = forge.util.createBuffer(); + return rval; + }; + + /** + * Gets the signed data used to verify a client-side certificate. See + * tls.createCertificateVerify() for details. + * + * @param c the connection. + * @param callback the callback to call once the signed data is ready. + */ + tls.getClientSignature = function(c, callback) { + // generate data to RSA encrypt + var b = forge.util.createBuffer(); + b.putBuffer(c.session.md5.digest()); + b.putBuffer(c.session.sha1.digest()); + b = b.getBytes(); + + // create default signing function as necessary + c.getSignature = c.getSignature || function(c, b, callback) { + // do rsa encryption, call callback + var privateKey = null; + if(c.getPrivateKey) { + try { + privateKey = c.getPrivateKey(c, c.session.clientCertificate); + privateKey = forge.pki.privateKeyFromPem(privateKey); + } catch(ex) { + c.error(c, { + message: 'Could not get private key.', + cause: ex, + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.internal_error + } + }); + } + } + if(privateKey === null) { + c.error(c, { + message: 'No private key set.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.internal_error + } + }); + } else { + b = privateKey.sign(b, null); + } + callback(c, b); + }; + + // get client signature + c.getSignature(c, b, callback); + }; + + /** + * Creates a CertificateVerify message. + * + * Meaning of this message: + * This structure conveys the client's Diffie-Hellman public value + * (Yc) if it was not already included in the client's certificate. + * The encoding used for Yc is determined by the enumerated + * PublicValueEncoding. This structure is a variant of the client + * key exchange message, not a message in itself. + * + * When this message will be sent: + * This message is used to provide explicit verification of a client + * certificate. This message is only sent following a client + * certificate that has signing capability (i.e. all certificates + * except those containing fixed Diffie-Hellman parameters). When + * sent, it will immediately follow the client key exchange message. + * + * struct { + * Signature signature; + * } CertificateVerify; + * + * CertificateVerify.signature.md5_hash + * MD5(handshake_messages); + * + * Certificate.signature.sha_hash + * SHA(handshake_messages); + * + * Here handshake_messages refers to all handshake messages sent or + * received starting at client hello up to but not including this + * message, including the type and length fields of the handshake + * messages. + * + * select(SignatureAlgorithm) { + * case anonymous: struct { }; + * case rsa: + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * case dsa: + * digitally-signed struct { + * opaque sha_hash[20]; + * }; + * } Signature; + * + * In digital signing, one-way hash functions are used as input for a + * signing algorithm. A digitally-signed element is encoded as an opaque + * vector <0..2^16-1>, where the length is specified by the signing + * algorithm and key. + * + * In RSA signing, a 36-byte structure of two hashes (one SHA and one + * MD5) is signed (encrypted with the private key). It is encoded with + * PKCS #1 block type 0 or type 1 as described in [PKCS1]. + * + * In DSS, the 20 bytes of the SHA hash are run directly through the + * Digital Signing Algorithm with no additional hashing. + * + * @param c the connection. + * @param signature the signature to include in the message. + * + * @return the CertificateVerify byte buffer. + */ + tls.createCertificateVerify = function(c, signature) { + /* Note: The signature will be stored in a "digitally-signed" opaque + vector that has the length prefixed using 2 bytes, so include those + 2 bytes in the handshake message length. This is done as a minor + optimization instead of calling writeVector(). */ + + // determine length of the handshake message + var length = signature.length + 2; + + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.certificate_verify); + rval.putInt24(length); + // add vector length bytes + rval.putInt16(signature.length); + rval.putBytes(signature); + return rval; + }; + + /** + * Creates a CertificateRequest message. + * + * @param c the connection. + * + * @return the CertificateRequest byte buffer. + */ + tls.createCertificateRequest = function(c) { + // TODO: support other certificate types + var certTypes = forge.util.createBuffer(); + + // common RSA certificate type + certTypes.putByte(0x01); + + // add distinguished names from CA store + var cAs = forge.util.createBuffer(); + for(var key in c.caStore.certs) { + var cert = c.caStore.certs[key]; + var dn = forge.pki.distinguishedNameToAsn1(cert.subject); + var byteBuffer = forge.asn1.toDer(dn); + cAs.putInt16(byteBuffer.length()); + cAs.putBuffer(byteBuffer); + } + + // TODO: TLS 1.2+ has a different format + + // determine length of the handshake message + var length = + 1 + certTypes.length() + + 2 + cAs.length(); + + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.certificate_request); + rval.putInt24(length); + writeVector(rval, 1, certTypes); + writeVector(rval, 2, cAs); + return rval; + }; + + /** + * Creates a ServerHelloDone message. + * + * @param c the connection. + * + * @return the ServerHelloDone byte buffer. + */ + tls.createServerHelloDone = function(c) { + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.server_hello_done); + rval.putInt24(0); + return rval; + }; + + /** + * Creates a ChangeCipherSpec message. + * + * The change cipher spec protocol exists to signal transitions in + * ciphering strategies. The protocol consists of a single message, + * which is encrypted and compressed under the current (not the pending) + * connection state. The message consists of a single byte of value 1. + * + * struct { + * enum { change_cipher_spec(1), (255) } type; + * } ChangeCipherSpec; + * + * @return the ChangeCipherSpec byte buffer. + */ + tls.createChangeCipherSpec = function() { + var rval = forge.util.createBuffer(); + rval.putByte(0x01); + return rval; + }; + + /** + * Creates a Finished message. + * + * struct { + * opaque verify_data[12]; + * } Finished; + * + * verify_data + * PRF(master_secret, finished_label, MD5(handshake_messages) + + * SHA-1(handshake_messages)) [0..11]; + * + * finished_label + * For Finished messages sent by the client, the string "client + * finished". For Finished messages sent by the server, the + * string "server finished". + * + * handshake_messages + * All of the data from all handshake messages up to but not + * including this message. This is only data visible at the + * handshake layer and does not include record layer headers. + * This is the concatenation of all the Handshake structures as + * defined in 7.4 exchanged thus far. + * + * @param c the connection. + * + * @return the Finished byte buffer. + */ + tls.createFinished = function(c) { + // generate verify_data + var b = forge.util.createBuffer(); + b.putBuffer(c.session.md5.digest()); + b.putBuffer(c.session.sha1.digest()); + + // TODO: determine prf function and verify length for TLS 1.2 + var client = (c.entity === tls.ConnectionEnd.client); + var sp = c.session.sp; + var vdl = 12; + var prf = prf_TLS1; + var label = client ? 'client finished' : 'server finished'; + b = prf(sp.master_secret, label, b.getBytes(), vdl); + + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(tls.HandshakeType.finished); + rval.putInt24(b.length()); + rval.putBuffer(b); + return rval; + }; + + /** + * Creates a HeartbeatMessage (See RFC 6520). + * + * struct { + * HeartbeatMessageType type; + * uint16 payload_length; + * opaque payload[HeartbeatMessage.payload_length]; + * opaque padding[padding_length]; + * } HeartbeatMessage; + * + * The total length of a HeartbeatMessage MUST NOT exceed 2^14 or + * max_fragment_length when negotiated as defined in [RFC6066]. + * + * type: The message type, either heartbeat_request or heartbeat_response. + * + * payload_length: The length of the payload. + * + * payload: The payload consists of arbitrary content. + * + * padding: The padding is random content that MUST be ignored by the + * receiver. The length of a HeartbeatMessage is TLSPlaintext.length + * for TLS and DTLSPlaintext.length for DTLS. Furthermore, the + * length of the type field is 1 byte, and the length of the + * payload_length is 2. Therefore, the padding_length is + * TLSPlaintext.length - payload_length - 3 for TLS and + * DTLSPlaintext.length - payload_length - 3 for DTLS. The + * padding_length MUST be at least 16. + * + * The sender of a HeartbeatMessage MUST use a random padding of at + * least 16 bytes. The padding of a received HeartbeatMessage message + * MUST be ignored. + * + * If the payload_length of a received HeartbeatMessage is too large, + * the received HeartbeatMessage MUST be discarded silently. + * + * @param c the connection. + * @param type the tls.HeartbeatMessageType. + * @param payload the heartbeat data to send as the payload. + * @param [payloadLength] the payload length to use, defaults to the + * actual payload length. + * + * @return the HeartbeatRequest byte buffer. + */ + tls.createHeartbeat = function(type, payload, payloadLength) { + if(typeof payloadLength === 'undefined') { + payloadLength = payload.length; + } + // build record fragment + var rval = forge.util.createBuffer(); + rval.putByte(type); // heartbeat message type + rval.putInt16(payloadLength); // payload length + rval.putBytes(payload); // payload + // padding + var plaintextLength = rval.length(); + var paddingLength = Math.max(16, plaintextLength - payloadLength - 3); + rval.putBytes(forge.random.getBytes(paddingLength)); + return rval; + }; + + /** + * Fragments, compresses, encrypts, and queues a record for delivery. + * + * @param c the connection. + * @param record the record to queue. + */ + tls.queue = function(c, record) { + // error during record creation + if(!record) { + return; + } + + if(record.fragment.length() === 0) { + if(record.type === tls.ContentType.handshake || + record.type === tls.ContentType.alert || + record.type === tls.ContentType.change_cipher_spec) { + // Empty handshake, alert of change cipher spec messages are not allowed per the TLS specification and should not be sent. + return; + } + } + + // if the record is a handshake record, update handshake hashes + if(record.type === tls.ContentType.handshake) { + var bytes = record.fragment.bytes(); + c.session.md5.update(bytes); + c.session.sha1.update(bytes); + bytes = null; + } + + // handle record fragmentation + var records; + if(record.fragment.length() <= tls.MaxFragment) { + records = [record]; + } else { + // fragment data as long as it is too long + records = []; + var data = record.fragment.bytes(); + while(data.length > tls.MaxFragment) { + records.push(tls.createRecord(c, { + type: record.type, + data: forge.util.createBuffer(data.slice(0, tls.MaxFragment)) + })); + data = data.slice(tls.MaxFragment); + } + // add last record + if(data.length > 0) { + records.push(tls.createRecord(c, { + type: record.type, + data: forge.util.createBuffer(data) + })); + } + } + + // compress and encrypt all fragmented records + for(var i = 0; i < records.length && !c.fail; ++i) { + // update the record using current write state + var rec = records[i]; + var s = c.state.current.write; + if(s.update(c, rec)) { + // store record + c.records.push(rec); + } + } + }; + + /** + * Flushes all queued records to the output buffer and calls the + * tlsDataReady() handler on the given connection. + * + * @param c the connection. + * + * @return true on success, false on failure. + */ + tls.flush = function(c) { + for(var i = 0; i < c.records.length; ++i) { + var record = c.records[i]; + + // add record header and fragment + c.tlsData.putByte(record.type); + c.tlsData.putByte(record.version.major); + c.tlsData.putByte(record.version.minor); + c.tlsData.putInt16(record.fragment.length()); + c.tlsData.putBuffer(c.records[i].fragment); + } + c.records = []; + return c.tlsDataReady(c); + }; + + /** + * Maps a pki.certificateError to a tls.Alert.Description. + * + * @param error the error to map. + * + * @return the alert description. + */ + var _certErrorToAlertDesc = function(error) { + switch(error) { + case true: + return true; + case forge.pki.certificateError.bad_certificate: + return tls.Alert.Description.bad_certificate; + case forge.pki.certificateError.unsupported_certificate: + return tls.Alert.Description.unsupported_certificate; + case forge.pki.certificateError.certificate_revoked: + return tls.Alert.Description.certificate_revoked; + case forge.pki.certificateError.certificate_expired: + return tls.Alert.Description.certificate_expired; + case forge.pki.certificateError.certificate_unknown: + return tls.Alert.Description.certificate_unknown; + case forge.pki.certificateError.unknown_ca: + return tls.Alert.Description.unknown_ca; + default: + return tls.Alert.Description.bad_certificate; + } + }; + + /** + * Maps a tls.Alert.Description to a pki.certificateError. + * + * @param desc the alert description. + * + * @return the certificate error. + */ + var _alertDescToCertError = function(desc) { + switch(desc) { + case true: + return true; + case tls.Alert.Description.bad_certificate: + return forge.pki.certificateError.bad_certificate; + case tls.Alert.Description.unsupported_certificate: + return forge.pki.certificateError.unsupported_certificate; + case tls.Alert.Description.certificate_revoked: + return forge.pki.certificateError.certificate_revoked; + case tls.Alert.Description.certificate_expired: + return forge.pki.certificateError.certificate_expired; + case tls.Alert.Description.certificate_unknown: + return forge.pki.certificateError.certificate_unknown; + case tls.Alert.Description.unknown_ca: + return forge.pki.certificateError.unknown_ca; + default: + return forge.pki.certificateError.bad_certificate; + } + }; + + /** + * Verifies a certificate chain against the given connection's + * Certificate Authority store. + * + * @param c the TLS connection. + * @param chain the certificate chain to verify, with the root or highest + * authority at the end. + * + * @return true if successful, false if not. + */ + tls.verifyCertificateChain = function(c, chain) { + try { + // Make a copy of c.verifyOptions so that we can modify options.verify + // without modifying c.verifyOptions. + var options = {}; + for (var key in c.verifyOptions) { + options[key] = c.verifyOptions[key]; + } + + options.verify = function(vfd, depth, chain) { + // convert pki.certificateError to tls alert description + var desc = _certErrorToAlertDesc(vfd); + + // call application callback + var ret = c.verify(c, vfd, depth, chain); + if(ret !== true) { + if(typeof ret === 'object' && !forge.util.isArray(ret)) { + // throw custom error + var error = new Error('The application rejected the certificate.'); + error.send = true; + error.alert = { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.bad_certificate + }; + if(ret.message) { + error.message = ret.message; + } + if(ret.alert) { + error.alert.description = ret.alert; + } + throw error; + } + + // convert tls alert description to pki.certificateError + if(ret !== vfd) { + ret = _alertDescToCertError(ret); + } + } + + return ret; + }; + + // verify chain + forge.pki.verifyCertificateChain(c.caStore, chain, options); + } catch(ex) { + // build tls error if not already customized + var err = ex; + if(typeof err !== 'object' || forge.util.isArray(err)) { + err = { + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: _certErrorToAlertDesc(ex) + } + }; + } + if(!('send' in err)) { + err.send = true; + } + if(!('alert' in err)) { + err.alert = { + level: tls.Alert.Level.fatal, + description: _certErrorToAlertDesc(err.error) + }; + } + + // send error + c.error(c, err); + } + + return !c.fail; + }; + + /** + * Creates a new TLS session cache. + * + * @param cache optional map of session ID to cached session. + * @param capacity the maximum size for the cache (default: 100). + * + * @return the new TLS session cache. + */ + tls.createSessionCache = function(cache, capacity) { + var rval = null; + + // assume input is already a session cache object + if(cache && cache.getSession && cache.setSession && cache.order) { + rval = cache; + } else { + // create cache + rval = {}; + rval.cache = cache || {}; + rval.capacity = Math.max(capacity || 100, 1); + rval.order = []; + + // store order for sessions, delete session overflow + for(var key in cache) { + if(rval.order.length <= capacity) { + rval.order.push(key); + } else { + delete cache[key]; + } + } + + // get a session from a session ID (or get any session) + rval.getSession = function(sessionId) { + var session = null; + var key = null; + + // if session ID provided, use it + if(sessionId) { + key = forge.util.bytesToHex(sessionId); + } else if(rval.order.length > 0) { + // get first session from cache + key = rval.order[0]; + } + + if(key !== null && key in rval.cache) { + // get cached session and remove from cache + session = rval.cache[key]; + delete rval.cache[key]; + for(var i in rval.order) { + if(rval.order[i] === key) { + rval.order.splice(i, 1); + break; + } + } + } + + return session; + }; + + // set a session in the cache + rval.setSession = function(sessionId, session) { + // remove session from cache if at capacity + if(rval.order.length === rval.capacity) { + var key = rval.order.shift(); + delete rval.cache[key]; + } + // add session to cache + var key = forge.util.bytesToHex(sessionId); + rval.order.push(key); + rval.cache[key] = session; + }; + } + + return rval; + }; + + /** + * Creates a new TLS connection. + * + * See public createConnection() docs for more details. + * + * @param options the options for this connection. + * + * @return the new TLS connection. + */ + tls.createConnection = function(options) { + var caStore = null; + if(options.caStore) { + // if CA store is an array, convert it to a CA store object + if(forge.util.isArray(options.caStore)) { + caStore = forge.pki.createCaStore(options.caStore); + } else { + caStore = options.caStore; + } + } else { + // create empty CA store + caStore = forge.pki.createCaStore(); + } + + // setup default cipher suites + var cipherSuites = options.cipherSuites || null; + if(cipherSuites === null) { + cipherSuites = []; + for(var key in tls.CipherSuites) { + cipherSuites.push(tls.CipherSuites[key]); + } + } + + // set default entity + var entity = (options.server || false) ? + tls.ConnectionEnd.server : tls.ConnectionEnd.client; + + // create session cache if requested + var sessionCache = options.sessionCache ? + tls.createSessionCache(options.sessionCache) : null; + + // create TLS connection + var c = { + version: {major: tls.Version.major, minor: tls.Version.minor}, + entity: entity, + sessionId: options.sessionId, + caStore: caStore, + sessionCache: sessionCache, + cipherSuites: cipherSuites, + connected: options.connected, + virtualHost: options.virtualHost || null, + verifyClient: options.verifyClient || false, + verify: options.verify || function(cn, vfd, dpth, cts) {return vfd;}, + verifyOptions: options.verifyOptions || {}, + getCertificate: options.getCertificate || null, + getPrivateKey: options.getPrivateKey || null, + getSignature: options.getSignature || null, + input: forge.util.createBuffer(), + tlsData: forge.util.createBuffer(), + data: forge.util.createBuffer(), + tlsDataReady: options.tlsDataReady, + dataReady: options.dataReady, + heartbeatReceived: options.heartbeatReceived, + closed: options.closed, + error: function(c, ex) { + // set origin if not set + ex.origin = ex.origin || + ((c.entity === tls.ConnectionEnd.client) ? 'client' : 'server'); + + // send TLS alert + if(ex.send) { + tls.queue(c, tls.createAlert(c, ex.alert)); + tls.flush(c); + } + + // error is fatal by default + var fatal = (ex.fatal !== false); + if(fatal) { + // set fail flag + c.fail = true; + } + + // call error handler first + options.error(c, ex); + + if(fatal) { + // fatal error, close connection, do not clear fail + c.close(false); + } + }, + deflate: options.deflate || null, + inflate: options.inflate || null + }; + + /** + * Resets a closed TLS connection for reuse. Called in c.close(). + * + * @param clearFail true to clear the fail flag (default: true). + */ + c.reset = function(clearFail) { + c.version = {major: tls.Version.major, minor: tls.Version.minor}; + c.record = null; + c.session = null; + c.peerCertificate = null; + c.state = { + pending: null, + current: null + }; + c.expect = (c.entity === tls.ConnectionEnd.client) ? SHE : CHE; + c.fragmented = null; + c.records = []; + c.open = false; + c.handshakes = 0; + c.handshaking = false; + c.isConnected = false; + c.fail = !(clearFail || typeof(clearFail) === 'undefined'); + c.input.clear(); + c.tlsData.clear(); + c.data.clear(); + c.state.current = tls.createConnectionState(c); + }; + + // do initial reset of connection + c.reset(); + + /** + * Updates the current TLS engine state based on the given record. + * + * @param c the TLS connection. + * @param record the TLS record to act on. + */ + var _update = function(c, record) { + // get record handler (align type in table by subtracting lowest) + var aligned = record.type - tls.ContentType.change_cipher_spec; + var handlers = ctTable[c.entity][c.expect]; + if(aligned in handlers) { + handlers[aligned](c, record); + } else { + // unexpected record + tls.handleUnexpected(c, record); + } + }; + + /** + * Reads the record header and initializes the next record on the given + * connection. + * + * @param c the TLS connection with the next record. + * + * @return 0 if the input data could be processed, otherwise the + * number of bytes required for data to be processed. + */ + var _readRecordHeader = function(c) { + var rval = 0; + + // get input buffer and its length + var b = c.input; + var len = b.length(); + + // need at least 5 bytes to initialize a record + if(len < 5) { + rval = 5 - len; + } else { + // enough bytes for header + // initialize record + c.record = { + type: b.getByte(), + version: { + major: b.getByte(), + minor: b.getByte() + }, + length: b.getInt16(), + fragment: forge.util.createBuffer(), + ready: false + }; + + // check record version + var compatibleVersion = (c.record.version.major === c.version.major); + if(compatibleVersion && c.session && c.session.version) { + // session version already set, require same minor version + compatibleVersion = (c.record.version.minor === c.version.minor); + } + if(!compatibleVersion) { + c.error(c, { + message: 'Incompatible TLS version.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: tls.Alert.Description.protocol_version + } + }); + } + } + + return rval; + }; + + /** + * Reads the next record's contents and appends its message to any + * previously fragmented message. + * + * @param c the TLS connection with the next record. + * + * @return 0 if the input data could be processed, otherwise the + * number of bytes required for data to be processed. + */ + var _readRecord = function(c) { + var rval = 0; + + // ensure there is enough input data to get the entire record + var b = c.input; + var len = b.length(); + if(len < c.record.length) { + // not enough data yet, return how much is required + rval = c.record.length - len; + } else { + // there is enough data to parse the pending record + // fill record fragment and compact input buffer + c.record.fragment.putBytes(b.getBytes(c.record.length)); + b.compact(); + + // update record using current read state + var s = c.state.current.read; + if(s.update(c, c.record)) { + // see if there is a previously fragmented message that the + // new record's message fragment should be appended to + if(c.fragmented !== null) { + // if the record type matches a previously fragmented + // record, append the record fragment to it + if(c.fragmented.type === c.record.type) { + // concatenate record fragments + c.fragmented.fragment.putBuffer(c.record.fragment); + c.record = c.fragmented; + } else { + // error, invalid fragmented record + c.error(c, { + message: 'Invalid fragmented record.', + send: true, + alert: { + level: tls.Alert.Level.fatal, + description: + tls.Alert.Description.unexpected_message + } + }); + } + } + + // record is now ready + c.record.ready = true; + } + } + + return rval; + }; + + /** + * Performs a handshake using the TLS Handshake Protocol, as a client. + * + * This method should only be called if the connection is in client mode. + * + * @param sessionId the session ID to use, null to start a new one. + */ + c.handshake = function(sessionId) { + // error to call this in non-client mode + if(c.entity !== tls.ConnectionEnd.client) { + // not fatal error + c.error(c, { + message: 'Cannot initiate handshake as a server.', + fatal: false + }); + } else if(c.handshaking) { + // handshake is already in progress, fail but not fatal error + c.error(c, { + message: 'Handshake already in progress.', + fatal: false + }); + } else { + // clear fail flag on reuse + if(c.fail && !c.open && c.handshakes === 0) { + c.fail = false; + } + + // now handshaking + c.handshaking = true; + + // default to blank (new session) + sessionId = sessionId || ''; + + // if a session ID was specified, try to find it in the cache + var session = null; + if(sessionId.length > 0) { + if(c.sessionCache) { + session = c.sessionCache.getSession(sessionId); + } + + // matching session not found in cache, clear session ID + if(session === null) { + sessionId = ''; + } + } + + // no session given, grab a session from the cache, if available + if(sessionId.length === 0 && c.sessionCache) { + session = c.sessionCache.getSession(); + if(session !== null) { + sessionId = session.id; + } + } + + // set up session + c.session = { + id: sessionId, + version: null, + cipherSuite: null, + compressionMethod: null, + serverCertificate: null, + certificateRequest: null, + clientCertificate: null, + sp: {}, + md5: forge.md.md5.create(), + sha1: forge.md.sha1.create() + }; + + // use existing session information + if(session) { + // only update version on connection, session version not yet set + c.version = session.version; + c.session.sp = session.sp; + } + + // generate new client random + c.session.sp.client_random = tls.createRandom().getBytes(); + + // connection now open + c.open = true; + + // send hello + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.handshake, + data: tls.createClientHello(c) + })); + tls.flush(c); + } + }; + + /** + * Called when TLS protocol data has been received from somewhere and should + * be processed by the TLS engine. + * + * @param data the TLS protocol data, as a string, to process. + * + * @return 0 if the data could be processed, otherwise the number of bytes + * required for data to be processed. + */ + c.process = function(data) { + var rval = 0; + + // buffer input data + if(data) { + c.input.putBytes(data); + } + + // process next record if no failure, process will be called after + // each record is handled (since handling can be asynchronous) + if(!c.fail) { + // reset record if ready and now empty + if(c.record !== null && + c.record.ready && c.record.fragment.isEmpty()) { + c.record = null; + } + + // if there is no pending record, try to read record header + if(c.record === null) { + rval = _readRecordHeader(c); + } + + // read the next record (if record not yet ready) + if(!c.fail && c.record !== null && !c.record.ready) { + rval = _readRecord(c); + } + + // record ready to be handled, update engine state + if(!c.fail && c.record !== null && c.record.ready) { + _update(c, c.record); + } + } + + return rval; + }; + + /** + * Requests that application data be packaged into a TLS record. The + * tlsDataReady handler will be called when the TLS record(s) have been + * prepared. + * + * @param data the application data, as a raw 'binary' encoded string, to + * be sent; to send utf-16/utf-8 string data, use the return value + * of util.encodeUtf8(str). + * + * @return true on success, false on failure. + */ + c.prepare = function(data) { + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.application_data, + data: forge.util.createBuffer(data) + })); + return tls.flush(c); + }; + + /** + * Requests that a heartbeat request be packaged into a TLS record for + * transmission. The tlsDataReady handler will be called when TLS record(s) + * have been prepared. + * + * When a heartbeat response has been received, the heartbeatReceived + * handler will be called with the matching payload. This handler can + * be used to clear a retransmission timer, etc. + * + * @param payload the heartbeat data to send as the payload in the message. + * @param [payloadLength] the payload length to use, defaults to the + * actual payload length. + * + * @return true on success, false on failure. + */ + c.prepareHeartbeatRequest = function(payload, payloadLength) { + if(payload instanceof forge.util.ByteBuffer) { + payload = payload.bytes(); + } + if(typeof payloadLength === 'undefined') { + payloadLength = payload.length; + } + c.expectedHeartbeatPayload = payload; + tls.queue(c, tls.createRecord(c, { + type: tls.ContentType.heartbeat, + data: tls.createHeartbeat( + tls.HeartbeatMessageType.heartbeat_request, payload, payloadLength) + })); + return tls.flush(c); + }; + + /** + * Closes the connection (sends a close_notify alert). + * + * @param clearFail true to clear the fail flag (default: true). + */ + c.close = function(clearFail) { + // save session if connection didn't fail + if(!c.fail && c.sessionCache && c.session) { + // only need to preserve session ID, version, and security params + var session = { + id: c.session.id, + version: c.session.version, + sp: c.session.sp + }; + session.sp.keys = null; + c.sessionCache.setSession(session.id, session); + } + + if(c.open) { + // connection no longer open, clear input + c.open = false; + c.input.clear(); + + // if connected or handshaking, send an alert + if(c.isConnected || c.handshaking) { + c.isConnected = c.handshaking = false; + + // send close_notify alert + tls.queue(c, tls.createAlert(c, { + level: tls.Alert.Level.warning, + description: tls.Alert.Description.close_notify + })); + tls.flush(c); + } + + // call handler + c.closed(c); + } + + // reset TLS connection, do not clear fail flag + c.reset(clearFail); + }; + + return c; + }; + + /* TLS API */ + var tls_1 = forge.tls = forge.tls || {}; + + // expose non-functions + for(var key in tls) { + if(typeof tls[key] !== 'function') { + forge.tls[key] = tls[key]; + } + } + + // expose prf_tls1 for testing + forge.tls.prf_tls1 = prf_TLS1; + + // expose sha1 hmac method + forge.tls.hmac_sha1 = hmac_sha1; + + // expose session cache creation + forge.tls.createSessionCache = tls.createSessionCache; + + /** + * Creates a new TLS connection. This does not make any assumptions about the + * transport layer that TLS is working on top of, ie: it does not assume there + * is a TCP/IP connection or establish one. A TLS connection is totally + * abstracted away from the layer is runs on top of, it merely establishes a + * secure channel between a client" and a "server". + * + * A TLS connection contains 4 connection states: pending read and write, and + * current read and write. + * + * At initialization, the current read and write states will be null. Only once + * the security parameters have been set and the keys have been generated can + * the pending states be converted into current states. Current states will be + * updated for each record processed. + * + * A custom certificate verify callback may be provided to check information + * like the common name on the server's certificate. It will be called for + * every certificate in the chain. It has the following signature: + * + * variable func(c, certs, index, preVerify) + * Where: + * c The TLS connection + * verified Set to true if certificate was verified, otherwise the alert + * tls.Alert.Description for why the certificate failed. + * depth The current index in the chain, where 0 is the server's cert. + * certs The certificate chain, *NOTE* if the server was anonymous then + * the chain will be empty. + * + * The function returns true on success and on failure either the appropriate + * tls.Alert.Description or an object with 'alert' set to the appropriate + * tls.Alert.Description and 'message' set to a custom error message. If true + * is not returned then the connection will abort using, in order of + * availability, first the returned alert description, second the preVerify + * alert description, and lastly the default 'bad_certificate'. + * + * There are three callbacks that can be used to make use of client-side + * certificates where each takes the TLS connection as the first parameter: + * + * getCertificate(conn, hint) + * The second parameter is a hint as to which certificate should be + * returned. If the connection entity is a client, then the hint will be + * the CertificateRequest message from the server that is part of the + * TLS protocol. If the connection entity is a server, then it will be + * the servername list provided via an SNI extension the ClientHello, if + * one was provided (empty array if not). The hint can be examined to + * determine which certificate to use (advanced). Most implementations + * will just return a certificate. The return value must be a + * PEM-formatted certificate or an array of PEM-formatted certificates + * that constitute a certificate chain, with the first in the array/chain + * being the client's certificate. + * getPrivateKey(conn, certificate) + * The second parameter is an forge.pki X.509 certificate object that + * is associated with the requested private key. The return value must + * be a PEM-formatted private key. + * getSignature(conn, bytes, callback) + * This callback can be used instead of getPrivateKey if the private key + * is not directly accessible in javascript or should not be. For + * instance, a secure external web service could provide the signature + * in exchange for appropriate credentials. The second parameter is a + * string of bytes to be signed that are part of the TLS protocol. These + * bytes are used to verify that the private key for the previously + * provided client-side certificate is accessible to the client. The + * callback is a function that takes 2 parameters, the TLS connection + * and the RSA encrypted (signed) bytes as a string. This callback must + * be called once the signature is ready. + * + * @param options the options for this connection: + * server: true if the connection is server-side, false for client. + * sessionId: a session ID to reuse, null for a new connection. + * caStore: an array of certificates to trust. + * sessionCache: a session cache to use. + * cipherSuites: an optional array of cipher suites to use, + * see tls.CipherSuites. + * connected: function(conn) called when the first handshake completes. + * virtualHost: the virtual server name to use in a TLS SNI extension. + * verifyClient: true to require a client certificate in server mode, + * 'optional' to request one, false not to (default: false). + * verify: a handler used to custom verify certificates in the chain. + * verifyOptions: an object with options for the certificate chain validation. + * See documentation of pki.verifyCertificateChain for possible options. + * verifyOptions.verify is ignored. If you wish to specify a verify handler + * use the verify key. + * getCertificate: an optional callback used to get a certificate or + * a chain of certificates (as an array). + * getPrivateKey: an optional callback used to get a private key. + * getSignature: an optional callback used to get a signature. + * tlsDataReady: function(conn) called when TLS protocol data has been + * prepared and is ready to be used (typically sent over a socket + * connection to its destination), read from conn.tlsData buffer. + * dataReady: function(conn) called when application data has + * been parsed from a TLS record and should be consumed by the + * application, read from conn.data buffer. + * closed: function(conn) called when the connection has been closed. + * error: function(conn, error) called when there was an error. + * deflate: function(inBytes) if provided, will deflate TLS records using + * the deflate algorithm if the server supports it. + * inflate: function(inBytes) if provided, will inflate TLS records using + * the deflate algorithm if the server supports it. + * + * @return the new TLS connection. + */ + forge.tls.createConnection = tls.createConnection; + + var aesCipherSuites = createCommonjsModule(function (module) { + /** + * A Javascript implementation of AES Cipher Suites for TLS. + * + * @author Dave Longley + * + * Copyright (c) 2009-2015 Digital Bazaar, Inc. + * + */ + + + + + var tls = module.exports = forge.tls; + + /** + * Supported cipher suites. + */ + tls.CipherSuites['TLS_RSA_WITH_AES_128_CBC_SHA'] = { + id: [0x00, 0x2f], + name: 'TLS_RSA_WITH_AES_128_CBC_SHA', + initSecurityParameters: function(sp) { + sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes; + sp.cipher_type = tls.CipherType.block; + sp.enc_key_length = 16; + sp.block_length = 16; + sp.fixed_iv_length = 16; + sp.record_iv_length = 16; + sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1; + sp.mac_length = 20; + sp.mac_key_length = 20; + }, + initConnectionState: initConnectionState + }; + tls.CipherSuites['TLS_RSA_WITH_AES_256_CBC_SHA'] = { + id: [0x00, 0x35], + name: 'TLS_RSA_WITH_AES_256_CBC_SHA', + initSecurityParameters: function(sp) { + sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes; + sp.cipher_type = tls.CipherType.block; + sp.enc_key_length = 32; + sp.block_length = 16; + sp.fixed_iv_length = 16; + sp.record_iv_length = 16; + sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1; + sp.mac_length = 20; + sp.mac_key_length = 20; + }, + initConnectionState: initConnectionState + }; + + function initConnectionState(state, c, sp) { + var client = (c.entity === forge.tls.ConnectionEnd.client); + + // cipher setup + state.read.cipherState = { + init: false, + cipher: forge.cipher.createDecipher('AES-CBC', client ? + sp.keys.server_write_key : sp.keys.client_write_key), + iv: client ? sp.keys.server_write_IV : sp.keys.client_write_IV + }; + state.write.cipherState = { + init: false, + cipher: forge.cipher.createCipher('AES-CBC', client ? + sp.keys.client_write_key : sp.keys.server_write_key), + iv: client ? sp.keys.client_write_IV : sp.keys.server_write_IV + }; + state.read.cipherFunction = decrypt_aes_cbc_sha1; + state.write.cipherFunction = encrypt_aes_cbc_sha1; + + // MAC setup + state.read.macLength = state.write.macLength = sp.mac_length; + state.read.macFunction = state.write.macFunction = tls.hmac_sha1; + } + + /** + * Encrypts the TLSCompressed record into a TLSCipherText record using AES + * in CBC mode. + * + * @param record the TLSCompressed record to encrypt. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ + function encrypt_aes_cbc_sha1(record, s) { + var rval = false; + + // append MAC to fragment, update sequence number + var mac = s.macFunction(s.macKey, s.sequenceNumber, record); + record.fragment.putBytes(mac); + s.updateSequenceNumber(); + + // TLS 1.1+ use an explicit IV every time to protect against CBC attacks + var iv; + if(record.version.minor === tls.Versions.TLS_1_0.minor) { + // use the pre-generated IV when initializing for TLS 1.0, otherwise use + // the residue from the previous encryption + iv = s.cipherState.init ? null : s.cipherState.iv; + } else { + iv = forge.random.getBytesSync(16); + } + + s.cipherState.init = true; + + // start cipher + var cipher = s.cipherState.cipher; + cipher.start({iv: iv}); + + // TLS 1.1+ write IV into output + if(record.version.minor >= tls.Versions.TLS_1_1.minor) { + cipher.output.putBytes(iv); + } + + // do encryption (default padding is appropriate) + cipher.update(record.fragment); + if(cipher.finish(encrypt_aes_cbc_sha1_padding)) { + // set record fragment to encrypted output + record.fragment = cipher.output; + record.length = record.fragment.length(); + rval = true; + } + + return rval; + } + + /** + * Handles padding for aes_cbc_sha1 in encrypt mode. + * + * @param blockSize the block size. + * @param input the input buffer. + * @param decrypt true in decrypt mode, false in encrypt mode. + * + * @return true on success, false on failure. + */ + function encrypt_aes_cbc_sha1_padding(blockSize, input, decrypt) { + /* The encrypted data length (TLSCiphertext.length) is one more than the sum + of SecurityParameters.block_length, TLSCompressed.length, + SecurityParameters.mac_length, and padding_length. + + The padding may be any length up to 255 bytes long, as long as it results in + the TLSCiphertext.length being an integral multiple of the block length. + Lengths longer than necessary might be desirable to frustrate attacks on a + protocol based on analysis of the lengths of exchanged messages. Each uint8 + in the padding data vector must be filled with the padding length value. + + The padding length should be such that the total size of the + GenericBlockCipher structure is a multiple of the cipher's block length. + Legal values range from zero to 255, inclusive. This length specifies the + length of the padding field exclusive of the padding_length field itself. + + This is slightly different from PKCS#7 because the padding value is 1 + less than the actual number of padding bytes if you include the + padding_length uint8 itself as a padding byte. */ + if(!decrypt) { + // get the number of padding bytes required to reach the blockSize and + // subtract 1 for the padding value (to make room for the padding_length + // uint8) + var padding = blockSize - (input.length() % blockSize); + input.fillWithByte(padding - 1, padding); + } + return true; + } + + /** + * Handles padding for aes_cbc_sha1 in decrypt mode. + * + * @param blockSize the block size. + * @param output the output buffer. + * @param decrypt true in decrypt mode, false in encrypt mode. + * + * @return true on success, false on failure. + */ + function decrypt_aes_cbc_sha1_padding(blockSize, output, decrypt) { + var rval = true; + if(decrypt) { + /* The last byte in the output specifies the number of padding bytes not + including itself. Each of the padding bytes has the same value as that + last byte (known as the padding_length). Here we check all padding + bytes to ensure they have the value of padding_length even if one of + them is bad in order to ward-off timing attacks. */ + var len = output.length(); + var paddingLength = output.last(); + for(var i = len - 1 - paddingLength; i < len - 1; ++i) { + rval = rval && (output.at(i) == paddingLength); + } + if(rval) { + // trim off padding bytes and last padding length byte + output.truncate(paddingLength + 1); + } + } + return rval; + } + + /** + * Decrypts a TLSCipherText record into a TLSCompressed record using + * AES in CBC mode. + * + * @param record the TLSCipherText record to decrypt. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ + function decrypt_aes_cbc_sha1(record, s) { + var rval = false; + + var iv; + if(record.version.minor === tls.Versions.TLS_1_0.minor) { + // use pre-generated IV when initializing for TLS 1.0, otherwise use the + // residue from the previous decryption + iv = s.cipherState.init ? null : s.cipherState.iv; + } else { + // TLS 1.1+ use an explicit IV every time to protect against CBC attacks + // that is appended to the record fragment + iv = record.fragment.getBytes(16); + } + + s.cipherState.init = true; + + // start cipher + var cipher = s.cipherState.cipher; + cipher.start({iv: iv}); + + // do decryption + cipher.update(record.fragment); + rval = cipher.finish(decrypt_aes_cbc_sha1_padding); + + // even if decryption fails, keep going to minimize timing attacks + + // decrypted data: + // first (len - 20) bytes = application data + // last 20 bytes = MAC + var macLen = s.macLength; + + // create a random MAC to check against should the mac length check fail + // Note: do this regardless of the failure to keep timing consistent + var mac = forge.random.getBytesSync(macLen); + + // get fragment and mac + var len = cipher.output.length(); + if(len >= macLen) { + record.fragment = cipher.output.getBytes(len - macLen); + mac = cipher.output.getBytes(macLen); + } else { + // bad data, but get bytes anyway to try to keep timing consistent + record.fragment = cipher.output.getBytes(); + } + record.fragment = forge.util.createBuffer(record.fragment); + record.length = record.fragment.length(); + + // see if data integrity checks out, update sequence number + var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record); + s.updateSequenceNumber(); + rval = compareMacs(s.macKey, mac, mac2) && rval; + return rval; + } + + /** + * Safely compare two MACs. This function will compare two MACs in a way + * that protects against timing attacks. + * + * TODO: Expose elsewhere as a utility API. + * + * See: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ + * + * @param key the MAC key to use. + * @param mac1 as a binary-encoded string of bytes. + * @param mac2 as a binary-encoded string of bytes. + * + * @return true if the MACs are the same, false if not. + */ + function compareMacs(key, mac1, mac2) { + var hmac = forge.hmac.create(); + + hmac.start('SHA1', key); + hmac.update(mac1); + mac1 = hmac.digest().getBytes(); + + hmac.start(null, null); + hmac.update(mac2); + mac2 = hmac.digest().getBytes(); + + return mac1 === mac2; + } + }); + + /** + * Debugging support for web applications. + * + * @author David I. Lehn + * + * Copyright 2008-2013 Digital Bazaar, Inc. + */ + + + /* DEBUG API */ + var debug = forge.debug = forge.debug || {}; + + // Private storage for debugging. + // Useful to expose data that is otherwise unviewable behind closures. + // NOTE: remember that this can hold references to data and cause leaks! + // format is "forge._debug.. = data" + // Example: + // (function() { + // var cat = 'forge.test.Test'; // debugging category + // var sState = {...}; // local state + // forge.debug.set(cat, 'sState', sState); + // })(); + forge.debug.storage = {}; + + /** + * Gets debug data. Omit name for all cat data Omit name and cat for + * all data. + * + * @param cat name of debugging category. + * @param name name of data to get (optional). + * @return object with requested debug data or undefined. + */ + forge.debug.get = function(cat, name) { + var rval; + if(typeof(cat) === 'undefined') { + rval = forge.debug.storage; + } else if(cat in forge.debug.storage) { + if(typeof(name) === 'undefined') { + rval = forge.debug.storage[cat]; + } else { + rval = forge.debug.storage[cat][name]; + } + } + return rval; + }; + + /** + * Sets debug data. + * + * @param cat name of debugging category. + * @param name name of data to set. + * @param data data to set. + */ + forge.debug.set = function(cat, name, data) { + if(!(cat in forge.debug.storage)) { + forge.debug.storage[cat] = {}; + } + forge.debug.storage[cat][name] = data; + }; + + /** + * Clears debug data. Omit name for all cat data. Omit name and cat for + * all data. + * + * @param cat name of debugging category. + * @param name name of data to clear or omit to clear entire category. + */ + forge.debug.clear = function(cat, name) { + if(typeof(cat) === 'undefined') { + forge.debug.storage = {}; + } else if(cat in forge.debug.storage) { + if(typeof(name) === 'undefined') { + delete forge.debug.storage[cat]; + } else { + delete forge.debug.storage[cat][name]; + } + } + }; + + var sha512_1 = createCommonjsModule(function (module) { + /** + * Secure Hash Algorithm with a 1024-bit block size implementation. + * + * This includes: SHA-512, SHA-384, SHA-512/224, and SHA-512/256. For + * SHA-256 (block size 512 bits), see sha256.js. + * + * See FIPS 180-4 for details. + * + * @author Dave Longley + * + * Copyright (c) 2014-2015 Digital Bazaar, Inc. + */ + + + + + var sha512 = module.exports = forge.sha512 = forge.sha512 || {}; + + // SHA-512 + forge.md.sha512 = forge.md.algorithms.sha512 = sha512; + + // SHA-384 + var sha384 = forge.sha384 = forge.sha512.sha384 = forge.sha512.sha384 || {}; + sha384.create = function() { + return sha512.create('SHA-384'); + }; + forge.md.sha384 = forge.md.algorithms.sha384 = sha384; + + // SHA-512/256 + forge.sha512.sha256 = forge.sha512.sha256 || { + create: function() { + return sha512.create('SHA-512/256'); + } + }; + forge.md['sha512/256'] = forge.md.algorithms['sha512/256'] = + forge.sha512.sha256; + + // SHA-512/224 + forge.sha512.sha224 = forge.sha512.sha224 || { + create: function() { + return sha512.create('SHA-512/224'); + } + }; + forge.md['sha512/224'] = forge.md.algorithms['sha512/224'] = + forge.sha512.sha224; + + /** + * Creates a SHA-2 message digest object. + * + * @param algorithm the algorithm to use (SHA-512, SHA-384, SHA-512/224, + * SHA-512/256). + * + * @return a message digest object. + */ + sha512.create = function(algorithm) { + // do initialization as necessary + if(!_initialized) { + _init(); + } + + if(typeof algorithm === 'undefined') { + algorithm = 'SHA-512'; + } + + if(!(algorithm in _states)) { + throw new Error('Invalid SHA-512 algorithm: ' + algorithm); + } + + // SHA-512 state contains eight 64-bit integers (each as two 32-bit ints) + var _state = _states[algorithm]; + var _h = null; + + // input buffer + var _input = forge.util.createBuffer(); + + // used for 64-bit word storage + var _w = new Array(80); + for(var wi = 0; wi < 80; ++wi) { + _w[wi] = new Array(2); + } + + // determine digest length by algorithm name (default) + var digestLength = 64; + switch(algorithm) { + case 'SHA-384': + digestLength = 48; + break; + case 'SHA-512/256': + digestLength = 32; + break; + case 'SHA-512/224': + digestLength = 28; + break; + } + + // message digest object + var md = { + // SHA-512 => sha512 + algorithm: algorithm.replace('-', '').toLowerCase(), + blockLength: 128, + digestLength: digestLength, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 16 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength128 for backwards-compatibility) + md.fullMessageLength = md.messageLength128 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge.util.createBuffer(); + _h = new Array(_state.length); + for(var i = 0; i < _state.length; ++i) { + _h[i] = _state[i].slice(0); + } + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = ((len[1] / 0x100000000) >>> 0); + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update(_h, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate SHA-512 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 896 mod 1024. In other words, + the data to be digested must be a multiple of 1024 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 16 bytes (128 + bits), that means that the last segment of the data must have 112 bytes + (896 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 896 mod 1024 because + 1024 - 128 = 896. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 896 mod 1024, then 1024 padding bits must be added. */ + + var finalBlock = forge.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in big-endian order; since length + // is stored in bytes we multiply by 8 and add carry from next int + var next, carry; + var bits = md.fullMessageLength[0] * 8; + for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { + next = md.fullMessageLength[i + 1] * 8; + carry = (next / 0x100000000) >>> 0; + bits += carry; + finalBlock.putInt32(bits >>> 0); + bits = next >>> 0; + } + finalBlock.putInt32(bits); + + var h = new Array(_h.length); + for(var i = 0; i < _h.length; ++i) { + h[i] = _h[i].slice(0); + } + _update(h, _w, finalBlock); + var rval = forge.util.createBuffer(); + var hlen; + if(algorithm === 'SHA-512') { + hlen = h.length; + } else if(algorithm === 'SHA-384') { + hlen = h.length - 2; + } else { + hlen = h.length - 4; + } + for(var i = 0; i < hlen; ++i) { + rval.putInt32(h[i][0]); + if(i !== hlen - 1 || algorithm !== 'SHA-512/224') { + rval.putInt32(h[i][1]); + } + } + return rval; + }; + + return md; + }; + + // sha-512 padding bytes not initialized yet + var _padding = null; + var _initialized = false; + + // table of constants + var _k = null; + + // initial hash states + var _states = null; + + /** + * Initializes the constant tables. + */ + function _init() { + // create padding + _padding = String.fromCharCode(128); + _padding += forge.util.fillString(String.fromCharCode(0x00), 128); + + // create K table for SHA-512 + _k = [ + [0x428a2f98, 0xd728ae22], [0x71374491, 0x23ef65cd], + [0xb5c0fbcf, 0xec4d3b2f], [0xe9b5dba5, 0x8189dbbc], + [0x3956c25b, 0xf348b538], [0x59f111f1, 0xb605d019], + [0x923f82a4, 0xaf194f9b], [0xab1c5ed5, 0xda6d8118], + [0xd807aa98, 0xa3030242], [0x12835b01, 0x45706fbe], + [0x243185be, 0x4ee4b28c], [0x550c7dc3, 0xd5ffb4e2], + [0x72be5d74, 0xf27b896f], [0x80deb1fe, 0x3b1696b1], + [0x9bdc06a7, 0x25c71235], [0xc19bf174, 0xcf692694], + [0xe49b69c1, 0x9ef14ad2], [0xefbe4786, 0x384f25e3], + [0x0fc19dc6, 0x8b8cd5b5], [0x240ca1cc, 0x77ac9c65], + [0x2de92c6f, 0x592b0275], [0x4a7484aa, 0x6ea6e483], + [0x5cb0a9dc, 0xbd41fbd4], [0x76f988da, 0x831153b5], + [0x983e5152, 0xee66dfab], [0xa831c66d, 0x2db43210], + [0xb00327c8, 0x98fb213f], [0xbf597fc7, 0xbeef0ee4], + [0xc6e00bf3, 0x3da88fc2], [0xd5a79147, 0x930aa725], + [0x06ca6351, 0xe003826f], [0x14292967, 0x0a0e6e70], + [0x27b70a85, 0x46d22ffc], [0x2e1b2138, 0x5c26c926], + [0x4d2c6dfc, 0x5ac42aed], [0x53380d13, 0x9d95b3df], + [0x650a7354, 0x8baf63de], [0x766a0abb, 0x3c77b2a8], + [0x81c2c92e, 0x47edaee6], [0x92722c85, 0x1482353b], + [0xa2bfe8a1, 0x4cf10364], [0xa81a664b, 0xbc423001], + [0xc24b8b70, 0xd0f89791], [0xc76c51a3, 0x0654be30], + [0xd192e819, 0xd6ef5218], [0xd6990624, 0x5565a910], + [0xf40e3585, 0x5771202a], [0x106aa070, 0x32bbd1b8], + [0x19a4c116, 0xb8d2d0c8], [0x1e376c08, 0x5141ab53], + [0x2748774c, 0xdf8eeb99], [0x34b0bcb5, 0xe19b48a8], + [0x391c0cb3, 0xc5c95a63], [0x4ed8aa4a, 0xe3418acb], + [0x5b9cca4f, 0x7763e373], [0x682e6ff3, 0xd6b2b8a3], + [0x748f82ee, 0x5defb2fc], [0x78a5636f, 0x43172f60], + [0x84c87814, 0xa1f0ab72], [0x8cc70208, 0x1a6439ec], + [0x90befffa, 0x23631e28], [0xa4506ceb, 0xde82bde9], + [0xbef9a3f7, 0xb2c67915], [0xc67178f2, 0xe372532b], + [0xca273ece, 0xea26619c], [0xd186b8c7, 0x21c0c207], + [0xeada7dd6, 0xcde0eb1e], [0xf57d4f7f, 0xee6ed178], + [0x06f067aa, 0x72176fba], [0x0a637dc5, 0xa2c898a6], + [0x113f9804, 0xbef90dae], [0x1b710b35, 0x131c471b], + [0x28db77f5, 0x23047d84], [0x32caab7b, 0x40c72493], + [0x3c9ebe0a, 0x15c9bebc], [0x431d67c4, 0x9c100d4c], + [0x4cc5d4be, 0xcb3e42b6], [0x597f299c, 0xfc657e2a], + [0x5fcb6fab, 0x3ad6faec], [0x6c44198c, 0x4a475817] + ]; + + // initial hash states + _states = {}; + _states['SHA-512'] = [ + [0x6a09e667, 0xf3bcc908], + [0xbb67ae85, 0x84caa73b], + [0x3c6ef372, 0xfe94f82b], + [0xa54ff53a, 0x5f1d36f1], + [0x510e527f, 0xade682d1], + [0x9b05688c, 0x2b3e6c1f], + [0x1f83d9ab, 0xfb41bd6b], + [0x5be0cd19, 0x137e2179] + ]; + _states['SHA-384'] = [ + [0xcbbb9d5d, 0xc1059ed8], + [0x629a292a, 0x367cd507], + [0x9159015a, 0x3070dd17], + [0x152fecd8, 0xf70e5939], + [0x67332667, 0xffc00b31], + [0x8eb44a87, 0x68581511], + [0xdb0c2e0d, 0x64f98fa7], + [0x47b5481d, 0xbefa4fa4] + ]; + _states['SHA-512/256'] = [ + [0x22312194, 0xFC2BF72C], + [0x9F555FA3, 0xC84C64C2], + [0x2393B86B, 0x6F53B151], + [0x96387719, 0x5940EABD], + [0x96283EE2, 0xA88EFFE3], + [0xBE5E1E25, 0x53863992], + [0x2B0199FC, 0x2C85B8AA], + [0x0EB72DDC, 0x81C52CA2] + ]; + _states['SHA-512/224'] = [ + [0x8C3D37C8, 0x19544DA2], + [0x73E19966, 0x89DCD4D6], + [0x1DFAB7AE, 0x32FF9C82], + [0x679DD514, 0x582F9FCF], + [0x0F6D2B69, 0x7BD44DA8], + [0x77E36F73, 0x04C48942], + [0x3F9D85A8, 0x6A1D36C8], + [0x1112E6AD, 0x91D692A1] + ]; + + // now initialized + _initialized = true; + } + + /** + * Updates a SHA-512 state with the given byte buffer. + * + * @param s the SHA-512 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ + function _update(s, w, bytes) { + // consume 512 bit (128 byte) chunks + var t1_hi, t1_lo; + var t2_hi, t2_lo; + var s0_hi, s0_lo; + var s1_hi, s1_lo; + var ch_hi, ch_lo; + var maj_hi, maj_lo; + var a_hi, a_lo; + var b_hi, b_lo; + var c_hi, c_lo; + var d_hi, d_lo; + var e_hi, e_lo; + var f_hi, f_lo; + var g_hi, g_lo; + var h_hi, h_lo; + var i, hi, lo, w2, w7, w15, w16; + var len = bytes.length(); + while(len >= 128) { + // the w array will be populated with sixteen 64-bit big-endian words + // and then extended into 64 64-bit words according to SHA-512 + for(i = 0; i < 16; ++i) { + w[i][0] = bytes.getInt32() >>> 0; + w[i][1] = bytes.getInt32() >>> 0; + } + for(; i < 80; ++i) { + // for word 2 words ago: ROTR 19(x) ^ ROTR 61(x) ^ SHR 6(x) + w2 = w[i - 2]; + hi = w2[0]; + lo = w2[1]; + + // high bits + t1_hi = ( + ((hi >>> 19) | (lo << 13)) ^ // ROTR 19 + ((lo >>> 29) | (hi << 3)) ^ // ROTR 61/(swap + ROTR 29) + (hi >>> 6)) >>> 0; // SHR 6 + // low bits + t1_lo = ( + ((hi << 13) | (lo >>> 19)) ^ // ROTR 19 + ((lo << 3) | (hi >>> 29)) ^ // ROTR 61/(swap + ROTR 29) + ((hi << 26) | (lo >>> 6))) >>> 0; // SHR 6 + + // for word 15 words ago: ROTR 1(x) ^ ROTR 8(x) ^ SHR 7(x) + w15 = w[i - 15]; + hi = w15[0]; + lo = w15[1]; + + // high bits + t2_hi = ( + ((hi >>> 1) | (lo << 31)) ^ // ROTR 1 + ((hi >>> 8) | (lo << 24)) ^ // ROTR 8 + (hi >>> 7)) >>> 0; // SHR 7 + // low bits + t2_lo = ( + ((hi << 31) | (lo >>> 1)) ^ // ROTR 1 + ((hi << 24) | (lo >>> 8)) ^ // ROTR 8 + ((hi << 25) | (lo >>> 7))) >>> 0; // SHR 7 + + // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^64 (carry lo overflow) + w7 = w[i - 7]; + w16 = w[i - 16]; + lo = (t1_lo + w7[1] + t2_lo + w16[1]); + w[i][0] = (t1_hi + w7[0] + t2_hi + w16[0] + + ((lo / 0x100000000) >>> 0)) >>> 0; + w[i][1] = lo >>> 0; + } + + // initialize hash value for this chunk + a_hi = s[0][0]; + a_lo = s[0][1]; + b_hi = s[1][0]; + b_lo = s[1][1]; + c_hi = s[2][0]; + c_lo = s[2][1]; + d_hi = s[3][0]; + d_lo = s[3][1]; + e_hi = s[4][0]; + e_lo = s[4][1]; + f_hi = s[5][0]; + f_lo = s[5][1]; + g_hi = s[6][0]; + g_lo = s[6][1]; + h_hi = s[7][0]; + h_lo = s[7][1]; + + // round function + for(i = 0; i < 80; ++i) { + // Sum1(e) = ROTR 14(e) ^ ROTR 18(e) ^ ROTR 41(e) + s1_hi = ( + ((e_hi >>> 14) | (e_lo << 18)) ^ // ROTR 14 + ((e_hi >>> 18) | (e_lo << 14)) ^ // ROTR 18 + ((e_lo >>> 9) | (e_hi << 23))) >>> 0; // ROTR 41/(swap + ROTR 9) + s1_lo = ( + ((e_hi << 18) | (e_lo >>> 14)) ^ // ROTR 14 + ((e_hi << 14) | (e_lo >>> 18)) ^ // ROTR 18 + ((e_lo << 23) | (e_hi >>> 9))) >>> 0; // ROTR 41/(swap + ROTR 9) + + // Ch(e, f, g) (optimized the same way as SHA-1) + ch_hi = (g_hi ^ (e_hi & (f_hi ^ g_hi))) >>> 0; + ch_lo = (g_lo ^ (e_lo & (f_lo ^ g_lo))) >>> 0; + + // Sum0(a) = ROTR 28(a) ^ ROTR 34(a) ^ ROTR 39(a) + s0_hi = ( + ((a_hi >>> 28) | (a_lo << 4)) ^ // ROTR 28 + ((a_lo >>> 2) | (a_hi << 30)) ^ // ROTR 34/(swap + ROTR 2) + ((a_lo >>> 7) | (a_hi << 25))) >>> 0; // ROTR 39/(swap + ROTR 7) + s0_lo = ( + ((a_hi << 4) | (a_lo >>> 28)) ^ // ROTR 28 + ((a_lo << 30) | (a_hi >>> 2)) ^ // ROTR 34/(swap + ROTR 2) + ((a_lo << 25) | (a_hi >>> 7))) >>> 0; // ROTR 39/(swap + ROTR 7) + + // Maj(a, b, c) (optimized the same way as SHA-1) + maj_hi = ((a_hi & b_hi) | (c_hi & (a_hi ^ b_hi))) >>> 0; + maj_lo = ((a_lo & b_lo) | (c_lo & (a_lo ^ b_lo))) >>> 0; + + // main algorithm + // t1 = (h + s1 + ch + _k[i] + _w[i]) modulo 2^64 (carry lo overflow) + lo = (h_lo + s1_lo + ch_lo + _k[i][1] + w[i][1]); + t1_hi = (h_hi + s1_hi + ch_hi + _k[i][0] + w[i][0] + + ((lo / 0x100000000) >>> 0)) >>> 0; + t1_lo = lo >>> 0; + + // t2 = s0 + maj modulo 2^64 (carry lo overflow) + lo = s0_lo + maj_lo; + t2_hi = (s0_hi + maj_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + t2_lo = lo >>> 0; + + h_hi = g_hi; + h_lo = g_lo; + + g_hi = f_hi; + g_lo = f_lo; + + f_hi = e_hi; + f_lo = e_lo; + + // e = (d + t1) modulo 2^64 (carry lo overflow) + lo = d_lo + t1_lo; + e_hi = (d_hi + t1_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + e_lo = lo >>> 0; + + d_hi = c_hi; + d_lo = c_lo; + + c_hi = b_hi; + c_lo = b_lo; + + b_hi = a_hi; + b_lo = a_lo; + + // a = (t1 + t2) modulo 2^64 (carry lo overflow) + lo = t1_lo + t2_lo; + a_hi = (t1_hi + t2_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + a_lo = lo >>> 0; + } + + // update hash state (additional modulo 2^64) + lo = s[0][1] + a_lo; + s[0][0] = (s[0][0] + a_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[0][1] = lo >>> 0; + + lo = s[1][1] + b_lo; + s[1][0] = (s[1][0] + b_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[1][1] = lo >>> 0; + + lo = s[2][1] + c_lo; + s[2][0] = (s[2][0] + c_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[2][1] = lo >>> 0; + + lo = s[3][1] + d_lo; + s[3][0] = (s[3][0] + d_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[3][1] = lo >>> 0; + + lo = s[4][1] + e_lo; + s[4][0] = (s[4][0] + e_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[4][1] = lo >>> 0; + + lo = s[5][1] + f_lo; + s[5][0] = (s[5][0] + f_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[5][1] = lo >>> 0; + + lo = s[6][1] + g_lo; + s[6][0] = (s[6][0] + g_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[6][1] = lo >>> 0; + + lo = s[7][1] + h_lo; + s[7][0] = (s[7][0] + h_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[7][1] = lo >>> 0; + + len -= 128; + } + } + }); + + /** + * Copyright (c) 2019 Digital Bazaar, Inc. + */ + + + + var asn1$2 = forge.asn1; + + var privateKeyValidator$1 = { + // PrivateKeyInfo + name: 'PrivateKeyInfo', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.SEQUENCE, + constructed: true, + value: [{ + // Version (INTEGER) + name: 'PrivateKeyInfo.version', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.INTEGER, + constructed: false, + capture: 'privateKeyVersion' + }, { + // privateKeyAlgorithm + name: 'PrivateKeyInfo.privateKeyAlgorithm', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.OID, + constructed: false, + capture: 'privateKeyOid' + }] + }, { + // PrivateKey + name: 'PrivateKeyInfo', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.OCTETSTRING, + constructed: false, + capture: 'privateKey' + }] + }; + + var publicKeyValidator$1 = { + name: 'SubjectPublicKeyInfo', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.SEQUENCE, + constructed: true, + captureAsn1: 'subjectPublicKeyInfo', + value: [{ + name: 'SubjectPublicKeyInfo.AlgorithmIdentifier', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.OID, + constructed: false, + capture: 'publicKeyOid' + }] + }, + // capture group for ed25519PublicKey + { + tagClass: asn1$2.Class.UNIVERSAL, + type: asn1$2.Type.BITSTRING, + constructed: false, + composed: true, + captureBitStringValue: 'ed25519PublicKey' + } + // FIXME: this is capture group for rsaPublicKey, use it in this API or + // discard? + /* { + // subjectPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.BITSTRING, + constructed: false, + value: [{ + // RSAPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + optional: true, + captureAsn1: 'rsaPublicKey' + }] + } */ + ] + }; + + var asn1Validator = { + privateKeyValidator: privateKeyValidator$1, + publicKeyValidator: publicKeyValidator$1 + }; + + /** + * JavaScript implementation of Ed25519. + * + * Copyright (c) 2017-2019 Digital Bazaar, Inc. + * + * This implementation is based on the most excellent TweetNaCl which is + * in the public domain. Many thanks to its contributors: + * + * https://github.com/dchest/tweetnacl-js + */ + + + + + + + var publicKeyValidator$2 = asn1Validator.publicKeyValidator; + var privateKeyValidator$2 = asn1Validator.privateKeyValidator; + + if(typeof BigInteger$4 === 'undefined') { + var BigInteger$4 = forge.jsbn.BigInteger; + } + + var ByteBuffer = forge.util.ByteBuffer; + var NativeBuffer = typeof Buffer === 'undefined' ? Uint8Array : Buffer; + + /* + * Ed25519 algorithms, see RFC 8032: + * https://tools.ietf.org/html/rfc8032 + */ + forge.pki = forge.pki || {}; + var ed25519_1 = forge.pki.ed25519 = forge.ed25519 = forge.ed25519 || {}; + var ed25519 = forge.ed25519; + + ed25519.constants = {}; + ed25519.constants.PUBLIC_KEY_BYTE_LENGTH = 32; + ed25519.constants.PRIVATE_KEY_BYTE_LENGTH = 64; + ed25519.constants.SEED_BYTE_LENGTH = 32; + ed25519.constants.SIGN_BYTE_LENGTH = 64; + ed25519.constants.HASH_BYTE_LENGTH = 64; + + ed25519.generateKeyPair = function(options) { + options = options || {}; + var seed = options.seed; + if(seed === undefined) { + // generate seed + seed = forge.random.getBytesSync(ed25519.constants.SEED_BYTE_LENGTH); + } else if(typeof seed === 'string') { + if(seed.length !== ed25519.constants.SEED_BYTE_LENGTH) { + throw new TypeError( + '"seed" must be ' + ed25519.constants.SEED_BYTE_LENGTH + + ' bytes in length.'); + } + } else if(!(seed instanceof Uint8Array)) { + throw new TypeError( + '"seed" must be a node.js Buffer, Uint8Array, or a binary string.'); + } + + seed = messageToNativeBuffer({message: seed, encoding: 'binary'}); + + var pk = new NativeBuffer(ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); + var sk = new NativeBuffer(ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); + for(var i = 0; i < 32; ++i) { + sk[i] = seed[i]; + } + crypto_sign_keypair(pk, sk); + return {publicKey: pk, privateKey: sk}; + }; + + /** + * Converts a private key from a RFC8410 ASN.1 encoding. + * + * @param obj - The asn1 representation of a private key. + * + * @returns {Object} keyInfo - The key information. + * @returns {Buffer|Uint8Array} keyInfo.privateKeyBytes - 32 private key bytes. + */ + ed25519.privateKeyFromAsn1 = function(obj) { + var capture = {}; + var errors = []; + var valid = forge.asn1.validate(obj, privateKeyValidator$2, capture, errors); + if(!valid) { + var error = new Error('Invalid Key.'); + error.errors = errors; + throw error; + } + var oid = forge.asn1.derToOid(capture.privateKeyOid); + var ed25519Oid = forge.oids.EdDSA25519; + if(oid !== ed25519Oid) { + throw new Error('Invalid OID "' + oid + '"; OID must be "' + + ed25519Oid + '".'); + } + var privateKey = capture.privateKey; + // manually extract the private key bytes from nested octet string, see FIXME: + // https://github.com/digitalbazaar/forge/blob/master/lib/asn1.js#L542 + var privateKeyBytes = messageToNativeBuffer({ + message: forge.asn1.fromDer(privateKey).value, + encoding: 'binary' + }); + // TODO: RFC8410 specifies a format for encoding the public key bytes along + // with the private key bytes. `publicKeyBytes` can be returned in the + // future. https://tools.ietf.org/html/rfc8410#section-10.3 + return {privateKeyBytes: privateKeyBytes}; + }; + + /** + * Converts a public key from a RFC8410 ASN.1 encoding. + * + * @param obj - The asn1 representation of a public key. + * + * @return {Buffer|Uint8Array} - 32 public key bytes. + */ + ed25519.publicKeyFromAsn1 = function(obj) { + // get SubjectPublicKeyInfo + var capture = {}; + var errors = []; + var valid = forge.asn1.validate(obj, publicKeyValidator$2, capture, errors); + if(!valid) { + var error = new Error('Invalid Key.'); + error.errors = errors; + throw error; + } + var oid = forge.asn1.derToOid(capture.publicKeyOid); + var ed25519Oid = forge.oids.EdDSA25519; + if(oid !== ed25519Oid) { + throw new Error('Invalid OID "' + oid + '"; OID must be "' + + ed25519Oid + '".'); + } + var publicKeyBytes = capture.ed25519PublicKey; + if(publicKeyBytes.length !== ed25519.constants.PUBLIC_KEY_BYTE_LENGTH) { + throw new Error('Key length is invalid.'); + } + return messageToNativeBuffer({ + message: publicKeyBytes, + encoding: 'binary' + }); + }; + + ed25519.publicKeyFromPrivateKey = function(options) { + options = options || {}; + var privateKey = messageToNativeBuffer({ + message: options.privateKey, encoding: 'binary' + }); + if(privateKey.length !== ed25519.constants.PRIVATE_KEY_BYTE_LENGTH) { + throw new TypeError( + '"options.privateKey" must have a byte length of ' + + ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); + } + + var pk = new NativeBuffer(ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); + for(var i = 0; i < pk.length; ++i) { + pk[i] = privateKey[32 + i]; + } + return pk; + }; + + ed25519.sign = function(options) { + options = options || {}; + var msg = messageToNativeBuffer(options); + var privateKey = messageToNativeBuffer({ + message: options.privateKey, + encoding: 'binary' + }); + if(privateKey.length === ed25519.constants.SEED_BYTE_LENGTH) { + var keyPair = ed25519.generateKeyPair({seed: privateKey}); + privateKey = keyPair.privateKey; + } else if(privateKey.length !== ed25519.constants.PRIVATE_KEY_BYTE_LENGTH) { + throw new TypeError( + '"options.privateKey" must have a byte length of ' + + ed25519.constants.SEED_BYTE_LENGTH + ' or ' + + ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); + } + + var signedMsg = new NativeBuffer( + ed25519.constants.SIGN_BYTE_LENGTH + msg.length); + crypto_sign(signedMsg, msg, msg.length, privateKey); + + var sig = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH); + for(var i = 0; i < sig.length; ++i) { + sig[i] = signedMsg[i]; + } + return sig; + }; + + ed25519.verify = function(options) { + options = options || {}; + var msg = messageToNativeBuffer(options); + if(options.signature === undefined) { + throw new TypeError( + '"options.signature" must be a node.js Buffer, a Uint8Array, a forge ' + + 'ByteBuffer, or a binary string.'); + } + var sig = messageToNativeBuffer({ + message: options.signature, + encoding: 'binary' + }); + if(sig.length !== ed25519.constants.SIGN_BYTE_LENGTH) { + throw new TypeError( + '"options.signature" must have a byte length of ' + + ed25519.constants.SIGN_BYTE_LENGTH); + } + var publicKey = messageToNativeBuffer({ + message: options.publicKey, + encoding: 'binary' + }); + if(publicKey.length !== ed25519.constants.PUBLIC_KEY_BYTE_LENGTH) { + throw new TypeError( + '"options.publicKey" must have a byte length of ' + + ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); + } + + var sm = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH + msg.length); + var m = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH + msg.length); + var i; + for(i = 0; i < ed25519.constants.SIGN_BYTE_LENGTH; ++i) { + sm[i] = sig[i]; + } + for(i = 0; i < msg.length; ++i) { + sm[i + ed25519.constants.SIGN_BYTE_LENGTH] = msg[i]; + } + return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); + }; + + function messageToNativeBuffer(options) { + var message = options.message; + if(message instanceof Uint8Array || message instanceof NativeBuffer) { + return message; + } + + var encoding = options.encoding; + if(message === undefined) { + if(options.md) { + // TODO: more rigorous validation that `md` is a MessageDigest + message = options.md.digest().getBytes(); + encoding = 'binary'; + } else { + throw new TypeError('"options.message" or "options.md" not specified.'); + } + } + + if(typeof message === 'string' && !encoding) { + throw new TypeError('"options.encoding" must be "binary" or "utf8".'); + } + + if(typeof message === 'string') { + if(typeof Buffer !== 'undefined') { + return Buffer.from(message, encoding); + } + message = new ByteBuffer(message, encoding); + } else if(!(message instanceof ByteBuffer)) { + throw new TypeError( + '"options.message" must be a node.js Buffer, a Uint8Array, a forge ' + + 'ByteBuffer, or a string with "options.encoding" specifying its ' + + 'encoding.'); + } + + // convert to native buffer + var buffer = new NativeBuffer(message.length()); + for(var i = 0; i < buffer.length; ++i) { + buffer[i] = message.at(i); + } + return buffer; + } + + var gf0 = gf(); + var gf1 = gf([1]); + var D$1 = gf([ + 0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, + 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]); + var D2 = gf([ + 0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, + 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]); + var X = gf([ + 0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, + 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]); + var Y = gf([ + 0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, + 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]); + var L = new Float64Array([ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); + var I = gf([ + 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, + 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); + + // TODO: update forge buffer implementation to use `Buffer` or `Uint8Array`, + // whichever is available, to improve performance + function sha512(msg, msgLen) { + // Note: `out` and `msg` are NativeBuffer + var md = forge.md.sha512.create(); + var buffer = new ByteBuffer(msg); + md.update(buffer.getBytes(msgLen), 'binary'); + var hash = md.digest().getBytes(); + if(typeof Buffer !== 'undefined') { + return Buffer.from(hash, 'binary'); + } + var out = new NativeBuffer(ed25519.constants.HASH_BYTE_LENGTH); + for(var i = 0; i < 64; ++i) { + out[i] = hash.charCodeAt(i); + } + return out; + } + + function crypto_sign_keypair(pk, sk) { + var p = [gf(), gf(), gf(), gf()]; + var i; + + var d = sha512(sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p, d); + pack(pk, p); + + for(i = 0; i < 32; ++i) { + sk[i + 32] = pk[i]; + } + return 0; + } + + // Note: difference from C - smlen returned, not passed as argument. + function crypto_sign(sm, m, n, sk) { + var i, j, x = new Float64Array(64); + var p = [gf(), gf(), gf(), gf()]; + + var d = sha512(sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + var smlen = n + 64; + for(i = 0; i < n; ++i) { + sm[64 + i] = m[i]; + } + for(i = 0; i < 32; ++i) { + sm[32 + i] = d[32 + i]; + } + + var r = sha512(sm.subarray(32), n + 32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for(i = 32; i < 64; ++i) { + sm[i] = sk[i]; + } + var h = sha512(sm, n + 64); + reduce(h); + + for(i = 32; i < 64; ++i) { + x[i] = 0; + } + for(i = 0; i < 32; ++i) { + x[i] = r[i]; + } + for(i = 0; i < 32; ++i) { + for(j = 0; j < 32; j++) { + x[i + j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return smlen; + } + + function crypto_sign_open(m, sm, n, pk) { + var i, mlen; + var t = new NativeBuffer(32); + var p = [gf(), gf(), gf(), gf()], + q = [gf(), gf(), gf(), gf()]; + + mlen = -1; + if(n < 64) { + return -1; + } + + if(unpackneg(q, pk)) { + return -1; + } + + for(i = 0; i < n; ++i) { + m[i] = sm[i]; + } + for(i = 0; i < 32; ++i) { + m[i + 32] = pk[i]; + } + var h = sha512(m, n); + reduce(h); + scalarmult(p, q, h); + + scalarbase(q, sm.subarray(32)); + add(p, q); + pack(t, p); + + n -= 64; + if(crypto_verify_32(sm, 0, t, 0)) { + for(i = 0; i < n; ++i) { + m[i] = 0; + } + return -1; + } + + for(i = 0; i < n; ++i) { + m[i] = sm[i + 64]; + } + mlen = n; + return mlen; + } + + function modL(r, x) { + var carry, i, j, k; + for(i = 63; i >= 32; --i) { + carry = 0; + for(j = i - 32, k = i - 12; j < k; ++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = (x[j] + 128) >> 8; + x[j] -= carry * 256; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for(j = 0; j < 32; ++j) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for(j = 0; j < 32; ++j) { + x[j] -= carry * L[j]; + } + for(i = 0; i < 32; ++i) { + x[i + 1] += x[i] >> 8; + r[i] = x[i] & 255; + } + } + + function reduce(r) { + var x = new Float64Array(64); + for(var i = 0; i < 64; ++i) { + x[i] = r[i]; + r[i] = 0; + } + modL(r, x); + } + + function add(p, q) { + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(), + g = gf(), h = gf(), t = gf(); + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A$1(b, p[0], p[1]); + A$1(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A$1(d, d, d); + Z(e, b, a); + Z(f, d, c); + A$1(g, d, c); + A$1(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); + } + + function cswap(p, q, b) { + for(var i = 0; i < 4; ++i) { + sel25519(p[i], q[i], b); + } + } + + function pack(r, p) { + var tx = gf(), ty = gf(), zi = gf(); + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; + } + + function pack25519(o, n) { + var i, j, b; + var m = gf(), t = gf(); + for(i = 0; i < 16; ++i) { + t[i] = n[i]; + } + car25519(t); + car25519(t); + car25519(t); + for(j = 0; j < 2; ++j) { + m[0] = t[0] - 0xffed; + for(i = 1; i < 15; ++i) { + m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); + m[i-1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); + b = (m[15] >> 16) & 1; + m[14] &= 0xffff; + sel25519(t, m, 1 - b); + } + for (i = 0; i < 16; i++) { + o[2 * i] = t[i] & 0xff; + o[2 * i + 1] = t[i] >> 8; + } + } + + function unpackneg(r, p) { + var t = gf(), chk = gf(), num = gf(), + den = gf(), den2 = gf(), den4 = gf(), + den6 = gf(); + + set25519(r[2], gf1); + unpack25519(r[1], p); + S(num, r[1]); + M(den, num, D$1); + Z(num, num, r[2]); + A$1(den, r[2], den); + + S(den2, den); + S(den4, den2); + M(den6, den4, den2); + M(t, den6, num); + M(t, t, den); + + pow2523(t, t); + M(t, t, num); + M(t, t, den); + M(t, t, den); + M(r[0], t, den); + + S(chk, r[0]); + M(chk, chk, den); + if(neq25519(chk, num)) { + M(r[0], r[0], I); + } + + S(chk, r[0]); + M(chk, chk, den); + if(neq25519(chk, num)) { + return -1; + } + + if(par25519(r[0]) === (p[31] >> 7)) { + Z(r[0], gf0, r[0]); + } + + M(r[3], r[0], r[1]); + return 0; + } + + function unpack25519(o, n) { + var i; + for(i = 0; i < 16; ++i) { + o[i] = n[2 * i] + (n[2 * i + 1] << 8); + } + o[15] &= 0x7fff; + } + + function pow2523(o, i) { + var c = gf(); + var a; + for(a = 0; a < 16; ++a) { + c[a] = i[a]; + } + for(a = 250; a >= 0; --a) { + S(c, c); + if(a !== 1) { + M(c, c, i); + } + } + for(a = 0; a < 16; ++a) { + o[a] = c[a]; + } + } + + function neq25519(a, b) { + var c = new NativeBuffer(32); + var d = new NativeBuffer(32); + pack25519(c, a); + pack25519(d, b); + return crypto_verify_32(c, 0, d, 0); + } + + function crypto_verify_32(x, xi, y, yi) { + return vn(x, xi, y, yi, 32); + } + + function vn(x, xi, y, yi, n) { + var i, d = 0; + for(i = 0; i < n; ++i) { + d |= x[xi + i] ^ y[yi + i]; + } + return (1 & ((d - 1) >>> 8)) - 1; + } + + function par25519(a) { + var d = new NativeBuffer(32); + pack25519(d, a); + return d[0] & 1; + } + + function scalarmult(p, q, s) { + var b, i; + set25519(p[0], gf0); + set25519(p[1], gf1); + set25519(p[2], gf1); + set25519(p[3], gf0); + for(i = 255; i >= 0; --i) { + b = (s[(i / 8)|0] >> (i & 7)) & 1; + cswap(p, q, b); + add(q, p); + add(p, p); + cswap(p, q, b); + } + } + + function scalarbase(p, s) { + var q = [gf(), gf(), gf(), gf()]; + set25519(q[0], X); + set25519(q[1], Y); + set25519(q[2], gf1); + M(q[3], X, Y); + scalarmult(p, q, s); + } + + function set25519(r, a) { + var i; + for(i = 0; i < 16; i++) { + r[i] = a[i] | 0; + } + } + + function inv25519(o, i) { + var c = gf(); + var a; + for(a = 0; a < 16; ++a) { + c[a] = i[a]; + } + for(a = 253; a >= 0; --a) { + S(c, c); + if(a !== 2 && a !== 4) { + M(c, c, i); + } + } + for(a = 0; a < 16; ++a) { + o[a] = c[a]; + } + } + + function car25519(o) { + var i, v, c = 1; + for(i = 0; i < 16; ++i) { + v = o[i] + c + 65535; + c = Math.floor(v / 65536); + o[i] = v - c * 65536; + } + o[0] += c - 1 + 37 * (c - 1); + } + + function sel25519(p, q, b) { + var t, c = ~(b - 1); + for(var i = 0; i < 16; ++i) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } + } + + function gf(init) { + var i, r = new Float64Array(16); + if(init) { + for(i = 0; i < init.length; ++i) { + r[i] = init[i]; + } + } + return r; + } + + function A$1(o, a, b) { + for(var i = 0; i < 16; ++i) { + o[i] = a[i] + b[i]; + } + } + + function Z(o, a, b) { + for(var i = 0; i < 16; ++i) { + o[i] = a[i] - b[i]; + } + } + + function S(o, a) { + M(o, a, a); + } + + function M(o, a, b) { + var v, c, + t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, + t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, + t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, + t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, + b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11], + b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + + v = a[0]; + t0 += v * b0; + t1 += v * b1; + t2 += v * b2; + t3 += v * b3; + t4 += v * b4; + t5 += v * b5; + t6 += v * b6; + t7 += v * b7; + t8 += v * b8; + t9 += v * b9; + t10 += v * b10; + t11 += v * b11; + t12 += v * b12; + t13 += v * b13; + t14 += v * b14; + t15 += v * b15; + v = a[1]; + t1 += v * b0; + t2 += v * b1; + t3 += v * b2; + t4 += v * b3; + t5 += v * b4; + t6 += v * b5; + t7 += v * b6; + t8 += v * b7; + t9 += v * b8; + t10 += v * b9; + t11 += v * b10; + t12 += v * b11; + t13 += v * b12; + t14 += v * b13; + t15 += v * b14; + t16 += v * b15; + v = a[2]; + t2 += v * b0; + t3 += v * b1; + t4 += v * b2; + t5 += v * b3; + t6 += v * b4; + t7 += v * b5; + t8 += v * b6; + t9 += v * b7; + t10 += v * b8; + t11 += v * b9; + t12 += v * b10; + t13 += v * b11; + t14 += v * b12; + t15 += v * b13; + t16 += v * b14; + t17 += v * b15; + v = a[3]; + t3 += v * b0; + t4 += v * b1; + t5 += v * b2; + t6 += v * b3; + t7 += v * b4; + t8 += v * b5; + t9 += v * b6; + t10 += v * b7; + t11 += v * b8; + t12 += v * b9; + t13 += v * b10; + t14 += v * b11; + t15 += v * b12; + t16 += v * b13; + t17 += v * b14; + t18 += v * b15; + v = a[4]; + t4 += v * b0; + t5 += v * b1; + t6 += v * b2; + t7 += v * b3; + t8 += v * b4; + t9 += v * b5; + t10 += v * b6; + t11 += v * b7; + t12 += v * b8; + t13 += v * b9; + t14 += v * b10; + t15 += v * b11; + t16 += v * b12; + t17 += v * b13; + t18 += v * b14; + t19 += v * b15; + v = a[5]; + t5 += v * b0; + t6 += v * b1; + t7 += v * b2; + t8 += v * b3; + t9 += v * b4; + t10 += v * b5; + t11 += v * b6; + t12 += v * b7; + t13 += v * b8; + t14 += v * b9; + t15 += v * b10; + t16 += v * b11; + t17 += v * b12; + t18 += v * b13; + t19 += v * b14; + t20 += v * b15; + v = a[6]; + t6 += v * b0; + t7 += v * b1; + t8 += v * b2; + t9 += v * b3; + t10 += v * b4; + t11 += v * b5; + t12 += v * b6; + t13 += v * b7; + t14 += v * b8; + t15 += v * b9; + t16 += v * b10; + t17 += v * b11; + t18 += v * b12; + t19 += v * b13; + t20 += v * b14; + t21 += v * b15; + v = a[7]; + t7 += v * b0; + t8 += v * b1; + t9 += v * b2; + t10 += v * b3; + t11 += v * b4; + t12 += v * b5; + t13 += v * b6; + t14 += v * b7; + t15 += v * b8; + t16 += v * b9; + t17 += v * b10; + t18 += v * b11; + t19 += v * b12; + t20 += v * b13; + t21 += v * b14; + t22 += v * b15; + v = a[8]; + t8 += v * b0; + t9 += v * b1; + t10 += v * b2; + t11 += v * b3; + t12 += v * b4; + t13 += v * b5; + t14 += v * b6; + t15 += v * b7; + t16 += v * b8; + t17 += v * b9; + t18 += v * b10; + t19 += v * b11; + t20 += v * b12; + t21 += v * b13; + t22 += v * b14; + t23 += v * b15; + v = a[9]; + t9 += v * b0; + t10 += v * b1; + t11 += v * b2; + t12 += v * b3; + t13 += v * b4; + t14 += v * b5; + t15 += v * b6; + t16 += v * b7; + t17 += v * b8; + t18 += v * b9; + t19 += v * b10; + t20 += v * b11; + t21 += v * b12; + t22 += v * b13; + t23 += v * b14; + t24 += v * b15; + v = a[10]; + t10 += v * b0; + t11 += v * b1; + t12 += v * b2; + t13 += v * b3; + t14 += v * b4; + t15 += v * b5; + t16 += v * b6; + t17 += v * b7; + t18 += v * b8; + t19 += v * b9; + t20 += v * b10; + t21 += v * b11; + t22 += v * b12; + t23 += v * b13; + t24 += v * b14; + t25 += v * b15; + v = a[11]; + t11 += v * b0; + t12 += v * b1; + t13 += v * b2; + t14 += v * b3; + t15 += v * b4; + t16 += v * b5; + t17 += v * b6; + t18 += v * b7; + t19 += v * b8; + t20 += v * b9; + t21 += v * b10; + t22 += v * b11; + t23 += v * b12; + t24 += v * b13; + t25 += v * b14; + t26 += v * b15; + v = a[12]; + t12 += v * b0; + t13 += v * b1; + t14 += v * b2; + t15 += v * b3; + t16 += v * b4; + t17 += v * b5; + t18 += v * b6; + t19 += v * b7; + t20 += v * b8; + t21 += v * b9; + t22 += v * b10; + t23 += v * b11; + t24 += v * b12; + t25 += v * b13; + t26 += v * b14; + t27 += v * b15; + v = a[13]; + t13 += v * b0; + t14 += v * b1; + t15 += v * b2; + t16 += v * b3; + t17 += v * b4; + t18 += v * b5; + t19 += v * b6; + t20 += v * b7; + t21 += v * b8; + t22 += v * b9; + t23 += v * b10; + t24 += v * b11; + t25 += v * b12; + t26 += v * b13; + t27 += v * b14; + t28 += v * b15; + v = a[14]; + t14 += v * b0; + t15 += v * b1; + t16 += v * b2; + t17 += v * b3; + t18 += v * b4; + t19 += v * b5; + t20 += v * b6; + t21 += v * b7; + t22 += v * b8; + t23 += v * b9; + t24 += v * b10; + t25 += v * b11; + t26 += v * b12; + t27 += v * b13; + t28 += v * b14; + t29 += v * b15; + v = a[15]; + t15 += v * b0; + t16 += v * b1; + t17 += v * b2; + t18 += v * b3; + t19 += v * b4; + t20 += v * b5; + t21 += v * b6; + t22 += v * b7; + t23 += v * b8; + t24 += v * b9; + t25 += v * b10; + t26 += v * b11; + t27 += v * b12; + t28 += v * b13; + t29 += v * b14; + t30 += v * b15; + + t0 += 38 * t16; + t1 += 38 * t17; + t2 += 38 * t18; + t3 += 38 * t19; + t4 += 38 * t20; + t5 += 38 * t21; + t6 += 38 * t22; + t7 += 38 * t23; + t8 += 38 * t24; + t9 += 38 * t25; + t10 += 38 * t26; + t11 += 38 * t27; + t12 += 38 * t28; + t13 += 38 * t29; + t14 += 38 * t30; + // t15 left as is + + // first car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + // second car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + o[ 0] = t0; + o[ 1] = t1; + o[ 2] = t2; + o[ 3] = t3; + o[ 4] = t4; + o[ 5] = t5; + o[ 6] = t6; + o[ 7] = t7; + o[ 8] = t8; + o[ 9] = t9; + o[10] = t10; + o[11] = t11; + o[12] = t12; + o[13] = t13; + o[14] = t14; + o[15] = t15; + } + + /** + * Javascript implementation of RSA-KEM. + * + * @author Lautaro Cozzani Rodriguez + * @author Dave Longley + * + * Copyright (c) 2014 Lautaro Cozzani + * Copyright (c) 2014 Digital Bazaar, Inc. + */ + + + + + + var kem = forge.kem = forge.kem || {}; + + var BigInteger$5 = forge.jsbn.BigInteger; + + /** + * The API for the RSA Key Encapsulation Mechanism (RSA-KEM) from ISO 18033-2. + */ + forge.kem.rsa = {}; + + /** + * Creates an RSA KEM API object for generating a secret asymmetric key. + * + * The symmetric key may be generated via a call to 'encrypt', which will + * produce a ciphertext to be transmitted to the recipient and a key to be + * kept secret. The ciphertext is a parameter to be passed to 'decrypt' which + * will produce the same secret key for the recipient to use to decrypt a + * message that was encrypted with the secret key. + * + * @param kdf the KDF API to use (eg: new forge.kem.kdf1()). + * @param options the options to use. + * [prng] a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". + */ + forge.kem.rsa.create = function(kdf, options) { + options = options || {}; + var prng = options.prng || forge.random; + + var kem = {}; + + /** + * Generates a secret key and its encapsulation. + * + * @param publicKey the RSA public key to encrypt with. + * @param keyLength the length, in bytes, of the secret key to generate. + * + * @return an object with: + * encapsulation: the ciphertext for generating the secret key, as a + * binary-encoded string of bytes. + * key: the secret key to use for encrypting a message. + */ + kem.encrypt = function(publicKey, keyLength) { + // generate a random r where 1 < r < n + var byteLength = Math.ceil(publicKey.n.bitLength() / 8); + var r; + do { + r = new BigInteger$5( + forge.util.bytesToHex(prng.getBytesSync(byteLength)), + 16).mod(publicKey.n); + } while(r.compareTo(BigInteger$5.ONE) <= 0); + + // prepend r with zeros + r = forge.util.hexToBytes(r.toString(16)); + var zeros = byteLength - r.length; + if(zeros > 0) { + r = forge.util.fillString(String.fromCharCode(0), zeros) + r; + } + + // encrypt the random + var encapsulation = publicKey.encrypt(r, 'NONE'); + + // generate the secret key + var key = kdf.generate(r, keyLength); + + return {encapsulation: encapsulation, key: key}; + }; + + /** + * Decrypts an encapsulated secret key. + * + * @param privateKey the RSA private key to decrypt with. + * @param encapsulation the ciphertext for generating the secret key, as + * a binary-encoded string of bytes. + * @param keyLength the length, in bytes, of the secret key to generate. + * + * @return the secret key as a binary-encoded string of bytes. + */ + kem.decrypt = function(privateKey, encapsulation, keyLength) { + // decrypt the encapsulation and generate the secret key + var r = privateKey.decrypt(encapsulation, 'NONE'); + return kdf.generate(r, keyLength); + }; + + return kem; + }; + + // TODO: add forge.kem.kdf.create('KDF1', {md: ..., ...}) API? + + /** + * Creates a key derivation API object that implements KDF1 per ISO 18033-2. + * + * @param md the hash API to use. + * @param [digestLength] an optional digest length that must be positive and + * less than or equal to md.digestLength. + * + * @return a KDF1 API object. + */ + forge.kem.kdf1 = function(md, digestLength) { + _createKDF(this, md, 0, digestLength || md.digestLength); + }; + + /** + * Creates a key derivation API object that implements KDF2 per ISO 18033-2. + * + * @param md the hash API to use. + * @param [digestLength] an optional digest length that must be positive and + * less than or equal to md.digestLength. + * + * @return a KDF2 API object. + */ + forge.kem.kdf2 = function(md, digestLength) { + _createKDF(this, md, 1, digestLength || md.digestLength); + }; + + /** + * Creates a KDF1 or KDF2 API object. + * + * @param md the hash API to use. + * @param counterStart the starting index for the counter. + * @param digestLength the digest length to use. + * + * @return the KDF API object. + */ + function _createKDF(kdf, md, counterStart, digestLength) { + /** + * Generate a key of the specified length. + * + * @param x the binary-encoded byte string to generate a key from. + * @param length the number of bytes to generate (the size of the key). + * + * @return the key as a binary-encoded string. + */ + kdf.generate = function(x, length) { + var key = new forge.util.ByteBuffer(); + + // run counter from counterStart to ceil(length / Hash.len) + var k = Math.ceil(length / digestLength) + counterStart; + + var c = new forge.util.ByteBuffer(); + for(var i = counterStart; i < k; ++i) { + // I2OSP(i, 4): convert counter to an octet string of 4 octets + c.putInt32(i); + + // digest 'x' and the counter and add the result to the key + md.start(); + md.update(x + c.getBytes()); + var hash = md.digest(); + key.putBytes(hash.getBytes(digestLength)); + } + + // truncate to the correct key length + key.truncate(key.length() - length); + return key.getBytes(); + }; + } + + /** + * Cross-browser support for logging in a web application. + * + * @author David I. Lehn + * + * Copyright (c) 2008-2013 Digital Bazaar, Inc. + */ + + + + /* LOG API */ + var log = forge.log = forge.log || {}; + + /** + * Application logging system. + * + * Each logger level available as it's own function of the form: + * forge.log.level(category, args...) + * The category is an arbitrary string, and the args are the same as + * Firebug's console.log API. By default the call will be output as: + * 'LEVEL [category] , args[1], ...' + * This enables proper % formatting via the first argument. + * Each category is enabled by default but can be enabled or disabled with + * the setCategoryEnabled() function. + */ + // list of known levels + forge.log.levels = [ + 'none', 'error', 'warning', 'info', 'debug', 'verbose', 'max']; + // info on the levels indexed by name: + // index: level index + // name: uppercased display name + var sLevelInfo = {}; + // list of loggers + var sLoggers = []; + /** + * Standard console logger. If no console support is enabled this will + * remain null. Check before using. + */ + var sConsoleLogger = null; + + // logger flags + /** + * Lock the level at the current value. Used in cases where user config may + * set the level such that only critical messages are seen but more verbose + * messages are needed for debugging or other purposes. + */ + forge.log.LEVEL_LOCKED = (1 << 1); + /** + * Always call log function. By default, the logging system will check the + * message level against logger.level before calling the log function. This + * flag allows the function to do its own check. + */ + forge.log.NO_LEVEL_CHECK = (1 << 2); + /** + * Perform message interpolation with the passed arguments. "%" style + * fields in log messages will be replaced by arguments as needed. Some + * loggers, such as Firebug, may do this automatically. The original log + * message will be available as 'message' and the interpolated version will + * be available as 'fullMessage'. + */ + forge.log.INTERPOLATE = (1 << 3); + + // setup each log level + for(var i = 0; i < forge.log.levels.length; ++i) { + var level = forge.log.levels[i]; + sLevelInfo[level] = { + index: i, + name: level.toUpperCase() + }; + } + + /** + * Message logger. Will dispatch a message to registered loggers as needed. + * + * @param message message object + */ + forge.log.logMessage = function(message) { + var messageLevelIndex = sLevelInfo[message.level].index; + for(var i = 0; i < sLoggers.length; ++i) { + var logger = sLoggers[i]; + if(logger.flags & forge.log.NO_LEVEL_CHECK) { + logger.f(message); + } else { + // get logger level + var loggerLevelIndex = sLevelInfo[logger.level].index; + // check level + if(messageLevelIndex <= loggerLevelIndex) { + // message critical enough, call logger + logger.f(logger, message); + } + } + } + }; + + /** + * Sets the 'standard' key on a message object to: + * "LEVEL [category] " + message + * + * @param message a message log object + */ + forge.log.prepareStandard = function(message) { + if(!('standard' in message)) { + message.standard = + sLevelInfo[message.level].name + + //' ' + +message.timestamp + + ' [' + message.category + '] ' + + message.message; + } + }; + + /** + * Sets the 'full' key on a message object to the original message + * interpolated via % formatting with the message arguments. + * + * @param message a message log object. + */ + forge.log.prepareFull = function(message) { + if(!('full' in message)) { + // copy args and insert message at the front + var args = [message.message]; + args = args.concat([] || message['arguments']); + // format the message + message.full = forge.util.format.apply(this, args); + } + }; + + /** + * Applies both preparseStandard() and prepareFull() to a message object and + * store result in 'standardFull'. + * + * @param message a message log object. + */ + forge.log.prepareStandardFull = function(message) { + if(!('standardFull' in message)) { + // FIXME implement 'standardFull' logging + forge.log.prepareStandard(message); + message.standardFull = message.standard; + } + }; + + // create log level functions + { + // levels for which we want functions + var levels = ['error', 'warning', 'info', 'debug', 'verbose']; + for(var i = 0; i < levels.length; ++i) { + // wrap in a function to ensure proper level var is passed + (function(level) { + // create function for this level + forge.log[level] = function(category, message/*, args...*/) { + // convert arguments to real array, remove category and message + var args = Array.prototype.slice.call(arguments).slice(2); + // create message object + // Note: interpolation and standard formatting is done lazily + var msg = { + timestamp: new Date(), + level: level, + category: category, + message: message, + 'arguments': args + /*standard*/ + /*full*/ + /*fullMessage*/ + }; + // process this message + forge.log.logMessage(msg); + }; + })(levels[i]); + } + } + + /** + * Creates a new logger with specified custom logging function. + * + * The logging function has a signature of: + * function(logger, message) + * logger: current logger + * message: object: + * level: level id + * category: category + * message: string message + * arguments: Array of extra arguments + * fullMessage: interpolated message and arguments if INTERPOLATE flag set + * + * @param logFunction a logging function which takes a log message object + * as a parameter. + * + * @return a logger object. + */ + forge.log.makeLogger = function(logFunction) { + var logger = { + flags: 0, + f: logFunction + }; + forge.log.setLevel(logger, 'none'); + return logger; + }; + + /** + * Sets the current log level on a logger. + * + * @param logger the target logger. + * @param level the new maximum log level as a string. + * + * @return true if set, false if not. + */ + forge.log.setLevel = function(logger, level) { + var rval = false; + if(logger && !(logger.flags & forge.log.LEVEL_LOCKED)) { + for(var i = 0; i < forge.log.levels.length; ++i) { + var aValidLevel = forge.log.levels[i]; + if(level == aValidLevel) { + // set level + logger.level = level; + rval = true; + break; + } + } + } + + return rval; + }; + + /** + * Locks the log level at its current value. + * + * @param logger the target logger. + * @param lock boolean lock value, default to true. + */ + forge.log.lock = function(logger, lock) { + if(typeof lock === 'undefined' || lock) { + logger.flags |= forge.log.LEVEL_LOCKED; + } else { + logger.flags &= ~forge.log.LEVEL_LOCKED; + } + }; + + /** + * Adds a logger. + * + * @param logger the logger object. + */ + forge.log.addLogger = function(logger) { + sLoggers.push(logger); + }; + + // setup the console logger if possible, else create fake console.log + if(typeof(console) !== 'undefined' && 'log' in console) { + var logger; + if(console.error && console.warn && console.info && console.debug) { + // looks like Firebug-style logging is available + // level handlers map + var levelHandlers = { + error: console.error, + warning: console.warn, + info: console.info, + debug: console.debug, + verbose: console.debug + }; + var f = function(logger, message) { + forge.log.prepareStandard(message); + var handler = levelHandlers[message.level]; + // prepend standard message and concat args + var args = [message.standard]; + args = args.concat(message['arguments'].slice()); + // apply to low-level console function + handler.apply(console, args); + }; + logger = forge.log.makeLogger(f); + } else { + // only appear to have basic console.log + var f = function(logger, message) { + forge.log.prepareStandardFull(message); + console.log(message.standardFull); + }; + logger = forge.log.makeLogger(f); + } + forge.log.setLevel(logger, 'debug'); + forge.log.addLogger(logger); + sConsoleLogger = logger; + } else { + // define fake console.log to avoid potential script errors on + // browsers that do not have console logging + console = { + log: function() {} + }; + } + + /* + * Check for logging control query vars. + * + * console.level= + * Set's the console log level by name. Useful to override defaults and + * allow more verbose logging before a user config is loaded. + * + * console.lock= + * Lock the console log level at whatever level it is set at. This is run + * after console.level is processed. Useful to force a level of verbosity + * that could otherwise be limited by a user config. + */ + if(sConsoleLogger !== null) { + var query = forge.util.getQueryVariables(); + if('console.level' in query) { + // set with last value + forge.log.setLevel( + sConsoleLogger, query['console.level'].slice(-1)[0]); + } + if('console.lock' in query) { + // set with last value + var lock = query['console.lock'].slice(-1)[0]; + if(lock == 'true') { + forge.log.lock(sConsoleLogger); + } + } + } + + // provide public access to console logger + forge.log.consoleLogger = sConsoleLogger; + + var pkcs7 = createCommonjsModule(function (module) { + /** + * Javascript implementation of PKCS#7 v1.5. + * + * @author Stefan Siegl + * @author Dave Longley + * + * Copyright (c) 2012 Stefan Siegl + * Copyright (c) 2012-2015 Digital Bazaar, Inc. + * + * Currently this implementation only supports ContentType of EnvelopedData, + * EncryptedData, or SignedData at the root level. The top level elements may + * contain only a ContentInfo of ContentType Data, i.e. plain data. Further + * nesting is not (yet) supported. + * + * The Forge validators for PKCS #7's ASN.1 structures are available from + * a separate file pkcs7asn1.js, since those are referenced from other + * PKCS standards like PKCS #12. + */ + + + + + + + + + + + + // shortcut for ASN.1 API + var asn1 = forge.asn1; + + // shortcut for PKCS#7 API + var p7 = module.exports = forge.pkcs7 = forge.pkcs7 || {}; + + /** + * Converts a PKCS#7 message from PEM format. + * + * @param pem the PEM-formatted PKCS#7 message. + * + * @return the PKCS#7 message. + */ + p7.messageFromPem = function(pem) { + var msg = forge.pem.decode(pem)[0]; + + if(msg.type !== 'PKCS7') { + var error = new Error('Could not convert PKCS#7 message from PEM; PEM ' + + 'header type is not "PKCS#7".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert PKCS#7 message from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1.fromDer(msg.body); + + return p7.messageFromAsn1(obj); + }; + + /** + * Converts a PKCS#7 message to PEM format. + * + * @param msg The PKCS#7 message object + * @param maxline The maximum characters per line, defaults to 64. + * + * @return The PEM-formatted PKCS#7 message. + */ + p7.messageToPem = function(msg, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var pemObj = { + type: 'PKCS7', + body: asn1.toDer(msg.toAsn1()).getBytes() + }; + return forge.pem.encode(pemObj, {maxline: maxline}); + }; + + /** + * Converts a PKCS#7 message from an ASN.1 object. + * + * @param obj the ASN.1 representation of a ContentInfo. + * + * @return the PKCS#7 message. + */ + p7.messageFromAsn1 = function(obj) { + // validate root level ContentInfo and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(obj, p7.asn1.contentInfoValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#7 message. ' + + 'ASN.1 object is not an PKCS#7 ContentInfo.'); + error.errors = errors; + throw error; + } + + var contentType = asn1.derToOid(capture.contentType); + var msg; + + switch(contentType) { + case forge.pki.oids.envelopedData: + msg = p7.createEnvelopedData(); + break; + + case forge.pki.oids.encryptedData: + msg = p7.createEncryptedData(); + break; + + case forge.pki.oids.signedData: + msg = p7.createSignedData(); + break; + + default: + throw new Error('Cannot read PKCS#7 message. ContentType with OID ' + + contentType + ' is not (yet) supported.'); + } + + msg.fromAsn1(capture.content.value[0]); + return msg; + }; + + p7.createSignedData = function() { + var msg = null; + msg = { + type: forge.pki.oids.signedData, + version: 1, + certificates: [], + crls: [], + // TODO: add json-formatted signer stuff here? + signers: [], + // populated during sign() + digestAlgorithmIdentifiers: [], + contentInfo: null, + signerInfos: [], + + fromAsn1: function(obj) { + // validate SignedData content block and capture data. + _fromAsn1(msg, obj, p7.asn1.signedDataValidator); + msg.certificates = []; + msg.crls = []; + msg.digestAlgorithmIdentifiers = []; + msg.contentInfo = null; + msg.signerInfos = []; + + if(msg.rawCapture.certificates) { + var certs = msg.rawCapture.certificates.value; + for(var i = 0; i < certs.length; ++i) { + msg.certificates.push(forge.pki.certificateFromAsn1(certs[i])); + } + } + + // TODO: parse crls + }, + + toAsn1: function() { + // degenerate case with no content + if(!msg.contentInfo) { + msg.sign(); + } + + var certs = []; + for(var i = 0; i < msg.certificates.length; ++i) { + certs.push(forge.pki.certificateToAsn1(msg.certificates[i])); + } + + var crls = []; + // TODO: implement CRLs + + // [0] SignedData + var signedData = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(msg.version).getBytes()), + // DigestAlgorithmIdentifiers + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SET, true, + msg.digestAlgorithmIdentifiers), + // ContentInfo + msg.contentInfo + ]) + ]); + if(certs.length > 0) { + // [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL + signedData.value[0].value.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, certs)); + } + if(crls.length > 0) { + // [1] IMPLICIT CertificateRevocationLists OPTIONAL + signedData.value[0].value.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, crls)); + } + // SignerInfos + signedData.value[0].value.push( + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, + msg.signerInfos)); + + // ContentInfo + return asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // ContentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(msg.type).getBytes()), + // [0] SignedData + signedData + ]); + }, + + /** + * Add (another) entity to list of signers. + * + * Note: If authenticatedAttributes are provided, then, per RFC 2315, + * they must include at least two attributes: content type and + * message digest. The message digest attribute value will be + * auto-calculated during signing and will be ignored if provided. + * + * Here's an example of providing these two attributes: + * + * forge.pkcs7.createSignedData(); + * p7.addSigner({ + * issuer: cert.issuer.attributes, + * serialNumber: cert.serialNumber, + * key: privateKey, + * digestAlgorithm: forge.pki.oids.sha1, + * authenticatedAttributes: [{ + * type: forge.pki.oids.contentType, + * value: forge.pki.oids.data + * }, { + * type: forge.pki.oids.messageDigest + * }] + * }); + * + * TODO: Support [subjectKeyIdentifier] as signer's ID. + * + * @param signer the signer information: + * key the signer's private key. + * [certificate] a certificate containing the public key + * associated with the signer's private key; use this option as + * an alternative to specifying signer.issuer and + * signer.serialNumber. + * [issuer] the issuer attributes (eg: cert.issuer.attributes). + * [serialNumber] the signer's certificate's serial number in + * hexadecimal (eg: cert.serialNumber). + * [digestAlgorithm] the message digest OID, as a string, to use + * (eg: forge.pki.oids.sha1). + * [authenticatedAttributes] an optional array of attributes + * to also sign along with the content. + */ + addSigner: function(signer) { + var issuer = signer.issuer; + var serialNumber = signer.serialNumber; + if(signer.certificate) { + var cert = signer.certificate; + if(typeof cert === 'string') { + cert = forge.pki.certificateFromPem(cert); + } + issuer = cert.issuer.attributes; + serialNumber = cert.serialNumber; + } + var key = signer.key; + if(!key) { + throw new Error( + 'Could not add PKCS#7 signer; no private key specified.'); + } + if(typeof key === 'string') { + key = forge.pki.privateKeyFromPem(key); + } + + // ensure OID known for digest algorithm + var digestAlgorithm = signer.digestAlgorithm || forge.pki.oids.sha1; + switch(digestAlgorithm) { + case forge.pki.oids.sha1: + case forge.pki.oids.sha256: + case forge.pki.oids.sha384: + case forge.pki.oids.sha512: + case forge.pki.oids.md5: + break; + default: + throw new Error( + 'Could not add PKCS#7 signer; unknown message digest algorithm: ' + + digestAlgorithm); + } + + // if authenticatedAttributes is present, then the attributes + // must contain at least PKCS #9 content-type and message-digest + var authenticatedAttributes = signer.authenticatedAttributes || []; + if(authenticatedAttributes.length > 0) { + var contentType = false; + var messageDigest = false; + for(var i = 0; i < authenticatedAttributes.length; ++i) { + var attr = authenticatedAttributes[i]; + if(!contentType && attr.type === forge.pki.oids.contentType) { + contentType = true; + if(messageDigest) { + break; + } + continue; + } + if(!messageDigest && attr.type === forge.pki.oids.messageDigest) { + messageDigest = true; + if(contentType) { + break; + } + continue; + } + } + + if(!contentType || !messageDigest) { + throw new Error('Invalid signer.authenticatedAttributes. If ' + + 'signer.authenticatedAttributes is specified, then it must ' + + 'contain at least two attributes, PKCS #9 content-type and ' + + 'PKCS #9 message-digest.'); + } + } + + msg.signers.push({ + key: key, + version: 1, + issuer: issuer, + serialNumber: serialNumber, + digestAlgorithm: digestAlgorithm, + signatureAlgorithm: forge.pki.oids.rsaEncryption, + signature: null, + authenticatedAttributes: authenticatedAttributes, + unauthenticatedAttributes: [] + }); + }, + + /** + * Signs the content. + * @param options Options to apply when signing: + * [detached] boolean. If signing should be done in detached mode. Defaults to false. + */ + sign: function(options) { + options = options || {}; + // auto-generate content info + if(typeof msg.content !== 'object' || msg.contentInfo === null) { + // use Data ContentInfo + msg.contentInfo = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // ContentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(forge.pki.oids.data).getBytes()) + ]); + + // add actual content, if present + if('content' in msg) { + var content; + if(msg.content instanceof forge.util.ByteBuffer) { + content = msg.content.bytes(); + } else if(typeof msg.content === 'string') { + content = forge.util.encodeUtf8(msg.content); + } + + if (options.detached) { + msg.detachedContent = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, content); + } else { + msg.contentInfo.value.push( + // [0] EXPLICIT content + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + content) + ])); + } + } + } + + // no signers, return early (degenerate case for certificate container) + if(msg.signers.length === 0) { + return; + } + + // generate digest algorithm identifiers + var mds = addDigestAlgorithmIds(); + + // generate signerInfos + addSignerInfos(mds); + }, + + verify: function() { + throw new Error('PKCS#7 signature verification not yet implemented.'); + }, + + /** + * Add a certificate. + * + * @param cert the certificate to add. + */ + addCertificate: function(cert) { + // convert from PEM + if(typeof cert === 'string') { + cert = forge.pki.certificateFromPem(cert); + } + msg.certificates.push(cert); + }, + + /** + * Add a certificate revokation list. + * + * @param crl the certificate revokation list to add. + */ + addCertificateRevokationList: function(crl) { + throw new Error('PKCS#7 CRL support not yet implemented.'); + } + }; + return msg; + + function addDigestAlgorithmIds() { + var mds = {}; + + for(var i = 0; i < msg.signers.length; ++i) { + var signer = msg.signers[i]; + var oid = signer.digestAlgorithm; + if(!(oid in mds)) { + // content digest + mds[oid] = forge.md[forge.pki.oids[oid]].create(); + } + if(signer.authenticatedAttributes.length === 0) { + // no custom attributes to digest; use content message digest + signer.md = mds[oid]; + } else { + // custom attributes to be digested; use own message digest + // TODO: optimize to just copy message digest state if that + // feature is ever supported with message digests + signer.md = forge.md[forge.pki.oids[oid]].create(); + } + } + + // add unique digest algorithm identifiers + msg.digestAlgorithmIdentifiers = []; + for(var oid in mds) { + msg.digestAlgorithmIdentifiers.push( + // AlgorithmIdentifier + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(oid).getBytes()), + // parameters (null) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ])); + } + + return mds; + } + + function addSignerInfos(mds) { + var content; + + if (msg.detachedContent) { + // Signature has been made in detached mode. + content = msg.detachedContent; + } else { + // Note: ContentInfo is a SEQUENCE with 2 values, second value is + // the content field and is optional for a ContentInfo but required here + // since signers are present + // get ContentInfo content + content = msg.contentInfo.value[1]; + // skip [0] EXPLICIT content wrapper + content = content.value[0]; + } + + if(!content) { + throw new Error( + 'Could not sign PKCS#7 message; there is no content to sign.'); + } + + // get ContentInfo content type + var contentType = asn1.derToOid(msg.contentInfo.value[0].value); + + // serialize content + var bytes = asn1.toDer(content); + + // skip identifier and length per RFC 2315 9.3 + // skip identifier (1 byte) + bytes.getByte(); + // read and discard length bytes + asn1.getBerValueLength(bytes); + bytes = bytes.getBytes(); + + // digest content DER value bytes + for(var oid in mds) { + mds[oid].start().update(bytes); + } + + // sign content + var signingTime = new Date(); + for(var i = 0; i < msg.signers.length; ++i) { + var signer = msg.signers[i]; + + if(signer.authenticatedAttributes.length === 0) { + // if ContentInfo content type is not "Data", then + // authenticatedAttributes must be present per RFC 2315 + if(contentType !== forge.pki.oids.data) { + throw new Error( + 'Invalid signer; authenticatedAttributes must be present ' + + 'when the ContentInfo content type is not PKCS#7 Data.'); + } + } else { + // process authenticated attributes + // [0] IMPLICIT + signer.authenticatedAttributesAsn1 = asn1.create( + asn1.Class.CONTEXT_SPECIFIC, 0, true, []); + + // per RFC 2315, attributes are to be digested using a SET container + // not the above [0] IMPLICIT container + var attrsAsn1 = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SET, true, []); + + for(var ai = 0; ai < signer.authenticatedAttributes.length; ++ai) { + var attr = signer.authenticatedAttributes[ai]; + if(attr.type === forge.pki.oids.messageDigest) { + // use content message digest as value + attr.value = mds[signer.digestAlgorithm].digest(); + } else if(attr.type === forge.pki.oids.signingTime) { + // auto-populate signing time if not already set + if(!attr.value) { + attr.value = signingTime; + } + } + + // convert to ASN.1 and push onto Attributes SET (for signing) and + // onto authenticatedAttributesAsn1 to complete SignedData ASN.1 + // TODO: optimize away duplication + attrsAsn1.value.push(_attributeToAsn1(attr)); + signer.authenticatedAttributesAsn1.value.push(_attributeToAsn1(attr)); + } + + // DER-serialize and digest SET OF attributes only + bytes = asn1.toDer(attrsAsn1).getBytes(); + signer.md.start().update(bytes); + } + + // sign digest + signer.signature = signer.key.sign(signer.md, 'RSASSA-PKCS1-V1_5'); + } + + // add signer info + msg.signerInfos = _signersToAsn1(msg.signers); + } + }; + + /** + * Creates an empty PKCS#7 message of type EncryptedData. + * + * @return the message. + */ + p7.createEncryptedData = function() { + var msg = null; + msg = { + type: forge.pki.oids.encryptedData, + version: 0, + encryptedContent: { + algorithm: forge.pki.oids['aes256-CBC'] + }, + + /** + * Reads an EncryptedData content block (in ASN.1 format) + * + * @param obj The ASN.1 representation of the EncryptedData content block + */ + fromAsn1: function(obj) { + // Validate EncryptedData content block and capture data. + _fromAsn1(msg, obj, p7.asn1.encryptedDataValidator); + }, + + /** + * Decrypt encrypted content + * + * @param key The (symmetric) key as a byte buffer + */ + decrypt: function(key) { + if(key !== undefined) { + msg.encryptedContent.key = key; + } + _decryptContent(msg); + } + }; + return msg; + }; + + /** + * Creates an empty PKCS#7 message of type EnvelopedData. + * + * @return the message. + */ + p7.createEnvelopedData = function() { + var msg = null; + msg = { + type: forge.pki.oids.envelopedData, + version: 0, + recipients: [], + encryptedContent: { + algorithm: forge.pki.oids['aes256-CBC'] + }, + + /** + * Reads an EnvelopedData content block (in ASN.1 format) + * + * @param obj the ASN.1 representation of the EnvelopedData content block. + */ + fromAsn1: function(obj) { + // validate EnvelopedData content block and capture data + var capture = _fromAsn1(msg, obj, p7.asn1.envelopedDataValidator); + msg.recipients = _recipientsFromAsn1(capture.recipientInfos.value); + }, + + toAsn1: function() { + // ContentInfo + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // ContentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(msg.type).getBytes()), + // [0] EnvelopedData + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(msg.version).getBytes()), + // RecipientInfos + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, + _recipientsToAsn1(msg.recipients)), + // EncryptedContentInfo + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, + _encryptedContentToAsn1(msg.encryptedContent)) + ]) + ]) + ]); + }, + + /** + * Find recipient by X.509 certificate's issuer. + * + * @param cert the certificate with the issuer to look for. + * + * @return the recipient object. + */ + findRecipient: function(cert) { + var sAttr = cert.issuer.attributes; + + for(var i = 0; i < msg.recipients.length; ++i) { + var r = msg.recipients[i]; + var rAttr = r.issuer; + + if(r.serialNumber !== cert.serialNumber) { + continue; + } + + if(rAttr.length !== sAttr.length) { + continue; + } + + var match = true; + for(var j = 0; j < sAttr.length; ++j) { + if(rAttr[j].type !== sAttr[j].type || + rAttr[j].value !== sAttr[j].value) { + match = false; + break; + } + } + + if(match) { + return r; + } + } + + return null; + }, + + /** + * Decrypt enveloped content + * + * @param recipient The recipient object related to the private key + * @param privKey The (RSA) private key object + */ + decrypt: function(recipient, privKey) { + if(msg.encryptedContent.key === undefined && recipient !== undefined && + privKey !== undefined) { + switch(recipient.encryptedContent.algorithm) { + case forge.pki.oids.rsaEncryption: + case forge.pki.oids.desCBC: + var key = privKey.decrypt(recipient.encryptedContent.content); + msg.encryptedContent.key = forge.util.createBuffer(key); + break; + + default: + throw new Error('Unsupported asymmetric cipher, ' + + 'OID ' + recipient.encryptedContent.algorithm); + } + } + + _decryptContent(msg); + }, + + /** + * Add (another) entity to list of recipients. + * + * @param cert The certificate of the entity to add. + */ + addRecipient: function(cert) { + msg.recipients.push({ + version: 0, + issuer: cert.issuer.attributes, + serialNumber: cert.serialNumber, + encryptedContent: { + // We simply assume rsaEncryption here, since forge.pki only + // supports RSA so far. If the PKI module supports other + // ciphers one day, we need to modify this one as well. + algorithm: forge.pki.oids.rsaEncryption, + key: cert.publicKey + } + }); + }, + + /** + * Encrypt enveloped content. + * + * This function supports two optional arguments, cipher and key, which + * can be used to influence symmetric encryption. Unless cipher is + * provided, the cipher specified in encryptedContent.algorithm is used + * (defaults to AES-256-CBC). If no key is provided, encryptedContent.key + * is (re-)used. If that one's not set, a random key will be generated + * automatically. + * + * @param [key] The key to be used for symmetric encryption. + * @param [cipher] The OID of the symmetric cipher to use. + */ + encrypt: function(key, cipher) { + // Part 1: Symmetric encryption + if(msg.encryptedContent.content === undefined) { + cipher = cipher || msg.encryptedContent.algorithm; + key = key || msg.encryptedContent.key; + + var keyLen, ivLen, ciphFn; + switch(cipher) { + case forge.pki.oids['aes128-CBC']: + keyLen = 16; + ivLen = 16; + ciphFn = forge.aes.createEncryptionCipher; + break; + + case forge.pki.oids['aes192-CBC']: + keyLen = 24; + ivLen = 16; + ciphFn = forge.aes.createEncryptionCipher; + break; + + case forge.pki.oids['aes256-CBC']: + keyLen = 32; + ivLen = 16; + ciphFn = forge.aes.createEncryptionCipher; + break; + + case forge.pki.oids['des-EDE3-CBC']: + keyLen = 24; + ivLen = 8; + ciphFn = forge.des.createEncryptionCipher; + break; + + default: + throw new Error('Unsupported symmetric cipher, OID ' + cipher); + } + + if(key === undefined) { + key = forge.util.createBuffer(forge.random.getBytes(keyLen)); + } else if(key.length() != keyLen) { + throw new Error('Symmetric key has wrong length; ' + + 'got ' + key.length() + ' bytes, expected ' + keyLen + '.'); + } + + // Keep a copy of the key & IV in the object, so the caller can + // use it for whatever reason. + msg.encryptedContent.algorithm = cipher; + msg.encryptedContent.key = key; + msg.encryptedContent.parameter = forge.util.createBuffer( + forge.random.getBytes(ivLen)); + + var ciph = ciphFn(key); + ciph.start(msg.encryptedContent.parameter.copy()); + ciph.update(msg.content); + + // The finish function does PKCS#7 padding by default, therefore + // no action required by us. + if(!ciph.finish()) { + throw new Error('Symmetric encryption failed.'); + } + + msg.encryptedContent.content = ciph.output; + } + + // Part 2: asymmetric encryption for each recipient + for(var i = 0; i < msg.recipients.length; ++i) { + var recipient = msg.recipients[i]; + + // Nothing to do, encryption already done. + if(recipient.encryptedContent.content !== undefined) { + continue; + } + + switch(recipient.encryptedContent.algorithm) { + case forge.pki.oids.rsaEncryption: + recipient.encryptedContent.content = + recipient.encryptedContent.key.encrypt( + msg.encryptedContent.key.data); + break; + + default: + throw new Error('Unsupported asymmetric cipher, OID ' + + recipient.encryptedContent.algorithm); + } + } + } + }; + return msg; + }; + + /** + * Converts a single recipient from an ASN.1 object. + * + * @param obj the ASN.1 RecipientInfo. + * + * @return the recipient object. + */ + function _recipientFromAsn1(obj) { + // validate EnvelopedData content block and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(obj, p7.asn1.recipientInfoValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#7 RecipientInfo. ' + + 'ASN.1 object is not an PKCS#7 RecipientInfo.'); + error.errors = errors; + throw error; + } + + return { + version: capture.version.charCodeAt(0), + issuer: forge.pki.RDNAttributesAsArray(capture.issuer), + serialNumber: forge.util.createBuffer(capture.serial).toHex(), + encryptedContent: { + algorithm: asn1.derToOid(capture.encAlgorithm), + parameter: capture.encParameter.value, + content: capture.encKey + } + }; + } + + /** + * Converts a single recipient object to an ASN.1 object. + * + * @param obj the recipient object. + * + * @return the ASN.1 RecipientInfo. + */ + function _recipientToAsn1(obj) { + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(obj.version).getBytes()), + // IssuerAndSerialNumber + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Name + forge.pki.distinguishedNameToAsn1({attributes: obj.issuer}), + // Serial + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + forge.util.hexToBytes(obj.serialNumber)) + ]), + // KeyEncryptionAlgorithmIdentifier + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(obj.encryptedContent.algorithm).getBytes()), + // Parameter, force NULL, only RSA supported for now. + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]), + // EncryptedKey + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + obj.encryptedContent.content) + ]); + } + + /** + * Map a set of RecipientInfo ASN.1 objects to recipient objects. + * + * @param infos an array of ASN.1 representations RecipientInfo (i.e. SET OF). + * + * @return an array of recipient objects. + */ + function _recipientsFromAsn1(infos) { + var ret = []; + for(var i = 0; i < infos.length; ++i) { + ret.push(_recipientFromAsn1(infos[i])); + } + return ret; + } + + /** + * Map an array of recipient objects to ASN.1 RecipientInfo objects. + * + * @param recipients an array of recipientInfo objects. + * + * @return an array of ASN.1 RecipientInfos. + */ + function _recipientsToAsn1(recipients) { + var ret = []; + for(var i = 0; i < recipients.length; ++i) { + ret.push(_recipientToAsn1(recipients[i])); + } + return ret; + } + + /** + * Converts a single signerInfo object to an ASN.1 object. + * + * @param obj the signerInfo object. + * + * @return the ASN.1 representation of a SignerInfo. + */ + function _signerToAsn1(obj) { + // SignerInfo + var rval = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(obj.version).getBytes()), + // issuerAndSerialNumber + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // name + forge.pki.distinguishedNameToAsn1({attributes: obj.issuer}), + // serial + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + forge.util.hexToBytes(obj.serialNumber)) + ]), + // digestAlgorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(obj.digestAlgorithm).getBytes()), + // parameters (null) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]) + ]); + + // authenticatedAttributes (OPTIONAL) + if(obj.authenticatedAttributesAsn1) { + // add ASN.1 previously generated during signing + rval.value.push(obj.authenticatedAttributesAsn1); + } + + // digestEncryptionAlgorithm + rval.value.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(obj.signatureAlgorithm).getBytes()), + // parameters (null) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ])); + + // encryptedDigest + rval.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, obj.signature)); + + // unauthenticatedAttributes (OPTIONAL) + if(obj.unauthenticatedAttributes.length > 0) { + // [1] IMPLICIT + var attrsAsn1 = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, []); + for(var i = 0; i < obj.unauthenticatedAttributes.length; ++i) { + var attr = obj.unauthenticatedAttributes[i]; + attrsAsn1.values.push(_attributeToAsn1(attr)); + } + rval.value.push(attrsAsn1); + } + + return rval; + } + + /** + * Map an array of signer objects to ASN.1 objects. + * + * @param signers an array of signer objects. + * + * @return an array of ASN.1 SignerInfos. + */ + function _signersToAsn1(signers) { + var ret = []; + for(var i = 0; i < signers.length; ++i) { + ret.push(_signerToAsn1(signers[i])); + } + return ret; + } + + /** + * Convert an attribute object to an ASN.1 Attribute. + * + * @param attr the attribute object. + * + * @return the ASN.1 Attribute. + */ + function _attributeToAsn1(attr) { + var value; + + // TODO: generalize to support more attributes + if(attr.type === forge.pki.oids.contentType) { + value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(attr.value).getBytes()); + } else if(attr.type === forge.pki.oids.messageDigest) { + value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + attr.value.bytes()); + } else if(attr.type === forge.pki.oids.signingTime) { + /* Note per RFC 2985: Dates between 1 January 1950 and 31 December 2049 + (inclusive) MUST be encoded as UTCTime. Any dates with year values + before 1950 or after 2049 MUST be encoded as GeneralizedTime. [Further,] + UTCTime values MUST be expressed in Greenwich Mean Time (Zulu) and MUST + include seconds (i.e., times are YYMMDDHHMMSSZ), even where the + number of seconds is zero. Midnight (GMT) must be represented as + "YYMMDD000000Z". */ + // TODO: make these module-level constants + var jan_1_1950 = new Date('1950-01-01T00:00:00Z'); + var jan_1_2050 = new Date('2050-01-01T00:00:00Z'); + var date = attr.value; + if(typeof date === 'string') { + // try to parse date + var timestamp = Date.parse(date); + if(!isNaN(timestamp)) { + date = new Date(timestamp); + } else if(date.length === 13) { + // YYMMDDHHMMSSZ (13 chars for UTCTime) + date = asn1.utcTimeToDate(date); + } else { + // assume generalized time + date = asn1.generalizedTimeToDate(date); + } + } + + if(date >= jan_1_1950 && date < jan_1_2050) { + value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false, + asn1.dateToUtcTime(date)); + } else { + value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false, + asn1.dateToGeneralizedTime(date)); + } + } + + // TODO: expose as common API call + // create a RelativeDistinguishedName set + // each value in the set is an AttributeTypeAndValue first + // containing the type (an OID) and second the value + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // AttributeType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(attr.type).getBytes()), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ + // AttributeValue + value + ]) + ]); + } + + /** + * Map messages encrypted content to ASN.1 objects. + * + * @param ec The encryptedContent object of the message. + * + * @return ASN.1 representation of the encryptedContent object (SEQUENCE). + */ + function _encryptedContentToAsn1(ec) { + return [ + // ContentType, always Data for the moment + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(forge.pki.oids.data).getBytes()), + // ContentEncryptionAlgorithmIdentifier + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(ec.algorithm).getBytes()), + // Parameters (IV) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + ec.parameter.getBytes()) + ]), + // [0] EncryptedContent + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + ec.content.getBytes()) + ]) + ]; + } + + /** + * Reads the "common part" of an PKCS#7 content block (in ASN.1 format) + * + * This function reads the "common part" of the PKCS#7 content blocks + * EncryptedData and EnvelopedData, i.e. version number and symmetrically + * encrypted content block. + * + * The result of the ASN.1 validate and capture process is returned + * to allow the caller to extract further data, e.g. the list of recipients + * in case of a EnvelopedData object. + * + * @param msg the PKCS#7 object to read the data to. + * @param obj the ASN.1 representation of the content block. + * @param validator the ASN.1 structure validator object to use. + * + * @return the value map captured by validator object. + */ + function _fromAsn1(msg, obj, validator) { + var capture = {}; + var errors = []; + if(!asn1.validate(obj, validator, capture, errors)) { + var error = new Error('Cannot read PKCS#7 message. ' + + 'ASN.1 object is not a supported PKCS#7 message.'); + error.errors = error; + throw error; + } + + // Check contentType, so far we only support (raw) Data. + var contentType = asn1.derToOid(capture.contentType); + if(contentType !== forge.pki.oids.data) { + throw new Error('Unsupported PKCS#7 message. ' + + 'Only wrapped ContentType Data supported.'); + } + + if(capture.encryptedContent) { + var content = ''; + if(forge.util.isArray(capture.encryptedContent)) { + for(var i = 0; i < capture.encryptedContent.length; ++i) { + if(capture.encryptedContent[i].type !== asn1.Type.OCTETSTRING) { + throw new Error('Malformed PKCS#7 message, expecting encrypted ' + + 'content constructed of only OCTET STRING objects.'); + } + content += capture.encryptedContent[i].value; + } + } else { + content = capture.encryptedContent; + } + msg.encryptedContent = { + algorithm: asn1.derToOid(capture.encAlgorithm), + parameter: forge.util.createBuffer(capture.encParameter.value), + content: forge.util.createBuffer(content) + }; + } + + if(capture.content) { + var content = ''; + if(forge.util.isArray(capture.content)) { + for(var i = 0; i < capture.content.length; ++i) { + if(capture.content[i].type !== asn1.Type.OCTETSTRING) { + throw new Error('Malformed PKCS#7 message, expecting ' + + 'content constructed of only OCTET STRING objects.'); + } + content += capture.content[i].value; + } + } else { + content = capture.content; + } + msg.content = forge.util.createBuffer(content); + } + + msg.version = capture.version.charCodeAt(0); + msg.rawCapture = capture; + + return capture; + } + + /** + * Decrypt the symmetrically encrypted content block of the PKCS#7 message. + * + * Decryption is skipped in case the PKCS#7 message object already has a + * (decrypted) content attribute. The algorithm, key and cipher parameters + * (probably the iv) are taken from the encryptedContent attribute of the + * message object. + * + * @param The PKCS#7 message object. + */ + function _decryptContent(msg) { + if(msg.encryptedContent.key === undefined) { + throw new Error('Symmetric key not available.'); + } + + if(msg.content === undefined) { + var ciph; + + switch(msg.encryptedContent.algorithm) { + case forge.pki.oids['aes128-CBC']: + case forge.pki.oids['aes192-CBC']: + case forge.pki.oids['aes256-CBC']: + ciph = forge.aes.createDecryptionCipher(msg.encryptedContent.key); + break; + + case forge.pki.oids['desCBC']: + case forge.pki.oids['des-EDE3-CBC']: + ciph = forge.des.createDecryptionCipher(msg.encryptedContent.key); + break; + + default: + throw new Error('Unsupported symmetric cipher, OID ' + + msg.encryptedContent.algorithm); + } + ciph.start(msg.encryptedContent.parameter); + ciph.update(msg.encryptedContent.content); + + if(!ciph.finish()) { + throw new Error('Symmetric decryption failed.'); + } + + msg.content = ciph.output; + } + } + }); + + var ssh_1 = createCommonjsModule(function (module) { + /** + * Functions to output keys in SSH-friendly formats. + * + * This is part of the Forge project which may be used under the terms of + * either the BSD License or the GNU General Public License (GPL) Version 2. + * + * See: https://github.com/digitalbazaar/forge/blob/cbebca3780658703d925b61b2caffb1d263a6c1d/LICENSE + * + * @author https://github.com/shellac + */ + + + + + + + + var ssh = module.exports = forge.ssh = forge.ssh || {}; + + /** + * Encodes (and optionally encrypts) a private RSA key as a Putty PPK file. + * + * @param privateKey the key. + * @param passphrase a passphrase to protect the key (falsy for no encryption). + * @param comment a comment to include in the key file. + * + * @return the PPK file as a string. + */ + ssh.privateKeyToPutty = function(privateKey, passphrase, comment) { + comment = comment || ''; + passphrase = passphrase || ''; + var algorithm = 'ssh-rsa'; + var encryptionAlgorithm = (passphrase === '') ? 'none' : 'aes256-cbc'; + + var ppk = 'PuTTY-User-Key-File-2: ' + algorithm + '\r\n'; + ppk += 'Encryption: ' + encryptionAlgorithm + '\r\n'; + ppk += 'Comment: ' + comment + '\r\n'; + + // public key into buffer for ppk + var pubbuffer = forge.util.createBuffer(); + _addStringToBuffer(pubbuffer, algorithm); + _addBigIntegerToBuffer(pubbuffer, privateKey.e); + _addBigIntegerToBuffer(pubbuffer, privateKey.n); + + // write public key + var pub = forge.util.encode64(pubbuffer.bytes(), 64); + var length = Math.floor(pub.length / 66) + 1; // 66 = 64 + \r\n + ppk += 'Public-Lines: ' + length + '\r\n'; + ppk += pub; + + // private key into a buffer + var privbuffer = forge.util.createBuffer(); + _addBigIntegerToBuffer(privbuffer, privateKey.d); + _addBigIntegerToBuffer(privbuffer, privateKey.p); + _addBigIntegerToBuffer(privbuffer, privateKey.q); + _addBigIntegerToBuffer(privbuffer, privateKey.qInv); + + // optionally encrypt the private key + var priv; + if(!passphrase) { + // use the unencrypted buffer + priv = forge.util.encode64(privbuffer.bytes(), 64); + } else { + // encrypt RSA key using passphrase + var encLen = privbuffer.length() + 16 - 1; + encLen -= encLen % 16; + + // pad private key with sha1-d data -- needs to be a multiple of 16 + var padding = _sha1(privbuffer.bytes()); + + padding.truncate(padding.length() - encLen + privbuffer.length()); + privbuffer.putBuffer(padding); + + var aeskey = forge.util.createBuffer(); + aeskey.putBuffer(_sha1('\x00\x00\x00\x00', passphrase)); + aeskey.putBuffer(_sha1('\x00\x00\x00\x01', passphrase)); + + // encrypt some bytes using CBC mode + // key is 40 bytes, so truncate *by* 8 bytes + var cipher = forge.aes.createEncryptionCipher(aeskey.truncate(8), 'CBC'); + cipher.start(forge.util.createBuffer().fillWithByte(0, 16)); + cipher.update(privbuffer.copy()); + cipher.finish(); + var encrypted = cipher.output; + + // Note: this appears to differ from Putty -- is forge wrong, or putty? + // due to padding we finish as an exact multiple of 16 + encrypted.truncate(16); // all padding + + priv = forge.util.encode64(encrypted.bytes(), 64); + } + + // output private key + length = Math.floor(priv.length / 66) + 1; // 64 + \r\n + ppk += '\r\nPrivate-Lines: ' + length + '\r\n'; + ppk += priv; + + // MAC + var mackey = _sha1('putty-private-key-file-mac-key', passphrase); + + var macbuffer = forge.util.createBuffer(); + _addStringToBuffer(macbuffer, algorithm); + _addStringToBuffer(macbuffer, encryptionAlgorithm); + _addStringToBuffer(macbuffer, comment); + macbuffer.putInt32(pubbuffer.length()); + macbuffer.putBuffer(pubbuffer); + macbuffer.putInt32(privbuffer.length()); + macbuffer.putBuffer(privbuffer); + + var hmac = forge.hmac.create(); + hmac.start('sha1', mackey); + hmac.update(macbuffer.bytes()); + + ppk += '\r\nPrivate-MAC: ' + hmac.digest().toHex() + '\r\n'; + + return ppk; + }; + + /** + * Encodes a public RSA key as an OpenSSH file. + * + * @param key the key. + * @param comment a comment. + * + * @return the public key in OpenSSH format. + */ + ssh.publicKeyToOpenSSH = function(key, comment) { + var type = 'ssh-rsa'; + comment = comment || ''; + + var buffer = forge.util.createBuffer(); + _addStringToBuffer(buffer, type); + _addBigIntegerToBuffer(buffer, key.e); + _addBigIntegerToBuffer(buffer, key.n); + + return type + ' ' + forge.util.encode64(buffer.bytes()) + ' ' + comment; + }; + + /** + * Encodes a private RSA key as an OpenSSH file. + * + * @param key the key. + * @param passphrase a passphrase to protect the key (falsy for no encryption). + * + * @return the public key in OpenSSH format. + */ + ssh.privateKeyToOpenSSH = function(privateKey, passphrase) { + if(!passphrase) { + return forge.pki.privateKeyToPem(privateKey); + } + // OpenSSH private key is just a legacy format, it seems + return forge.pki.encryptRsaPrivateKey(privateKey, passphrase, + {legacy: true, algorithm: 'aes128'}); + }; + + /** + * Gets the SSH fingerprint for the given public key. + * + * @param options the options to use. + * [md] the message digest object to use (defaults to forge.md.md5). + * [encoding] an alternative output encoding, such as 'hex' + * (defaults to none, outputs a byte buffer). + * [delimiter] the delimiter to use between bytes for 'hex' encoded + * output, eg: ':' (defaults to none). + * + * @return the fingerprint as a byte buffer or other encoding based on options. + */ + ssh.getPublicKeyFingerprint = function(key, options) { + options = options || {}; + var md = options.md || forge.md.md5.create(); + + var type = 'ssh-rsa'; + var buffer = forge.util.createBuffer(); + _addStringToBuffer(buffer, type); + _addBigIntegerToBuffer(buffer, key.e); + _addBigIntegerToBuffer(buffer, key.n); + + // hash public key bytes + md.start(); + md.update(buffer.getBytes()); + var digest = md.digest(); + if(options.encoding === 'hex') { + var hex = digest.toHex(); + if(options.delimiter) { + return hex.match(/.{2}/g).join(options.delimiter); + } + return hex; + } else if(options.encoding === 'binary') { + return digest.getBytes(); + } else if(options.encoding) { + throw new Error('Unknown encoding "' + options.encoding + '".'); + } + return digest; + }; + + /** + * Adds len(val) then val to a buffer. + * + * @param buffer the buffer to add to. + * @param val a big integer. + */ + function _addBigIntegerToBuffer(buffer, val) { + var hexVal = val.toString(16); + // ensure 2s complement +ve + if(hexVal[0] >= '8') { + hexVal = '00' + hexVal; + } + var bytes = forge.util.hexToBytes(hexVal); + buffer.putInt32(bytes.length); + buffer.putBytes(bytes); + } + + /** + * Adds len(val) then val to a buffer. + * + * @param buffer the buffer to add to. + * @param val a string. + */ + function _addStringToBuffer(buffer, val) { + buffer.putInt32(val.length); + buffer.putString(val); + } + + /** + * Hashes the arguments into one value using SHA-1. + * + * @return the sha1 hash of the provided arguments. + */ + function _sha1() { + var sha = forge.md.sha1.create(); + var num = arguments.length; + for (var i = 0; i < num; ++i) { + sha.update(arguments[i]); + } + return sha.digest(); + } + }); + + /** + * Support for concurrent task management and synchronization in web + * applications. + * + * @author Dave Longley + * @author David I. Lehn + * + * Copyright (c) 2009-2013 Digital Bazaar, Inc. + */ + + + + + + // logging category + var cat = 'forge.task'; + + // track tasks for debugging + var sTasks = {}; + var sNextTaskId = 0; + // debug access + forge.debug.set(cat, 'tasks', sTasks); + + // a map of task type to task queue + var sTaskQueues = {}; + // debug access + forge.debug.set(cat, 'queues', sTaskQueues); + + // name for unnamed tasks + var sNoTaskName = '?'; + + // maximum number of doNext() recursions before a context swap occurs + // FIXME: might need to tweak this based on the browser + var sMaxRecursions = 30; + + // time slice for doing tasks before a context swap occurs + // FIXME: might need to tweak this based on the browser + var sTimeSlice = 20; + + /** + * Task states. + * + * READY: ready to start processing + * RUNNING: task or a subtask is running + * BLOCKED: task is waiting to acquire N permits to continue + * SLEEPING: task is sleeping for a period of time + * DONE: task is done + * ERROR: task has an error + */ + var READY = 'ready'; + var RUNNING = 'running'; + var BLOCKED = 'blocked'; + var SLEEPING = 'sleeping'; + var DONE = 'done'; + var ERROR = 'error'; + + /** + * Task actions. Used to control state transitions. + * + * STOP: stop processing + * START: start processing tasks + * BLOCK: block task from continuing until 1 or more permits are released + * UNBLOCK: release one or more permits + * SLEEP: sleep for a period of time + * WAKEUP: wakeup early from SLEEPING state + * CANCEL: cancel further tasks + * FAIL: a failure occured + */ + var STOP = 'stop'; + var START = 'start'; + var BLOCK = 'block'; + var UNBLOCK = 'unblock'; + var SLEEP = 'sleep'; + var WAKEUP = 'wakeup'; + var CANCEL = 'cancel'; + var FAIL = 'fail'; + + /** + * State transition table. + * + * nextState = sStateTable[currentState][action] + */ + var sStateTable = {}; + + sStateTable[READY] = {}; + sStateTable[READY][STOP] = READY; + sStateTable[READY][START] = RUNNING; + sStateTable[READY][CANCEL] = DONE; + sStateTable[READY][FAIL] = ERROR; + + sStateTable[RUNNING] = {}; + sStateTable[RUNNING][STOP] = READY; + sStateTable[RUNNING][START] = RUNNING; + sStateTable[RUNNING][BLOCK] = BLOCKED; + sStateTable[RUNNING][UNBLOCK] = RUNNING; + sStateTable[RUNNING][SLEEP] = SLEEPING; + sStateTable[RUNNING][WAKEUP] = RUNNING; + sStateTable[RUNNING][CANCEL] = DONE; + sStateTable[RUNNING][FAIL] = ERROR; + + sStateTable[BLOCKED] = {}; + sStateTable[BLOCKED][STOP] = BLOCKED; + sStateTable[BLOCKED][START] = BLOCKED; + sStateTable[BLOCKED][BLOCK] = BLOCKED; + sStateTable[BLOCKED][UNBLOCK] = BLOCKED; + sStateTable[BLOCKED][SLEEP] = BLOCKED; + sStateTable[BLOCKED][WAKEUP] = BLOCKED; + sStateTable[BLOCKED][CANCEL] = DONE; + sStateTable[BLOCKED][FAIL] = ERROR; + + sStateTable[SLEEPING] = {}; + sStateTable[SLEEPING][STOP] = SLEEPING; + sStateTable[SLEEPING][START] = SLEEPING; + sStateTable[SLEEPING][BLOCK] = SLEEPING; + sStateTable[SLEEPING][UNBLOCK] = SLEEPING; + sStateTable[SLEEPING][SLEEP] = SLEEPING; + sStateTable[SLEEPING][WAKEUP] = SLEEPING; + sStateTable[SLEEPING][CANCEL] = DONE; + sStateTable[SLEEPING][FAIL] = ERROR; + + sStateTable[DONE] = {}; + sStateTable[DONE][STOP] = DONE; + sStateTable[DONE][START] = DONE; + sStateTable[DONE][BLOCK] = DONE; + sStateTable[DONE][UNBLOCK] = DONE; + sStateTable[DONE][SLEEP] = DONE; + sStateTable[DONE][WAKEUP] = DONE; + sStateTable[DONE][CANCEL] = DONE; + sStateTable[DONE][FAIL] = ERROR; + + sStateTable[ERROR] = {}; + sStateTable[ERROR][STOP] = ERROR; + sStateTable[ERROR][START] = ERROR; + sStateTable[ERROR][BLOCK] = ERROR; + sStateTable[ERROR][UNBLOCK] = ERROR; + sStateTable[ERROR][SLEEP] = ERROR; + sStateTable[ERROR][WAKEUP] = ERROR; + sStateTable[ERROR][CANCEL] = ERROR; + sStateTable[ERROR][FAIL] = ERROR; + + /** + * Creates a new task. + * + * @param options options for this task + * run: the run function for the task (required) + * name: the run function for the task (optional) + * parent: parent of this task (optional) + * + * @return the empty task. + */ + var Task = function(options) { + // task id + this.id = -1; + + // task name + this.name = options.name || sNoTaskName; + + // task has no parent + this.parent = options.parent || null; + + // save run function + this.run = options.run; + + // create a queue of subtasks to run + this.subtasks = []; + + // error flag + this.error = false; + + // state of the task + this.state = READY; + + // number of times the task has been blocked (also the number + // of permits needed to be released to continue running) + this.blocks = 0; + + // timeout id when sleeping + this.timeoutId = null; + + // no swap time yet + this.swapTime = null; + + // no user data + this.userData = null; + + // initialize task + // FIXME: deal with overflow + this.id = sNextTaskId++; + sTasks[this.id] = this; + }; + + /** + * Logs debug information on this task and the system state. + */ + Task.prototype.debug = function(msg) { + msg = msg || ''; + forge.log.debug(cat, msg, + '[%s][%s] task:', this.id, this.name, this, + 'subtasks:', this.subtasks.length, + 'queue:', sTaskQueues); + }; + + /** + * Adds a subtask to run after task.doNext() or task.fail() is called. + * + * @param name human readable name for this task (optional). + * @param subrun a function to run that takes the current task as + * its first parameter. + * + * @return the current task (useful for chaining next() calls). + */ + Task.prototype.next = function(name, subrun) { + // juggle parameters if it looks like no name is given + if(typeof(name) === 'function') { + subrun = name; + + // inherit parent's name + name = this.name; + } + // create subtask, set parent to this task, propagate callbacks + var subtask = new Task({ + run: subrun, + name: name, + parent: this + }); + // start subtasks running + subtask.state = RUNNING; + subtask.type = this.type; + subtask.successCallback = this.successCallback || null; + subtask.failureCallback = this.failureCallback || null; + + // queue a new subtask + this.subtasks.push(subtask); + + return this; + }; + + /** + * Adds subtasks to run in parallel after task.doNext() or task.fail() + * is called. + * + * @param name human readable name for this task (optional). + * @param subrun functions to run that take the current task as + * their first parameter. + * + * @return the current task (useful for chaining next() calls). + */ + Task.prototype.parallel = function(name, subrun) { + // juggle parameters if it looks like no name is given + if(forge.util.isArray(name)) { + subrun = name; + + // inherit parent's name + name = this.name; + } + // Wrap parallel tasks in a regular task so they are started at the + // proper time. + return this.next(name, function(task) { + // block waiting for subtasks + var ptask = task; + ptask.block(subrun.length); + + // we pass the iterator from the loop below as a parameter + // to a function because it is otherwise included in the + // closure and changes as the loop changes -- causing i + // to always be set to its highest value + var startParallelTask = function(pname, pi) { + forge.task.start({ + type: pname, + run: function(task) { + subrun[pi](task); + }, + success: function(task) { + ptask.unblock(); + }, + failure: function(task) { + ptask.unblock(); + } + }); + }; + + for(var i = 0; i < subrun.length; i++) { + // Type must be unique so task starts in parallel: + // name + private string + task id + sub-task index + // start tasks in parallel and unblock when the finish + var pname = name + '__parallel-' + task.id + '-' + i; + var pi = i; + startParallelTask(pname, pi); + } + }); + }; + + /** + * Stops a running task. + */ + Task.prototype.stop = function() { + this.state = sStateTable[this.state][STOP]; + }; + + /** + * Starts running a task. + */ + Task.prototype.start = function() { + this.error = false; + this.state = sStateTable[this.state][START]; + + // try to restart + if(this.state === RUNNING) { + this.start = new Date(); + this.run(this); + runNext(this, 0); + } + }; + + /** + * Blocks a task until it one or more permits have been released. The + * task will not resume until the requested number of permits have + * been released with call(s) to unblock(). + * + * @param n number of permits to wait for(default: 1). + */ + Task.prototype.block = function(n) { + n = typeof(n) === 'undefined' ? 1 : n; + this.blocks += n; + if(this.blocks > 0) { + this.state = sStateTable[this.state][BLOCK]; + } + }; + + /** + * Releases a permit to unblock a task. If a task was blocked by + * requesting N permits via block(), then it will only continue + * running once enough permits have been released via unblock() calls. + * + * If multiple processes need to synchronize with a single task then + * use a condition variable (see forge.task.createCondition). It is + * an error to unblock a task more times than it has been blocked. + * + * @param n number of permits to release (default: 1). + * + * @return the current block count (task is unblocked when count is 0) + */ + Task.prototype.unblock = function(n) { + n = typeof(n) === 'undefined' ? 1 : n; + this.blocks -= n; + if(this.blocks === 0 && this.state !== DONE) { + this.state = RUNNING; + runNext(this, 0); + } + return this.blocks; + }; + + /** + * Sleep for a period of time before resuming tasks. + * + * @param n number of milliseconds to sleep (default: 0). + */ + Task.prototype.sleep = function(n) { + n = typeof(n) === 'undefined' ? 0 : n; + this.state = sStateTable[this.state][SLEEP]; + var self = this; + this.timeoutId = setTimeout(function() { + self.timeoutId = null; + self.state = RUNNING; + runNext(self, 0); + }, n); + }; + + /** + * Waits on a condition variable until notified. The next task will + * not be scheduled until notification. A condition variable can be + * created with forge.task.createCondition(). + * + * Once cond.notify() is called, the task will continue. + * + * @param cond the condition variable to wait on. + */ + Task.prototype.wait = function(cond) { + cond.wait(this); + }; + + /** + * If sleeping, wakeup and continue running tasks. + */ + Task.prototype.wakeup = function() { + if(this.state === SLEEPING) { + cancelTimeout(this.timeoutId); + this.timeoutId = null; + this.state = RUNNING; + runNext(this, 0); + } + }; + + /** + * Cancel all remaining subtasks of this task. + */ + Task.prototype.cancel = function() { + this.state = sStateTable[this.state][CANCEL]; + // remove permits needed + this.permitsNeeded = 0; + // cancel timeouts + if(this.timeoutId !== null) { + cancelTimeout(this.timeoutId); + this.timeoutId = null; + } + // remove subtasks + this.subtasks = []; + }; + + /** + * Finishes this task with failure and sets error flag. The entire + * task will be aborted unless the next task that should execute + * is passed as a parameter. This allows levels of subtasks to be + * skipped. For instance, to abort only this tasks's subtasks, then + * call fail(task.parent). To abort this task's subtasks and its + * parent's subtasks, call fail(task.parent.parent). To abort + * all tasks and simply call the task callback, call fail() or + * fail(null). + * + * The task callback (success or failure) will always, eventually, be + * called. + * + * @param next the task to continue at, or null to abort entirely. + */ + Task.prototype.fail = function(next) { + // set error flag + this.error = true; + + // finish task + finish(this, true); + + if(next) { + // propagate task info + next.error = this.error; + next.swapTime = this.swapTime; + next.userData = this.userData; + + // do next task as specified + runNext(next, 0); + } else { + if(this.parent !== null) { + // finish root task (ensures it is removed from task queue) + var parent = this.parent; + while(parent.parent !== null) { + // propagate task info + parent.error = this.error; + parent.swapTime = this.swapTime; + parent.userData = this.userData; + parent = parent.parent; + } + finish(parent, true); + } + + // call failure callback if one exists + if(this.failureCallback) { + this.failureCallback(this); + } + } + }; + + /** + * Asynchronously start a task. + * + * @param task the task to start. + */ + var start = function(task) { + task.error = false; + task.state = sStateTable[task.state][START]; + setTimeout(function() { + if(task.state === RUNNING) { + task.swapTime = +new Date(); + task.run(task); + runNext(task, 0); + } + }, 0); + }; + + /** + * Run the next subtask or finish this task. + * + * @param task the task to process. + * @param recurse the recursion count. + */ + var runNext = function(task, recurse) { + // get time since last context swap (ms), if enough time has passed set + // swap to true to indicate that doNext was performed asynchronously + // also, if recurse is too high do asynchronously + var swap = + (recurse > sMaxRecursions) || + (+new Date() - task.swapTime) > sTimeSlice; + + var doNext = function(recurse) { + recurse++; + if(task.state === RUNNING) { + if(swap) { + // update swap time + task.swapTime = +new Date(); + } + + if(task.subtasks.length > 0) { + // run next subtask + var subtask = task.subtasks.shift(); + subtask.error = task.error; + subtask.swapTime = task.swapTime; + subtask.userData = task.userData; + subtask.run(subtask); + if(!subtask.error) { + runNext(subtask, recurse); + } + } else { + finish(task); + + if(!task.error) { + // chain back up and run parent + if(task.parent !== null) { + // propagate task info + task.parent.error = task.error; + task.parent.swapTime = task.swapTime; + task.parent.userData = task.userData; + + // no subtasks left, call run next subtask on parent + runNext(task.parent, recurse); + } + } + } + } + }; + + if(swap) { + // we're swapping, so run asynchronously + setTimeout(doNext, 0); + } else { + // not swapping, so run synchronously + doNext(recurse); + } + }; + + /** + * Finishes a task and looks for the next task in the queue to start. + * + * @param task the task to finish. + * @param suppressCallbacks true to suppress callbacks. + */ + var finish = function(task, suppressCallbacks) { + // subtask is now done + task.state = DONE; + + delete sTasks[task.id]; + + // only do queue processing for root tasks + if(task.parent === null) { + // report error if queue is missing + if(!(task.type in sTaskQueues)) { + forge.log.error(cat, + '[%s][%s] task queue missing [%s]', + task.id, task.name, task.type); + } else if(sTaskQueues[task.type].length === 0) { + // report error if queue is empty + forge.log.error(cat, + '[%s][%s] task queue empty [%s]', + task.id, task.name, task.type); + } else if(sTaskQueues[task.type][0] !== task) { + // report error if this task isn't the first in the queue + forge.log.error(cat, + '[%s][%s] task not first in queue [%s]', + task.id, task.name, task.type); + } else { + // remove ourselves from the queue + sTaskQueues[task.type].shift(); + // clean up queue if it is empty + if(sTaskQueues[task.type].length === 0) { + /* Note: Only a task can delete a queue of its own type. This + is used as a way to synchronize tasks. If a queue for a certain + task type exists, then a task of that type is running. + */ + delete sTaskQueues[task.type]; + } else { + sTaskQueues[task.type][0].start(); + } + } + + if(!suppressCallbacks) { + // call final callback if one exists + if(task.error && task.failureCallback) { + task.failureCallback(task); + } else if(!task.error && task.successCallback) { + task.successCallback(task); + } + } + } + }; + + /* Tasks API */ + var task = forge.task = forge.task || {}; + + /** + * Starts a new task that will run the passed function asynchronously. + * + * In order to finish the task, either task.doNext() or task.fail() + * *must* be called. + * + * The task must have a type (a string identifier) that can be used to + * synchronize it with other tasks of the same type. That type can also + * be used to cancel tasks that haven't started yet. + * + * To start a task, the following object must be provided as a parameter + * (each function takes a task object as its first parameter): + * + * { + * type: the type of task. + * run: the function to run to execute the task. + * success: a callback to call when the task succeeds (optional). + * failure: a callback to call when the task fails (optional). + * } + * + * @param options the object as described above. + */ + forge.task.start = function(options) { + // create a new task + var task = new Task({ + run: options.run, + name: options.name || sNoTaskName + }); + task.type = options.type; + task.successCallback = options.success || null; + task.failureCallback = options.failure || null; + + // append the task onto the appropriate queue + if(!(task.type in sTaskQueues)) { + // create the queue with the new task + sTaskQueues[task.type] = [task]; + start(task); + } else { + // push the task onto the queue, it will be run after a task + // with the same type completes + sTaskQueues[options.type].push(task); + } + }; + + /** + * Cancels all tasks of the given type that haven't started yet. + * + * @param type the type of task to cancel. + */ + forge.task.cancel = function(type) { + // find the task queue + if(type in sTaskQueues) { + // empty all but the current task from the queue + sTaskQueues[type] = [sTaskQueues[type][0]]; + } + }; + + /** + * Creates a condition variable to synchronize tasks. To make a task wait + * on the condition variable, call task.wait(condition). To notify all + * tasks that are waiting, call condition.notify(). + * + * @return the condition variable. + */ + forge.task.createCondition = function() { + var cond = { + // all tasks that are blocked + tasks: {} + }; + + /** + * Causes the given task to block until notify is called. If the task + * is already waiting on this condition then this is a no-op. + * + * @param task the task to cause to wait. + */ + cond.wait = function(task) { + // only block once + if(!(task.id in cond.tasks)) { + task.block(); + cond.tasks[task.id] = task; + } + }; + + /** + * Notifies all waiting tasks to wake up. + */ + cond.notify = function() { + // since unblock() will run the next task from here, make sure to + // clear the condition's blocked task list before unblocking + var tmp = cond.tasks; + cond.tasks = {}; + for(var id in tmp) { + tmp[id].unblock(); + } + }; + + return cond; + }; + + /** + * Node.js module for Forge. + * + * @author Dave Longley + * + * Copyright 2011-2016 Digital Bazaar, Inc. + */ + var lib$1 = forge; + + /** + * Verify the Sec-WebSocket-Accept header field by computing its expected value. + * @param {Uint8Array} key 4-bytes sec-websocket-key used for client handshake + * @param {string} resp received header field value string + * @returns boolean true if the received value is the expected + * @private + */ + function verifySecWebSocketAccept(key, resp) { + const fromHexString = hexString => + new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); + + const keyb64 = naclUtil.encodeBase64(key); + let hashed = lib$1.md.sha1.create(); + hashed.update(keyb64 + GUID); + const hashedBytes = fromHexString(hashed.digest().toHex()); + const expected = naclUtil.encodeBase64(hashedBytes); + return resp === expected; + } + + // Utilities + + /** + * A MessageEvent implementation for Node. + * + * @private + */ + class MessageEvent$1 { + constructor(type, init = undefined) { + this.type = type; + if (init) { + this.data = init.data; + this.origin = init.origin; + this.lastEventId = init.lastEventId; + this.channel = init.channel; + this.source = init.source; + this.port = init.port; + } + } + } + + /** + * A CloseEvent implementation for Node. + * + * @private + */ + class CloseEvent$1 extends MessageEvent$1 { + constructor(type, init = undefined) { + super(type, init); + if (init) { + this.wasClean = init.wasClean; + this.code = init.code; + this.reason = init.reason; + } + } + } + + /** + * Simple implementation of EventTarget. + * See {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget}. + * + * Used for mocking browsers' DOM EventTarget. + * + * @private + */ + class EventTarget$1 { + constructor() { + this.listeners = {}; + } + + addEventListener(type, callback) { + if (!(type in this.listeners)) { + this.listeners[type] = []; + } + this.listeners[type].push(callback); + } + + removeEventListener(type, callback) { + if (!(type in this.listeners)) { + return; + } + const stack = this.listeners[type]; + for (let i = 0, l = stack.length; i < l; i++) { + if (stack[i] === callback) { + stack.splice(i, 1); + return; + } + } + } + + dispatchEvent(event) { + if (!(event.type in this.listeners)) { + return true; + } + const stack = this.listeners[event.type].slice(); + + for (let i = 0, l = stack.length; i < l; i++) { + stack[i].call(this, event); + } + return !event.defaultPrevented; + + } + + } + + /* + * Mocks for use in node/broswer. + */ + + let EventTargetClass; + let MessageEventClass; + let BlobClass; + let CloseEventClass; + + if (lib_3) { + // running in node + EventTargetClass = EventTarget$1; + MessageEventClass = MessageEvent$1; + BlobClass = require("cross-blob"); + CloseEventClass = CloseEvent$1; + } else { + EventTargetClass = EventTarget; + MessageEventClass = MessageEvent; + BlobClass = Blob; + CloseEventClass = CloseEvent; + } + + /** + * Packet handling for WebSockets. + */ + + /** + * Return a handler for received websocket packets when in open state, for given WebSocket. + * @param {WebSocket} ws websocket handling the packets. + * @param {Boolean} noMasking disable masking of frames sent, for testing purposes only + * @private + */ + function onOpenMessage(ws, noMasking = false) { + return (pkt) => { + + // add the packet to the stream handler + ws._streamHandler.add(pkt); + + let frame; + // process all frames that are ready + while ((frame = ws._streamHandler.get()) !== undefined) { + ws._frameDefragmenter.add(frame); + } + + while ((frame = ws._frameDefragmenter.get()) !== undefined) { + if (isControlFrame(frame.opcode)) { + handleControlFrame(ws, frame, noMasking); + } else { + handleDataFrame(ws, frame); + } + } + + }; + } + + /** + * Handle a data frame. + * + * @param {WebSocket} ws websocket handling the frame + * @param {Frame} dataFrame frame to handle + * @private + */ + function handleDataFrame(ws, dataFrame) { + if (dataFrame.payload === undefined) { + return; + } + + // wrap to event + let eventData; + try { + if (dataFrame.opcode === opcodes.text) { + eventData = naclUtil.encodeUTF8(dataFrame.payload); + } else if (dataFrame.opcode === opcodes.binary) { + if (ws.binaryType === binaryTypes.blob) { + eventData = new Blob([dataFrame.payload]); + } else if (ws.binaryType === binaryTypes.arraybuffer) { + eventData = dataFrame.payload.buffer; + } + } else { + console.warn(`unknown opcode: ${dataFrame.opcode}, dropping frame`); + return; + } + } catch (err) { + console.warn(`error: tried to decode websocket data packet: ${err}`); + return; + } + let event = new MessageEventClass( + "message", + { + data: eventData, + origin: ws._url.href, + lastEventId: "", // TODO ? + source: null, // TODO ? + ports: [], // TODO ? + } + ); + + ws._received(event); + ws.__onmessage(event); // user defined handler + } + + /** + * Handle a control frame. + * + * @param {WebSocket} ws websocket handling the frame + * @param {Frame} controlFrame frame to handle + * @param {Boolean} noMasking disable masking of frames sent, for testing purposes only + * @private + */ + function handleControlFrame(ws, controlFrame, noMasking) { + const payload = controlFrame.payload; + switch (controlFrame.opcode) { + case opcodes.close: { + // status and reason are parsed but not needed for now + // the whole payload is echoed back + let status = 1005; + let reason = ""; + if (payload.length >= 2) { + status = payload[0] << 8 + payload[1]; + let reasonBytes = payload.slice(2); + if (reasonBytes.length > 0) { + // read reason + reason = naclUtil.encodeUTF8(reasonBytes); + } + } + + if (!ws._the_websocket_closing_handshake_is_started) { + // send back a close frame + ws._closing(); + + // if present, echo back status and reason + // otherwise use defaults + if (payload.length >= 2) { + // 2-byte unsigned integer + status = (payload[0] << 8) + payload[1]; + if (payload.length > 2) { + reason = naclUtil.encodeUTF8(payload.slice(2)); + } + } + + if (noMasking) { + ws._socket.send(closeFrame(status, reason, new Uint8Array(4))); + } else { + ws._socket.send(closeFrame(status, reason)); + } + // end of the closing handshake + ws._close_the_websocket_connection(); + } else { + // end of the closing handshake + ws._close_the_websocket_connection(); + } + break; + } + case opcodes.ping: { + // send back a pong frame, with received (decoded) payload if any + if (noMasking) { + ws._socket.send(pongFrame(payload, new Uint8Array(4))); + } else { + ws._socket.send(pongFrame(payload)); + } + break; + } + } + return; + } + + /** + * HTTP packet parsing utilities. + */ + + /** + * Parse the headers of a HTTP packet. + * No validation is performed on fields and keys. + * + * @param {string} headers HTTP headers + * @returns a dictionnary of key-values in the header, + * if multiple header key is present, values will be comma separated + * the header field names and values are set to lower-case, except for case-sensitive values + * @private + */ + function parseHeaders(headers) { + let parsed = {}; + + if (!headers) { return parsed; } + + headers.split('\r\n') + .forEach(line => { + // split header line in key - value + let i = line.indexOf(':'); + let key = line.substr(0, i).trim().toLowerCase(); + let val; + // Header fields names should be case-insensitive (RFC2616 4.2) + // So we only use lower case versions, except for 'sec-websocket' headers. + // For some reason WebSocket servers do not understand lower case 'sec-websocket' headers. + if (key != "sec-websocket-accept" && key != "sec-websocket-key") { + val = line.substr(i + 1).trim().toLowerCase(); + } else { + val = line.substr(i + 1).trim(); + } + + if (key) { + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + } + }); + + return parsed; + } + + /** + * The interface between a stream-oriented socket to a WebSocket. + * Reconstruct websocket frames from stream messages. + * + * To be used when receiving data from the TCP stream, + * feed this data into the add() method, + * and use get() method to poll for ready frames. + * + * @private + */ + class StreamHandler { + constructor() { + // the queue containing ready websocket frames + this._outputQueue = []; + // the buffer containing remaining bytes to be consumed + // invariant: the start of the buffer corresponds to the start of a websocket frame + this._buffer = []; + } + + /** + * Add a received packet. + * After this call, zero, one or more frames may be used by calling get() multiple times. + * @param {Uint8Array} data raw data taken from the streaming socket + */ + add(data) { + this._buffer.push(...data); + + // consume buffer to add new ready frames to the output queue + let frame; + while ((frame = this._consume()) !== undefined) { + this._outputQueue.push(frame); + } + } + + /** + * Return the next websocket frame. + * @returns {Uint8Array | undefined} a raw websocket frame + * or undefined if no frame is ready. + */ + get() { + return this._outputQueue.shift(); + } + + + /** + * Try to consume buffer into a websocket frame. + * @returns {Uint8Array} the websocket frame constructed, or undefined if not successful + */ + _consume() { + // check if we have a full frame header in the buffer + const headerLen = nextHeaderLength(this._buffer); + if (headerLen === 0) { + return undefined; + } + + // we have a full frame header available + // parse it to get the payload length + const payloadLen = headerPayloadLength(this._buffer.slice(0, headerLen)); + + // check if we have the payload ready in the buffer + if (this._buffer.length < (headerLen + payloadLen)) { + return undefined; + } + + // we can extract a frame from the buffer + let rawFrame = this._buffer.splice(0, headerLen + payloadLen); + + // unmask if needed + let frame = unmaskFrame(rawFrame, headerLen); + + return new Uint8Array(frame); + } + } + + /** + * Unmask websocket frame if needed. + * + * @param {Array} frame byte array + * @param {number} headerLen the length of the header in the frame + * @returns {Array} the unmasked frame + * @private + */ + function unmaskFrame(frame, headerLen) { + const pLen = frame[1] & 127; + + let maskIndex; + if (pLen < 126) { + maskIndex = 2; + } else if (pLen === 127) { + maskIndex = 4; + } else { + maskIndex = 10; + } + let maskingKey = frame.slice(maskIndex, maskIndex + 4); + + const payload = maskWithKey(frame.slice(headerLen), maskingKey); + + frame.slice(0, headerLen).push(...payload); + + return frame; + } + + /** + * Returns the payload length from a frame header. + * @param {Array} header the input header, assumed valid and no extra bytes, only contains bytes + * @returns {number} the length of the payload associated with the header + * @private + */ + function headerPayloadLength(header) { + const pLen = header[1] & 127; // 7 last bits of 2nd byte + + if (pLen < 126) { + return pLen; + } else if (pLen === 126) { + // if 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length + return (header[2] << 8) + header[3]; + } else if (pLen === 127) { + // if 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length + let len = 0; + + for (let i = 0; i < 8; i++) { + len += (header[2 + i] << (8 * (7 - i))); + } + return len; + } + } + + /** + * Try to read a header from the start of the input buffer. + * @param {Array} data input buffer, contaning only bytes + * @returns {boolean} the byte length of the header contained in the start of the input buffer if any, 0 otherwise + * @private + */ + function nextHeaderLength(data) { + // a frame header is between 2 and 12 bytes long + if (data.length < 2) { return 0; } + + const mask = (data[1] & 128) === 128; // mask is true if mask is set in header + const payloadLen = data[1] & 127; // 7 last bits of 2nd byte + + // now check all the cases... + + if (!mask && payloadLen < 126) { + // header length is 2B + return 2; + } else if (!mask && payloadLen === 126) { + // header length is (2 + 2) = 4B + if (data.length < 4) { return 0; } else { return 4; } + } else if (!mask && payloadLen === 127) { + // header length is (2 + 8) = 10B + if (data.length < 10) { return 0; } else { return 10; } + } else if (mask && payloadLen < 126) { + // header length is (2 + 4) = 6B + if (data.length < 6) { return 0; } else { return 6; } + } else if (mask && payloadLen === 126) { + // header length is (2 + 2 + 4) = 8B + if (data.length < 8) { return 0; } else { return 8; } + } else if (mask && payloadLen === 127) { + // header length is (2 + 8 + 4) = 14B + if (data.length < 14) { return 0; } else { return 14; } + } + } + + /** + * Defragments WebSocket frames + * Used when receiving websocket frames that may have been fragmented. + * + * @private + */ + class FrameDefragmenter { + + constructor() { + this._outputQueue = []; + this._parsed = undefined; + } + + + /** + * Add a received frame, that may be fragmented. + * + * @param {frame} Uint8Array packet received, unmasked + * @throws error when fed out of order frames + * @return {undefined} control frame if given packet is a control frame, undefined otherwise + */ + add(frame) { + let parsed = FrameDefragmenter._fields(frame); + + if (parsed === undefined) { + console.warn("received websocket frame could not be parsed"); + return undefined; + } + + if (isControlFrame(parsed['opcode'])) { + this._outputQueue.push(new Frame( + parsed["rsv1"] === 1, + parsed["rsv2"] === 1, + parsed["rsv3"] === 1, + parsed["opcode"], + parsed["payload data"], + )); + return; + } + + const fin = parsed["fin"]; + const opcode = parsed["opcode"]; + + if (this._parsed === undefined) { + if (fin && opcode !== opcodes.continuation) { + // unfragmented + this._outputQueue.push(new Frame( + parsed["rsv1"] === 1, + parsed["rsv2"] === 1, + parsed["rsv3"] === 1, + parsed["opcode"], + parsed["payload data"], + )); + this._parsed = undefined; + return; + } else if (!fin && opcode !== opcodes.continuation) { + // first fragmented frame + this._parsed = parsed; + return; + } else { + throw `Error: FrameBuilder was given an out of order frame`; + } + } else { + if (!fin && opcode === opcodes.continuation) { + // continuation frame + // append the payload to the current fragments' payload + this._parsed["payload data"] = concatenate(this._parsed["payload data"], parsed["payload data"]); + return; + } else if (fin && opcode === opcodes.continuation) { + // last fragmented frame + // append the payload to the current fragments' payload + this._parsed["payload data"] = concatenate(this._parsed["payload data"], parsed["payload data"]); + + this._outputQueue.push(new Frame( + this._parsed["rsv1"] === 1, + this._parsed["rsv2"] === 1, + this._parsed["rsv3"] === 1, + this._parsed["opcode"], + this._parsed["payload data"], + )); + this._parsed = undefined; + return; + } else { + throw `Error: FrameBuilder was given an out of order frame`; + } + } + } + + /** + * Return the next websocket frame. + * @returns {Uint8Array | undefined} an unfragmented websocket frame + * or undefined if no frame is ready. + */ + get() { + return this._outputQueue.shift(); + } + + /** + * Parse a websocket frame into key-value fields. + * Do not decode payload if masked. + * + * @private + * @param {Uint8Array} frame an encapsulated websocket frame, or undefined if error + * @returns dictionnary of fields and fields values of the encapsulated packet, or undefined if packet is invalid + * keys are a subset of ['fin', 'rsv1', 'rsv2', 'rsv3', 'opcode', 'mask', 'Payload Len', 'masking-key', 'payload data'] + * or undefined if the frame is bogus + */ + static _fields(frame) { + let parsed = {}; + let restLen = frame.byteLength; + if (restLen < 2) { + // bogus frame + return undefined; + } + + let byteIterator = frame.entries(); + + // first byte + const bits0 = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split('').map(c => c === "1" ? 1 : 0); + parsed["fin"] = bits0[0]; + parsed["rsv1"] = bits0[1]; + parsed["rsv2"] = bits0[2]; + parsed["rsv3"] = bits0[3]; + parsed["opcode"] = parseInt(bits0.slice(4, 8).join(''), 2); + restLen--; + + // second byte + const bits1 = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split('').map(c => c === "1" ? 1 : 0); + parsed["mask"] = bits1[0]; + parsed["payload len"] = parseInt(bits1.slice(1, 8).join(''), 2); + restLen--; + + // rest + + if (parsed["payload len"] == 126) { + // if 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length + if (restLen < 2) { + console.warn("error: received websocket frame with incorrect 'payload len'"); + return undefined; + } + let pLen = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split(''); + pLen = pLen.concat((byteIterator.next().value[1]).toString(2).padStart(8, '0').split('')); + parsed["payload len"] = parseInt(pLen.join(""), 2); + restLen -= 2; + } else if (parsed["payload len"] == 127) { + // if 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length + if (restLen < 8) { + console.warn("error: received websocket frame with incorrect 'payload len'"); + return undefined; + } + let pLenBits = []; + for (let i = 0; i < 8; i++) { + pLenBits = pLenBits.concat((byteIterator.next().value[1]).toString(2).padStart(8, '0').split('')); + } + parsed["payload len"] = parseInt(pLenBits.join(""), 2); + restLen -= 8; + } + + if (parsed["mask"]) { + // next 4 bytes is the masking key + if (restLen < 4) { + console.warn("error: received websocket frame with masking"); + return undefined; + } + let maskingKeyBits = ""; + for (let i = 0; i < 4; i++) { + maskingKeyBits += (byteIterator.next().value[1]).toString(2).padStart(8, '0'); + } + parsed["masking-key"] = parseInt(maskingKeyBits, 2); + restLen -= 4; + } + + if (restLen <= 0) { + parsed["payload data"] = new Uint8Array(0); + } else { + // parsed["payload data"] = frame.slice(-restLen); + parsed["payload data"] = frame.slice(-parsed["payload len"]); + } + + return parsed; + } + + } + + /** + * A definition of a WebSocket client. + * + * @module websocket-client + */ + + let binaryTypes = { + blob: "blob", + arraybuffer: "arraybuffer", + }; + + /** + * An abstract WebSocket client. + * + * Uses an underlying socket to be supplied by implementing classes when calling {@linkcode WebSocketClient._start_opening_handshake}. + */ + class WebSocketClient extends EventTargetClass { + // CONSTANTS + // static getters are used to implement static constants + static get CONNECTING() { return 0; } + static get OPEN() { return 1; } + static get CLOSING() { return 2; } + static get CLOSED() { return 3; } + + constructor(url, protocols = []) { + super(); + + if (protocols.length > 0) { + console.error(`websocket subprotocols are not yet supported: ${protocols}`); + } + + // url + this._url = new URL(url); + + // TODO: see https://www.w3.org/TR/websockets/#dom-websocket-bufferedamount + // need to use the underlying buffer measures as well, + // lightnion-js uses lnn.stream.tcp.cache.length + this._bufferedAmount = 0; + + this._extensions = ""; + this._protocol = ""; + this._readyState = WebSocketClient.CONNECTING; + this._binaryType = binaryTypes.blob; // defaults + + // 'private' event handlers + // these are the handlers called by the underlying socket + // each of them will call the user-defined handler (e.g. this.onmessage) after some processing + this.__onclose = (event) => { this.onclose(event); }; + this.__onerror = (event) => { this.onerror(event); }; + this.__onmessage = (event) => { this.onmessage(event); }; + this.__onopen = (event) => { this.onopen(event); }; + + // 'public' event handlers + this._onclose = () => { }; + this._onerror = () => { }; + this._onmessage = () => { }; + this._onopen = () => { }; + + + // true if the closing handshake has been initiated + this._the_websocket_closing_handshake_is_started = false; + + // for translation of stream to frames + this._streamHandler = new StreamHandler(); + + // for reception of fragmented message + this._frameDefragmenter = new FrameDefragmenter(); + + // check if duplicates in protocols + // TODO + // if (new Set(this.protocols).size != this.protocols.length) { + // throw SyntaxError(`duplicates in protocols: ${this.protocols}`); + // } + + + let origin = ""; + if (!lib_3) { + origin = new URL(window.location.href); + } else { + origin = "http://localhost/"; + } + + // parse url + let secure; + try { + secure = parseURL(this._url)[3]; + } catch (err) { + throw SyntaxError(`could not parse url: ${err}`); + } + + if (secure && origin.protocol !== "https") { + throw Error(`SecurityError: cannot open non-secure websocket from a secure origin`); + } + + // transport level socket connection + // should be set when the handshake is requested + this._socket = undefined; + } + + // PROPERTIES + + // url: read-only DOMString + get url() { + return this._url.href; + } + + // readyState: read-only unsigned short + get readyState() { + return this._readyState; + } + + // bufferedAmount: read-only unsigned long + get bufferedAmount() { + return this._bufferedAmount; + } + + // extensions: read-only DOMString + get extensions() { + return this._extensions; + } + + // protocol: read-only DOMString + get protocol() { + return this._protocol; + } + + // binaryType: DOMString + get binaryType() { return this._binaryType; } + set binaryType(binaryType) { + switch (binaryType) { + case "blob": + this._binaryType = binaryTypes.blob; + break; + case "arraybuffer": + this._binaryType = binaryTypes.arraybuffer; + break; + default: + throw new SyntaxError(`websocket binaryType cannot be set to ${binaryType}, allowed values are 'blob' and 'arraybuffer'`); + } + } + + + // EVENT HANDLERS + + /** + * Get the onopen handler. + */ + get onopen() { + return this._onopen; + } + /** + * Set the onopen handler. + */ + set onopen(onopen) { + this._onopen = onopen; + } + + /** + * Get the onmessage handler. + */ + get onmessage() { + return this._onmessage; + } + + /** + * Set the onmessage handler. + */ + set onmessage(onmessage) { + this._onmessage = onmessage; + } + + /** + * Get the onerror handler. + */ + get onerror() { + return this._onerror; + } + /** + * Set the onerror handler. + */ + set onerror(onerror) { + this._onerror = onerror; + } + + /** + * Get the onclose handler. + */ + get onclose() { + return this._onclose; + } + /** + * Set the onclose handler. + */ + set onclose(onclose) { + this._onclose = onclose; + } + + + // INTERFACE METHODS + + /** + * Send to the websocket endpoint. + * @param {string|Blob|ArrayBuffer|ArrayBufferView} data the payload to send + */ + send(data) { + // FIXME: bufferedAmount, closing handshake started + + if (!(this._socket)) { + throw `Socket not initialized`; + } + + if (this._readyState === WebSocketClient.CONNECTING) { + throw `InvalidStateError: cannot send data while websocket is in CONNECTING state`; + } + + let frame; + if (typeof data === "string") { + // convert data to a sequence of Unicode characters + const payload = naclUtil.decodeUTF8(data); + if (this._readyState === WebSocketClient.OPEN) { + frame = new Frame(false, false, false, opcodes.text, payload); + } + } else if (data instanceof Blob) { + frame = new Frame(false, false, false, opcodes.binary, data); + } else if (data instanceof ArrayBuffer) { + frame = new Frame(false, false, false, opcodes.binary, data); + } else { + // assume ArrayBufferView + // send data stored in the section of the buffer described by the ArrayBuffer object that the ArrayBufferView object references + frame = new Frame(false, false, false, opcodes.binary, data); + } + + if (frame) { + // console.debug("[WS] sending websocket message"); + // console.debug(frame); + this._socket.send(frame.encapsulate()); + } else { + // not connected or closing, ... + return; + } + } + + /** + * Close the WebSocket connection. + * @param {int} code + * @param {DOMString} reason + */ + close(code, reason) { + // check code + if (code && (code !== 1000 || (code >= 3000 && code <= 4999))) { + throw Error(`InvalidAccessError: code must be 1000 or in the range 3000-4999`); + } + + if (reason) { + const unicodeReason = naclUtil.encodeUTF8(reason); + if (unicodeReason.byteLength > 123) { + throw SyntaxError(`reason is too long: ${reason}`); + } + } + + if (this._readyState === WebSocketClient.CLOSED || this._readyState === WebSocketClient.CLOSING) { + // do nothing + return; + } else if (this._readyState !== WebSocketClient.OPEN) { + // connection not yet established + // fail the websocket connection and set the readyState attribute's value to CLOSING + this._closing(); + this._fail_the_websocket_connection(); + } else if (!this._the_websocket_closing_handshake_is_started) { + // the closing handshake has not yet been started + // start the closing handshake and set the readyState attribute's value to CLOSING + this._closing(); + this._start_the_websocket_closing_handshake(code, reason); + } else { + this._closing(); + } + } + + // CLOSING THE CONNECTION + // https://tools.ietf.org/html/rfc6455#section-7 + + /** + * Close the WebSocket Connection + * @private + */ + _close_the_websocket_connection() { + // cleanly close the TLS & TCP connection + if (this._socket) { + this._socket.close(); + } + this._readyState = WebSocketClient.CLOSED; + this._closed(true); + } + + /** + * Start the WebSocket Closing Handshake + * @param {int} code status code for closing the connection + * @param {reason} string reason for closing the connection + * @private + */ + _start_the_websocket_closing_handshake(code, reason = undefined) { + if (!(this._socket)) { + throw `Socket not initialized`; + } + + this._the_websocket_closing_handshake_is_started = true; + this._socket.send(closeFrame(code, reason)); + + // wait for the close control frame from the endpoint + // and _close_the_websocket_connection + // this is done in the onmessage callback + } + + /** + * Fail the WebSocket Connection. + * @private + */ + _fail_the_websocket_connection() { + this._close_the_websocket_connection(); + } + + // TASKS + + /** + * Task to run when "the WebSocket connection is established" + * @private + */ + _established() { + // 1. change the readyState attribute's value to OPEN + this._readyState = WebSocketClient.OPEN; + + // 2. TODO: change the extensions attribute's value to the extensions in use, if is not the null value + // this._extensions = + + // 3. TODO: change the protocol attribute's value to the subprotocol in use, if is not the null value + // this._protocol = + + // 4. TODO: act as if the user agent had received a set-cookie-string consisting of the cookies + // set during the server's opening handshake, for the URL url given to the WebSocket() constructor + // document.cookie = + + // 5. fire a simple event named open at the WebSocket object + this.dispatchEvent(new Event("open")); + } + + /** + * Task to run when "a WebSocket message has been received" + * @private + */ + _received(event) { + + // 1. If the readyState attribute's value is not OPEN (1), then abort these steps + if (this._readyState !== WebSocketClient.OPEN) { + return; + } + + // 2. let event be an event that uses the MessageEvent interface, + // with the event type message, which does not bubble, is not cancelable, + // and has no default action. + // 3. initialize event's origin attribute to the Unicode serialization of the origin of the URL + // that was passed to the WebSocket object's constructor. + // 4. - if type indicates that the data is Text, then initialize event's data attribute to data + // - if type indicates that the data is Binary, and binaryType is set to "blob", + // then initialize event's data attribute to a new Blob object that represents data as its raw data + // - if type indicates that the data is Binary, and binaryType is set to "arraybuffer", + // then initialize event's data attribute to a new read-only ArrayBuffer object whose contents are data + + // 2+3+4 already done before + + let e = new MessageEventClass("message", { + origin: this._url.href, + data: event.data, + }); + + // 5. dispatch event at the WebSocket object. + this.dispatchEvent(e); + } + + /** + * Task to run when "the WebSocket closing handshake is started" + * @private + */ + _closing() { + // change the readyState attribute to CLOSING (2) + this._readyState = WebSocketClient.CLOSING; + } + + + /** + * Task to run when "the WebSocket connection is closed" + * @private + */ + _closed(wasClean, code = 1005, reason = "") { + // 1. change the readyState attribute's value to CLOSED (3) + this._readyState = WebSocketClient.CLOSED; + + // 2. if the user agent was required to fail the WebSocket connection + // or the WebSocket connection is closed with prejudice, + // fire a simple event named error at the WebSocket object + + // TODO + + // 3. Create an event that uses the CloseEvent interface, + // with the event type close, which does not bubble, is not cancelable, has no default action, + // whose wasClean attribute is initialized to true if the connection closed cleanly and false otherwise, + // whose code attribute is initialized to the WebSocket connection close code, + // and whose reason attribute is initialized to the WebSocket connection close reason decoded as UTF-8, + // with error handling, and dispatch the event at the WebSocket object + + const event = new CloseEventClass("close", { + wasClean: wasClean, + code: code, + reason: reason, + }); + + this.dispatchEvent(event); + } + + // Handshake helper methods + + /** + * Perform the opening websocket handshake. + * Non-blocking, as needed when calling the method in the constructor. + * + * This method should be called by the constructor of the derived class, + * setting the socket specific to this derived class. + * + * @param socket underlying socket + */ + _start_opening_handshake(socket) { + // TODO: check interface + this._socket = socket; + + // parse url + let host, port, ressourceName, secure; + try { + [host, port, ressourceName, secure] = parseURL(this._url); + } catch (err) { + throw SyntaxError(`could not parse url: ${err}`); + } + + // perform handshake + this.__do_opening_handhake(host, port, ressourceName, secure).then(() => { + this._established(); + this._socket.onmessage = onOpenMessage(this); + this.__onopen(); + }).catch(() => { + this._readyState = WebSocketClient.CLOSED; + this._fail_the_websocket_connection(); + }); + } + + + /** + * Perform the WebSocket connection handshake. + * + * @returns Promise that resolves when connection was successfully established, + * or rejects otherwise with an error message. + * @private + */ + __do_opening_handhake(host, port, ressourceName, secure) { + if (secure) { + console.error("secure websocket not yet supported"); + } + + return new Promise((resolve, reject) => { + if (!(this._socket)) { + reject(`Socket not initialized`); + } + + let statusLine = ""; + let headerLines = []; + + const [clientHS, secWebSocketKey] = clientHandshake(host, port, ressourceName); + + // change onmessage of underlying socket + this._socket.onmessage = (pkt) => { // TODO: refactor to avoid request ? + let payload = naclUtil.encodeUTF8(pkt); + + // parse received packet as a HTTP websocket connection response + let lines = payload.split("\r\n"); + if (lines.length < 1) { + reject(`failed to connect to websocket: received empty http response`); + } + + if (statusLine) { + // following message (response was fragmented) + headerLines = headerLines.concat(lines); + } else { + // first message + statusLine = lines[0].split(" "); + headerLines = headerLines.concat(lines.slice(1)); + + // status code verification + if (statusLine.length < 3) { + reject(`failed to connect to websocket: invalid status line ${statusLine.join(" ")}`); + return; + } + + const statusCode = statusLine[1]; + + if (statusCode != "101") { + reject(`failed to connect to websocket: got status code ${statusCode}`); + return; + } + } + + if (headerLines[headerLines.length - 1] !== "") { + return; + } else { + // last line of headers, no body expected + // this means that this is the last packet expected + let headers = parseHeaders(headerLines.join("\r\n")); + + // verification of the headers + + // check for the upgrade header field + if (!("upgrade" in headers) || !(headers["upgrade"].toLowerCase().split(", ").includes("websocket"))) { + reject(`failed to connect to websoket: server handshake response invalid, does not contain 'upgrade: websocket' header line: ${headers}`); + return; + } + + // check for the connection header field + if (!("connection" in headers) || !(headers["connection"].toLowerCase().split(", ").includes("upgrade"))) { + reject(`failed to connect to websocket: server handshake response invalid, does not contain 'connection: upgrade' header line: ${headers}`); + return; + } + + // check for the sec-websocket-accept header field + if (!("sec-websocket-accept" in headers)) { + reject(`failed to connect to websocket: server handshake response invalid, does not contain 'sec-websocket-accept' header line: ${headers}`); + return; + } + + if (!verifySecWebSocketAccept(secWebSocketKey, headers["sec-websocket-accept"].trim())) { + reject(`failed to connect to websocket: 'sec-websocket-accept' could not be verified`); + return; + } + + // check for the sec-websocket-extensions header field + if ("sec-websocket-extensions" in headers) { + const serverExtensions = headers["sec-websocket-extensions"].split(", "); + // TODO: no support for extensions + if (serverExtensions.length > 1 || serverExtensions[0] !== "") { + reject(`failed to connect to websocket: extensions are not supported: ${headers["sec-websocket-extensions"]}`); + return; + } + } + + // check for the sec-websocket-protocol header field + if ("sec-websocket-protocol" in headers) { + const serverSubProtocols = headers["sec-websocket-protocol"].split(", "); + // TODO: no support for subprotocols + if (serverSubProtocols.length > 1 || serverSubProtocols[0] !== "") { + reject(`failed to connect to websocket: sub protocols are not supported: ${headers["sec-websocket-protocol"]}`); + return; + } + } + + resolve(); + } + }; + this._socket.send(naclUtil.decodeUTF8(clientHS)); + }); + + } + + } + + /** + * Helpers for the lightnion js-client code. + */ + + /** + * A Lightnion tunelled TCP socket. + * @private + */ + class LTCP { + // TODO: onclose + constructor(host) { + this.connected = false; + // TODO: document + // onmessage takes a UInt8Array argument + this.onmessage = (msg) => { console.error(`LTCP received non-handled message: ${msg}`); }; + this.host = host; + } + + send() { + throw "LTPC: undefined send method"; + } + } + + /** + * Connect to a Lightnion Proxy. + * @param {string} lnnHost host of the lightnion proxy + * @param {Number} lnnPort port of the lightnion proxy + * @returns a promise that resolves on connection success, and rejects in case of a failure; + * in case of success, return the lightnion endpoint, in case of failure, an error message + * @private + */ + function lnnOpen(lnnHost, lnnPort) { + return new Promise((resolve, reject) => { + lnn$2.open(lnnHost, lnnPort, function (endpoint) { + if (endpoint.state != lnn$2.state.success) { + console.error("lightnion proxy connection failed"); + reject(`could not connect to lightnion proxy at ${lnnHost}:${lnnPort}`); + } + console.debug("lightnion proxy connection established"); + resolve(endpoint); + }); + }); + } + + // Connect to TCP endpoint + // return a promise that resolves on connection success, and rejects in case of failure + // in case of succes, return a TCP object, in case of failure, an error message + /** + * Connect to a TCP endpoint through a Lightnion proxy. + * + * @param lnnEndpoint the lightnion proxy endpoint object, returned by {@link lnnOpen} + * @param host host of the TCP endpoint + * @param port port of the TCP endpoint + * @private + */ + function ltcpOpen(lnnEndpoint, host, port) { + + return new Promise((resolve, reject) => { + + let ltcp = new LTCP(host); + + function handler(socket) { + + let pkt; + + switch (socket.state) { + case lnn$2.state.created: + ltcp.connected = true; + ltcp.send = socket.send; + resolve(ltcp); + break; + case lnn$2.state.pending: + pkt = socket.recv(); + if (pkt !== undefined) { + ltcp.onmessage(pkt); + } + break; + case lnn$2.state.success: + ltcp.connected = false; + reject(`could not connect to TCP host at ${host}:${port}`); + break; + } + } + lnn$2.stream.tcp(lnnEndpoint, host, port, handler); + }); + } + + // TLS support. + // Uses forge.tls module. + // TODO: tests. + // export function ltlsOpen(lnnEndpoint, host, port) { + + // return ltcpOpen(lnnEndpoint, host, port).then(ltcp => { + // console.debug("tcp socket connected") + // return new Promise((resolve, reject) => { + // let tlsSocket = new LTCP(host); + + // // create tls client working on tcp + // let tlsClient = forge.tls.createConnection({ + // // see: https://github.com/digitalbazaar/forge#tls + // server: false, + // verify: function (connection, verified, depth, certs) { + // // FIXME + // return true; // skip cert. verif. (testing) + // }, + // connected: function (connection) { + // // (tls handshake finished, now ready to send) + // tlsSocket.onmessage = (req) => { tlsClient.process(lnn.enc.bin(req.recv())); }; + // tlsSocket.send = tlsClient.send; + // resolve(tlsSocket); + // }, + // tlsDataReady: function (connection) { + // // TLS -> TCP + // // (decode binary data into array before processing) + // ltcp.send(lnn.dec.bin(connection.tlsData.getBytes())); + // }, + // dataReady: function (connection) { + // // TLS -> Application + // // (receive decrypted data from the tls transport) + // var data = connection.data.getBytes(); + // onReceive(data); + // }, + // closed: function (connection) { + // console.info("tls connection closed"); + // }, + // error: function (connection, err) { + // console.error(`tls connection error: ${err}`); + // } + // }); + // console.debug("initiating tls handshake"); + // tlsClient.handshake(); + // }); + // }); + // } + + /** + * @module lightnion-websocket + */ + // import { ltlsOpen } from "./lightnion-helpers.js"; // TODO: TLS support + + /** + * LightnionWebSocket is a WebSocket client tunnelled through Lightnion. + */ + class LightnionWebSocket extends WebSocketClient { + + /** + * Create a LightnionWebSocket, a WebSocket tunelled through Tor via a Lightnion proxy. + * + * @param {string} url the WebSocket server URL + * @param {array} protocols a list of subprotocols to use, currently not-supported + * @param {string} lightnionHost the lightnion proxy host + * @param {Number} lightnionPort the lightnion proxy port + */ + constructor(url, protocols = [], lightnionHost = "localhost", lightnionPort = 4990) { + let urlP = new URL(url); + + let port = urlP.port; + if (!port) { + port = urlP.protocol == "ws:" ? "80" : "443"; + } + + super(urlP, protocols); + + // user defined event handlers + this.onmessage = () => { }; + this.onopen = () => { }; + this.onclose = () => { }; + this.onerror = () => { }; + + // schedule the tcp handshake to start when the underlying socket is ready + lnnOpen(lightnionHost, lightnionPort).then(lnnEndpoint => { + // open tcp socket to host, through lightnion + return ltcpOpen(lnnEndpoint, urlP.hostname, port); + // or open a tls socket + // return ltlsOpen(lnnEndpoint, urlP.hostname, port); + }).then(ltcp => { + console.debug("[LTCP]: connected"); + + // start websocket handshake protocol + this._start_opening_handshake(ltcp); + + // install handlers + this.__onmessage = (event) => { + this.onmessage(event); + }; + this.__onopen = (event) => { + this.onopen(event); + }; + this.__onclose = (event) => { + this.onclose(event); + }; + this.__onerror = (event) => { + this.onerror(event); + }; + + }); + } + } + + /* + * Exprots for Lightnion WebSocket Client. + * To use as a library. + */ + + /** + * @module lnn + */ + + if (!lib_3) { + // saving WebSocket default + // when using lightnion with redirected WebSockets, + // the client must still create a WebSocket to the lightnion proxy + // hence we save the standard WebSocket as _WebSocket + window._WebSocket = WebSocket; + } + + // header + let lnn$2 = lnn$1; + + // api + lnn$2.fast = fast; + lnn$2.auth = auth; + lnn$2.open = open; + lnn$2.agents = agents; + lnn$2.send_req = send_req; + lnn$2.http_request = http_request; + + // consensus parser + lnn$2.consensusParser = consensusParser; + + // endpoint + lnn$2.endpoint = endpoint; + + // get + lnn$2.get = {}; + lnn$2.get.guard = guard; + lnn$2.get.consensus = consensus; + lnn$2.get.descriptors = descriptors; + lnn$2.get.consensus_raw = consensus_raw; + lnn$2.get.descriptors_raw = descriptors_raw; + lnn$2.get.signing_keys = signing_keys; + + // io + lnn$2.io = {}; + lnn$2.io.polling = polling; + lnn$2.io.socket = socket; + + // ntor + lnn$2.ntor = ntor; + + // onion + lnn$2.onion = {}; + lnn$2.onion.ctr = ctr; + lnn$2.onion.sha = sha; + lnn$2.onion.forward = forward; + lnn$2.onion.backward = backward; + lnn$2.onion.build = build; + lnn$2.onion.peel = peel; + + // parser + lnn$2.parser = parser; + + // path + lnn$2.path = path; + + // post + lnn$2.post = {}; + lnn$2.post.create = create; + lnn$2.post.circuit_info = circuit_info; + lnn$2.post.handshake = handshake; + lnn$2.post.channel = channel; + lnn$2.post.extend = extend; + lnn$2.post.close = close; + + // relay + lnn$2.relay = relay; + + // signature + lnn$2.signature = {}; + lnn$2.signature.verify = verify; + lnn$2.signature.get_hash = get_hash; + lnn$2.signature.verify_key = verify_key; + lnn$2.signature.get_sig_and_keys_digests = get_sig_and_keys_digests; + lnn$2.signature.get_signature_big_int = get_signature_big_int; + lnn$2.signature.get_hash_from_rsa_cipher = get_hash_from_rsa_cipher; + + // stream + lnn$2.stream = stream; + + // utils + lnn$2.enc = {}; + lnn$2.enc.bits = enc.bits; + lnn$2.enc.utf8 = enc.utf8; + lnn$2.enc.base64 = enc.base64; + lnn$2.enc.bin = enc.bin; + + lnn$2.dec = {}; + lnn$2.dec.bits = dec.bits; + lnn$2.dec.utf8 = dec.utf8; + lnn$2.dec.base64 = dec.base64; + lnn$2.dec.bin = dec.bin; + + // websocket + lnn$2.websocket = LightnionWebSocket; + + window.lnn = lnn$2; + + exports.lnn = lnn$2; + + return exports; + +}({})); +//# sourceMappingURL=lightnion.bundle.js.map diff --git a/js-client/integration-tests/lightnion-websocket/requirements.txt b/js-client/integration-tests/lightnion-websocket/requirements.txt new file mode 100644 index 0000000..00b8ac7 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/requirements.txt @@ -0,0 +1,4 @@ +selenium +aiohttp +pytest +psutil diff --git a/js-client/integration-tests/lightnion-websocket/run_integration_tests.py b/js-client/integration-tests/lightnion-websocket/run_integration_tests.py new file mode 100644 index 0000000..7b883df --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/run_integration_tests.py @@ -0,0 +1,22 @@ + +import logging +import signal +import unittest + +from tests.test_normal_behavior import NormalBehaviorTest + +if __name__ == "__main__": + def sigint_handler(signal, frame): + NormalBehaviorTest.close() + raise KeyboardInterrupt + + logging.basicConfig(level=logging.INFO) + signal.signal(signal.SIGINT, sigint_handler) + + suite = unittest.TestSuite() + suite.addTest(NormalBehaviorTest("test_webpage_get")) + suite.addTest(NormalBehaviorTest("test_echo_message")) + suite.addTest(NormalBehaviorTest("test_using_redirection")) + + runner = unittest.TextTestRunner() + runner.run(suite) diff --git a/js-client/integration-tests/lightnion-websocket/tests/lightion_websocket_test.py b/js-client/integration-tests/lightnion-websocket/tests/lightion_websocket_test.py new file mode 100644 index 0000000..7c702fc --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/tests/lightion_websocket_test.py @@ -0,0 +1,185 @@ +import logging +import threading +import unittest +import subprocess +import sys +import time +import os +import re +import psutil + +from signal import SIGKILL +from abc import ABC, abstractclassmethod +from pathlib import Path + +from selenium import webdriver +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.firefox.options import Options +from selenium.webdriver.support.wait import WebDriverWait + +from common.endpoint import Endpoint +from .utils import ReceivedMessage, WebSocketStatus, received_messages, sent_messages +from config import * + +""" +Integration tests for lightnion javascript websocket redirection. +""" + + +class LightnionWebSocketTest(ABC, unittest.TestCase): + """Abstract base class for tests of lightnion's websocket redirection. + + Instanciates: + - an endpoint (http+websocket) + - a Tor test network (chutney) + - a ligthnion proxy + """ + tor_pids = [] + + @abstractclassmethod + def endpoint_cls(self): + """Returns the class of the endpoint.""" + raise NotImplementedError + + @classmethod + def setUpClass(cls, http_port: int = HTTP_PORT, ws_port: int = WS_PORT, profile = None): + + # instanciate endpoint server + cls.endpoint = cls.endpoint_cls()(HOST, http_port, ws_port) + cls.endpoint_thread = threading.Thread( + target=cls.endpoint.start, name="endpoint-thread", daemon=True + ) + + if not os.path.exists(LOG_DIRECTORY): + os.mkdir(LOG_DIRECTORY) + cls.chutney_stdout = os.open("logs/chutney_stdout.log", os.O_WRONLY | os.O_CREAT) + cls.chutney_stderr = os.open("logs/chutney_stderr.log", os.O_WRONLY | os.O_CREAT) + cls.lightnion_stdout = os.open("logs/lightnion_stdout.log", os.O_WRONLY | os.O_CREAT) + cls.lightnion_stderr = os.open("logs/lightnion_stderrr.log", os.O_WRONLY | os.O_CREAT) + + # start external programs + # TODO + try: + cls.start_chutney() + time.sleep(30) + cls.start_lightnion() + cls.start_endpoint() + time.sleep(30) + except RuntimeError: + logging.error("could not set up test infrastructure") + cls.close() + sys.exit(1) + + # instanciate driver + options = Options() + options.headless = True + if profile is None: + cls.driver = webdriver.Firefox(options=options) + else: + cls.driver = webdriver.Firefox(options=options, firefox_profile=profile) + cls.driver.implicitly_wait(BROWSER_WAIT) + + @classmethod + def close(cls): + cls.stop_endpoint() + cls.stop_lightnion() + cls.stop_chutney() + try: + cls.driver.close() + except AttributeError: + pass + + @classmethod + def tearDownClass(cls): + cls.close() + + @classmethod + def start_chutney(cls): + """Start test Tor network.""" + logging.info("starting chutney") + p = subprocess.run([CHUTNEY, "configure", CHUTNEY_NET], stdout=cls.chutney_stdout, stderr=cls.chutney_stderr) + if p.returncode != 0: + logging.error("could not configure chutney test network") + raise RuntimeError + + p = subprocess.run([CHUTNEY, "start", CHUTNEY_NET], stdout=cls.chutney_stdout, stderr=cls.chutney_stderr) + if p.returncode != 0: + logging.error("could not start chutney test network") + raise RuntimeError + time.sleep(2) + + try: + output = subprocess.check_output([CHUTNEY, "status", CHUTNEY_NET]) + # find pids of tor test nodes from output of status command + pids_str = re.findall(r"PID\s+\d+", str(output)) + cls.tor_pids = [int(s[4:]) for s in pids_str] + + for line in str(output).split("\\n"): + logging.info(f"\t{line}") + except subprocess.CalledProcessError: + logging.error("could not status chutney test network") + raise RuntimeError + + @classmethod + def stop_chutney(cls): + """Stop test Tor network.""" + logging.info("stopping chutney") + p = subprocess.run([CHUTNEY, "stop", CHUTNEY_NET], stdout=cls.chutney_stdout, stderr=cls.chutney_stderr) + if p.returncode != 0: + logging.error("could not stop chutney test network") + + @classmethod + def start_lightnion(cls): + """Start lightnion proxy.""" + logging.info("starting lightnion") + cwd = Path.cwd() / Path(LIGHTNION_CWD) + cls.__lightnion_process = subprocess.Popen(LIGHTNION.split(' '), cwd=cwd, shell=False, stdout=cls.lightnion_stdout, stderr=cls.lightnion_stderr) + + @classmethod + def stop_lightnion(cls): + """Stop lightnion proxy.""" + logging.info("stopping lightnion") + try: + cls.__lightnion_process.kill() + except AttributeError: + # lightnion process was not initialized + pass + + @classmethod + def start_endpoint(cls): + """Start http/websocket endpoint.""" + logging.info("starting endpoint") + cls.endpoint_thread.start() + + @classmethod + def stop_endpoint(cls): + """Start http/websocket endpoint""" + logging.info("stopping endpoint") + # no need to kill thread since daemon + pass + + def driver_connections(self): + """Return the set of remote ports the driver is connected to.""" + browser_connections = psutil.Process( + self.driver.service.process.pid + ).connections() + browser_rports = [c.raddr.port for c in browser_connections if c.raddr] + return browser_rports + + def setUp(self): + pass + + def tearDown(self): + pass + + def wait_for_websocket(self): + wait = WebDriverWait(self.driver, WEBSOCKET_CONNECTING_WAIT) + state = wait.until(WebSocketStatus("window.ws")) + + if not state: + # could not connect, still in CONNECTING state + self.fail( + f"websocket could not connect, still in CONNECTING state after {WEBSOCKET_CONNECTING_WAIT} seconds" + ) + return state + diff --git a/js-client/integration-tests/lightnion-websocket/tests/test_missing_websocket_server.py b/js-client/integration-tests/lightnion-websocket/tests/test_missing_websocket_server.py new file mode 100644 index 0000000..7caf3ba --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/tests/test_missing_websocket_server.py @@ -0,0 +1,58 @@ +import threading +import unittest +import signal +import logging +import psutil + +from selenium import webdriver +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.firefox.options import Options +from selenium.webdriver.support.wait import WebDriverWait + +from common.endpoint import Endpoint +from .config import * +from .lightion_websocket_test import LightnionWebSocketTest +from .utils import ReceivedMessage, WebSocketStatus, received_messages, sent_messages + + +class NonExistingWebSocketServerTest(LightnionWebSocketTest): + """Test cases when the client connects to a non existing websocket server.""" + + @classmethod + def endpoint_cls(cls): + return Endpoint + + @classmethod + def setUpClass(cls): + super().setUpClass( + HTTP_PORT, WS_PORT + 1 + ) # setup ws server on a different port + cls.demo_url = f"http://{HOST}:{HTTP_PORT}/{DEMO_PATH}" + + def setUp(self): + super().setUp() + + def tearDown(self): + super().tearDown() + + def test_webpage_get(self): + """Test that the webpage is available and that the websocket connection does not establishes.""" + self.driver.get(self.demo_url) + self.assertIn("lightnion websocket redirect echo demo", self.driver.title) + + # wait for a state change + state = self.wait_for_websocket() + self.assertEqual(state, 3, "websocket expected to be closed") + + # TODO: verify no direct connection trial + + +def sigint_handler(signal, frame): + NonExistingWebSocketServerTest.close() + raise KeyboardInterrupt + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + signal.signal(signal.SIGINT, sigint_handler) + unittest.main() diff --git a/js-client/integration-tests/lightnion-websocket/tests/test_normal_behavior.py b/js-client/integration-tests/lightnion-websocket/tests/test_normal_behavior.py new file mode 100755 index 0000000..7cf7868 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/tests/test_normal_behavior.py @@ -0,0 +1,149 @@ +import threading +import unittest +import signal +import logging +import psutil +import time + +from selenium import webdriver +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.firefox.options import Options +from selenium.webdriver.support.wait import WebDriverWait + +from common.endpoint import Endpoint +from config import * +from .lightion_websocket_test import LightnionWebSocketTest +from .utils import ReceivedMessage, WebSocketStatus, received_messages, sent_messages + +class NormalBehaviorTest(LightnionWebSocketTest): + """Test cases for normal operations.""" + + @classmethod + def endpoint_cls(cls): + return Endpoint + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.demo_url = f"http://{HOST}:{HTTP_PORT}/{DEMO_PATH}" + cls.ws_url = f"ws://{HOST}:{WS_PORT}/ws" + + def setUp(self): + super().setUp() + + def tearDown(self): + super().tearDown() + + def wait_for_websocket(self): + wait = WebDriverWait(self.driver, WEBSOCKET_CONNECTING_WAIT) + state = wait.until(WebSocketStatus("window.ws")) + + if not state: + # could not connect, still in CONNECTING state + self.fail( + f"websocket could not connect, still in CONNECTING state after {WEBSOCKET_CONNECTING_WAIT} seconds" + ) + return state + + def expect_message(self, expected_message): + """Wait for a message to be received by the websocket, fail if not received.""" + wait = WebDriverWait(self.driver, WEBSOCKET_RESPONSE_WAIT) + received = wait.until(ReceivedMessage(expected_message)) + + self.assertTrue( + received, + f"did not receive expeceted message from server: {expected_message}", + ) + + def send(self, msg: str) -> None: + """Send a message via the user interface.""" + self.driver.find_element_by_id("echo-input").clear() + self.driver.find_element_by_id("echo-input").send_keys(msg) + self.driver.find_element_by_id("echo-button").click() + + @property + def sent_messages(self): + """Return the list of client messages.""" + return sent_messages(self.driver) + + @property + def received_messages(self): + return received_messages(self.driver) + + def test_webpage_get(self): + """Test that the webpage is available and that the websocket connection establishes to the correct endpoint.""" + self.driver.get(self.demo_url) + self.assertIn("lightnion websocket redirect echo demo", self.driver.title) + + # wait for a state change + state = self.wait_for_websocket() + self.assertEqual(state, 1, "could not connect to websocket") + + # get url of the websocket endpoint + ws_url = self.driver.execute_script("return window.ws.url;") + self.assertEqual( + ws_url, + self.ws_url, + f"websocket is not connected to the correct endpoint: expected {self.ws_url}, got: {ws_url}", + ) + + def test_echo_message(self): + """Test that a message sent is echoed back, + hence it is really sent and well received.""" + self.driver.get(self.demo_url) + + # wait for a state change + state = self.wait_for_websocket() + self.assertEqual(state, 1, "could not connect to websocket") + + # send message and expect response + time.sleep(5) + message = "test message" + self.send(message) + self.expect_message(message) + + def test_using_redirection(self): + """Test that the websocket connection is redirected. + + For that, list the ESTABLISHED TCP connections of the browser (webdriver) process, + and check that remote addresses do not match with the websocket server's. + """ + self.driver.get(self.demo_url) + + # wait for a state change + state = self.wait_for_websocket() + self.assertEqual(state, 1, "could not connect to websocket") + + # list remote ports connected to the browser + for c in self.driver_connections(): + self.assertTrue( + c != WS_PORT, + "browser is connected to the websocket directly, not redirected", + ) + + # check that all connections to the websocket are from Tor nodes + + tor_ports = set() # ports used by the tor processes + for pid in self.tor_pids: + p = psutil.Process(pid) + for c in p.connections(): + if c.laddr: + tor_ports.add(c.laddr.port) + + for peer in self.endpoint.ws_connected_peers: + port = peer[1] + self.assertTrue( + port in tor_ports, + "found a peer connected to the websocket that is not a tor process", + ) + + +def sigint_handler(signal, frame): + NonExistingWebSocketServerTest.close() + raise KeyboardInterrupt + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + signal.signal(signal.SIGINT, sigint_handler) + unittest.main() diff --git a/js-client/integration-tests/lightnion-websocket/tests/utils.py b/js-client/integration-tests/lightnion-websocket/tests/utils.py new file mode 100755 index 0000000..8b7b203 --- /dev/null +++ b/js-client/integration-tests/lightnion-websocket/tests/utils.py @@ -0,0 +1,47 @@ +"""Some utilities for integration tests.""" + + +def messages_with_class_name(driver, cname): + messages = driver.find_element_by_id( + "messages").find_elements_by_class_name(cname) + return [m.text for m in messages] + + +def sent_messages(driver): + return messages_with_class_name(driver, "client") + + +def received_messages(driver): + return messages_with_class_name(driver, "server") + + +class WebSocketStatus: + """An expectation for checking that a websocket is in a OPEN, CLOSING or CLOSED state. + + Used to wait on a websocket to be connected (or failed). + + see https://selenium-python.OPENreadthedocs.io/waits.html + """ + + def __init__(self, websocket_name): + self.ws_name = websocket_name + + def __call__(self, driver): + try: + state = driver.execute_script( + f"return {self.ws_name}.readyState;") + if state >= 1: + return state + else: + return False + except: + return False + +class ReceivedMessage: + """An expectation for checking that a websocket received a specific message.""" + + def __init__(self, expected_message): + self.msg = expected_message + + def __call__(self, driver): + return self.msg in received_messages(driver) diff --git a/js-client/src/lightnion-websocket/README.md b/js-client/src/lightnion-websocket/README.md index 6e71c2e..162cdfd 100644 --- a/js-client/src/lightnion-websocket/README.md +++ b/js-client/src/lightnion-websocket/README.md @@ -51,7 +51,7 @@ The library is split in different folders under `src/lightnion-websocket/`: ### Integration Tests -TODO +See [here](../../integration-tests/lightnion-websocket/README.md) ### WebSocketClient socket interface From 42a2e1b2d4d0f1fc136be661ed0f2eb558c3b5c5 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Wed, 19 Feb 2020 14:02:32 +0100 Subject: [PATCH 07/30] Add first doc draft. --- docs/Makefile | 19 + docs/make.bat | 35 + docs/source/_build/html/.buildinfo | 4 + .../_build/html/.doctrees/environment.pickle | Bin 0 -> 404954 bytes .../_build/html/.doctrees/index.doctree | Bin 0 -> 6932 bytes .../_build/html/.doctrees/install.doctree | Bin 0 -> 2231 bytes .../html/.doctrees/lightnion.cell.doctree | Bin 0 -> 274731 bytes .../.doctrees/lightnion.cell.relay.doctree | Bin 0 -> 60351 bytes .../html/.doctrees/lightnion.crypto.doctree | Bin 0 -> 26947 bytes .../_build/html/.doctrees/lightnion.doctree | Bin 0 -> 379837 bytes .../html/.doctrees/lightnion.http.doctree | Bin 0 -> 53206 bytes .../html/.doctrees/lightnion.proxy.doctree | Bin 0 -> 137797 bytes .../html/.doctrees/lightnion.tests.doctree | Bin 0 -> 37174 bytes .../_build/html/.doctrees/modules.doctree | Bin 0 -> 2550 bytes docs/source/_build/html/.nojekyll | 0 docs/source/_build/html/_modules/index.html | 237 + .../_build/html/_modules/lightnion/cache.html | 298 + .../_build/html/_modules/lightnion/cell.html | 276 + .../html/_modules/lightnion/cell/address.html | 244 + .../html/_modules/lightnion/cell/certs.html | 231 + .../_modules/lightnion/cell/challenge.html | 238 + .../html/_modules/lightnion/cell/common.html | 205 + .../html/_modules/lightnion/cell/create2.html | 223 + .../_modules/lightnion/cell/create_fast.html | 222 + .../_modules/lightnion/cell/created2.html | 211 + .../_modules/lightnion/cell/created_fast.html | 221 + .../html/_modules/lightnion/cell/destroy.html | 226 + .../html/_modules/lightnion/cell/netinfo.html | 253 + .../html/_modules/lightnion/cell/padding.html | 210 + .../html/_modules/lightnion/cell/relay.html | 336 + .../lightnion/cell/relay/extend2.html | 307 + .../lightnion/cell/relay/extended2.html | 201 + .../_modules/lightnion/cell/relay_early.html | 226 + .../_modules/lightnion/cell/versions.html | 257 + .../html/_modules/lightnion/cell/view.html | 1076 ++ .../html/_modules/lightnion/consensus.html | 1092 ++ .../html/_modules/lightnion/constants.html | 207 + .../html/_modules/lightnion/create.html | 467 + .../html/_modules/lightnion/crypto/kdf.html | 209 + .../html/_modules/lightnion/crypto/ntor.html | 356 + .../html/_modules/lightnion/descriptors.html | 855 ++ .../html/_modules/lightnion/extend.html | 231 + .../_build/html/_modules/lightnion/hop.html | 415 + .../_build/html/_modules/lightnion/http.html | 296 + .../html/_modules/lightnion/http/ntor.html | 213 + .../html/_modules/lightnion/http/polling.html | 303 + .../_modules/lightnion/http/websocket.html | 317 + .../_build/html/_modules/lightnion/link.html | 407 + .../_build/html/_modules/lightnion/onion.html | 457 + .../_modules/lightnion/path_selection.html | 686 + .../html/_modules/lightnion/proxy/auth.html | 273 + .../_modules/lightnion/proxy/forward.html | 594 + .../html/_modules/lightnion/proxy/jobs.html | 665 + .../html/_modules/lightnion/proxy/link.html | 593 + .../html/_modules/lightnion/proxy/parts.html | 230 + .../html/_modules/lightnion/proxy/path.html | 452 + .../_modules/lightnion/proxy/relayinfo.html | 207 + .../html/_modules/lightnion/signature.html | 347 + .../html/_modules/lightnion/socket.html | 398 + .../lightnion/tests/path_selection_test.html | 250 + .../tests/test_consensus_chutney.html | 213 + .../lightnion/tests/test_create_chutney.html | 223 + .../tests/test_descriptors_chutney.html | 226 + .../lightnion/tests/test_extend_chutney.html | 255 + .../lightnion/tests/test_hop_chutney.html | 206 + .../lightnion/tests/test_link_chutney.html | 197 + .../tests/test_path_selection_chutney.html | 203 + .../_build/html/_modules/lightnion/utils.html | 416 + .../source/_build/html/_sources/index.rst.txt | 29 + .../_build/html/_sources/install.rst.txt | 2 + .../_sources/lightnion.cell.relay.rst.txt | 30 + .../html/_sources/lightnion.cell.rst.txt | 133 + .../html/_sources/lightnion.crypto.rst.txt | 30 + .../html/_sources/lightnion.http.rst.txt | 38 + .../html/_sources/lightnion.proxy.rst.txt | 70 + .../_build/html/_sources/lightnion.rst.txt | 129 + .../html/_sources/lightnion.tests.rst.txt | 78 + .../_build/html/_sources/modules.rst.txt | 7 + .../_build/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes docs/source/_build/html/_static/basic.css | 676 + .../_build/html/_static/comment-bright.png | Bin 0 -> 756 bytes .../_build/html/_static/comment-close.png | Bin 0 -> 829 bytes docs/source/_build/html/_static/comment.png | Bin 0 -> 641 bytes .../_build/html/_static/css/badge_only.css | 1 + docs/source/_build/html/_static/css/theme.css | 4 + docs/source/_build/html/_static/doctools.js | 315 + .../html/_static/documentation_options.js | 10 + .../_build/html/_static/down-pressed.png | Bin 0 -> 222 bytes docs/source/_build/html/_static/down.png | Bin 0 -> 202 bytes docs/source/_build/html/_static/file.png | Bin 0 -> 286 bytes .../_build/html/_static/fonts/Lato-Bold.ttf | Bin 0 -> 683116 bytes .../_build/html/_static/fonts/Lato-Bold.woff2 | Bin 0 -> 208512 bytes .../html/_static/fonts/Lato-BoldItalic.ttf | Bin 0 -> 714640 bytes .../html/_static/fonts/Lato-BoldItalic.woff2 | Bin 0 -> 221928 bytes .../_build/html/_static/fonts/Lato-Italic.ttf | Bin 0 -> 693228 bytes .../html/_static/fonts/Lato-Italic.woff2 | Bin 0 -> 219592 bytes .../html/_static/fonts/Lato-Regular.ttf | Bin 0 -> 661592 bytes .../html/_static/fonts/Lato-Regular.woff2 | Bin 0 -> 203936 bytes .../html/_static/fonts/RobotoSlab-Bold.ttf | Bin 0 -> 170616 bytes .../html/_static/fonts/RobotoSlab-Bold.woff2 | Bin 0 -> 67536 bytes .../html/_static/fonts/RobotoSlab-Regular.ttf | Bin 0 -> 169064 bytes .../_static/fonts/RobotoSlab-Regular.woff2 | Bin 0 -> 66512 bytes .../_static/fonts/fontawesome-webfont.eot | Bin 0 -> 165742 bytes .../_static/fonts/fontawesome-webfont.svg | 2671 ++++ .../_static/fonts/fontawesome-webfont.ttf | Bin 0 -> 165548 bytes .../_static/fonts/fontawesome-webfont.woff | Bin 0 -> 98024 bytes .../_static/fonts/fontawesome-webfont.woff2 | Bin 0 -> 77160 bytes docs/source/_build/html/_static/jquery.js | 10365 ++++++++++++++++ .../_build/html/_static/js/modernizr.min.js | 1 + docs/source/_build/html/_static/js/theme.js | 241 + .../_build/html/_static/language_data.js | 297 + docs/source/_build/html/_static/minus.png | Bin 0 -> 90 bytes docs/source/_build/html/_static/plus.png | Bin 0 -> 90 bytes docs/source/_build/html/_static/pygments.css | 69 + .../source/_build/html/_static/searchtools.js | 481 + docs/source/_build/html/_static/underscore.js | 1692 +++ .../source/_build/html/_static/up-pressed.png | Bin 0 -> 214 bytes docs/source/_build/html/_static/up.png | Bin 0 -> 203 bytes docs/source/_build/html/_static/websupport.js | 808 ++ docs/source/_build/html/genindex.html | 1594 +++ docs/source/_build/html/index.html | 224 + docs/source/_build/html/install.html | 192 + docs/source/_build/html/lightnion.cell.html | 1183 ++ .../_build/html/lightnion.cell.relay.html | 407 + docs/source/_build/html/lightnion.crypto.html | 288 + docs/source/_build/html/lightnion.html | 1916 +++ docs/source/_build/html/lightnion.http.html | 384 + docs/source/_build/html/lightnion.proxy.html | 675 + docs/source/_build/html/lightnion.tests.html | 320 + docs/source/_build/html/modules.html | 277 + docs/source/_build/html/objects.inv | Bin 0 -> 4100 bytes docs/source/_build/html/py-modindex.html | 480 + docs/source/_build/html/search.html | 206 + docs/source/_build/html/searchindex.js | 1 + docs/source/conf.py | 187 + docs/source/deploy.rst | 87 + docs/source/index.rst | 31 + docs/source/lightnion-fail.service | 6 + docs/source/lightnion-nginx-tls.conf | 62 + docs/source/lightnion.cell.relay.rst | 30 + docs/source/lightnion.cell.rst | 133 + docs/source/lightnion.crypto.rst | 30 + docs/source/lightnion.http.rst | 38 + docs/source/lightnion.proxy.rst | 70 + docs/source/lightnion.rst | 129 + docs/source/lightnion.service | 16 + docs/source/lightnion.tests.rst | 78 + docs/source/modules.rst | 7 + 148 files changed, 45443 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/source/_build/html/.buildinfo create mode 100644 docs/source/_build/html/.doctrees/environment.pickle create mode 100644 docs/source/_build/html/.doctrees/index.doctree create mode 100644 docs/source/_build/html/.doctrees/install.doctree create mode 100644 docs/source/_build/html/.doctrees/lightnion.cell.doctree create mode 100644 docs/source/_build/html/.doctrees/lightnion.cell.relay.doctree create mode 100644 docs/source/_build/html/.doctrees/lightnion.crypto.doctree create mode 100644 docs/source/_build/html/.doctrees/lightnion.doctree create mode 100644 docs/source/_build/html/.doctrees/lightnion.http.doctree create mode 100644 docs/source/_build/html/.doctrees/lightnion.proxy.doctree create mode 100644 docs/source/_build/html/.doctrees/lightnion.tests.doctree create mode 100644 docs/source/_build/html/.doctrees/modules.doctree create mode 100644 docs/source/_build/html/.nojekyll create mode 100644 docs/source/_build/html/_modules/index.html create mode 100644 docs/source/_build/html/_modules/lightnion/cache.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/address.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/certs.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/challenge.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/common.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/create2.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/create_fast.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/created2.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/created_fast.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/destroy.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/netinfo.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/padding.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/relay.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/relay/extend2.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/relay/extended2.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/relay_early.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/versions.html create mode 100644 docs/source/_build/html/_modules/lightnion/cell/view.html create mode 100644 docs/source/_build/html/_modules/lightnion/consensus.html create mode 100644 docs/source/_build/html/_modules/lightnion/constants.html create mode 100644 docs/source/_build/html/_modules/lightnion/create.html create mode 100644 docs/source/_build/html/_modules/lightnion/crypto/kdf.html create mode 100644 docs/source/_build/html/_modules/lightnion/crypto/ntor.html create mode 100644 docs/source/_build/html/_modules/lightnion/descriptors.html create mode 100644 docs/source/_build/html/_modules/lightnion/extend.html create mode 100644 docs/source/_build/html/_modules/lightnion/hop.html create mode 100644 docs/source/_build/html/_modules/lightnion/http.html create mode 100644 docs/source/_build/html/_modules/lightnion/http/ntor.html create mode 100644 docs/source/_build/html/_modules/lightnion/http/polling.html create mode 100644 docs/source/_build/html/_modules/lightnion/http/websocket.html create mode 100644 docs/source/_build/html/_modules/lightnion/link.html create mode 100644 docs/source/_build/html/_modules/lightnion/onion.html create mode 100644 docs/source/_build/html/_modules/lightnion/path_selection.html create mode 100644 docs/source/_build/html/_modules/lightnion/proxy/auth.html create mode 100644 docs/source/_build/html/_modules/lightnion/proxy/forward.html create mode 100644 docs/source/_build/html/_modules/lightnion/proxy/jobs.html create mode 100644 docs/source/_build/html/_modules/lightnion/proxy/link.html create mode 100644 docs/source/_build/html/_modules/lightnion/proxy/parts.html create mode 100644 docs/source/_build/html/_modules/lightnion/proxy/path.html create mode 100644 docs/source/_build/html/_modules/lightnion/proxy/relayinfo.html create mode 100644 docs/source/_build/html/_modules/lightnion/signature.html create mode 100644 docs/source/_build/html/_modules/lightnion/socket.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/path_selection_test.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/test_consensus_chutney.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/test_create_chutney.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/test_descriptors_chutney.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/test_extend_chutney.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/test_hop_chutney.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/test_link_chutney.html create mode 100644 docs/source/_build/html/_modules/lightnion/tests/test_path_selection_chutney.html create mode 100644 docs/source/_build/html/_modules/lightnion/utils.html create mode 100644 docs/source/_build/html/_sources/index.rst.txt create mode 100644 docs/source/_build/html/_sources/install.rst.txt create mode 100644 docs/source/_build/html/_sources/lightnion.cell.relay.rst.txt create mode 100644 docs/source/_build/html/_sources/lightnion.cell.rst.txt create mode 100644 docs/source/_build/html/_sources/lightnion.crypto.rst.txt create mode 100644 docs/source/_build/html/_sources/lightnion.http.rst.txt create mode 100644 docs/source/_build/html/_sources/lightnion.proxy.rst.txt create mode 100644 docs/source/_build/html/_sources/lightnion.rst.txt create mode 100644 docs/source/_build/html/_sources/lightnion.tests.rst.txt create mode 100644 docs/source/_build/html/_sources/modules.rst.txt create mode 100644 docs/source/_build/html/_static/ajax-loader.gif create mode 100644 docs/source/_build/html/_static/basic.css create mode 100644 docs/source/_build/html/_static/comment-bright.png create mode 100644 docs/source/_build/html/_static/comment-close.png create mode 100644 docs/source/_build/html/_static/comment.png create mode 100644 docs/source/_build/html/_static/css/badge_only.css create mode 100644 docs/source/_build/html/_static/css/theme.css create mode 100644 docs/source/_build/html/_static/doctools.js create mode 100644 docs/source/_build/html/_static/documentation_options.js create mode 100644 docs/source/_build/html/_static/down-pressed.png create mode 100644 docs/source/_build/html/_static/down.png create mode 100644 docs/source/_build/html/_static/file.png create mode 100644 docs/source/_build/html/_static/fonts/Lato-Bold.ttf create mode 100644 docs/source/_build/html/_static/fonts/Lato-Bold.woff2 create mode 100644 docs/source/_build/html/_static/fonts/Lato-BoldItalic.ttf create mode 100644 docs/source/_build/html/_static/fonts/Lato-BoldItalic.woff2 create mode 100644 docs/source/_build/html/_static/fonts/Lato-Italic.ttf create mode 100644 docs/source/_build/html/_static/fonts/Lato-Italic.woff2 create mode 100644 docs/source/_build/html/_static/fonts/Lato-Regular.ttf create mode 100644 docs/source/_build/html/_static/fonts/Lato-Regular.woff2 create mode 100644 docs/source/_build/html/_static/fonts/RobotoSlab-Bold.ttf create mode 100644 docs/source/_build/html/_static/fonts/RobotoSlab-Bold.woff2 create mode 100644 docs/source/_build/html/_static/fonts/RobotoSlab-Regular.ttf create mode 100644 docs/source/_build/html/_static/fonts/RobotoSlab-Regular.woff2 create mode 100644 docs/source/_build/html/_static/fonts/fontawesome-webfont.eot create mode 100644 docs/source/_build/html/_static/fonts/fontawesome-webfont.svg create mode 100644 docs/source/_build/html/_static/fonts/fontawesome-webfont.ttf create mode 100644 docs/source/_build/html/_static/fonts/fontawesome-webfont.woff create mode 100644 docs/source/_build/html/_static/fonts/fontawesome-webfont.woff2 create mode 100644 docs/source/_build/html/_static/jquery.js create mode 100644 docs/source/_build/html/_static/js/modernizr.min.js create mode 100644 docs/source/_build/html/_static/js/theme.js create mode 100644 docs/source/_build/html/_static/language_data.js create mode 100644 docs/source/_build/html/_static/minus.png create mode 100644 docs/source/_build/html/_static/plus.png create mode 100644 docs/source/_build/html/_static/pygments.css create mode 100644 docs/source/_build/html/_static/searchtools.js create mode 100644 docs/source/_build/html/_static/underscore.js create mode 100644 docs/source/_build/html/_static/up-pressed.png create mode 100644 docs/source/_build/html/_static/up.png create mode 100644 docs/source/_build/html/_static/websupport.js create mode 100644 docs/source/_build/html/genindex.html create mode 100644 docs/source/_build/html/index.html create mode 100644 docs/source/_build/html/install.html create mode 100644 docs/source/_build/html/lightnion.cell.html create mode 100644 docs/source/_build/html/lightnion.cell.relay.html create mode 100644 docs/source/_build/html/lightnion.crypto.html create mode 100644 docs/source/_build/html/lightnion.html create mode 100644 docs/source/_build/html/lightnion.http.html create mode 100644 docs/source/_build/html/lightnion.proxy.html create mode 100644 docs/source/_build/html/lightnion.tests.html create mode 100644 docs/source/_build/html/modules.html create mode 100644 docs/source/_build/html/objects.inv create mode 100644 docs/source/_build/html/py-modindex.html create mode 100644 docs/source/_build/html/search.html create mode 100644 docs/source/_build/html/searchindex.js create mode 100644 docs/source/conf.py create mode 100644 docs/source/deploy.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/lightnion-fail.service create mode 100644 docs/source/lightnion-nginx-tls.conf create mode 100644 docs/source/lightnion.cell.relay.rst create mode 100644 docs/source/lightnion.cell.rst create mode 100644 docs/source/lightnion.crypto.rst create mode 100644 docs/source/lightnion.http.rst create mode 100644 docs/source/lightnion.proxy.rst create mode 100644 docs/source/lightnion.rst create mode 100644 docs/source/lightnion.service create mode 100644 docs/source/lightnion.tests.rst create mode 100644 docs/source/modules.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..69fe55e --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..543c6b1 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/source/_build/html/.buildinfo b/docs/source/_build/html/.buildinfo new file mode 100644 index 0000000..4bf79d7 --- /dev/null +++ b/docs/source/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: aee8bc56d238abbb697652f22fed45c2 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/source/_build/html/.doctrees/environment.pickle b/docs/source/_build/html/.doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..e6e9dd1cef4d5b748f471a57c87bf1021b6c5df2 GIT binary patch literal 404954 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 z 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 CjU^ZW literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/.doctrees/install.doctree b/docs/source/_build/html/.doctrees/install.doctree new file mode 100644 index 0000000000000000000000000000000000000000..900ce592a105e8876f54673dfd74027645db4e09 GIT binary patch literal 2231 zcmZuy%WfMt6!l9lTb3WGyJ&2rMG>?yAj?3z2>Jm93IkfD*%bseq(s6Ta!PV6d10Vk z6i5K>%Kk+^vWGLHu_aU+4G-^&hv#1Yaq!Q-{hjI;M$BZTm&)B}!?=r~pMaceAODW; z{)|uY`!KL{=}c)e9>WeSG9eYST*u#{*aBXy>U? zv~p?84nFWz%D1)qSFG|Q-g)R26d8RKr(##^hi+5PG#n_Yd7PFr8V;%VR?bR~bELZW zC3C1T^fE=A1BmaArg{CWz(9Fbc{&%?m7!>NEtg@3A~=mZeo#9eb0JM0MIlx(@2H zk1?Fjjq%!e{$lfPHykHv=`ts)xv_Z!GIF@#f@CI75_Jgqx<8}X41-k+gVN8(@5fH!`*L%WaBGbvf@-F?1<$F}%*SwIO1~MUQ$>m4 zYHMdJg!mXnb$t;V@36%qzewZ8PGja4$R-Jd4kQqhlB<%3D@V;Gw7dr5%2op3Tnzp+gNS+#1-j!KZh@?YA}wtO~V+XO&l?(_y_~PU83tw-J|w& zMFhrOHS!|Hu1WG9x}2h!elO9x4xX>7b-g6YWVB)MDiaiKg8Qv|3OAO94}tf6S)iEo z4pomu)9arh5|c?i$5pSJ|2&NYSI#!=PI*4#4E^|sT!M3tXcw6>^q%mXN<}EcV^z)n zPhp?yhxAy4emw@zcTkbkOhVV5cxo3MV+Hg042hr$kH-<*u=F%MVNh+L_45H3(dO-< zo79h&2Y4@m^|!bcV;2Sq@Q($^dWzz9>ckuTkHwJ-$1ks{@;=Ta#!yO+h&7VhX>C`R z`4Xw^P&_UypBdHOer5W_7T8)3HX;tzSu3aWjrbUg)~7jqu^p?~*$I6#duukrtBoGP fi|a5)>VR!eZ@@<_TwTc_OJk<#$n^A;vzz|_sb_n- literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/.doctrees/lightnion.cell.doctree b/docs/source/_build/html/.doctrees/lightnion.cell.doctree new file mode 100644 index 0000000000000000000000000000000000000000..269b37cb0eda3b831d2313101554721230edba1c GIT binary patch literal 274731 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�E#my=I7e8_f}UQRw22?j1F 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 L9%+b2cCPzB6-2<^ literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/.doctrees/lightnion.cell.relay.doctree b/docs/source/_build/html/.doctrees/lightnion.cell.relay.doctree new file mode 100644 index 0000000000000000000000000000000000000000..39108bfcb43743cb5252938d2e12ff88ea4205a9 GIT binary patch literal 60351 zcmdsA4Uim1b=J?_=}yw!NwQ_^lZ4NfjZU(3Cya4yVI0fS`6o7KW6Q?2EY@?ob2ro4 z+g(}pn{a*J>_x*hjKlQ^^^j|oVD`u;KpRY_7iaEDZ z4+k+}!7T*!hw8h3tA1a7A{;6^Co9EjIqTNLRgfd=`T1PgE!2^f-Ld)vJnRqrAnz)V!tHr~-U|v)U^46G^OI#a?<|d%oa}LD-mPOfDAsqxT|@@j zV6t2R=C|LlraJ4bXM*Q~^hWu8xc=7a>_RbD%>#>6 zR$H|sDUkiZ*CgX>#@mjq_jW*&y>mgn=fU4j_`4APc0qHz-Lx4OvFzR+;G$nG5U#Jt zS{+{8NL7dpNttkBW|JnAHtiHbQpEuZ;1+ThkF(bD#>UDkrEooPa&0mx99E<-Se*?= zD<#h_EKWMPTx22rej(>BDmu;7y{UY|b)XGppDNV^D5hVS2a^adY}xDy*6!W)a3{Ok z*D8D68<+{|4))~j(B!BMVY!t;3VKs$hf~xJry{9OmX;2n!UEfc`SIf1xX5hjqRFUG z=7jH_L=|2QD*QICvPp#FWy4EUV&fCkFvtBuO9ntlyAv?@DiRggrFUD{2f&+c(5DG_ zGJ;Ps6(7JR08ml#gcVg#6Q1kj+%oNfH_sFc?%we^f6>iB(Ra8a!OiC~h+0uX&Iz1` zd+fvLIaE+~GIKr@tI(v~)C!TWQOcK7C=>(7!2WQ6^%=KVek+Y~05tT0ct#lxEiU8_ zRA6)fgBdK9-HKa2;Znr%pidD9bhRz8}HmB(zXY@w{cxDApE+;ZNB5l|7J z+Y_Z0I?ZfNaHDdv$>fAfsPTa=rDxS)lnnXK3K)6VMJ+yIxnI?EHSMzVJG zs#OUpb(?w`T%(@0SzBMRkY7@?IvSX73pbX)(SmV4vk3leV}@1XfM1|Kw6x8r?ACDb zD069#)%7Orv@|IkMv-SB%m81eaJ=pqPAEAK3VCDXwU)AK)^Hv087!4>NZ=If5Tv+s zx#EK37wX~KN|39E8z9A9Eam;IAJk9L41rUgcLVUfGLaK4U2%&S1i=81@N;$Vy+F%_=B(j~ce@;90`+%u(J?!&>g*+|z8d{K#X3SkzIyn$7w+EMzpB?tk`4};r z3I`$&*&Zu#=M36H$7S#o!@;>~KF`9JkK;J;PEeO6hUapeVB=c0SO7O%h2^O0SA|0e zmGfn%yhU=m-Qio&`=)+MI4~?*x zXvhvo5Lmf0ZcP}f=6x7voV>y?nM3Lrb#4vEnlmd|gZ7UR0)sbFx5%x78S8|1A5REJOfqz$=6A$%?yg5B!EbeR|8&%a z-nMpg3w%TZZ=F0TN`*mh0#mcC)CGROXlonaI}$;gT)JfbL9{WhWWY&RBt!ll2~a-& zobySZ#xw>|X7}l}zmT|g@XM{Wle2*oXMkyu2D?$x`3<=MMw|HrFGFV2=*d1vY~~33 zhoyju5)vWFWsp^a#{-zKd>#Pp105Iz8jg_{+cC<9d~zM;188Fdz9M+0EE3$v6OdC3 z`_WxA@{^n3*(q`}{I(hL$t{q_8z8sBf3yJzbTHVHPhdJ7QKi0-+aOWz@d@j}J8qN_Dg{Exb-d1D0wMybEoRb|$of(ihfk+(^gM=~I zp9`f;y`3NdR1kNl-)5m;S7h#`X}Y`{iW|C29)Rk}2s|L~#w&yf@*uJltAV73`EhtB zr{G5!*-slZQ+EQ@Af7uxE{Cj<6EcdI)T7W9cJyFj9JLT!KAfbQ;(D8uJbNRz`SyX$QDWXOsmXlPYBKBOKK&5#UPhSa80H;5xF;vqIt zvTf!pBKaWlhA|KM5MB)lo2-*Rg#_|Pz!`ZIuGBb(SzF}3Hz%%eW%C)D7c{wwf-uI> zM{OKomI1=3eu1dQ0sfiyYHvb)ZPSwg{<#b%nI zB8}!lZ&oxzGGrNg89fh9xwBUp1#Qgju5TJ(Kf6-M{`lcH33-)RV%RB8Sy;>vSEym31P zaYc3t`2rF!aOH7Gleog}QsYWfmE_p+glLLnszYqCkxGFrKLF0Ug)K*Jyft&=(9M}k zI`&VJV2h}2`LIPHX=0212(d+`=-9HVk2$*BM{4ets{YC^gvOj6Y>};DQyy{_s#{J) z6!>+Eyxu9Ji8}?cMRp1qK>`N0yrN+XyIXE-k^RE4<>x|EBvTz?i;YwYY`Ym?}@h0(GWT%ijk${0M zS3{cgTi9K)z4a#%D)GSwlr*hr zdasS6WnHhrInem;37RvD`g?*Rh(e+|s`2%zp05NkRwyL2SR^}FV|`-Jad=z1vUhyX zp5yTT>3oHMek2{1Sj%RQ2~AI8w2z8Xr&Cy6eOK`*(Zsld!DTZk81f_%pq(nG`Q%y| z>vJ~UXQb*L+vgMWfkT~@k5BOz*uqVw_C$lR{K#g2<>2o*@LQd?7l1c&$w6H(;Ep|f z!$ZD8^D3Y5406rob;tz0mhUF6r8$yuj^G;*tBks_%J>Tl|1DP;e{LzDinW(-c0LEZ zG+kx^zn3r@CZxZgs-uB_HY!z-be=)J*DlyJ>LExpGhn=Icr5 zTt$sa^(6*(C@S>J==dI1>n|~Ms!d$19)03q^3u-7f)DB0J5o#}%jIM(M*0(fDhy{` z0#T}0FVE_&kD}DBdRgxgZA{{2Ny(50k$~Z4jhO9VsAwkZNceDKPSDS?at48y{48Ogr^C7B^qVs(msx{$C1sguR zqr)*z^C}LKZ^sl5Uv9u#C4Gm)4Ym{+^|()RB1!HUgzy8>(n1%-+r*;Q^a<#U4yG>$({TM6<3a`Ixh=N~y0Pf%vnoHZ^Mw zOD$(zhX*ZDDs!&45ym07R+9Kc7&FpQwvTTNR{;YW1J;-kV#|;fgT3|q9V@m6oVt_$ z=v(N~1mn@Jq2h>whIBDVknJEK!1FQu4|=Hm`Y{hfUn5G;F!Y=hVW@S7KPC9w)*|>c zLQct5=p_z0Ga0|&2boN~h!ZC%mL zE^ds1QQUQ+R8Q4HkJ`3chh6SJHhC&6l}2bsMLXiQ9wRi_dU6*MFe0=e(es=aB}K2_ zPh3C7W!CyvZd~@8AOv&FS4V8_C*#t^Nt!o(Ty`pDoqGHgFE0B)nmWw@ELL3hSo#`e z0H)O_lXZoDGEI$^=qsw!@y`ql z(WF@*+R-vDlhN35;Gt!V z<7}f%@QN>Joe_6+!BZr(1s2XIk9b=7#@j`mjMPNQS;`lk+?!{2?c(pS$WL(kqw1I% zM|V2>Umr<{SKj=kZw~J0M@@@TVWC&S4VRtqhR6m*0?cca6W)!_wuV}oE{nUNRi^c- zw#Oxa?$jMI^Wsn_rA6L`g2NVcV< zH;ju{0Yy13vb$vCBB5wXw^e^1vKMWuel=W2L!<2R#%)!?dUs zNUw#ODHKh330H={CiI5Y(jJX*PT_e`DxB>$8e_{S0?RevCi4Z6^VH<2j=bL$Er{E0 zoK2AJCNClZeKvu771P+zM|(uC^2dp*#DULNWjCOF?fS-{s3nxIvJ~hslv9B>MekpN zyju;fp&h-Yz#Gu}pMj!8Z+4dqz4>>Os3{z}zby1ZDpmWarkf{XOhVVHGva!9llDZ6 z%aJ;>l2`{u=vMS5i`pd%cz(@7!LGR0fM*(tTLYdw@PGw8*t;y?iPga7A6NDWU1`jN zogOphxec;LG0#PKNn;*;<+I_Oi>SvN(nar*wWG3N0hdzJhQ!YESKKXbo@~7cLOrhOuxxgkSmfV~AH zNRa6|B%B2jRRfInvknLeTSTcILV|1pi}qKPhj5{gSQ1E(awZob0Rs|-Ax%O8yIT%O zkdo$*Fe=!WjC2SIHc}}d;RfKWOJ2eh8)Xk4JaRB*Y+weNY)?Kpq9dskKrmubGB9Ah zWSDydYLagGj_A_38i|&FOq2>2x45PmT(xlO| zyN-?C)F^K6cL~lV4;|XOjZ_MIe?M^6WqZHnrkj_`-htFI**m4w#NPQc81A{fW0G#~ zkBcsitBh#x9}}f|Y45Z_E6?7a5yFZqVzhTDV)9ueVA%UdAWhmkyIU4}MaU32jH`!e>OT>s!hFw$cG{ekXXyhQlZH)b=~BX^9|;(i{v+rBY3b~)V@o%*i5vQl zMJG!ZIy7_}sT7937bMapLw|i_D0du*Z|n9CWfT*o#8R01rbb%E@V-%Hn>+M+qHgzB zC)P@|`zuAMu-H4hkHoj~O#iJyTyen_O8Va)4v?jr0KJ}j!nN&v$*xYN$@VY z=+OFYq*7S_N#LwY)_<{TMzEbovq4;&>VI9cTzsgf`g?H-``>KZKM*qjU|8dvBY=^r zL%{Ee9*(P>2mz-=sj$>z2!K|vJPi1tkXKwOBL+w*lShz%fdLOdn#2Hh*D(fIw2Onl zgMxXon*Oxi;bFr10y=~90<&0 z9SOcJx;d_nA`-kHN`?3K7zt2}D-Q}@76OYaW`qJMX7W8GU_in1kS3vk-E|BFHVxxg z@KwRRA(}&}_1Wg?W%_RVODbPS!mlf3WrfrGNv)ixb2Q-yn(x)W-k?Myd`3 z1<}KC6%;)KB1-izMi9+fd5*z-LSAvDjE;enGI=KwFkrxiGzkOju45RmXcq^8dBMD7 zqeBp|kxBsq9|6v~1Oicv5b0dpMS*rP0wM6!+pHzih4^aO4YrF!TI zh!#+bP(HI>rcZmK@8gzNrFuA9s5EWm`34^s5{oNmj18om$;Xg@fe613X%Z3GUB`%E)iMqV4+-`qBOOA5 zjZ_Lqcpfw%pvfj(9HVj(CO^UI?4 zjMQ?dJ*Q+*d-YMI_ED0q_8HNmN$~!tDAhBy=M6%YQ{et~;6$oDyGyV3QDt21?-0!; z3wW7A?QNt|sQrV$P8ZdFu2@ds>a;}rh}1Huy`a>n_Sz$+_B=^f`wxm9O``UHC`$E8 z?K$@*+CK!GNVR8osnwoW#?}5|(OmKuc$q@&ZKP7D{TG0p)@t9JIJAx&Sq;q@Bere7 znin*;S=9D4{Hm3sW!ckk7d_Ir?eWU6L(w_bcbC~2zS?_=Nj5gTo>m|EeHlNucN|_^ z+&hlvP3;{oyV>G=!GDK~o6+9AxPL$X?bs$JGi1YZ_9 z8rP6<6Tz26sW98+mmQh((R7rctnInVKNAebZ5D=MvRUM(NPyNVPdYfX44oLglP0&@ zT`!69*HhIb9d-vdwcZbqZ$yQg?e@{U%Gm{ChfSEnvh3}6RvOxUsLq^!cB6BCK^p33 z+0BI4*X*&*!NqAfSiOf=23I=WtJ2UN5?0RXD=B(CGimA>U=YG9;kSAXcPFl)IoNYe z#I2ldX4Q@TKTlZrZ@K?x#Zth&jUu@WM!ayS?9Szi3yxo?lLMHr0TSHBQr^${LH!hc z9ysNBH>ihkPc`@-0Gg)zf0o)YXy5-+3Y?*z>?ZPUs7^XQ>@Jz(!}tG0#<{2S9Yjld z{*(mH4ySW$q$L0C_Chm{xqbo!*y!jii(9dW?omRIkZQkUvi&GmNx^XIllT|+N-D4F zqo1CGu1GdPg!A=(CrX8Wmpu(B$8PM_{58>#xE={QTC(}%Uyy*|2d!6m#&8Z|HYG`i z_ZJg$fIg9x1L+g3v{QM10zyzHKukd4;}&{Q|4s8M9#q5WyL?C3Ie*d3Wh&suvqNQd z!LQz&uFg(Qe;Q3wXGf<$?MPpvJmx79EMr6_>vFv)O^uc_o}x-EPxN{(Ph4;F0gUS# z`bjoZ>xQ3ntA+oTe$vgB0=@Q=UIJrm>L&#C=#<`#L zEL=x^l7MrIpVa-+pWX!mQwL*xd-RTpG zkSH64#+sKj!l&Q0bX~H|(BEUBVAoFTX6O$?al?@(4?wfXJKzD^3>~{L)#*8iF;5e&s zb_U;J(n@^-)aN2W@!I8ziYaIg@aRiDD@t|!?O(ISkxMHbH|Md;ijYG_uH{+A04Im8%D>!0g7^TWOvC%M?x``o&mLPiyR<73xuNq zQg(S~XF%CVHTT2J#R>fks9nHf<1_+=pd@EN*@pl4ENSZ{Z?tlxPHafR6Jg6ExWm!t zfNpW_xXVF|Kaxk1w>;k*P7#;2hTDY?pdPV~?t?S$)`j{g`6lsLvq`Gh<1$~QSm;9y zd1G+MIh|;t$Cj^Y1v}vYGxxf;2g|MwN3zv&*)0T_D19c}$W!uu!L84PgB3Rj{K9;t z9&XMRv(>=QS0?Amu$=7{a&XAn?M}YxR_YJcBcEqvCLEe~3vSs7ie)H21k>QKQsXR? z;AR7>CIhsO!|nR$wpz}^-EdIM(pTZ|DOA@Fe3h5#;g-2#F(?!RS9y5D>TtN?W&=2* zA+rdJj0<&08G)H&zm&-q7Z#vs1xRjVDQ@1SDVdXg;AN;I2P{L4Q33SqXu`&_TPl`= zOx``==Ib}C3Dd=~?TH%@c!~UE*Tb&1bBe1ev09io}T&RMSp`h$! zU3|ZL+(NdPgIx7+s2a@eyKG;@hwJV7!;D)l7t0yXDdh5Q8RU$tW?>R_ zv{(&vD*coSOs^VG3=)KZeS{;7uH>QrwjkD)%aAf17JvV&`gkspUaeBj@Vy>3BGW|sRl(@ z(Bnzr8aUQ69L`l2N*SSeAXu8=o5zMkT(08=;q3`GLSrgm0#4u;3qW)@%9fe)^U%0s z^>C!*mNGc+4W^W3ii9b%4pfc09gcfJP^ui5nmTzBqJ^cvD;6e;<@u?cdtwT5R;KFV zRxE)Ou|y_t7eLAZNOcg>_g%RE5)jKsc`j>IgDJ9_?Yx?xSOhEe-C&MZ;{^+OsA4E^ zX2Aqr`66og#>#>N_H=I*%(nt1&!G40Hj^)Aok)T^vYrE$0{zR(3VICj zCj+IAS4+Um2w+d(2Ou71?x#RWidnxf2VKqWe+wc)r8=wU+vG0H;!ISq1a)~XEJU0N zw`Sq6)8iQz)-CcGCzmU`6aZ@BTDNeb4hyT{AVUH$JDgvzt z01!boId`s7zYnlVOD#AH&}v8qYIEXd0JT3y)7N1lyPhD2ar`<6Ki)y_O7finxchhb z@d7U(Phj*#e~zw!EBf;kUeOrnmW#}O@1P_y7Ke&fHp+C5>G@(DZ zV*E_2daer;HPSY{@|x7g#O?w z>V*E_tGe{e7BWko0YP17tRQNS2_!<>@jiA(LsKjdor9DH1T%!W6 zQQ_98U~5#UH7d{=6=sbJvPOkiqXMi^;nk?%YE)=7DzF+AR*ed(Muk+P0;*Br)Tm%; zR46qnkQx<6jS8Yhg;1+{=iXPJVCuQSyVARe>E>bbEmTpMhKd&Xgdfn)!VYoP56vh% z9DdS!*zZ@s)v5#i-Q;o9{W0%ww1m3%t>OYA_Kvn-9q57Y}E2{c)LiIl> zRR0%vMOFV=q56;F6;=HJjex5DHE0A>^Kel8c=8HDFY% zMa;goqLES4LKl@>hDO$^PRtOiPPtM>E(OX_oz#BuYEb5S%ye-RT4uVqCnYmo+?kGW4Xbn)XfX1e%M3Nu~&5P+F3z8TF-7he`-ri<^-G1J8rUS_&Dhe@@ThRfA(SRLdj z?heD^G#$=yIAtm5i12(2;MEkC4~BXe>K0~;c`>MZEY*%&FSKs&5_o}MyuYYd(#dEE{(~ESRQEP&&+GrzvYp`?JfU^WVU9WzpBgp$WOMn>QS{_1A2l-YpE*BjC+C8y2NSIzlA9G zPl8}@{@;QBcj5otAjLl|NO*^A?%x9}W|AHFk(M2`th;Aw6TlWMKQyo`NyP+B zCk%r$D=t;H3zAArWZyQH>L16*KRO)M?@v%Y-`?V@t%e_jyX)m@RcXOY5LUh2gxpGz z?#WL+hna5%LV$`8!XVs%*z=Q4GK-SV(;a?7UY&I{>-e*qai>f(^*BgWIP(krgw4R& zkh--2uC6!s&XW)Vy>O=xZ5K?V1nbw)uoOp4lE&*GjZbLl8-{Mb!tYja3Pqt>g&=ee z2hwlpkH-HG?a&$jF+L4LSm~PkBJQlvol+}+5s0Dei8g#qQC@_xEY-`g*9^+F(?XW1 z=c?#g4#OxeXRIZkmAuk&uZvd1XEFcJ=M!EOK*3 z8OS58aZ^qs@WtT}_*EAI#{>d!Vc-u$rWU{q(oh zt-N*;nsu)M^RMJ-_!}+~r=zg8mq1ckl*jl|!wajhNu^!**X{;~_-qggA8r|<`mXW$ zr=?51&`HztS6MXq^5ww0QbBA3BO6}ol(Sy&FM;!)XL}_Z@j0Lu?=?uDG^`F{B5%7I z)yqNH;Zv=++Tn|+@pc=vpc2HLtD-?%Zti$7+(1eBZyNz53^Za7bPcK<{}nzfz*ai^ zXjVal3cmqlzup(wX`s;T@M%A;*F={;v2!AW0?#_J*f@3{m&%*-neBk$lB;}H`D1=# z78!CEKwH=?_$fZW-LBPSVDt(p+s|OoJ*gg6*`zV3L}8qaE=|C5h%b;#?=;H|KOqhL zruUW+qMa|C7o(lO7;P~GoEMd4g?6g@RuXKLf1Isdcj!=3QT=ad*Tz>}ASt4)1<=KE zErA6q5Ey9=W+eu8JV@nnb|)HSXQs%fg>3V~jXko)duJubyrg`AU+i{*ew^LvfRSvP z5JkoNq#Uvhbng;Fcz-pGY?1B*3rRMK8%ePiQcaeTLH{i=-j#AQ>|CW;eZxQDU#0*- zv9-OGkfrVblifg6*)B(^h=@7Mr6h&Kj1_8^m7m@t@mZ~hg3EK59jUFFMe}51MHPFJ zI4~DRGP)B)T@k`T@s+?7e!&h^>>r?U8=;<+@zz=B#aYE}Pn*+3vqZ$DgI%L{#Nlid zjo`Fj6x|&|g^1xaWF@Zs8yWM-m|#2e)hziZa;_nmXL^Xp|L7RuqWMi68J=369l zy8~uwmyVbdcnulu5UjybvuNcb)T@jeG@lkwil+-jgv*k^?x>lDqZNabL+c8UWYnCX zU(Tezt1X{&qecHYUBMS63e|F4)-mg6%*~tJW9n$F*KH$O!alxiq-2m>>97M48~cpu zHTgNDknjtJ=o!UQY4cSnP0}j{xx6GH227B|evJT#Q1r`Y+-aHv$=a{FD%Y?)p%!UW zUIV0lc2)Bfp&a{4&bEl=oXA@H$bJ!^Obnq)DvV$YxObHu!LK9Q7wXEEaMPb<%lN}y z#SfW4gbwTlsuz1JmPKq8m6{(vl6xH z>t))-;&bFh-!zS`%*H3RI^;TyVBa;9mDj4_^nrcb^qQcRmJ4!P%pLFwc6v$+XkMBr zX0c>km~XmZi9HctLe2fh{RooK|D1G zD~Ca}Jnb@wZ(9lv-hIpzs25%KYAy8;ucJ7v(t1Wccinv3$miN+1V8|Rh#pV(xupGA9*|Com;i2 zatTM>AN2~w9t#VYtAcs5278lt^=`Lr!DZGW8dtsF+;5k1l^j+I6lATK*t9#697f7v zvMOy`Ur=1qBM;t#Alv$B(~Iv+Y^9MUQ#cLlqGt*}RCwTi9dD~rnz&yvXy$cR~jQw#XtJZg96)I1HaX$8?-M$wMUO0%ZxxYEyRm zZ^1}+NACaq9x&?;1%(KYyZ?7zHQ4c5F)j6bt5KmvPmfdzcv!%Xs!+MxdbeGd0LM_b zn}xb5ys+XwgK=9eJgTRc{#GLA6k=K?O*t)Jq%b%a$QC0cIiEZyBaBRoyO>Y0kA7fOT=D!2~B4L z|0UWcmi2RLsx^F5PLHuXJ?t30wNK+iOL`|?4laVd+l96}g1yt#G{Hq1Z%krIkApe# z1xf%Nq3msg&~t>cmbqP_?4Lmntc91Qku5xXh>%m8x8ES~meH({^bw7^3si5h${O`0 zX{w|NRd)R%5S@@+e^=Cw8|`?wNb2o<%z6Ue7`FYWkgF7|Of0pSy@@B`Qgvxda2YI= z^E-_FYnoo%pQve15#tD_?t7QEbQDgZl&0=e2G6|IQ8;C(W6u+SOgL3XomDnj8d=$R z_l#=QiwyD>jS*GP1uDPlb;VP!0<#I}-RVYidq6N{qNrYnsbqQqW(+kuBGgQvqTIJV zP@EE=)8(`s zSTlGIV+SmC>_!5R)>OQgMdBb`o?TERYu9v}G&XkwSl&g&9XZ=l!0*KO-~#@KU8uMN z{s&!6uU){ul+=liBjSJ0Ap9H=zvZr!A#0%6|D;TM<+LEAX4i2tKNuD_}64Ic#R$ID!M^u0S~mm=y3Wx2Ps@5D$vTs!XG(w%rLImapE z&2D2)&-$m{MH}kL(q(inX5WXh8%O$OCw*$5UWG~O|mk2<{<4g&3Rm4fxX*Rz$^q3TJI>)qISo3=Bv(6@S1J7TW zmT9!U2DI|JoZrvcmRyb#@q=?Y-*Tbib~*pxYI@CF4tpKLI~>j54Z_OdXe>{=9L1lL#o|3NMhCC&uImmHJI$_Hz4oPV?lIK*}c!2!1d>4tm8%@!4OT2bHH7yw^6-ySS})cOsu4yvx+j8OExu zGhI%bySEIQd5I%~Z;507NdPhi|CBZO&RH1U{x8ktxBv5^ZNmOf6EfQR%R-tN$H##_ zr$kK;V9Mz+isOu-U6u}wl|xI9@W9X`^tLuh59XZogY#e?a-r?^V2`?*UONxAnAAIm z6Z^m*^c+siGPlc#{XI0yIx$%q-H8Q+oN{9SXq4Zo@rX{$1**4L<#A$HfoOjx)*C)8 zXVl|uuElTfj#?$RKv94^=L zw9Dmw9-~;7D@#MVT)h!X2y1`)1zf8|qtWLP{jCdBZ&Av+wQSOc4}g8$zV<*o+v%2% zhbm~fIM}iE$lM|zjN#YLNfauz0B>k3x2B%mP5L+UmhOZ-+(j^Zcn|jx(`#~RUKFD< z4sJ$OOaG=yX~P;Bu*mD_o)c{op3eB3 z{yyl_TeA_LT@ve^r%kZJ2;Q}br;%hkNU^1 zrq|A+K8xWU9`$R3uyS}*%hN88`UJpPk19(edQ?JKd(Wz6|$H4)tVctf6#7hl>Tm#K1a)z@t(?cZ7yLpUcd0mg|6l|Wn@9U8#FB523Z203t ztt?BWAPnMCX<(W>l^ZW94?S_?s|stCBed1AITY0`J4byd9Bj2CCKAbO3DYU(jnXFC zs2q(ZEq&KOQ*y?|{2_CD?~_rJjNZS8rvEy=QfW6SMSRI5sbA7HGFd&JZ+UTyoVZBD zf4#}fzugo$Q;}nK_VIG9jU?kHBksy3U)b?NWGjWvbWlLfF1$rpt~XFvl*5!n;@eH+ zZWlTHOYLS2H<#n6QljMcbQi0t9hcPbR~%Wl6asCC}Tv`LFL@vL}FsE5jEpd&AaT?I*%OY zM||vI>*5T*-rI$Y(d#Zk$pUUv*b0KQL{w3d}2lBt zq=>GTszIx~RU<+amUCJm{CoHkh-pCuWR`SDjcQif4(J02_)^14!)ug4lLu9*2zrr8 zx&d*;&?MWu;Ky;Jb$(;x%9SfHP~CGT#}iI#hhP{fglwzK2-wVROx#h&%suuYAOG; zs0OrcQ=p96^tlf-pQB27U1aZrezJ$i8$awn$hPo8IxA6@huDwVF}k-(Ka}87{!kV> zk=Rb;KaxL`>Vt_NdKX^29?$5VN%=!BbTRQmFR(E2L(f->N3Iz?04IOwgg3gIra3)lbm{b8edL5JuWGyo}TlNQ%{Fwa_VUhPfk6pJ;cujU*on>UT7bclZqO2ijqT5L&P1eYEFxN0w^{uF8Y@cX)W2VxyUPwV) z(4&e@$5QYS7c^rEMAovf)E%U6g{w2oR*+pD9zyMnNr1+qrK%TAwJ=CWs^nyqKcd*L Hy|w;-nexTd literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/.doctrees/lightnion.doctree b/docs/source/_build/html/.doctrees/lightnion.doctree new file mode 100644 index 0000000000000000000000000000000000000000..82ae3a172590b4fba0522b7c1dab4bfdaf0cd616 GIT binary patch literal 379837 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

      l0WgP9(yu;sM0DA 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 J)6s)yBCQYkfob$>;%T4*-m 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 PglYJw7ENY*X6pX}fsBxb literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/.doctrees/lightnion.tests.doctree b/docs/source/_build/html/.doctrees/lightnion.tests.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a0aac7a250400ee3e2080b990cf74fa64012ce8b GIT binary patch literal 37174 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 literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/.doctrees/modules.doctree b/docs/source/_build/html/.doctrees/modules.doctree new file mode 100644 index 0000000000000000000000000000000000000000..cf66db8ec2b4029d9d29b6648c4c6ea38f482d17 GIT binary patch literal 2550 zcmZ8jNpBlB6n1QDvn|I{Q4JnZ@hn#Y;WuO7t zLyH*Tt?aMtpXkS#(O9y8frgK7{oXcz?Ed@TXsiCk2{T3TQn@p27@f}>b;e-;1NQ0 zc}Fq__u`;X)Hx9G-qW;f-i9nxcZV4*E-jyDo)8C~F7j0p6Y)gsXN%%#{9!6g$)}2j z?8(&GV%mi<1z>L4I5jN|3yQll>)`LR^X)K0fWyL+l?j@y;m|-74_zgsUY=3LTKosz z6yEZ6%o<*Cg22RcK=w7BZ}7ap^AgXKIB4x6VEAWc9p=S4pnoSC52P+sV0yJKRC#(}uzouPNkOdO=oA1B?8S$CDS?%zKDZTAFZLLpg$2w_uBp|)3LKWx5|oj*wBR|Y z^f^wXu7W3A7lwfgBO&DyB$@&0V{l5lH{C4y?EP(Vl=Vk>-#hbH(*m#j;q@Z?H5+0^GDVbal=%7L_A4p!YD-oyh0 z<52&!ogCwqjjYB@oK(CbhzYYo7j?V`nKGj=oeMjDCA_cPPt)o3_4QeG@#xACe zUroX3rYSzo5?N!GAfA^%*#p%f=%+8f`w_5A?7X;VCR6UrJX@LZ#$e$|?&q}`;Y$S* zBTr|jf0k$AFrJ{AO42n}=RR>&PVa5}vi3%5$8C-rMVm2VsN#L>%kGG-J90PL(B~^TnY_m9 z3EcKN#x*EX&yng?^B?DN;KFQ^?}%fFGxXyPYzfXiv^_4Ap_hc0R4RhiWO=P3~lr7(9hM6 z?G5@M6PtJOLA-NulnMT(0$87t_;BIGbNs&(`!0^xQ&mfk3yCq5%|l~D$?de_YusF? zG< + + + + + + + + Overview: module code — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Overview: module code
      • + + +
      • + +
      • + +
      + + +
      +
      + +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cache.html b/docs/source/_build/html/_modules/lightnion/cache.html new file mode 100644 index 0000000..ffba96b --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cache.html @@ -0,0 +1,298 @@ + + + + + + + + + + + lightnion.cache — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cache

      +import os
      +import time
      +import json
      +import shutil
      +import base64
      +import logging
      +
      +cache_directory = '.lightnion-cache.d'
      +
      +
      [docs]def directory(base_dir=None): + if base_dir is None: + base_dir = os.getcwd() + base_dir = os.path.join(base_dir, cache_directory) + + if not os.path.isdir(base_dir): + logging.info( + 'Note: creating {} to cache descriptors.'.format(base_dir)) + os.mkdir(base_dir) + + if not os.path.isdir(base_dir): + raise RuntimeError( + 'Unable to fetch cache directory: {}'.format(base_dir)) + + return base_dir
      + +
      [docs]def purge(): + base_dir = directory() + logging.warning('Note: removing {} to purge cache.'.format(base_dir)) + shutil.rmtree(base_dir)
      + +
      [docs]class descriptors: +
      [docs] @staticmethod + def filename(descriptor, get=False): + base_dir = 'descriptors' + if 'micro' in descriptor['flavor']: + base_dir = 'micro-' + base_dir + base_dir = os.path.join(directory(), base_dir) + + if not os.path.isdir(base_dir): + os.mkdir(base_dir) + + field = 'digest' + if 'micro' in descriptor['flavor']: + field = 'micro-digest' + + digest = descriptor[field] + if (not get) or 'micro' in descriptor['flavor']: + digest = base64.b64decode(descriptor[field] + '====').hex() + + half_dir = os.path.join(base_dir, digest[:2]) + if not os.path.isdir(half_dir): + os.mkdir(half_dir) + + return os.path.join(half_dir, digest)
      + +
      [docs] @staticmethod + def put(descriptor): + filename = descriptors.filename(descriptor) + if os.path.isfile(filename): + return + with open(filename, 'w') as f: + json.dump(descriptor, f)
      + +
      [docs] @staticmethod + def get(flavor, digest): + field = 'digest' + if 'micro' in flavor: + field = 'micro-digest' + + descriptor = {'flavor': flavor, field: digest} + filename = descriptors.filename(descriptor, get=True) + with open(filename, 'r') as f: + descriptor = json.load(f) + + if not descriptor['flavor'] == flavor: + raise ValueError('Mismatched flavor.') + + new_digest = descriptor[field] + if not 'micro' in field: + new_digest = base64.b64decode(new_digest + '====').hex() + + if not new_digest == digest: + raise ValueError('Mismatched digest.') + + return descriptor
      + +
      [docs]class consensus: +
      [docs] @staticmethod + def filename(flavor): + return os.path.join(directory(), 'consensus-{}'.format(flavor))
      + +
      [docs] @staticmethod + def put(fields): + filename = consensus.filename(fields['flavor']) + with open(filename, 'w') as f: + json.dump(fields, f)
      + +
      [docs] @staticmethod + def get(flavor): + filename = consensus.filename(flavor) + with open(filename, 'r') as f: + fields = json.load(f) + + if not fields['flavor'] == flavor: + raise ValueError('Mismatched flavor.') + + if fields['headers']['valid-until']['stamp'] < time.time(): + raise ValueError('Consensus need to be refreshed: {} < {}'.format( + fields['headers']['valid-until']['stamp'], time.time())) + + return fields
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell.html b/docs/source/_build/html/_modules/lightnion/cell.html new file mode 100644 index 0000000..2138bcd --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell.html @@ -0,0 +1,276 @@ + + + + + + + + + + + lightnion.cell — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell

      +from .. import constants
      +from . import view
      +
      +
      [docs]class cmd(view.enum(1)): + PADDING = 0x00 + CREATE = 0x01 + CREATED = 0x02 + RELAY = 0x03 + DESTROY = 0x04 + CREATE_FAST = 0x05 + CREATED_FAST = 0x06 + VERSIONS = 0x07 + NETINFO = 0x08 + RELAY_EARLY = 0x09 + CREATE2 = 0x0a + CREATED2 = 0x0b + PADDING_NEGOTIATE = 0x0c + VPADDING = 0x80 + CERTS = 0x81 + AUTH_CHALLENGE = 0x82 + AUTHENTICATE = 0x83 + AUTHORIZE = 0x84 + + @property + def is_fixed(self): + return not self.is_variable + + @property + def is_variable(self): + if bool(0x80 & self._value_): + return True + return self._value_ == int(cmd.VERSIONS)
      + +header_view = view.fields( + circuit_id=view.uint(4), cmd=cmd) +header_legacy_view = view.fields( + circuit_id=view.uint(2), cmd=cmd, length=view.cache(view.uint, init=[2])) +header_variable_view = view.fields( + circuit_id=view.uint(4), cmd=cmd, length=view.cache(view.uint, init=[2])) + +
      [docs]class cell_view(view.packet): + _whitelist = [header_view, header_legacy_view, header_variable_view] + def __init__(self, header): + if header not in self._whitelist: + raise ValueError('Invalid header type: {}'.format(header)) + super().__init__(header_view=header, fixed_size=constants.payload_len) + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd.is_fixed == self.fixed_size
      + +variable_size = view.like(cell_view(header_variable_view), 'variable_size') +legacy_size = view.like(cell_view(header_legacy_view), 'legacy_size') +fixed_size = view.like(cell_view(header_view), 'fixed_size') + +header = view.like(header_view, 'header') +header_legacy = view.like(header_legacy_view, 'header_legacy') +header_variable = view.like(header_variable_view, 'header_variable') + +
      [docs]def pad(payload): + try: + payload = payload.raw + except AttributeError: + pass + + cell_header = header(payload) + if not cell_header.valid: + raise RuntimeError('Invalid cell header: {}'.format(cell_header.raw)) + + length = constants.payload_len + cell_header.width + if not cell_header.cmd.is_fixed: + cell_header = header_variable(payload) + if not cell_header.valid: + raise RuntimeError( + 'Invalid variable cell header: {}'.format(cell_header.raw)) + + length = cell_header.length + cell_header.width + if length > constants.max_payload_len: + raise RuntimeError('Invalid cell length: {}'.format(length)) + + return payload.ljust(length, b'\x00')
      + +from . import address +from . import ( + padding, relay, destroy, create_fast, created_fast, versions, netinfo, + relay_early, create2, created2, certs, challenge) +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/address.html b/docs/source/_build/html/_modules/lightnion/cell/address.html new file mode 100644 index 0000000..286d1fe --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/address.html @@ -0,0 +1,244 @@ + + + + + + + + + + + lightnion.cell.address — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.address

      +from . import view as _view
      +
      +import ipaddress
      +
      +
      [docs]class addr_type(_view.enum(1, cached=True)): + HOSTNAME = 0x00 + IPV4_ADDR = 0x04 + IPV6_ADDR = 0x06 + ERROR_TRANS = 0xF0 + ERROR_NON_TRANS = 0xF1
      + +header_view = _view.fields(**{ + 'type': addr_type, + 'length': _view.cache(_view.uint, init=[1])}) + +
      [docs]class address_view(_view.packet): + _default_extra_fields = ['type'] + _default_header_view = header_view + _default_data_name = 'host' + + def __init__(self, *kargs, **kwargs): + super().__init__(*kargs, **kwargs) + + length = self.header._fields['length'] + self._fields['host'] = _view.union( + view_table={ + addr_type.HOSTNAME: _view.codec('utf8', size=length), + addr_type.IPV4_ADDR: _view.ip_address(version=4), + addr_type.IPV6_ADDR: _view.ip_address(version=6), + addr_type.ERROR_TRANS: _view.data(length), + addr_type.ERROR_NON_TRANS: _view.data(length) + }, union_tag=self.header._fields['type'])
      + +view = address_view() +address = _view.like(view, 'address') + +
      [docs]def pack(host, type_hint=None): + if type_hint is None: + try: + ipaddress.IPv4Address(host) + type_hint = addr_type.IPV4_ADDR + except ValueError: + ipaddress.IPv6Address(host) + type_hint = addr_type.IPV6_ADDR + + base = address(b'') + base.header.set(**{'type': type_hint, 'length': 0}) + + length = base._view.host.width() + if length == 0: + length = len(host) + base.header.set(length=length) + + base.set(host=host) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/certs.html b/docs/source/_build/html/_modules/lightnion/cell/certs.html new file mode 100644 index 0000000..27c00e1 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/certs.html @@ -0,0 +1,231 @@ + + + + + + + + + + + lightnion.cell.certs — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.certs

      +from .. import cell as _cell
      +from . import view as _view
      +
      +
      [docs]class cert_type(_view.enum(1)): + RSA_SIGNED_LINK_KEY = 0x01 + RSA_SELF_SIGNED_IDENTITY = 0x02 + RSA_SIGNED_AUTHENTICATE = 0x03 + ED_SIGNED_SIGNING_KEY = 0x04 + ED_SIGNED_TLS_LINK = 0x05 + ED_SIGNED_AUTHENTICATE = 0x06 + RSA_SIGNED_ED_IDENTITY = 0x07
      + +cert_header_view = _view.fields( + **{'type': cert_type, 'clen': _view.cache(_view.uint, init=[2])}) +cert_view = _view.packet(header_view=cert_header_view, field_name='clen') + +certs_header_view = _view.fields(quantity=_view.cache(_view.uint, init=[1])) +class _certs_view(_view.packet): + _default_header_view = certs_header_view + _default_field_name = 'quantity' + _default_data_name = 'listing' + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._fields['listing'] = _view.series(cert_view, + self._fields['header'].quantity) + +certs_view = _certs_view() +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_variable_view + _default_data_name = 'certs' + _default_data_view = certs_view + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.CERTS
      + +view = cell_view() +cell = _view.like(view, 'certs_cell') +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/challenge.html b/docs/source/_build/html/_modules/lightnion/cell/challenge.html new file mode 100644 index 0000000..899db46 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/challenge.html @@ -0,0 +1,238 @@ + + + + + + + + + + + lightnion.cell.challenge — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.challenge

      +from .. import cell as _cell
      +from . import view as _view
      +from . import common
      +
      +import os
      +
      +
      [docs]class auth_type(_view.enum(2)): + RSA_AUTH = 0x01 + ED_AUTH = 0x03
      + +auth_header_view = _view.fields( + challenge=_view.data(32), + quantity=common.length_halved_view(2)) + +class _auth_view(_view.packet): + _default_header_view = auth_header_view + _default_data_name = 'methods' + _max_size = 2 * auth_type.width() + + def __init__(self, *kargs, **kwargs): + super().__init__(*kargs, **kwargs) + self._fields['methods'] = _view.series( + auth_type, self._fields['header'].quantity) + +auth_view = _auth_view() +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_variable_view + _default_data_view = auth_view + _default_data_name = 'auth' + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.AUTH_CHALLENGE
      + +view = cell_view() +cell = _view.like(view, 'auth_challenge_cell') + +
      [docs]def pack(*methods, challenge=None): + if challenge is None: + challenge = os.urandom(32) + + base = cell(b'') + base.header.set(circuit_id=0, cmd=_cell.cmd.AUTH_CHALLENGE, length=0) + base.auth.set(challenge=challenge, quantity=len(methods), methods=methods) + base.set(length=base.auth.width) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/common.html b/docs/source/_build/html/_modules/lightnion/cell/common.html new file mode 100644 index 0000000..6d1455d --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/common.html @@ -0,0 +1,205 @@ + + + + + + + + + + + lightnion.cell.common — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.common

      +from . import view as _view
      +
      +
      [docs]class length_halved_view(_view.cache(_view.uint)): +
      [docs] def cache(self): + return super().cache() // 2
      + +
      [docs] def iseven(self): + return bool(self._cache.value % 2 == 0)
      + +
      [docs] def write(self, payload=b'', value=None): + return super().write(payload, value * 2)
      + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + return self.value(payload) > 0 and self.cached() and self.iseven()
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/create2.html b/docs/source/_build/html/_modules/lightnion/cell/create2.html new file mode 100644 index 0000000..c2c91ae --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/create2.html @@ -0,0 +1,223 @@ + + + + + + + + + + + lightnion.cell.create2 — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.create2

      +from .. import cell as _cell
      +from . import view as _view
      +
      +create_header_view = _view.fields(**{
      +    'type': _cell.relay.extend2.handshake_type,
      +    'length': _view.cache(_view.uint, init=[2])})
      +
      +
      [docs]class create_view(_view.packet): + _default_header_view = create_header_view
      + +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_view + _default_data_name = 'create2' + _default_data_view = create_view() + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.CREATE2
      + +view = cell_view() +cell = _view.like(view, 'create2_cell') + +
      [docs]def pack(circuit_id, handshake_data): + base = cell(b'') + base.set( + circuit_id=circuit_id, + cmd=_cell.cmd.CREATE2, + create2=dict(**{'type': _cell.relay.extend2.handshake_type.NTOR, + 'length': len(handshake_data), + 'data': handshake_data})) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/create_fast.html b/docs/source/_build/html/_modules/lightnion/cell/create_fast.html new file mode 100644 index 0000000..655b92c --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/create_fast.html @@ -0,0 +1,222 @@ + + + + + + + + + + + lightnion.cell.create_fast — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.create_fast

      +from .. import constants
      +from .. import cell as _cell
      +from . import view as _view
      +
      +import os
      +
      +create_fast_view = _view.fields(material=_view.data(constants.hash_len))
      +
      +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_view + _default_data_name = 'create_fast' + _default_data_view = create_fast_view + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.CREATE_FAST
      + +view = cell_view() +cell = _view.like(view, 'create_fast_cell') + +
      [docs]def pack(circuit_id, material=None): + if material is None: + material = os.urandom(constants.hash_len) + + base = cell(b'') + base.set( + circuit_id=circuit_id, + cmd=_cell.cmd.CREATE_FAST, + create_fast=dict(material=material)) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/created2.html b/docs/source/_build/html/_modules/lightnion/cell/created2.html new file mode 100644 index 0000000..da25643 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/created2.html @@ -0,0 +1,211 @@ + + + + + + + + + + + lightnion.cell.created2 — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.created2

      +from .. import cell as _cell
      +from . import view as _view
      +
      +created_header_view = _view.fields(length=_view.cache(_view.uint, init=[2]))
      +
      +
      [docs]class created_view(_view.packet): + _default_header_view = created_header_view
      + +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_view + _default_data_name = 'created2' + _default_data_view = created_view() + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.CREATED2
      + +view = cell_view() +cell = _view.like(view, 'created2_cell') +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/created_fast.html b/docs/source/_build/html/_modules/lightnion/cell/created_fast.html new file mode 100644 index 0000000..f5e6905 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/created_fast.html @@ -0,0 +1,221 @@ + + + + + + + + + + + lightnion.cell.created_fast — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.created_fast

      +from .. import constants
      +
      +from .. import cell as _cell
      +from . import view as _view
      +
      +import os
      +
      +created_fast_view = _view.fields(material=_view.data(constants.hash_len),
      +    derivative=_view.data(constants.hash_len))
      +
      +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_view + _default_data_name = 'created_fast' + _default_data_view = created_fast_view + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.CREATED_FAST
      + +view = cell_view() +cell = _view.like(view, 'created_fast_cell') + +
      [docs]def pack(circuit_id, material, derivative): + base = cell(b'') + base.set( + circuit_id=circuit_id, + cmd=_cell.cmd.CREATED_FAST, + created_fast=dict(material=material, derivative=derivative)) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/destroy.html b/docs/source/_build/html/_modules/lightnion/cell/destroy.html new file mode 100644 index 0000000..93c1f0d --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/destroy.html @@ -0,0 +1,226 @@ + + + + + + + + + + + lightnion.cell.destroy — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.destroy

      +from .. import cell as _cell
      +from . import view as _view
      +
      +
      [docs]class reason(_view.enum(1)): + NONE = 0x00 + PROTOCOL = 0x01 + INTERNAL = 0x02 + REQUESTED = 0x03 + HIBERNATING = 0x04 + RESOURCELIMIT = 0x05 + CONNECTFAILED = 0x06 + OR_IDENTITY = 0x07 + OR_CONN_CLOSED = 0x08 + FINISHED = 0x09 + TIMEOUT = 0x0a + DESTROYED = 0x0b + NOSUCHSERVICE = 0x0c
      + +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_view + _default_data_name = 'reason' + _default_data_view = reason + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.DESTROY
      + +view = cell_view() +cell = _view.like(view, 'destroy_cell') + +
      [docs]def pack(circuit_id, reason): + base = cell(b'') + base.set(circuit_id=circuit_id, cmd=_cell.cmd.DESTROY, reason=reason) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/netinfo.html b/docs/source/_build/html/_modules/lightnion/cell/netinfo.html new file mode 100644 index 0000000..ddaade2 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/netinfo.html @@ -0,0 +1,253 @@ + + + + + + + + + + + lightnion.cell.netinfo — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.netinfo

      +from .. import cell as _cell
      +from . import view as _view
      +
      +import time
      +
      +netinfo_header_view = _view.fields(timestamp=_view.uint(4),
      +    other=_cell.address.view, quantity=_view.cache(_view.uint, init=[1]))
      +
      +class _netinfo_view(_view.packet):
      +    _default_header_view = netinfo_header_view
      +    _default_field_name = 'quantity'
      +    _default_data_name = 'addresses'
      +
      +    _addr_type_whitelist = [
      +        _cell.address.addr_type.IPV4_ADDR, _cell.address.addr_type.IPV6_ADDR]
      +
      +    def __init__(self, **kwargs):
      +        super().__init__(**kwargs)
      +        self._fields['addresses'] = _view.series(_cell.address.view,
      +            self._fields['header'].quantity)
      +
      +    def valid(self, payload=b''):
      +        if not super().valid(payload):
      +            return False
      +
      +        number = self.header.value(payload, field='quantity')
      +        offset = self.offset(payload, field='addresses')
      +        for i in range(number):
      +            roff = self.addresses.offset(payload[offset:], field=i)
      +            addr = self.addresses.item.type.value(payload[offset+roff:])
      +            if addr not in self._addr_type_whitelist:
      +                return False
      +        return True
      +
      +netinfo_view = _netinfo_view()
      +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_view + _default_data_name = 'netinfo' + _default_data_view = netinfo_view + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.NETINFO
      + +view = cell_view() +cell = _view.like(view, 'netinfo_cell') + +
      [docs]def pack(other_address, *addresses, timestamp=None): + if timestamp is None: + timestamp = int(time.time()) + + base = cell(b'') + base.set( + circuit_id=0, + cmd=_cell.cmd.NETINFO, + netinfo=dict( + timestamp=timestamp, + other=_cell.address.pack(other_address).value(), + quantity=len(addresses), + addresses=[_cell.address.pack(a).value() for a in addresses])) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/padding.html b/docs/source/_build/html/_modules/lightnion/cell/padding.html new file mode 100644 index 0000000..6830483 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/padding.html @@ -0,0 +1,210 @@ + + + + + + + + + + + lightnion.cell.padding — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.padding

      +from .. import cell as _cell
      +from . import view as _view
      +
      +
      [docs]class cell_view(_view.packet): + _default_header_view = _cell.header_view + _default_fixed_size = 0 + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.PADDING
      + +view = cell_view() +cell = _view.like(view, 'padding_cell') + +
      [docs]def pack(): + base = cell(b'') + base.set(circuit_id=0, cmd=_cell.cmd.PADDING) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/relay.html b/docs/source/_build/html/_modules/lightnion/cell/relay.html new file mode 100644 index 0000000..cf0df7f --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/relay.html @@ -0,0 +1,336 @@ + + + + + + + + + + + lightnion.cell.relay — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.relay

      +from ... import constants
      +
      +from ... import cell as _cell
      +from .. import view as _view
      +
      +payload_len = constants.payload_len - 11
      +
      +
      [docs]class cmd(_view.enum(1)): + RELAY_BEGIN = 0x01 + RELAY_DATA = 0x02 + RELAY_END = 0x03 + RELAY_CONNECTED = 0x04 + RELAY_SENDME = 0x05 + RELAY_EXTEND = 0x06 + RELAY_EXTENDED = 0x07 + RELAY_TRUNCATE = 0x08 + RELAY_TRUNCATED = 0x09 + RELAY_DROP = 0x0a + RELAY_RESOLVE = 0x0b + RELAY_RESOLVED = 0x0c + RELAY_BEGIN_DIR = 0x0d + RELAY_EXTEND2 = 0x0e + RELAY_EXTENDED2 = 0x0f + + @property + def is_forward(self): + return self in [ + cmd.RELAY_BEGIN, + cmd.RELAY_DATA, + cmd.RELAY_END, + cmd.RELAY_SENDME, + cmd.RELAY_EXTEND, + cmd.RELAY_TRUNCATE, + cmd.RELAY_DROP, + cmd.RELAY_RESOLVE, + cmd.RELAY_BEGIN_DIR, + cmd.RELAY_EXTEND2] + + @property + def is_backward(self): + return self in [ + cmd.RELAY_DATA, + cmd.RELAY_END, + cmd.RELAY_CONNECTED, + cmd.RELAY_SENDME, + cmd.RELAY_EXTENDED, + cmd.RELAY_TRUNCATED, + cmd.RELAY_DROP, + cmd.RELAY_RESOLVED, + cmd.RELAY_EXTENDED2] + + @property + def is_circuit(self): + return self in [ + cmd.RELAY_BEGIN, + cmd.RELAY_DATA, + cmd.RELAY_END, + cmd.RELAY_CONNECTED, + cmd.RELAY_SENDME, + cmd.RELAY_RESOLVE, + cmd.RELAY_RESOLVED, + cmd.RELAY_BEGIN_DIR] + + @property + def is_control(self): + return self in [ + cmd.RELAY_SENDME, + cmd.RELAY_EXTEND, + cmd.RELAY_EXTENDED, + cmd.RELAY_TRUNCATE, + cmd.RELAY_TRUNCATED, + cmd.RELAY_DROP, + cmd.RELAY_EXTEND2, + cmd.RELAY_EXTENDED2]
      + +relay_header_view = _view.fields( + cmd=cmd, + recognized=_view.data(2), + stream_id=_view.uint(2), + digest=_view.data(4), + length=_view.cache(_view.uint, init=[2])) + +
      [docs]class relay_view(_view.packet): + _default_header_view = relay_header_view + _max_size = payload_len + +
      [docs] def valid(self, payload=b''): + if not self.header.valid(payload): + return False + + if not self.header.value(payload, 'recognized') == b'\x00\x00': + return True + + return super().valid(payload)
      + +payload_view = relay_view() +payload = _view.like(payload_view, 'relay_payload') + +
      [docs]class cell_view(_view.packet): + _default_data_view = payload_view + _default_data_name = 'relay' + _default_fixed_size = constants.payload_len + _default_header_view = _cell.header_view + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + if not cell_cmd == _cell.cmd.RELAY: + return False + + offset = self.offset(payload, field='relay') + circuit_id = self.header.value(payload, field='circuit_id') + relay_cmd = self.relay.header.value(payload[offset:], field='cmd') + if circuit_id == 0 and not relay_cmd.is_control: + return False + return True
      + +view = cell_view() +cell = _view.like(view, 'relay_cell') + +def _pack_details(base, cmd, recognized, stream_id, digest, data): + base.relay.header.set( + cmd=cmd, + recognized=recognized, + stream_id=stream_id, + digest=digest, + length=len(data)) + base.set(relay=dict(data=data)) + + # Preemptively add \x00 padding (as it is included within digests) + base.relay.raw = base.relay.raw.ljust(constants.payload_len, b'\x00') + if not base.valid: + raise RuntimeError( + 'Invalid RELAY cell after padding: {}'.format(base.raw)) + + return base + +
      [docs]def pack(circuit_id, cmd, data, recognized=b'\x00\x00', *, stream_id, digest): + base = cell(b'') + base.header.set( + circuit_id=circuit_id, + cmd=_cell.cmd.RELAY) + return _pack_details(base, cmd, recognized, stream_id, digest, data)
      + +from . import extend2, extended2 +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/relay/extend2.html b/docs/source/_build/html/_modules/lightnion/cell/relay/extend2.html new file mode 100644 index 0000000..7ed3094 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/relay/extend2.html @@ -0,0 +1,307 @@ + + + + + + + + + + + lightnion.cell.relay.extend2 — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.relay.extend2

      +import base64
      +
      +from ... import cell as _cell
      +from .. import view as _view
      +
      +
      [docs]class linkspec_type(_view.enum(1, cached=True)): + TLS_TCP_4 = 0x00 + TLS_TCP_6 = 0x01 + LEGACY_ID = 0x02 + ED_ID = 0x03
      + +linkspec_header_view = _view.fields(**{ + 'type': linkspec_type, + 'length': _view.cache(_view.uint, init=[1])}) + +
      [docs]class linkspec_view(_view.packet): + _default_extra_fields = ['type'] + _default_header_view = linkspec_header_view + + def __init__(self, *kargs, **kwargs): + super().__init__(*kargs, **kwargs) + + self._fields['data'] = _view.union( + view_table={ + linkspec_type.TLS_TCP_4: _view.fields( + addr=_view.ip_address(version=4), port=_view.uint(2)), + linkspec_type.TLS_TCP_6: _view.fields( + addr=_view.ip_address(version=6), port=_view.uint(2)), + linkspec_type.LEGACY_ID: _view.data(20), + linkspec_type.ED_ID: _view.data(32) + }, union_tag=self.header._fields['type'])
      +linkspec = _view.like(linkspec_view(), 'linkspec') + +linkspecs_header_view = _view.fields( + quantity=_view.cache(_view.uint, init=[1])) + +
      [docs]class linkspecs_view(_view.packet): + _default_header_view = linkspecs_header_view + _default_field_name = 'quantity' + _default_data_name = 'specs' + + def __init__(self, *kargs, **kwargs): + super().__init__(*kargs, **kwargs) + self._fields['specs'] = _view.series(linkspec_view(), + self._fields['header'].quantity)
      + +
      [docs]class handshake_type(_view.enum(2)): + # TAP = 0x0001 # TODO: add support for TAP handshakes? + NTOR = 0x0002
      + +extend2_header_view = _view.fields(**{'link': linkspecs_view(), + 'type': handshake_type, 'length': _view.cache(_view.uint, init=[2])}) + +
      [docs]class extend2_view(_view.packet): + _default_header_view = extend2_header_view
      + +view = extend2_view() +payload = _view.like(view, 'extend2_payload') + +def _pack_linkspec_addr(addr, port): + addr = _cell.address.pack(addr) + + base = linkspec(b'') + if addr['type'] == _cell.address.addr_type.IPV4_ADDR: + base.type = linkspec_type.TLS_TCP_4 + elif addr['type'] == _cell.address.addr_type.IPV6_ADDR: + base.type = linkspec_type.TLS_TCP_6 + else: + raise RuntimeError('Invalid address: {}'.format(addr)) + + base.length = 0 + base.data.addr = addr.host + base.data.port = port + + base.set(length=base.data.width) + return base + +def _pack_linkspec_identity(identity): + if isinstance(identity, str): + identity = base64.b64decode(identity + '====') + + base = linkspec(b'') + if len(identity) == 20: + base.type = linkspec_type.LEGACY_ID + elif len(identity) == 32: + base.type = linkspec_type.ED_ID + else: + raise RuntimeError('Invalid identity: {}'.format(identity)) + + base.length = 0 + base.data = identity + + base.set(length=len(identity)) + return base + +
      [docs]def pack(handshake, addresses=[], identities=[]): + if len(addresses) < 1: + raise RuntimeError('Expect at least one address!') + if len(identities) > 2: + raise RuntimeError('Expect at most two identities!') + + specs = [] + for addr, port in addresses: + specs.append(_pack_linkspec_addr(addr, port).value()) + + for identity in identities: + specs.append(_pack_linkspec_identity(identity).value()) + + if not any([s['type'] == linkspec_type.ED_ID for s in specs]): + raise RuntimeError('Require at least one ed25519 identity!') + + base = payload(b'') + base.header.link.set(quantity=len(specs), specs=specs) + base.header.set(**{'type': handshake_type.NTOR, 'length': len(handshake)}) + base.set(data=handshake) + return base
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/relay/extended2.html b/docs/source/_build/html/_modules/lightnion/cell/relay/extended2.html new file mode 100644 index 0000000..bf6fb11 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/relay/extended2.html @@ -0,0 +1,201 @@ + + + + + + + + + + + lightnion.cell.relay.extended2 — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.relay.extended2

      +from ... import cell as _cell
      +from .. import view as _view
      +
      +extended2_header_view = _view.fields(length=_view.cache(_view.uint, init=[2]))
      +
      +
      [docs]class extended2_view(_view.packet): + _default_header_view = extended2_header_view
      + +view = extended2_view() +payload = _view.like(view, 'extended2_payload') +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/relay_early.html b/docs/source/_build/html/_modules/lightnion/cell/relay_early.html new file mode 100644 index 0000000..50829af --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/relay_early.html @@ -0,0 +1,226 @@ + + + + + + + + + + + lightnion.cell.relay_early — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.relay_early

      +from .. import constants
      +
      +from .. import cell as _cell
      +from . import view as _view
      +
      +from . import relay
      +
      +
      [docs]class cell_view(_view.packet): + _default_data_view = relay.payload_view + _default_data_name = 'relay' + _default_fixed_size = constants.payload_len + _default_header_view = _cell.header_view + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + if not cell_cmd == _cell.cmd.RELAY_EARLY: + return False + + offset = self.offset(payload, field='relay') + circuit_id = self.header.value(payload, field='circuit_id') + relay_cmd = self.relay.header.value(payload[offset:], field='cmd') + if circuit_id == 0 and not relay_cmd.is_control: + return False + return True
      + +view = cell_view() +cell = _view.like(view, 'relay_early_cell') + +
      [docs]def pack(circuit_id, cmd, data, recognized=b'\x00\x00', *, stream_id, digest): + base = cell(b'') + base.header.set( + circuit_id=circuit_id, + cmd=_cell.cmd.RELAY_EARLY) + return relay._pack_details(base, cmd, recognized, stream_id, digest, data)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/versions.html b/docs/source/_build/html/_modules/lightnion/cell/versions.html new file mode 100644 index 0000000..bda9c6e --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/versions.html @@ -0,0 +1,257 @@ + + + + + + + + + + + lightnion.cell.versions — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.versions

      +from .. import constants
      +from . import common
      +
      +from .. import cell as _cell
      +from . import view as _view
      +
      +header_view = _view.fields(
      +    circuit_id=_view.uint(2),
      +    cmd=_cell.cmd,
      +    length=common.length_halved_view(2))
      +
      +
      [docs]class cell_view(_view.packet): + def __init__(self, header=header_view): + super().__init__(header_view=header, data_name='versions') + self._fields['versions'] = _view.series( + _view.uint(2), header.length) + self._max_size = 64 * 2 + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + cell_cmd = self.header.value(payload, field='cmd') + return cell_cmd == _cell.cmd.VERSIONS
      + +view = cell_view() +cell = _view.like(view, 'versions_cell') +header = _view.like(header_view, 'versions_header') + +
      [docs]def pack(versions): + vercell = cell(b'') + vercell.header.set( + circuit_id=0, + cmd=_cell.cmd.VERSIONS, + length=len(versions)) + vercell.set(versions=versions) + return vercell
      + +
      [docs]def recv(peer): + answer = peer.recv(_cell.header_legacy_view.width()) + + header = _cell.header_legacy(answer) + if not header.valid: + raise RuntimeError('Invalid v2 cell header: {}'.format(header.raw)) + if not header.cmd == _cell.cmd.VERSIONS: + raise RuntimeError('Expecting VERSIONS, got: {}'.format(header.cmd)) + + length = header.length + if length > constants.max_payload_len: + raise RuntimeError('VERSIONS cell too long: {}'.format(header.length)) + + answer += peer.recv(length) + if not view.valid(answer): + raise RuntimeError('Invalid VERSIONS cell: {}'.format(answer)) + + return cell(answer)
      + +
      [docs]def send(peer, payload): + try: + payload = payload.raw + except AttributeError: + pass + + vercell = cell(payload) + if not vercell.valid: + raise RuntimeError('VERSIONS cell invalid: {}'.format(payload)) + + return peer.sendall(payload)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/cell/view.html b/docs/source/_build/html/_modules/lightnion/cell/view.html new file mode 100644 index 0000000..5b6d825 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/cell/view.html @@ -0,0 +1,1076 @@ + + + + + + + + + + + lightnion.cell.view — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.cell.view

      +import collections
      +import threading
      +import ipaddress
      +import inspect
      +import codecs
      +import enum as _enum
      +
      +
      [docs]class basic: +
      [docs] def width(self, payload=b''): + raise NotImplementedError
      + +
      [docs] def valid(self, payload=b''): + raise NotImplementedError
      + +
      [docs] def value(self, payload=b'', field=None): + raise NotImplementedError
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + raise NotImplementedError
      + + def __contains__(self, field): + return False
      + +
      [docs]class composite(basic): +
      [docs] def write(self, payload=b'', value=None, **kwargs): + raise NotImplementedError
      + + def __len__(self): + raise NotImplementedError + + def __contains__(self, field): + raise NotImplementedError + + def __getitem__(self, field): + raise NotImplementedError
      + +
      [docs]class uint(basic): + def __init__(self, size, byteorder='big'): + if size < 1: + raise ValueError('Invalid uint size: {}'.format(size)) + if byteorder not in ['big', 'little']: + raise ValueError('Invalid uint byteorder: {}'.format(byteorder)) + self.byteorder = byteorder + self.size = size + +
      [docs] def width(self, payload=b''): + return self.size
      + +
      [docs] def valid(self, payload=b''): + return len(payload) >= self.size
      + +
      [docs] def value(self, payload=b'', field=None): + return int.from_bytes(payload[:self.size], byteorder=self.byteorder)
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + value = int(value).to_bytes(self.size, byteorder=self.byteorder) + return value + payload[self.size:]
      + +
      [docs]def enum(size, byteorder='big', typename=None, cached=False): + if typename is not None and not typename.isidentifier(): + raise ValueError('Typename {} is not an identifier'.format(typename)) + + @_enum.unique + class _anonymous_enum(_enum.Enum): + def __new__(cls, value): + member = object.__new__(cls) + member._value_ = value + return member + + @classmethod + def width(cls, payload=b''): + return size + + @classmethod + def valid(cls, payload=b''): + if len(payload) < size: + return False + + try: + cls.value(payload) + return True + except ValueError: + return False + + def __int__(self): + return self._value_ + + @classmethod + def value(cls, payload=b'', field=None): + value = int.from_bytes(payload[:size], byteorder='big') + return cls(value) + + @classmethod + def write(cls, payload=b'', value=None, **kwargs): + value = int(cls(value)).to_bytes(size, byteorder='big') + return value + payload[size:] + + if cached: + class _anonymous_cached_enum(_anonymous_enum): + @classmethod + def cache(cls): + if not cls.cached(): + raise RuntimeError('Bounded value unknown at runtime: ' + + 'Have you called .value() of parent view yet?') + return cls._cache.value + + @classmethod + def cached(cls): + return cls._cache.value is not None + + @classmethod + def value(cls, payload=b'', field=None): + value = int.from_bytes(payload[:size], byteorder='big') + cls._cache.value = cls(value) + return cls.cache() + + @classmethod + def write(cls, payload=b'', value=None, **kwargs): + cls._cache.value = cls(value) + packed = int(cls.cache()).to_bytes(size, byteorder='big') + return packed + payload[size:] + + _anonymous_cached_enum._cache = threading.local() + _anonymous_cached_enum._cache.value = None + _anonymous_enum = _anonymous_cached_enum + + if typename is not None: + _anonymous_enum.__qualname__ = typename + return _anonymous_enum
      + +
      [docs]class data(basic): + def __init__(self, size): + if isinstance(size, int) and not size < 0: + fixed = True + elif isview(size) and iscached(size): + fixed = False + else: + raise ValueError('Invalid size: {}'.format(size)) + self.length = size + self.fixed = fixed + + @property + def size(self): + if self.fixed: + return self.length + return self.length.cache() + +
      [docs] def width(self, payload=b''): + return self.size
      + +
      [docs] def valid(self, payload=b''): + if not self.fixed and not self.length.cached(): + return False + return len(payload) >= self.size
      + +
      [docs] def value(self, payload=b'', field=None): + return payload[:self.size]
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + if len(value) != self.size: + raise ValueError('Invalid value size: {} instead of {}'.format( + len(value), self.size)) + return value + payload[self.size:]
      + +
      [docs]class fields(composite): + def __init__(self, **kwargs): + for key, view in kwargs.items(): + if not isview(view): + raise TypeError('Field {} is not a view: {}'.format(key, view)) + self._fields = collections.OrderedDict(kwargs) + +
      [docs] def list_fields(self): + return list(self._fields)
      + +
      [docs] def visit(self, payload=b'', operator=lambda v, p: v.width(p)): + results = [] + for _, view in self._fields.items(): + width = view.width(payload) + results.append(operator(view, payload)) + payload = payload[width:] + return results
      + +
      [docs] def offset(self, payload=b'', field=None): + if field not in self: + raise ValueError('Field {} not in fields'.format(field)) + + offset = 0 + for key, view in self._fields.items(): + if key == field: + return offset + width = view.width(payload) + offset += width + payload = payload[width:]
      + +
      [docs] def width(self, payload=b''): + return sum(self.visit(payload, lambda v, p: v.width(p)))
      + +
      [docs] def valid(self, payload=b''): + for field, view in self._fields.items(): + if not view.valid(payload): + return False + width = view.width(payload) + payload = payload[width:] + return True
      + +
      [docs] def value(self, payload=b'', field=None): + if field is None: + values = self.visit(payload, lambda v, p: v.value(p)) + return {key: value + for (key, _), value in zip(self._fields.items(), values)} + + offset = self.offset(payload, field) + return self._fields[field].value(payload[offset:])
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + if len(kwargs) > 0: + if value is not None: + raise RuntimeError('Conflict: value and kwargs both given.') + value = kwargs + + for field, svalue in value.items(): + offset = self.offset(payload, field) + svalue = self._fields[field].write(payload[offset:], svalue) + payload = payload[:offset] + svalue + return payload
      + + def __len__(self): + return len(self._fields) + + def __contains__(self, field): + return field in self._fields + + def __getitem__(self, field): + return self.__getattr__(field) + + def __getattr__(self, field): + if field.startswith('__'): + raise AttributeError + return self._fields[field]
      + +
      [docs]class packet(fields): + _max_size = 1024 * 1024 + _default_extra_fields = None + _default_header_view = None + _default_field_name = 'length' + _default_fixed_size = 0 + _default_data_view = data + _default_data_name = 'data' + + def __init__(self, header_view=None, fixed_size=None, field_name=None, + data_name=None, data_view=None, extra_fields=None): + + if extra_fields is None: + extra_fields = self._default_extra_fields + if extra_fields is None: + extra_fields = [] + if header_view is None: + header_view = self._default_header_view + if field_name is None: + field_name = self._default_field_name + if fixed_size is None: + fixed_size = self._default_fixed_size + if data_view is None: + data_view = self._default_data_view + if data_name is None: + data_name = self._default_data_name + + if not isinstance(header_view, fields): + raise TypeError('Header not a view.fields: {}'.format(header_view)) + + self._fixed_size = True + if field_name in header_view: + self._fixed_size = False + extra_fields.append(field_name) + + if inspect.isclass(data_view): + if self._fixed_size: + data_view = data_view(fixed_size) + else: + data_view = data_view(header_view._fields[field_name]) + + if not isview(data_view): + raise TypeError('Data view not a view: {}'.format(data_view)) + + self._extra_fields = extra_fields + self._field_name = field_name + self._data_name = data_name + super().__init__(**{'header': header_view, data_name: data_view}) + + @property + def fixed_size(self): + return self._fixed_size + +
      [docs] def list_fields(self): + return list(self._fields) + self.header.list_fields()
      + +
      [docs] def cache_fields(self, payload=b'', value=None): + for field in self._extra_fields: + self.header.value(payload, field)
      + +
      [docs] def offset(self, payload=b'', field=None): + if field in self._fields: + return super().offset(payload, field=field) + return self.header.offset(payload, field=field)
      + +
      [docs] def width(self, payload=b''): + if len(self._extra_fields) > 0: + self.cache_fields(payload) + return super().width(payload)
      + +
      [docs] def valid(self, payload=b''): + if not self.header.valid(payload): + return False + if len(self._extra_fields) > 0: + self.cache_fields(payload) + if not self.fixed_size: + width = self.header.value(payload, self._field_name) + if width > self._max_size: + return False + return super().valid(payload)
      + +
      [docs] def value(self, payload=b'', field=None): + if field == self._data_name: + if len(self._extra_fields) > 0: + self.cache_fields(payload) + return super().value(payload, self._data_name) + elif field is None: + whole = self.header.value(payload, field=None) + whole[self._data_name] = self.value(payload, self._data_name) + return whole + return self.header.value(payload, field)
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + if len(kwargs) > 0: + if value is not None: + raise RuntimeError('Conflict: value and kwargs both given.') + value = kwargs + + if 'header' in value: + payload = super().write(payload, header=value['header']) + value = dict(value) + del value['header'] + + if len(self._extra_fields) > 0 and self._data_name in value: + self.cache_fields(payload) + + if self._data_name in value: + if len(value) > 1: + headers = dict(value) + del headers[self._data_name] + payload = self.header.write(payload, headers) + + return super().write(payload, + **{self._data_name: value[self._data_name]}) + + return self.header.write(payload, value)
      + + def __len__(self): + return len(self.header) + 1 + + def __contains__(self, field): + return field in self._fields or field in self.header + + def __getitem__(self, field): + return self.__getattr__(field) + + def __getattr__(self, field): + if field.startswith('__'): + raise AttributeError + if field in ['header', self._data_name]: + return self._fields[field] + return self.header[field]
      + +
      [docs]class series(composite): + max_quantity = 32 + def __init__(self, item_view, n): + if isinstance(n, int) and not n < 1: + fixed = True + elif isview(n) and iscached(n): + fixed = False + else: + raise ValueError('Invalid quantity: {}'.format(n)) + self.length = n + self.fixed = fixed + self.item = item_view + + @property + def quantity(self): + if self.fixed: + return self.length + return self.length.cache() + +
      [docs] def offset(self, payload=b'', field=None): + field = int(field) + if not self.quantity > field: + raise IndexError('Invalid item index: {}'.format(field)) + + total_offset = 0 + for _ in range(field): + width = self.item.width(payload) + payload = payload[width:] + total_offset += width + return total_offset
      + +
      [docs] def width(self, payload=b''): + offset = self.offset(payload, self.quantity - 1) + return offset + self.item.width(payload[offset:])
      + +
      [docs] def valid(self, payload=b''): + if self.quantity > self.max_quantity: + return False + + for _ in range(self.quantity): + if not self.item.valid(payload): + return False + width = self.item.width(payload) + payload = payload[width:] + return True
      + +
      [docs] def value(self, payload=b'', field=None): + if field is None: + results = [] + for _ in range(self.quantity): + results.append(self.item.value(payload)) + width = self.item.width(payload) + payload = payload[width:] + return results + + field = int(field) + if not self.quantity > field: + raise IndexError('Invalid item index: {}'.format(field)) + + return self.item.value(payload[self.offset(payload, field):])
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + if len(kwargs) > 0: + if value is not None: + raise RuntimeError('Conflict: value and kwargs both given.') + value = kwargs + + if isinstance(value, (list, tuple)): + if len(value) > self.quantity: + raise ValueError( + 'Input list too long: {} out of {} items'.format( + len(value), self.quantity)) + return self.write(payload, dict(enumerate(value))) + + for field, svalue in sorted(value.items()): + field = int(field) + offset = self.offset(payload, field) + svalue = self.item.write(payload[offset:], svalue) + payload = payload[:offset] + svalue + return payload
      + + def __len__(self): + return self.quantity + + def __contains__(self, field): + try: + return int(field) < self.quantity + except ValueError: + return False + + def __getitem__(self, field): + return self.item
      + +
      [docs]class union(composite): + def __init__(self, view_table, union_tag): + for key, view in view_table.items(): + if not isview(view): + raise TypeError('Union of {} not a view: {}'.format(key, view)) + + self.view_table = view_table + self.union_tag = union_tag + + @property + def tag(self): + return self.union_tag.cache() + + @property + def active_view(self): + return self.view_table[self.tag] + +
      [docs] def offset(self, payload=b'', field=None): + return 0
      + +
      [docs] def width(self, payload=b''): + return self.active_view.width(payload)
      + +
      [docs] def valid(self, payload=b''): + if self.tag not in self.view_table: + return False + + return self.active_view.valid(payload)
      + +
      [docs] def value(self, payload=b'', field=None): + return self.active_view.value(payload, field)
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + return self.active_view.write(payload, value=value, **kwargs)
      + + def __contains__(self, field): + return field in self.active_view + + def __getitem__(self, field): + return self.active_view.__getitem__(field)
      + +
      [docs]class wrapper: + '''This is a view bound to raw bytes. + + See self.fields to list fields within the view. + See help(self._view) for details on the underlying view.''' + + def __init__(self, parent_view): + if not isview(parent_view): + raise TypeError('Wrapping not a view: {}'.format(parent_view)) + self._view = parent_view + + @property + def raw(self): + raise NotImplementedError + + @raw.setter + def raw(self, value): + raise NotImplementedError + + @property + def width(self): + return self._view.width(self.raw) + + @property + def valid(self): + return self._view.valid(self.raw) + + @property + def fields(self, wrapper_attr=['raw']): + if (hasattr(self._view, 'list_fields') + and inspect.ismethod(self._view.list_fields)): + return wrapper_attr + self._view.list_fields() + return wrapper_attr + + @property + def truncated(self): + return self.raw[:self.width] + +
      [docs] def offset(self, field): + return self._view.offset(self.raw, field)
      + +
      [docs] def value(self, field=None): + if field is None: + return self._view.value(self.raw) + return self._view.value(self.raw, field=field)
      + +
      [docs] def write(self, value=None, **kwargs): + self.raw = self._view.write(self.raw, value, **kwargs)
      + +
      [docs] def set(self, *kargs, **kwargs): + self.write(*kargs, **kwargs) + self.finalize(truncate=True)
      + +
      [docs] def finalize(self, truncate=True): + if truncate: + self.raw = self.truncated + if not self.valid: + raise RuntimeError('Invalid payload for {} view: {}'.format( + self._view, self.raw))
      + + def __len__(self): + if not iscomposite(self._view): + raise NotImplementedError + return len(self._view) + + def __contains__(self, field): + if not iscomposite(self._view): + raise NotImplementedError + return field in self._view + + def __getitem__(self, field): + return self.__getattr__(str(field)) + + def __setitem__(self, field, value): + self.__setattr__(str(field), value) + + def __setattr__(self, field, value): + if (not field.startswith('_') + and iscomposite(self._view) and field in self._view): + self.write(value={field: value}) + else: + object.__setattr__(self, field, value) + + def __getattr__(self, field): + if field.startswith('__'): + raise AttributeError + if iscomposite(self._view) and field in self._view: + subview = self._view[field] + if iscomposite(subview): + return bind(subview, self, field) + return self._view.value(self.raw, field)
      + +def _forward_init(cls, args): + if args is None: + return cls + + if isinstance(args, dict): + if len(args) == 2 and 'kargs' in args and 'kwargs' in args: + return cls(*args['kargs'], **args['kwargs']) + if len(args) == 1 and 'kwargs' in args: + return cls(**args['kwargs']) + if len(args) == 1 and 'kargs' in args: + return cls(*args['kargs']) + + return cls(**args) + return cls(*args) + +
      [docs]def bind(parent_view, parent_wrapper, parent_field=None, init=[]): + class _anonymous_subwrapper(wrapper): + def __init__(self): + super().__init__(parent_view) + self._parent = parent_wrapper + self._field = parent_field + + @property + def raw(self): + if self._field is None: + return self._parent.raw + offset = self._parent.offset(self._field) + return self._parent.raw[offset:] + + @raw.setter + def raw(self, value): + if self._field is None: + self._parent.raw = value + return + parent = self._parent.raw + offset = self._parent.offset(self._field) + parent = parent[:offset] + value + parent[offset + len(value):] + self._parent.raw = parent + + typename = str(parent_field) + if typename is not None: + if not typename.isidentifier(): + try: + if int(typename) >= 0: + typename = 'idx_{}'.format(typename) + except ValueError: + pass + + if typename.isidentifier(): + _anonymous_subwrapper.__name__ = '{}'.format(typename) + + _anonymous_subwrapper.__qualname__ = '{}.{}'.format( + parent_wrapper.__class__.__qualname__, _anonymous_subwrapper.__name__) + return _forward_init(_anonymous_subwrapper, init)
      + +
      [docs]def like(parent_view, typename=None, init=None): + if typename is not None and not typename.isidentifier(): + raise ValueError('Typename {} is not an identifier'.format(typename)) + + class _anonymous_wrapper(wrapper): + def __init__(self, raw): + super().__init__(parent_view) + self._raw = raw + + @property + def raw(self): + return self._raw + + @raw.setter + def raw(self, value): + self._raw = value + + if typename is not None: + _anonymous_wrapper.__qualname__ = 'wrapper.{}'.format(typename) + _anonymous_wrapper.__name__ = '{}_wrapper'.format(typename) + + return _forward_init(_anonymous_wrapper, init)
      + +
      [docs]def cache(base, typename=None, init=None): + if typename is not None and not typename.isidentifier(): + raise ValueError('Typename {} is not an identifier'.format(typename)) + + if not inspect.isclass(base): + raise TypeError('Expect a class: {} is not.'.format(base)) + + if issubclass(base, _enum.Enum): + raise TypeError('Use view.enum(cached=True) to cache enumerations.') + + if iscached(base): + raise TypeError('Class {} already cached.'.format(base)) + + class _anonymous_cached_view(base): + def __init__(self, *kargs, **kwargs): + '''See help({}.__init__) for an accurate signature.'''.format( + base.__qualname__) + + base.__init__(self, *kargs, **kwargs) + self._cache = threading.local() + self._cache.value = None + + def cache(self): + if not self.cached(): + raise RuntimeError('Bounded value unknown at runtime: ' + + 'Have you called .value() of parent view yet?') + return self._cache.value + + def cached(self): + return self._cache.value is not None + + def value(self, payload=b'', field=None): + self._cache.value = super().value(payload) + return self.cache() + + def write(self, payload=b'', *kargs, **kwargs): + payload = super().write(payload, *kargs, **kwargs) + self._cache.value = super().value(payload) + return payload + + _anonymous_cached_view.__qualname__ = 'cached.{}'.format(base.__name__) + _anonymous_cached_view.__name__ = 'cached_{}'.format(base.__name__) + if typename is not None: + _anonymous_cached_view.__name__ = typename + + return _forward_init(_anonymous_cached_view, init)
      + +
      [docs]def isview(item): + if not hasattr(item, 'width') or not inspect.ismethod(item.width): + return False + if not hasattr(item, 'valid') or not inspect.ismethod(item.valid): + return False + if not hasattr(item, 'value') or not inspect.ismethod(item.value): + return False + if not hasattr(item, 'write') or not inspect.ismethod(item.write): + return False + return True
      + +
      [docs]def iscached(item): + if not hasattr(item, 'cache') or not inspect.ismethod(item.cache): + return False + if not hasattr(item, 'cached') or not inspect.ismethod(item.cache): + return False + return True
      + +
      [docs]def iscomposite(item): + if isinstance(item, union): + if not item.union_tag.cached(): + return True + return isinstance(item.active_view, composite) + return isinstance(item, composite)
      + +
      [docs]class ip_address(data): + def __init__(self, *, version): + if version not in [4, 6]: + raise ValueError('Invalid IP version: {}'.format(version)) + + if version == 4: + self._ip_type = ipaddress.IPv4Address + super().__init__(4) + else: + self._ip_type = ipaddress.IPv6Address + super().__init__(16) + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + try: + self.value(payload) + return True + except ipaddress.AddressValueError: + return False
      + +
      [docs] def value(self, payload=b'', field=None): + value = super().value(payload) + return self._ip_type(value)
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + if not isinstance(value, self._ip_type): + value = self._ip_type(value) + return super().write(payload, value=value.packed)
      + +
      [docs]class codec(data): + @staticmethod + def _is_text_encoding(c): + try: + codecs.encode(b'', c) + return False + except BaseException: + pass + + try: + if not isinstance(codecs.encode('', c), bytes): + return False + return True + except BaseException: + return False + + @staticmethod + def _is_bytes_mapping(c): + if codec._is_text_encoding(c): + return False + + try: + if not isinstance(codecs.encode(b'', c), bytes): + return False + return True + except BaseException: + return False + + @staticmethod + def _is_text_mapping(c): + return c in ['rot_13', 'rot13'] + + @staticmethod + def _build_encode_chain(codecs): + encode_chain = [] + is_input_str = True + for c in codecs: + if codec._is_text_encoding(c): + encode_chain.append((is_input_str, c)) + is_input_str = bool(not is_input_str) + continue + if codec._is_text_encoding(c) and not is_input_str: + raise ValueError( + 'Got bytes for {} in chain: {}'.format(c, codecs)) + if codec._is_bytes_mapping(c) and is_input_str: + raise ValueError( + 'Got str for {} in chain: {}'.format(c, codecs)) + encode_chain.append((True, c)) + + if is_input_str: + raise ValueError( + 'Chain encodes to str instead of bytes: {}'.format(codecs)) + return encode_chain + + @staticmethod + def _build_decode_chain(codecs): + decode_chain = [] + is_input_str = False + for c in reversed(codecs): + if codec._is_text_encoding(c): + decode_chain.append((is_input_str, c)) + is_input_str = bool(not is_input_str) + continue + if codec._is_text_encoding(c) and not is_input_str: + raise ValueError( + 'Got bytes for {} in chain: {}'.format(c, codecs)) + if codec._is_bytes_mapping(c) and is_input_str: + raise ValueError( + 'Got str for {} in chain: {}'.format(c, codecs)) + decode_chain.append((False, c)) + + if not is_input_str: + raise ValueError( + 'Chain decodes to bytes instead of str: {}'.format(codecs)) + return decode_chain + + def __init__(self, *codecs, size): + self.encode_chain = codec._build_encode_chain(codecs) + self.decode_chain = codec._build_decode_chain(codecs) + super().__init__(size) + +
      [docs] def valid(self, payload=b''): + if not super().valid(payload): + return False + + try: + self.value(payload) + return True + except ValueError: + return False
      + +
      [docs] def value(self, payload=b'', field=None): + value = super().value(payload) + for use_encode, c in self.decode_chain: + if use_encode: + value = codecs.encode(value, c) + else: + value = codecs.decode(value, c) + return value
      + +
      [docs] def write(self, payload=b'', value=None, **kwargs): + for use_encode, c in self.encode_chain: + if use_encode: + value = codecs.encode(value, c) + else: + value = codecs.decode(value, c) + return super().write(payload, value=value)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/consensus.html b/docs/source/_build/html/_modules/lightnion/consensus.html new file mode 100644 index 0000000..8e9d3c0 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/consensus.html @@ -0,0 +1,1092 @@ + + + + + + + + + + + lightnion.consensus — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.consensus

      +from base64 import b64encode, b64decode
      +import datetime
      +import binascii
      +import time
      +import os
      +import re
      +
      +import urllib.request
      +
      +import lightnion as lnn
      +from tools.keys import get_signing_keys_info
      +
      +
      +# TODO: remove extra (useless) checks/exceptions within this file
      +
      +
      [docs]def scrap(consensus, end_of_field): + """ + Consume lines upon matching a criterion. + + Returns (consensus-without-first-line, first-line) + if end_of_field(first-line) returns True, + else returns (consensus-with-first-line, None) + + :param bytes consensus: input which first line may be consumed + :param function end_of_field: passed a line, returns True when no match + + :returns: a tuple (updated-consensus, next-field-or-None) + """ + if b'\n' not in consensus: + return consensus, None + + line, remaining = consensus.split(b'\n', 1) + if end_of_field(line): + return consensus, None + return remaining, line
      + + +
      [docs]def scrap_signature(consensus, fix=b'SIGNATURE'): + """ + Consume a signature field if there is one to consume. + + :param bytes consensus: input which may start with a signature. + + :returns: a tuple (updated-consensus, signature-or-None) + """ + if not consensus.startswith(b'-----BEGIN ' + fix + b'-----'): + return consensus, None + + lines = consensus.split(b'\n', 22) # fits 0-1024o (for 256o sig) + try: + idx_endsig = lines.index(b'-----END ' + fix + b'-----') + except ValueError: + return consensus, None + + remaining = b'\n'.join(lines[idx_endsig + 1:]) + content = b''.join(lines[1:idx_endsig]) + return remaining, content
      + + +
      [docs]def parse_address(address): + """ + Take a Tor-formatted v4 or v6 IP address with a port, returns a + cleaned-up version. + + :param str address: input address to be processed + + :returns: a tuple (address, port, guessed-type) where port is an + integer and guessed-type is 4 or 6 (IPv4 or IPv6). + """ + address = address.split(':') + address, port = ':'.join(address[:-1]), address[-1] + + guessed_type = 4 + if address.startswith('['): + address = address[1:] + guessed_type = 6 + if address.endswith(']') or guessed_type == 6: + if not address.endswith(']'): + raise RuntimeError( + 'Seems like an invalid IPv6: {}'.format(address)) + address = address[:-1] + guessed_type = 6 + if address.count(':') > 3: + if not guessed_type == 6: + raise RuntimeError( + 'Seems like an very odd IPv6: {}'.format(address)) + guessed_type = 6 + + return address, int(port), guessed_type
      + + +
      [docs]def parse_range_once(value, expand=True): + """ + Take Tor-formatted ranges, then returns it as a list of integers if + expanded or a mix of integers and ranges as [low, high] tuples. + + For example, we use it to parse "p" fields: + https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L2322 + + :param str value: input value to be processed + :param bool expand: do we expand a range as integers? (default: True) + + :returns: a list of integers or a mix of integers and range list/tuples + """ + value = value.split(',') + subvalues = [] + for subvalue in value: + if '-' in subvalue: + low, high = [int(v) for v in subvalue.split('-')] + if expand: + subvalues += list(range(low, high + 1)) + elif low == high - 1: + subvalues += [low, high] + else: + subvalues += [[low, high]] + else: + subvalues += [int(subvalue)] + return subvalues
      + + +
      [docs]def parse_ranges(ranges, expand=True): + """ + Take Tor-formatted named ranges, then returns a keyword-based + dictionary of list of integers or mix of integers and range tuples (as + returned by parse_range_once), expanded or not. + + For example, we use it to parse "recommended-client-protocols" fields: + https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L780 + + :param str ranges: input ranges to be processed + :param bool expand: do we expand ranges as integers? (default: True) + + :returns: a dictionary with (range-name, range-content) items + """ + pairs = ranges.split(' ') + content = {} + for key, value in [pair.split('=') for pair in pairs if '=' in pair]: + content[key] = parse_range_once(value, expand) + return content
      + + +
      [docs]def parse_params(params): + """ + Take Tor-formatted parameters, then returns a keyword-based dictionary + of integers. + + For example, we use it to parse "params" fields: + https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L1820 + + :param str params: input params to be processed + + :returns: a dictionary with (param-name, param-integer-value) items + """ + pairs = params.split(' ') + content = dict() + for key, value in [pair.split('=') for pair in pairs]: + content[key] = int(value) + return content
      + + +
      [docs]def parse_fingerprint(payload): + asbytes = bytes.fromhex(payload) + fingers = asbytes.hex().upper() + fingers = ' '.join([fingers[i:i + 4] for i in range(0, len(fingers), 4)]) + if not fingers == payload: + raise RuntimeError( + 'Fingerprint not conform: {} vs {}'.format(fingers, payload)) + return fingers
      + + +
      [docs]def parse_base64(payload, decode=False): + """ + Take an input base64 string, decode it, re-encode it. + + For example, we use it to parse "shared-rand-current-value" fields: + https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L2069 + + :param str payload: input base64-encoded data + :param bool decode: return raw bytes (default: False) + + :returns: a base64-encoded string equivalent to the input + """ + decoded = b64decode(payload + '====') + value = str(b64encode(decoded), 'utf8') + + if not payload[-2:].count('=') == value[-2:].count('='): + value = value.rstrip('=') + '=' * payload[-2:].count('=') + + if not value == payload: + raise RuntimeError('Invalid base64 encoding: {} vs {}'.format( + value, payload)) + + if decode: + return decoded + + return value
      + + +
      [docs]def parse_time(timedate): + """ + Take a Tor-formatted (Y-m-d H:M:S) time, parse it, then returns the + corresponding date, time and datetime object. This function assumes + that the given time uses the UTC timezone – as it's the timezone used + into Tor consensuses. + + :param str timedate: input time and date to be parsed + + :returns: a tuple (date-str, time-str, datetime-object) + """ + when = datetime.datetime.strptime(timedate, '%Y-%m-%d %H:%M:%S') + + # convert to UTC-aware datetime object + when = datetime.datetime(*when.timetuple()[:6], + tzinfo=datetime.timezone.utc) + return (when.strftime('%Y-%m-%d'), when.strftime('%H:%M:%S'), when)
      + + +
      [docs]def consume_http(consensus): + """ + Consume HTTP headers if present, then returns the remaining input to be + further processed and a set of headers (or None, if none present). + + :param str consensus: input to be processed + + :returns: a tuple (remaining-input, headers-or-None) + """ + + def end_of_field(line): + return line[-1:] != b'\r' + + fields = dict(headers=dict()) + valid = False + while True: + consensus, header = scrap(consensus, end_of_field) + if header is None: + return consensus, fields if valid else None + + valid = True + if b' ' not in header: + continue + + header = header[:-1] + try: + header = str(header, 'utf8') + except Exception: + continue + + if header.startswith('HTTP/'): + version, fields['code'], _ = header.split(' ', 2) + fields['version'] = float(version.split('/', 1)[1]) + + keyword, content = header.split(' ', 1) + if keyword[-1:] == ':': + fields['headers'][keyword[:-1]] = content
      + + +
      [docs]def consume_headers(consensus, flavor='unflavored'): + """ + Consume consensus headers if present, then returns the remaining input + to be further processed and a set of headers (or None, if none + present). + + Will consume the following fields: + - network-status-version + - vote-status + - consensus-method + - valid-after + - fresh-until + - valid-until + - voting-delay + - client-versions + - server-versions + - known-flags + - recommended-client-protocols + - recommended-relay-protocols + - required-client-protocols + - required-relay-protocols + - params + - shared-rand-previous-value + - shared-rand-current-value + + :param str consensus: input to be processed + :param str flavor: consensus flavor ('unflavored' or 'microdesc') + + :returns: a tuple (remaining-input, headers-or-None) + """ + if flavor not in ['unflavored', 'microdesc']: + raise NotImplementedError( + 'Consensus flavor "{}" not supported.'.format(flavor)) + + whitelist = [ + b'network-status-version', b'vote-status', b'consensus-method', + b'valid-after', b'fresh-until', b'valid-until', b'voting-delay', + b'client-versions', b'server-versions', b'known-flags', + b'recommended-client-protocols', b'recommended-relay-protocols', + b'required-client-protocols', b'required-relay-protocols', b'params', + b'shared-rand-previous-value', b'shared-rand-current-value'] + + def end_of_field(line): + if b' ' not in line: + return True + keyword, _ = line.split(b' ', 1) + return keyword not in whitelist + + fields = dict() + valid = False + while True: + consensus, header = scrap(consensus, end_of_field) + if header is None: + return consensus, fields if valid else None + + valid = True + if b' ' not in header: + continue + + try: + header = str(header, 'utf8') + except: + continue + + keyword, content = header.split(' ', 1) + if keyword == 'network-status-version': + content = content.split(' ', 1) + if len(content) == 1: + content.append('unflavored') + version, variant = content + content = dict(version=int(version), flavor=variant) + + if not len(fields) == 0: + raise RuntimeError('Expecting {} as first field: {}'.format( + keyword, content)) + if not content['version'] >= 3: + raise RuntimeError('Expecting {} version >= 3 here: {}'.format( + keyword, content)) + if not content['flavor'] == flavor: + raise RuntimeError('Unmatched {} flavor {} here: {}'.format( + keyword, flavor, content)) + + if keyword == 'consensus-method': + content = int(content) + + if not content >= 26: + raise RuntimeError( + 'Consensus version >= 26 required: {}'.format(content)) + + if keyword in ['valid-after', 'fresh-until', 'valid-until']: + date, time_parsed, when = parse_time(content) + content = dict(date=date, time=time_parsed, stamp=when.timestamp()) + + if keyword == 'valid-after': + if not time.time() > content['stamp']: + raise RuntimeError('{} not yet valid! {}'.format( + keyword, content)) # valid-after + + if keyword == 'fresh-until': + if not content['stamp'] > fields['valid-after']['stamp']: + raise RuntimeError('{} not fresh! {}'.format( + keyword, content)) # fresh-until + + if keyword == 'valid-until': + if not time.time() < content['stamp']: + raise RuntimeError('{} no more valid! {}'.format( + keyword, content)) # valid-until + + if keyword == 'voting-delay': + vote, dist = content.split(' ', 1) + content = dict(vote=int(vote), dist=int(dist)) + + if keyword in ['client-versions', 'server-versions']: + content = content.split(',') + + if keyword == 'known-flags': + content = content.split(' ') + + if keyword.startswith(('recommended', 'required')): + content = parse_ranges(content) + + if keyword == 'params': + content = parse_params(content) + + if keyword.startswith('shared-rand'): + reveals, value = content.split(' ') + + value = parse_base64(value) + content = {'NumReveals': int(reveals), 'Value': value} + + if not content['NumReveals'] >= 0: + raise RuntimeError('{} must be >= 0 here: {}'.format( + keyword, content)) + + fields[keyword] = content
      + + +
      [docs]def consume_dir_sources(consensus): + """ + Consume directory source listing if present, then returns the remaining + input to be further processed and a set of directory sources (or None, + if none present). + + Will consume the following fields: + - dir-source + - contact + - vote-digest + + :param str consensus: input to be processed + + :returns: a tuple (remaining-input, headers-or-None) + """ + whitelist = [b'dir-source', b'contact', b'vote-digest'] + + def end_of_field(line): + if b' ' not in line: + return True + keyword, _ = line.split(b' ', 1) + return keyword not in whitelist + + fields = [] + valid = False + while True: + consensus, header = scrap(consensus, end_of_field) + if header is None: + if not valid: + return consensus, None + break + + valid = True + if b' ' not in header: + continue + + try: + header = str(header, 'utf8') + except: + continue + + keyword, content = header.split(' ', 1) + if keyword == 'vote-digest': + value = bytes.fromhex(content).hex() + if not value.lower() == content.lower(): + raise RuntimeError('Unmatched {} here: {} {}'.format( + keyword, value, content)) + content = value + + if keyword == 'dir-source': + nickname, identity, hostname, address, dirport, orport = ( + content.split(' ', 5)) + + value = bytes.fromhex(identity).hex() + if not value.lower() == identity.lower(): + raise RuntimeError('Unmatched {} here: {} {}'.format( + keyword, value, content)) + identity = value + + content = dict(nickname=nickname, identity=identity, + hostname=hostname, address=address, dirport=int(dirport), + orport=int(orport)) + + if not 0 < content['dirport'] < 65536: + raise RuntimeError('Invalid dirport here: {}'.format(content)) + if not 0 < content['orport'] < 65536: + raise RuntimeError('Invalid orport here: {}'.format(content)) + + if keyword != 'dir-source' and fields[-1][0] == 'dir-source': + if not (keyword not in fields[-1][1]): + raise RuntimeError( + 'Unexpected {} with: {}'.format(keyword, fields[-1])) + assert keyword not in fields[-1][1] + fields[-1][1][keyword] = content + continue + + fields.append((keyword, content)) + + full_entries_count = len([v for k, v in fields if k == 'dir-source']) + + if not full_entries_count == len(fields): + raise RuntimeError('Incomplete entry or corrupted?') + + if full_entries_count == len(fields): + fields = [v for k, v in fields] + + return consensus, fields
      + + +
      [docs]def consume_routers(consensus, flavor='unflavored'): + """ + Consume router listing if present, then returns the remaining input to + be further processed and a set of routers (or None, if none present). + + Will consume the following fields: + - r + - m + - s + - v + - pr + - w + - p (unflavored only) + - a (unflavored only) + + :param str consensus: input to be processed + :param str flavor: consensus flavor ('unflavored' or 'microdesc') + + :returns: a tuple (remaining-input, headers-or-None) + """ + if flavor not in ['unflavored', 'microdesc']: + raise NotImplementedError( + 'Consensus flavor "{}" not supported.'.format(flavor)) + + # TODO: check if 'a' fields in microdesc consensus are still a thing + if flavor == 'unflavored': + whitelist = [b'r', b'm', b's', b'v', b'pr', b'w', b'p', b'a'] + elif flavor == 'microdesc': + whitelist = [b'r', b'm', b's', b'v', b'pr', b'w', b'a'] + + aliases = dict(m='micro-digest', pr='protocols', s='flags', v='version', + p='exit-policy', a='or-address') + + def end_of_field(line): + if b' ' not in line: + return True + keyword, _ = line.split(b' ', 1) + return keyword not in whitelist + + fields = [] + valid = False + while True: + consensus, header = scrap(consensus, end_of_field) + if header is None: + if not valid: + return consensus, None + break + + valid = True + if b' ' not in header: + continue + + try: + header = str(header, 'utf8') + except: + continue + + keyword, content = header.split(' ', 1) + if keyword == 'm': + content = parse_base64(content) + + if keyword == 's': + content = content.split(' ') + + if keyword == 'pr': + content = parse_ranges(content) + + if keyword == 'w': + content = parse_params(content) + + if keyword == 'p': + policy_type, portlist = content.split(' ') + if not policy_type in ['accept', 'reject']: + raise RuntimeError('Unknown policy: {}'.format(policy_type)) + + portlist = parse_range_once(portlist, expand=False) + content = {'type': policy_type, 'PortList': portlist} + + if keyword == 'a': + address, port, guessed_type = parse_address(content) + content = [{'ip': address, 'port': port, 'type': guessed_type}] + + if keyword == 'r' and flavor == 'unflavored': + (nickname, identity, digest, date, time, address, orport, + dirport) = content.split(' ', 7) + + digest = parse_base64(digest) + identity = parse_base64(identity) + date, time, when = parse_time(' '.join([date, time])) + + content = dict(nickname=nickname, identity=identity, digest=digest, + date=date, time=time, stamp=when.timestamp(), address=address, + dirport=int(dirport), orport=int(orport)) + + if not 0 <= content['dirport'] < 65536: + raise RuntimeError('Invalid dirport here: {}'.format(content)) + if not 0 < content['orport'] < 65536: + raise RuntimeError('Invalid orport here: {}'.format(content)) + + if keyword == 'r' and flavor == 'microdesc': + nickname, identity, date, time, address, orport, dirport = ( + content.split(' ', 6)) + + identity = parse_base64(identity) + date, time, when = parse_time(date + ' ' + time) + + content = dict(nickname=nickname, identity=identity, date=date, + time=time, stamp=when.timestamp(), address=address, + dirport=int(dirport), orport=int(orport)) + + if not 0 <= content['dirport'] < 65536: + raise RuntimeError('Invalid dirport here: {}'.format(content)) + if not 0 < content['orport'] < 65536: + raise RuntimeError('Invalid orport here: {}'.format(content)) + + if keyword != 'r' and fields[-1][0] == 'r': + if keyword in aliases: + keyword = aliases[keyword] + + if keyword == 'or-address' and keyword in fields[-1][1]: + content[0]['ignored'] = True + fields[-1][1]['or-address'] += content + continue + + if not (keyword not in fields[-1][1]): + raise RuntimeError('Unexpected {} with: {}'.format(keyword, + fields[-1])) + + fields[-1][1][keyword] = content + continue + + fields.append((keyword, content)) + + full_entries_count = len([v for k, v in fields if k == 'r']) + if not full_entries_count == len(fields): + raise RuntimeError('Invalid or corrupted entry?') + + if full_entries_count == len(fields): + fields = [v for k, v in fields] + + return consensus, fields
      + + + + + +
      [docs]def parse(consensus, flavor='unflavored'): + """ + Parse a raw consensus with the given flavor, then returns sanitized + entries as a python dictionary. + + :param str consensus: input to be processed + :param str flavor: consensus flavor ('unflavored' or 'microdesc') + + :returns: a python dictionary + """ + fields = dict(flavor=flavor) + + consensus, http = consume_http(consensus) + if http is not None: + fields['http'] = http + + consensus, headers = consume_headers(consensus, flavor) + if headers is not None: + fields['headers'] = headers + + consensus, dir_sources = consume_dir_sources(consensus) + if dir_sources is not None: + fields['dir-sources'] = dir_sources + + consensus, routers = consume_routers(consensus, flavor) + if routers is not None: + fields['routers'] = routers + + consensus, footer = consume_footer(consensus, flavor) + if footer is not None: + fields['footer'] = footer + + if not ('headers' in fields + and 'dir-sources' in fields + and 'routers' in fields + and 'footer' in fields): + raise RuntimeError('Missing entry: {}'.format(list(fields))) + + return fields, consensus
      + + +
      [docs]def extract_date(consensus, field): + """ + Retrieve the value from a date field as a datetime object. + """ + + pattern = re.compile('{} [^\n]+'.format(field)) + found = pattern.search(consensus) + + if found is None: + raise RuntimeError('Field {} not found in consensus.'.format(field)) + + date_s = consensus[found.start():found.end()] + date = datetime.datetime.strptime(date_s, '{} %Y-%m-%d %H:%M:%S'.format(field)) + date.replace(tzinfo=datetime.timezone.utc) + + return date
      + + +
      [docs]def extract_nodes_digests_unflavored(consensus_raw): + """Retrieve a list of the digests of all routers in the consensus. + """ + + # We retrieve the third fields of the lines looking like that: + #r VSIFskylab AD14gl4Llgnuz/Xk4FKXF3cuU8c 3VZwLdY0Et7vqUbqDdXg3WGGHCw 2020-01-12 23:47:04 104.218.63.73 443 80 + digests_raw = re.findall(r'^r [^ ]+ [^ ]+ ([^ ]+)', consensus_raw, re.MULTILINE) + digests_bytes = [b64decode(digest + '====') for digest in digests_raw] + + return digests_bytes
      + + +
      [docs]def extract_nodes_digests_micro(consensus_raw): + """Retrieve a list of the digests of all routers in the consensus. + """ + # We retrieve the third fields of the lines looking like that: + #m v7E0VcMnwVepVUh+j193lrbqbWOg26g9hXOBwSYv32I + digests_raw = re.findall(r'^m ([^\n]+)', consensus_raw, re.MULTILINE) + digests_bytes = [digest for digest in digests_raw] + + return digests_bytes
      + + +
      [docs]def download(state, flavor='microdesc', cache=True): + if flavor not in ['unflavored', 'microdesc']: + raise NotImplementedError( + 'Consensus flavor "{}" not supported.'.format(flavor)) + + if cache: + try: + return state, lnn.cache.consensus.get(flavor) + except BaseException: + pass + + endpoint = '/tor/status-vote/current/consensus' + if flavor == 'microdesc': + endpoint += '-microdesc' + + ip = '%s:%d'%('127.0.0.1',7000) #for real tor, change to 9051 + keys = get_signing_keys_info(ip) + state, cons = lnn.hop.directory_query(state, endpoint) + + cons_original = cons + cons, http = consume_http(cons) + + if flavor != 'microdesc': + if not lnn.signature.verify(cons.decode('utf-8'), keys): + raise RuntimeError('Consensus Verification Failed') + + consensus, remaining = parse(cons_original, flavor=flavor) + + if consensus is None or remaining is None or not len(remaining) == 0: + raise RuntimeError('Unable to parse downloaded consensus!') + + if cache: + lnn.cache.consensus.put(consensus) + + return state, consensus
      + + +
      [docs]def download_direct(hostname, port, flavor='microdesc'): + """Retrieve consensus via a direct HTTP connection. + :param hostname: host name of the node from which to retrieve the consensus. + :param port: port of the node from which to retrieve the consensus. + :param flavor: flavour of the consensus to retrieve. + :param cache: if the retrieved consensus should put in the cache. + """ + + if flavor not in ['unflavored', 'microdesc']: + raise NotImplementedError( + 'Consensus flavor "{}" not supported.'.format(flavor)) + + endpoint = 'consensus-microdesc' if flavor == 'microdesc' else 'consensus' + uri = 'http://%s:%d/tor/status-vote/current/%s' % (hostname, port, endpoint) + + res = urllib.request.urlopen(uri) + cons = res.read() + + ip = '%s:%d'%(hostname,port) + keys = get_signing_keys_info(ip) + + if flavor != 'microdesc': + if not lnn.signature.verify(cons.decode('utf-8'), keys): + raise RuntimeError('Consensus Verification Failed') + + consensus, remaining = parse(cons, flavor=flavor) + + if consensus is None or remaining is None or not len(remaining) == 0: + raise RuntimeError('Unable to parse downloaded consensus!') + + return consensus, keys
      + +
      [docs]def download_raw(hostname, port, flavor='unflavored'): + """Retrieve raw consensus via a direct HTTP connection. + :param hostname: host name of the node from which to retrieve the consensus. + :param port: port of the node from which to retrieve the consensus. + :param flavor: flavour of the consensus to retrieve. + """ + + if flavor not in ['unflavored', 'microdesc']: + raise NotImplementedError( + 'Consensus flavor "{}" not supported.'.format(flavor)) + + endpoint = 'consensus-microdesc' if flavor == 'microdesc' else 'consensus' + uri = 'http://%s:%d/tor/status-vote/current/%s' % (hostname, port, endpoint) + + res = urllib.request.urlopen(uri) + cons = res.read().decode('utf-8') + + return cons
      + +
      [docs]def load(file_name, cache=True): + """Load the consensus from a file + :param file_name: the name of the file in consensus_file + :param cache: if we cache the newly downloaded consensus + :return: the parsed consensus""" + + abs_path = "/vagrant/consensus_files/"+file_name + + if not os.path.exists(abs_path): + raise FileNotFoundError() + + if cache: + try: + return lnn.cache.consensus.get("unflavored") + except BaseException: + pass + + with open(abs_path, "r") as file: + answer = file.read() + + consensus, remaining = consume_routers(answer) + + if consensus is None or remaining is None or not len(remaining) == 0: + raise RuntimeError('Unable to parse downloaded consensus!') + + if cache: + lnn.cache.consensus.put(consensus) + + return consensus
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/constants.html b/docs/source/_build/html/_modules/lightnion/constants.html new file mode 100644 index 0000000..8d14d65 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/constants.html @@ -0,0 +1,207 @@ + + + + + + + + + + + lightnion.constants — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.constants

      +
      +key_len = 16 # (aes128 CTR IV=0)
      +hash_len = 20 # (sha1)
      +
      +payload_len = 509
      +full_cell_len = payload_len + 5
      +max_payload_len = 1024 * 1024 # (arbitrary, TODO: find a good one)
      +
      +
      [docs]class flow: + # 7.3. Circuit-level flow control +
      [docs] class circuit: + default = 1000 + lowlimit = 900 + increment = 100
      + + # 7.4. Stream-level flow control +
      [docs] class stream: + default = 500 + lowlimit = 450 + increment = 50
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/create.html b/docs/source/_build/html/_modules/lightnion/create.html new file mode 100644 index 0000000..b0c2581 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/create.html @@ -0,0 +1,467 @@ + + + + + + + + + + + lightnion.create — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.create

      +import collections
      +import base64
      +import queue
      +import time
      +import asyncio
      +import logging
      +
      +import nacl.public
      +
      +import lightnion as lnn
      +
      +
      [docs]class circuit(collections.namedtuple('circuit', ['id', 'material'])): + stream_windows = None # per-stream window (see onion._auto_sendme hack) + last_stream_id = 0 + destroyed = False + window = None # per-circuit window (see onion._auto_sendme hack) + reason = None + queue = None + +
      [docs] def put(self, payload): + return self.queue.put(payload)
      + +
      [docs] def get(self, block=True): + return self.queue.get(block=block)
      + + +
      [docs]async def fast_async(link): + """Use a CREATE_FAST cell to initiate a one-hop circuit. + + The expected transcript is: + + (... perform a proper link handshake here ...) + + Onion Proxy (client) Onion Router (server) + + / [ 7] :------ CREATE_FAST¹ -------> [8] + | [10] <------ CREATED_FAST -------: [9] + | + | Shared circuit key (via KDF-TOR²) + \ + + ¹The initiator picks an available circuit ID (CircID) with its most + significant bit equal to 1 (v4-or-higher links). + + :param link: a link.link object, see: link.initiate + + :returns: a onion.state object, see: onion.state + """ + + # Pick an available ID (link version > 3) + link.last_id += 1 + circuit_id = 0x80000000 + link.last_id + while circuit_id in link.circuits: + circuit_id += 1 + + # Sanity checks + try: + packed = lnn.cell.view.uint(4).write(value=circuit_id) + assert circuit_id == lnn.cell.view.uint(4).value(packed) + except (OverflowError, AssertionError): + link.last_id = 0 + raise RuntimeError('Erroneous circuit ID: {} ({})'.format( + circuit_id, packed)) + + # Send CREATE_FAST cell (contains OP material) + op_cell = lnn.cell.create_fast.pack(circuit_id) + await link.send_async(op_cell) + + # (register a dummy circuit first to reuse the circuit API) + dummy = circuit(circuit_id, None) + await link.register_async(dummy) + + # Receive CREATED_FAST cell (contains OR material and key confirmation) + try: + or_cell = lnn.cell.created_fast.cell(await link.get_async(dummy)) + except KeyError: + raise RuntimeError('Got DESTROY cell while creating circuit.') + + # (unregister the dummy circuit before validation/material confirmation) + await link.unregister_async(dummy) + if not or_cell.valid: + raise RuntimeError('Got invalid CREATED cell: {}'.format(or_cell.raw)) + + # Compute KDF-TOR on OP+OR materials + material = lnn.crypto.kdf_tor( + op_cell.create_fast.material + or_cell.created_fast.material) + + # Confirm shared derived material + if not material.key_hash == or_cell.created_fast.derivative: + raise RuntimeError( + 'Invalid CREATE_FAST, invalid KDF-TOR confirmation: '.format( + (material.key_hash, or_cell.created_fast.derivative))) + + # Register the real circuit + final = circuit(circuit_id, material) + await link.register_async(final) + + return lnn.onion.state(link, final)
      + + +
      [docs]def fast(link): + """Use a CREATE_FAST cell to initiate a one-hop circuit. + + The expected transcript is: + + (... perform a proper link handshake here ...) + + Onion Proxy (client) Onion Router (server) + + / [ 7] :------ CREATE_FAST¹ -------> [8] + | [10] <------ CREATED_FAST -------: [9] + | + | Shared circuit key (via KDF-TOR²) + \ + + ¹The initiator picks an available circuit ID (CircID) with its most + significant bit equal to 1 (v4-or-higher links). + + :param link: a link.link object, see: link.initiate + + :returns: a onion.state object, see: onion.state + """ + + # Pick an available ID (link version > 3) + link.last_id += 1 + circuit_id = 0x80000000 + link.last_id + while circuit_id in link.circuits: + circuit_id += 1 + + # Sanity checks + try: + packed = lnn.cell.view.uint(4).write(value=circuit_id) + assert circuit_id == lnn.cell.view.uint(4).value(packed) + except (OverflowError, AssertionError): + link.last_id = 0 + raise RuntimeError('Erroneous circuit ID: {} ({})'.format( + circuit_id, packed)) + + # Send CREATE_FAST cell (contains OP material) + op_cell = lnn.cell.create_fast.pack(circuit_id) + link.send(op_cell) + + # (register a dummy circuit first to reuse the circuit API) + dummy = circuit(circuit_id, None) + link.register(dummy) + + # Receive CREATED_FAST cell (contains OR material and key confirmation) + try: + or_cell = lnn.cell.created_fast.cell(link.get(dummy)) + except KeyError: + raise RuntimeError('Got DESTROY cell while creating circuit.') + + # (unregister the dummy circuit before validation/material confirmation) + link.unregister(dummy) + if not or_cell.valid: + raise RuntimeError('Got invalid CREATED cell: {}'.format(or_cell.raw)) + + # Compute KDF-TOR on OP+OR materials + material = lnn.crypto.kdf_tor( + op_cell.create_fast.material + or_cell.created_fast.material) + + # Confirm shared derived material + if not material.key_hash == or_cell.created_fast.derivative: + raise RuntimeError( + 'Invalid CREATE_FAST, invalid KDF-TOR confirmation: '.format( + (material.key_hash, or_cell.created_fast.derivative))) + + # Register the real circuit + final = circuit(circuit_id, material) + link.register(final) + + return lnn.onion.state(link, final)
      + + +
      [docs]def ntor_raw(link, payload, timeout=None): + # Pick an available ID (link version > 3) + link.last_id += 1 + circuit_id = 0x80000000 + link.last_id + while circuit_id in link.circuits: + circuit_id += 1 + + # Sanity checks + try: + packed = lnn.cell.view.uint(4).write(value=circuit_id) + assert circuit_id == lnn.cell.view.uint(4).value(packed) + except (OverflowError, AssertionError): + link.last_id = 0 + raise RuntimeError('Erroneous circuit ID: {} ({})'.format( + circuit_id, packed)) + + # Build a CREATE2 cell containing this first handshake part + handshake = lnn.cell.create2.pack(circuit_id, payload) + + # Change: Instead, the handshake data is send to the client with the handshake data. + return circuit_id, lnn.cell.pad(handshake)
      + + +
      [docs]def ntor_raw2(circuit_id, payload): + + # Build a CREATE2 cell containing this first handshake part + handshake = lnn.cell.create2.pack(circuit_id, payload) + + # The handshake data is send to the client. + return lnn.cell.pad(handshake)
      + + +# Was in the method above, before. +
      [docs]def ntor_handshake(link, circuit_id, handshake, timeout=None): + link.send(handshake) + + # (register a dummy circuit first to reuse the circuit API) + dummy = circuit(circuit_id, None) + link.register(dummy) + + # Receive answers + cell = None + try: + if timeout is None: + cell = lnn.cell.created2.cell(link.get(dummy)) + else: + for _ in range(10): + try: + cell = lnn.cell.created2.cell( + link.get(dummy, block=False)) + break + except queue.Empty: + time.sleep(timeout / 10) + if cell is None: + link.unregister(dummy) + raise RuntimeError('Got timeout while creating circuit.') + except KeyError: + raise RuntimeError('Got DESTROY cell while creating circuit.') + + # (unregister the dummy circuit before validation/material confirmation) + link.unregister(dummy) + if not cell.valid: + raise RuntimeError('Got invalid CREATED2 cell: {}'.format(cell.raw)) + + return cell.created2.data
      + + +
      [docs]async def ntor_async(link, descriptor): + identity = base64.b64decode(descriptor['router']['identity'] + '====') + onion_key = base64.b64decode(descriptor['ntor-onion-key'] + '====') + + # Perform the first part of our handshake + ephemeral_key, payload = lnn.crypto.ntor.hand(identity, onion_key) + + circuit_id, payload = await ntor_raw_async(link, payload) + + # Perform the last part of our handshake + material = lnn.crypto.ntor.shake(ephemeral_key, payload, + identity, onion_key, length=92) + + # Register the real circuit + final = circuit(circuit_id, lnn.crypto.ntor.kdf(material)) + await link.register_async(final) + + return lnn.onion.state(link, final)
      + + +
      [docs]def ntor(link, descriptor): + identity = base64.b64decode(descriptor['router']['identity'] + '====') + onion_key = base64.b64decode(descriptor['ntor-onion-key'] + '====') + + # Perform the first part of our handshake + ephemeral_key, payload = lnn.crypto.ntor.hand(identity, onion_key) + + circuit_id, handshake = ntor_raw(link, payload) + payload = ntor_handshake(link, circuit_id, handshake) + + # Perform the last part of our handshake + material = lnn.crypto.ntor.shake(ephemeral_key, payload, + identity, onion_key, length=92) + + # Register the real circuit + final = circuit(circuit_id, lnn.crypto.ntor.kdf(material)) + link.register(final) + + return lnn.onion.state(link, final)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/crypto/kdf.html b/docs/source/_build/html/_modules/lightnion/crypto/kdf.html new file mode 100644 index 0000000..4a07861 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/crypto/kdf.html @@ -0,0 +1,209 @@ + + + + + + + + + + + lightnion.crypto.kdf — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.crypto.kdf

      +import hashlib
      +import collections
      +
      +from .. import constants
      +
      +
      [docs]class kdf_tor: + def __init__(self, raw_material): + counter = 0 + derived = bytes() + while len(derived) < constants.key_len * 2 + constants.hash_len * 3: + shasum = hashlib.sha1(raw_material + counter.to_bytes(1, 'big')) + derived += shasum.digest() + counter += 1 + + h = constants.hash_len + k = constants.key_len + + self.key_hash = derived[:h] + self.forward_digest = derived[h:h*2] + self.backward_digest = derived[h*2:h*3] + self.forward_key = derived[h*3:h*3+k] + self.backward_key = derived[h*3+k:h*3+k*2]
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/crypto/ntor.html b/docs/source/_build/html/_modules/lightnion/crypto/ntor.html new file mode 100644 index 0000000..40d2768 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/crypto/ntor.html @@ -0,0 +1,356 @@ + + + + + + + + + + + lightnion.crypto.ntor — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.crypto.ntor

      +import nacl.bindings
      +import nacl.public
      +import nacl.hash
      +
      +from .. import constants
      +
      +x25519_keylen = 32
      +sha256_outlen = 32
      +sha256_blklen = 64
      +
      +protoid = b'ntor-curve25519-sha256-1'
      +tweaks = dict(
      +    expand=protoid+b':key_expand',
      +    verify=protoid+b':verify',
      +    server=protoid+b'Server',
      +    key=protoid+b':key_extract',
      +    mac=protoid+b':mac')
      +
      +
      [docs]class hmac: + prf = lambda data: nacl.hash.sha256(data, encoder=nacl.encoding.RawEncoder) + block_size = sha256_blklen + output_size = sha256_outlen + +
      [docs] @staticmethod + def digest(key, message): + assert isinstance(key, bytes) and isinstance(message, bytes) + + if len(key) > hmac.block_size: + key = hmac.prf(key) + if len(key) < hmac.block_size: + key = key.ljust(hmac.block_size, b'\x00') + + outer_key = bytes([k ^ 0x5c for k in key]) + inner_key = bytes([k ^ 0x36 for k in key]) + + return hmac.prf(outer_key + hmac.prf(inner_key + message))
      + +
      [docs] @staticmethod + def tweaked(tweak): + tweak = tweaks[tweak] + def _hash(data): + return hmac.digest(tweak, data) + return _hash
      + +h_verify = hmac.tweaked('verify') +h_mac = hmac.tweaked('mac') + +
      [docs]class kdf: +
      [docs] @staticmethod + def rfc5869(material, salt, context, length): + key = hmac.digest(salt, material) + + n = (length // hmac.output_size) + 1 + output = b'' + previous = b'' + for idx in range(1, n + 1): + t_idx = previous + context + idx.to_bytes(1, byteorder='big') + t_idx = hmac.digest(key, t_idx) + + output += t_idx + previous = t_idx + return output[:length]
      + +
      [docs] @staticmethod + def ntor(material, length): + return kdf.rfc5869(material, tweaks['key'], tweaks['expand'], length)
      + + def __init__(self, material): + width = constants.key_len * 2 + constants.hash_len * 3 + if not len(material) == width: + raise RuntimeError( + 'Unexpected length: {} (need {})'.format(len(material), width)) + + h = constants.hash_len + k = constants.key_len + + self.key_hash = material[h*2+k*2:] + self.forward_digest = material[:h] + self.backward_digest = material[h:h*2] + self.forward_key = material[h*2:h*2+k] + self.backward_key = material[h*2+k:h*2+k*2]
      + +
      [docs]def hand(identity, onion_key): + client_keys = nacl.public.PrivateKey.generate() + message = identity + onion_key + bytes(client_keys.public_key) + + assert len(message) == constants.hash_len + x25519_keylen * 2 + return client_keys, message
      + +
      [docs]def server(server_keys, identity, message, length): + assert len(message) == constants.hash_len + x25519_keylen * 2 + + if identity != message[:20]: + return None + + if bytes(server_keys.public_key) != message[20:52]: + return None + + client_pubkey = nacl.public.PublicKey(message[52:]) + ephemeral_key = nacl.public.PrivateKey.generate() + + exp_share = nacl.bindings.crypto_scalarmult( + bytes(ephemeral_key), bytes(client_pubkey)) + exp_onion = nacl.bindings.crypto_scalarmult( + bytes(server_keys), bytes(client_pubkey)) + + if sum(exp_share) == 0 or sum(exp_onion) == 0: + return None + + secret_input = (exp_share + exp_onion + identity + + bytes(server_keys.public_key) + + bytes(client_pubkey) + + bytes(ephemeral_key.public_key) + + protoid) + verify = h_verify(secret_input) + + auth_input = (verify + identity + + bytes(server_keys.public_key) + + bytes(ephemeral_key.public_key) + + bytes(client_pubkey) + + tweaks['server']) + message = bytes(ephemeral_key.public_key) + h_mac(auth_input) + + return kdf.ntor(secret_input, length), message
      + +
      [docs]def shake(client_keys, message, identity, onion_key, length): + assert len(message) == x25519_keylen + sha256_outlen + + server_pubkey = nacl.public.PublicKey(message[:x25519_keylen]) + server_auth = message[x25519_keylen:] + + exp_share = nacl.bindings.crypto_scalarmult( + bytes(client_keys), bytes(server_pubkey)) + exp_onion = nacl.bindings.crypto_scalarmult( + bytes(client_keys), bytes(onion_key)) + + if sum(exp_share) == 0 or sum(exp_onion) == 0: + return None + + secret_input = (exp_share + exp_onion + identity + + bytes(onion_key) + + bytes(client_keys.public_key) + + bytes(server_pubkey) + + protoid) + verify = h_verify(secret_input) + + auth_input = (verify + identity + + bytes(onion_key) + + bytes(server_pubkey) + + bytes(client_keys.public_key) + + tweaks['server']) + + if h_mac(auth_input) != server_auth: + return None + + return kdf.ntor(secret_input, length)
      + +def _selfshake(length): + import os + server_keys = nacl.public.PrivateKey.generate() + onion_key = bytes(server_keys.public_key) + identity = os.urandom(constants.hash_len) + + client_keys, message = hand(identity, onion_key) + shared, message = server(server_keys, identity, message, length) + assert shared == shake(client_keys, message, identity, onion_key, length) + + assert len(shared) == length + return shared +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/descriptors.html b/docs/source/_build/html/_modules/lightnion/descriptors.html new file mode 100644 index 0000000..2492b2b --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/descriptors.html @@ -0,0 +1,855 @@ + + + + + + + + + + + lightnion.descriptors — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.descriptors

      +import base64
      +import hashlib
      +import logging
      +import urllib.request
      +
      +import lightnion as lnn
      +from lightnion import consensus
      +
      +
      [docs]def compute_descriptor_digest(fields, descriptors, entry, flavor): + """ + (details of the parser – private API) + + Plugs into our consumer to compute extra "digest" fields that expose + the (micro-)descriptor's (micro-)digest, enabling us to easily fetch + associated entries within a consensus. + + :param list fields: "fields" accumulator used by the consumer + :param bytes descriptors: remaining input to be parsed by the consumer + :param bytes entry: last line being parsed by the consumer + :param str flavor: flavor used by the consumer + + :returns: updated (or not) fields accumulator + """ + + if flavor == 'unflavored': + digest_name = 'digest' + pivot_field = 'router' + starts_hash = b'router ' + ends_hasher = b'router-signature' + base_offset = 1 + base_legacy = 0 + shalgorithm = hashlib.sha1 + # https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L602 + else: + digest_name = 'micro-digest' + pivot_field = 'onion-key' + starts_hash = b'onion-key' + ends_hasher = b'id ' + base_offset = 7 + 1 + 43 + 1 # 'ed25519 [identity]\n' + base_legacy = 7 + 1 + 27 + 1 # 'rsa1024 [identity]\n' + shalgorithm = hashlib.sha256 + # https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L3202 + + # 1. check if we're starting to parse a fresh entry before computing digest + if digest_name not in fields[-1] or ( + entry.startswith(starts_hash) and pivot_field in fields[-1]): + if pivot_field in fields[-1]: + fields.append(dict()) + + # 1.5 (extra sanity checks: double-check that we have what we need) + if not entry.startswith(starts_hash): + raise RuntimeError('Expecting {} to start the payload: {}'.format( + starts_hash, entry)) + if not ends_hasher in descriptors: + raise RuntimeError( + 'Expecting {} within: {}'.format(ends_hasher, descriptors)) + + try: + # 2. compute the offset to the ends what goes into the hash + sigoffset = descriptors.index(ends_hasher) + + # TODO: better support? + sigoffset += len(ends_hasher) + base_offset + if b'rsa1024' in descriptors[:sigoffset]: + sigoffset -= base_offset + sigoffset += base_legacy + + # 3. rebuild the original (including its first line being parsed) + full_desc = entry + b'\n' + descriptors[:sigoffset] + + # 4. compute the base64-encoded hash with the right algorithm + digest = base64.b64encode(shalgorithm(full_desc).digest()) + + # 5. strips the trailing '=' as specified + fields[-1][digest_name] = str(digest.rstrip(b'='), 'utf8') + except ValueError: + pass + + if not digest_name in fields[-1]: + raise RuntimeError('Was unable to generate proper sum.') + + return fields
      + +
      [docs]def consume_descriptors(descriptors, flavor='microdesc'): + if flavor not in ['microdesc', 'unflavored']: + raise NotImplementedError( + 'Consensus flavor "{}" not supported.'.format(flavor)) + + # TODO: check if family in microdesc are appropriate + if flavor == 'microdesc': + whitelist = [b'onion-key', b'ntor-onion-key', b'p', b'p6', b'id', + b'family'] + else: + whitelist = [b'router', b'identity-ed25519', b'master-key-ed25519', + b'platform', b'proto', b'published', b'fingerprint', b'uptime', + b'bandwidth', b'extra-info-digest', b'qkk', b'caches-extra-info', + b'onion-key', b'signing-key', b'onion-key-crosscert', + b'ntor-onion-key-crosscert', b'hidden-service-dir', b'contact', + b'ntor-onion-key', b'reject', b'accept', b'tunnelled-dir-server', + b'router-sig-ed25519', b'router-signature', b'ipv6-policy', + b'family', b'protocols', b'or-address', b'allow-single-hop-exits', + b'hibernating'] + aliases = {'p': 'policy', 'p6': 'ipv6-policy', 'id': 'identity'} + + def end_of_field(line): + if b' ' not in line: + line += b' ' + keyword, _ = line.split(b' ', 1) + return keyword not in whitelist + + fields = [dict()] + valid = False + while True: + descriptors, entry = consensus.scrap(descriptors, end_of_field) + if entry is None: + if not valid: + return descriptors, None + break + fields = compute_descriptor_digest(fields, descriptors, entry, flavor) + + valid = True + if b' ' not in entry: + entry += b' ' + + try: + entry = str(entry, 'utf8') + except: + continue + + keyword, content = entry.split(' ', 1) + if keyword == 'router': + nick, address, orport, socksport, dirport = content.split(' ', 4) + content = dict( + nickname=nick, + address=address, + orport=int(orport), + socksport=int(socksport), + dirport=int(dirport)) + + if keyword in ['platform', 'contact']: + pass # nothing to process + + if keyword in ['reject', 'accept']: + base = dict(type='exitpattern') + if 'policy' in fields[-1]: + base = fields[-1]['policy'] + if not base['type'] == 'exitpattern': + raise RuntimeError('Unknown policy: {}'.format(base)) + if 'rules' not in base: + base['rules'] = [] + + base['rules'].append(dict(type=keyword, pattern=content)) + fields[-1]['policy'] = base + continue + + if keyword == 'or-address': + base = [] + if 'or-address' in fields[-1]: + base = fields[-1]['or-address'] + + address, port, guess = consensus.parse_address(content) + content = [{'ip': address, 'port': port, 'type': guess}] + if len(base) > 0: + content[0]['ignored'] = True + + base += content + fields[-1]['or-address'] = base + continue + + if keyword == 'family': + content = content.split(' ') + + if keyword == 'proto': + content = consensus.parse_ranges(content) + + # The spec says 'New code should neither […] nor parse this line' + if keyword == 'protocols': + pass + + if keyword in ['allow-single-hop-exits', 'hibernating']: + content = True + + if keyword == 'published': + date, time, when = consensus.parse_time(content) + content = dict(date=date, time=time, stamp=when.timestamp()) + + if keyword == 'fingerprint': + content = consensus.parse_fingerprint(content) + + # Enrich 'router' with 'identity' fingerprint for convenience + if 'router' in fields[-1]: + identity = bytes.fromhex(content.replace(' ', '')) + identity = str(base64.b64encode(identity), 'utf8') + fields[-1]['router']['identity'] = identity.replace('=', '') + + if keyword == 'uptime': + content = int(content) + + if keyword == 'bandwidth': + avg, burst, observed = content.split(' ', 2) + content = dict( + avg=int(avg), burst=int(burst), observed=int(observed)) + + if keyword == 'extra-info-digest': + if ' ' in content: + sha1, sha256 = content.split(' ', 1) + sha256 = consensus.parse_base64(sha256) + content = dict(sha1=sha1, sha256=sha256) + else: + content = dict(sha1=content) + + if keyword in ['caches-extra-info', 'hidden-service-dir', + 'tunnelled-dir-server']: + content = True + + if keyword in ['onion-key', 'signing-key']: + if not content == '': + raise RuntimeError('Trailing content with {}: {}'.format( + keyword, content)) + + descriptors, pubkey = consensus.scrap_signature(descriptors, + fix=b'RSA PUBLIC KEY') + if pubkey is not None: + content = consensus.parse_base64(str(pubkey, 'utf8')) + + if keyword == 'onion-key-crosscert': + if not content == '': + raise RuntimeError('Trailing content with {}: {}'.format( + keyword, content)) + + descriptors, crosscrt = consensus.scrap_signature(descriptors, + fix=b'CROSSCERT') + if crosscrt is not None: + content = consensus.parse_base64(str(crosscrt, 'utf8')) + + if keyword == 'ntor-onion-key-crosscert': + bit = int(content) + + descriptors, edcert = consensus.scrap_signature(descriptors, + fix=b'ED25519 CERT') + if edcert is not None: + content = consensus.parse_base64(str(edcert, 'utf8')) + content = dict(bit=bit, cert=content) + + if keyword == 'ntor-onion-key': + content = consensus.parse_base64(content) + + if keyword in ['p', 'p6', 'ipv6-policy']: + policy_type, portlist = content.split(' ') + if not policy_type in ['accept', 'reject']: + raise RuntimeError('Unknown policy: {}'.format(policy_type)) + + portlist = consensus.parse_range_once(portlist, expand=False) + content = {'type': policy_type, 'PortList': portlist} + + if keyword == 'id': + id_type, data = content.split(' ') + if not id_type in ['rsa1024', 'ed25519']: + raise RuntimeError('Unknown id key type: {}'.format(id_type)) + + content = {'type': id_type, + 'master-key': consensus.parse_base64(data)} + + if keyword in ['router-sig-ed25519', 'router-signature']: + base = dict() + if 'router-signatures' in fields[-1]: + base = fields[-1]['router-signatures'] + + if keyword == 'router-sig-ed25519': + if 'router-signatures' in fields[-1]: + raise RuntimeError('Ed25519 must be first!') + if not 'identity' in fields[-1]: + raise RuntimeError('Need identity with {} here: {}'.format( + keyword, fields[-1])) + if not 'cert' in fields[-1]['identity']: + raise RuntimeError('Need cert. in identity: {}'.format( + fields[-1])) + base['ed25519'] = consensus.parse_base64(content) + + if keyword == 'router-signature': + descriptors, sig = consensus.scrap_signature(descriptors, + fix=b'SIGNATURE') + if sig is not None: + content = consensus.parse_base64(str(sig, 'utf8')) + base['rsa'] = content + + fields[-1]['router-signatures'] = base + continue + + if keyword in ['identity-ed25519', 'master-key-ed25519']: + base = dict() + if 'identity' in fields[-1]: + base = fields[-1]['identity'] + + if 'type' not in base: + base['type'] = 'ed25519' + if not base['type'] == 'ed25519': + raise RuntimeError('Invalid key type {} here:'.format(base)) + + if keyword == 'identity-ed25519': + if 'cert' in base: + raise RuntimeError('Extra cert. here: {}'.format(base)) + + descriptors, edcert = consensus.scrap_signature(descriptors, + fix=b'ED25519 CERT') + if edcert is not None: + base['cert'] = consensus.parse_base64(str(edcert, 'utf8')) + + if keyword == 'master-key-ed25519': + if 'master-key' in base: + raise RuntimeError('Extra master key: {}'.format(base)) + + base['master-key'] = consensus.parse_base64(content) + + # TODO: validation if both master-key & identity are present + fields[-1]['identity'] = base + continue + + if keyword in aliases: + keyword = aliases[keyword] + + if keyword in fields[-1]: + fields.append(dict()) + + fields[-1][keyword] = content + return descriptors, fields
      + + +
      [docs]def parse_descriptors(descriptors, flavor='microdesc'): + fields = dict(flavor=flavor) + nbdesc = descriptors.count(b'onion-key\n-----BEGIN') + + descriptors, http = consensus.consume_http(descriptors) + if http is not None: + fields['http'] = http + + descriptors, entries = consume_descriptors(descriptors, flavor) + if entries is None or len(entries) == 0: + entries = [] + fields['descriptors'] = entries + + if not len(fields['descriptors']) == nbdesc: + raise RuntimeError( + 'Unexpected or corrupted descriptor? ({}/{} found)'.format( + len(fields['descriptors']), nbdesc)) + + # Add flavor for convenience + for idx in range(len(fields['descriptors'])): + fields['descriptors'][idx]['flavor'] = flavor + + if descriptors == b'\n': + descriptors = b'' + return fields, descriptors
      + + +
      [docs]def batch_query(items, prefix, separator='-', fixed_max_length=4096-128): + # About batches: + # https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L3392 + + query = '' + for item in items: + if len(item) + len(query) >= fixed_max_length: + yield query + query = '' + + if len(query) == 0: + query += prefix + item + else: + query += separator + item + + if len(query) != 0: + yield query
      + + +
      [docs]def filter_descriptors(descriptors, digests, flavor='unflavored'): + """Filter out the invalid descriptors. + :param descriptors: Descriptors to be filtered. + :param digests: Digests from the consensus. + :param flavor: Flavor of the descriptor. + """ + + descriptor_digests = set() + descriptors_d = dict() + + # Content depends on descriptor flavour. + if flavor == 'microdesc': + for descriptor in descriptors: + fingerprint = descriptor['micro-digest'] + descriptor_digests.add(fingerprint) + descriptors_d[fingerprint] = descriptor + else: + for descriptor in descriptors: + fingerprint = base64.b64decode(descriptor['digest'] + '====').hex() + descriptor_digests.add(fingerprint) + descriptors_d[fingerprint] = descriptor + + fingerprints_valid = descriptor_digests.intersection(digests) + descriptors_valid = [descriptors_d[fingerprint] for fingerprint in fingerprints_valid] + + # For logging only. + desc_l = len(descriptors) + valid_l = len(descriptors_valid) + invalid_l = desc_l - valid_l + + logging.info('Filtered %d descriptors, %d valid, %d invalid.', desc_l, valid_l, invalid_l) + + return descriptors_valid
      + + +
      [docs]def download_direct(host, port, cons, flavor='unflavored'): + """Retrieve descriptor via a direct HTTP connection. + :param host: host from which to retrieve the descriptors. + :param port: port from which to retrieve the descriptors. + :param cons: consensus for which nodes a descriptor need to be retrieved. + """ + + if flavor == 'microdesc': + endpoint = '/tor/micro/d/' + separator = '-' + digests = [router['micro-digest'] for router in cons['routers']] + + else: + endpoint = '/tor/server/d/' + separator = '+' + digests = [base64.b64decode(router['digest'] + '====').hex() for router in cons['routers']] + + descriptors = [] + + # Retrieve descriptors not in the cache + for query in batch_query(digests, endpoint, separator): + uri = 'http://%s:%d%s' % (host, port, query) + res = urllib.request.urlopen(uri) + + if res is None or res.getcode() != 200: + raise RuntimeError('Unable to fetch descriptors.') + + # Rename parse to something sensible + new_batch, remaining = parse_descriptors(res.read(), flavor=flavor) + if new_batch is None or remaining is None or len(remaining) > 0: + raise RuntimeError('Unable to parse descriptors.') + + if (len(new_batch['descriptors']) == 0): + raise RuntimeError('No descriptor listed. http={}.'.format(new_batch['http'])) + + if new_batch is not None: + descriptors += new_batch['descriptors'] + + descriptors = filter_descriptors(descriptors, digests, flavor=flavor) + + if flavor == 'microdesc': + return {d['micro-digest']: d for d in descriptors} + else: + return {d['digest']: d for d in descriptors}
      + + +
      [docs]def download_relay_descriptor(host='127.0.0.1', port=9051): + """Retrieve a relay's own descriptor. + """ + + uri = 'http://{}:{}/tor/server/authority'.format(host, port) + res = urllib.request.urlopen(uri) + + if res is None or res.getcode() != 200: + raise RuntimeError('Unable to fetch descriptors.') + + descriptors, _ = parse_descriptors(res.read(), flavor='unflavored') + + return descriptors['descriptors'][0]
      + + +
      [docs]def download_raw(host, port, cons, flavor='unflavored'): + """Retrieve descriptor via a direct HTTP connection. + :param host: host from which to retrieve the descriptors. + :param port: port from which to retrieve the descriptors. + :param cons: consensus for which nodes a descriptor need to be retrieved. + """ + + if flavor == 'microdesc': + endpoint = '/tor/micro/d/' + separator = '-' + digests = [router['micro-digest'] for router in cons['routers']] + + else: + endpoint = '/tor/server/d/' + separator = '+' + digests = [base64.b64decode(router['digest'] + '====').hex() for router in cons['routers']] + + + # Retrieve descriptors not in the cache + desc = b"" + for query in batch_query(digests, endpoint, separator): + uri = 'http://%s:%d%s' % (host, port, query) + res = urllib.request.urlopen(uri) + + if res is None or res.getcode() != 200: + raise RuntimeError('Unable to fetch descriptors.') + + desc += res.read() + + return desc
      + + +
      [docs]def download_raw_by_digests_unflavored(host, port, digests_bytes): + """Retrieve descriptor via a direct HTTP connection. + :param host: host from which to retrieve the descriptors. + :param port: port from which to retrieve the descriptors. + :param digests: Digests (in a binary form) of the nodes for which a descriptor need to be retrieved. + """ + + digests = [digest.hex() for digest in digests_bytes] + endpoint = '/tor/server/d/' + separator = '+' + + return _download_raw_by_digests(host, port, digests, endpoint, separator)
      + + +
      [docs]def download_raw_by_digests_micro(host, port, digests_bytes): + """Retrieve descriptor via a direct HTTP connection. + :param host: host from which to retrieve the descriptors. + :param port: port from which to retrieve the descriptors. + :param digests: Digests (in a binary form) of the nodes for which a descriptor need to be retrieved. + """ + + endpoint = '/tor/micro/d/' + separator = '-' + digests = digests_bytes + return _download_raw_by_digests(host, port, digests, endpoint, separator)
      + + +def _download_raw_by_digests(host, port, digests, endpoint, separator): + """Retrieve descriptor via a direct HTTP connection. + """ + desc = b"" + for query in batch_query(digests, endpoint, separator): + uri = 'http://{}:{}{}'.format(host, port, query) + res = urllib.request.urlopen(uri) + + if res is None or res.getcode() != 200: + raise RuntimeError('Unable to fetch descriptors.') + + desc += res.read() + + return desc + + +
      [docs]def download(state, cons=None, flavor='microdesc', cache=True, fail_on_missing=False): + logging.warning('Use DEPRECATED method descriptor.download()!') + + if cons is None: + state, cons = consensus.download(state, flavor=flavor, cache=cache) + if cons is None: + return state, None + elif isinstance(cons, list): + cons = dict(routers=cons) + elif isinstance(cons, str): + digest_name = 'micro-digest' if flavor == 'microdesc' else 'digest' + cons = dict(routers={digest_name: cons}) + elif 'routers' not in cons and 'identity' in cons: + cons = dict(routers=[cons]) + + if not isinstance(cons, dict): + raise RuntimeError('Expecting a dict for cons, got: {}'.format(cons)) + + digests = [] + if flavor == 'microdesc': + digests = [router['micro-digest'] for router in cons['routers']] + endpoint = '/tor/micro/d/' + separator = '-' + else: + digests = [router['digest'] for router in cons['routers']] + digests = [base64.b64decode(d + '====').hex() for d in digests] + endpoint = '/tor/server/d/' + separator = '+' + + # retrieve descriptors from cache + descriptors = [] + partial_digests = digests + if cache: + digest_name = 'micro-digest' if flavor == 'microdesc' else 'digest' + cached_digests = [] + for digest in digests: + try: + descriptor = lnn.cache.descriptors.get(flavor, digest) + descriptors.append(descriptor) + cached_digests.append(digest) + except BaseException: + pass + partial_digests = [d for d in digests if d not in cached_digests] + + for query in batch_query(partial_digests, endpoint, separator): + state, answer = lnn.hop.directory_query(state, query) + + if answer is None or len(answer) == 0: + continue + + new_batch, remaining = parse_descriptors(answer, flavor=flavor) + if new_batch is None or remaining is None or len(remaining) > 0: + raise RuntimeError('Unable to parse descriptors.') + + if (len(new_batch['descriptors']) == 0 + and not new_batch['http']['code'] == '404'): + raise RuntimeError( + 'No descriptor listed. http={}.'.format(new_batch['http'])) + + if new_batch is not None: + descriptors += new_batch['descriptors'] + + if flavor == 'microdesc': + obtained = [d['micro-digest'] for d in descriptors] + else: + obtained = [d['digest'] for d in descriptors] + obtained = [base64.b64decode(d + '====').hex() for d in obtained] + + invalid = [] + for digest in digests: + if digest in obtained: + obtained.remove(digest) + else: + invalid.append(digest) + + if not len(obtained) == 0: + raise RuntimeError('Mismatched digest afterward! {} vs {}'.format( + sorted(invalid), sorted(obtained))) + + if fail_on_missing and len(invalid) > 0: + raise RuntimeError('Missing {} digests in answer: {}'.format( + len(invalid), invalid)) + + if cache: + for descriptor in descriptors: + lnn.cache.descriptors.put(descriptor) + + return state, descriptors
      + + +
      [docs]def download_authority(state): + state, answer = lnn.hop.directory_query(state, '/tor/server/authority') + if answer is None or len(answer) == 0: + return state, None + + result, remain = parse_descriptors(answer, flavor='unflavored') + if not (len(remain) == 0 + and result is not None + and len(result['descriptors']) == 1): + raise RuntimeError('Unable to parse authority descriptor.') + + return state, result['descriptors'][0]
      + + +
      [docs]def download_authority_direct(host, port): + """Retrieve authority. + :param host: host from which to retrieve the authority. + :param port: port from which to retrieve the authority. + :return: Authority. + """ + uri = 'http://%s:%d/tor/server/authority' % (host, port) + + res = urllib.request.urlopen(uri) + + if res is None or res.getcode() != 200: + return None + + result, remain = parse_descriptors(res.read(), flavor='unflavored') + + if not (len(remain) == 0 and result is not None and len(result['descriptors']) == 1): + raise RuntimeError('Unable to parse authority descriptor.') + + return result['descriptors'][0]
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/extend.html b/docs/source/_build/html/_modules/lightnion/extend.html new file mode 100644 index 0000000..7ba3f68 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/extend.html @@ -0,0 +1,231 @@ + + + + + + + + + + + lightnion.extend — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.extend

      +import random
      +import base64
      +import io
      +
      +import nacl.public
      +
      +import lightnion as lnn
      +
      +
      [docs]def circuit(state, descriptor): + onion_key = base64.b64decode(descriptor['ntor-onion-key'] + '====') + eidentity = descriptor['identity']['master-key'] # (assuming ed25519 here) + identity = base64.b64decode(descriptor['router']['identity'] + '====') + addr = descriptor['router']['address'] + port = descriptor['router']['orport'] + + eph_key, hdata = lnn.crypto.ntor.hand(identity, onion_key) + + payload = lnn.cell.relay.extend2.pack( + hdata, [(addr, port)], [identity, eidentity]) + + state = lnn.hop.send(state, + lnn.cell.relay.cmd.RELAY_EXTEND2, payload.raw, stream_id=0) + + state, cells = lnn.hop.recv(state, once=True) + if not len(cells) == 1: + raise RuntimeError('Expected exactly one cell, got: {}'.format(cells)) + + if not cells[0].relay.cmd == lnn.cell.relay.cmd.RELAY_EXTENDED2: + raise RuntimeError('Expected EXTENDED2, got {} here: {}'.format( + cells[0].relay.cmd, cell.relay.truncated)) + + payload = lnn.cell.relay.extended2.payload(cells[0].relay.data) + if not payload.valid: + raise RuntimeError('Invalid EXTENDED2 payload: {}'.format( + payload.truncated)) + + raw_material = lnn.crypto.ntor.shake(eph_key, payload.data, identity, + onion_key, length=92) + + material = lnn.crypto.ntor.kdf(raw_material) + extended = lnn.create.circuit(state.circuit.id, material) + + state.wrap(lnn.onion.state(state.link, extended)) + return state
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/hop.html b/docs/source/_build/html/_modules/lightnion/hop.html new file mode 100644 index 0000000..b005d10 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/hop.html @@ -0,0 +1,415 @@ + + + + + + + + + + + lightnion.hop — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.hop

      +import zlib
      +import time
      +import queue
      +
      +import lightnion as lnn
      +
      +
      [docs]def recv(state, block=True, once=False, auto_sendme=True): + '''Receive one or more RELAY{_EARLY,} cells from `state` attached circuit. + + :param state: a state object (see onion.state) + :param bool block: block while receiving? (default: True) + :param bool block: attempt only receiving once? (default: False) + + :returns: a tuple (updated state, received RELAY{_EARLY,} cells) + + Notes: + - returns an updated state that *MUST* be used afterwards. + - non-RELAY{_EARLY,} cells within the circuit *may be reordered.* + ''' + + while True: + try: + payload = state.link.get(circuit=state.circuit, block=block) + except queue.Empty: + return state, [] + except KeyError: + raise RuntimeError('Circuit got destroyed, reason: {}'.format( + state.circuit.reason)) + + header = lnn.cell.header(payload) + if header.cmd in [lnn.cell.cmd.RELAY, lnn.cell.cmd.RELAY_EARLY]: + break + + state.link.put(state.circuit, payload) + + cell_type = lnn.cell.relay.cell + if header.cmd is lnn.cell.cmd.RELAY_EARLY: + cell_type = lnn.cell.relay_early.cell + + cell = cell_type(payload) + #import pdb + #pdb.set_trace() + #if not cell.valid: + # raise RuntimeError( + # 'Got invalid (encrypted) RELAY cell: {}'.format(cell.raw)) + + state, cell = lnn.onion.peel(state, cell) + if not cell.valid: + raise RuntimeError( + 'Got invalid (decrypted) RELAY cell: {}'.format(cell.raw)) + + if auto_sendme: + state = _auto_sendme(state, cell) + + cells = [cell] + while not once: + state, new_cells = recv(state, block=False, once=True) + if len(new_cells) == 0: + break + cells += new_cells + return state, cells
      + +# TODO: better sendme handling +def _auto_sendme(state, cell): + if not cell.relay.cmd == lnn.cell.relay.cmd.RELAY_DATA: + return state + link, circuit, flow = state.link, state.circuit, lnn.constants.flow + + # Circuit-level sendme + # + if circuit.window is None: + circuit.window = flow.circuit.default + + circuit.window -= 1 + if circuit.window < flow.circuit.lowlimit: + circuit.window += flow.circuit.increment + state = send(state, lnn.cell.relay.cmd.RELAY_SENDME) + + # Stream-level sendme + # + if not cell.relay.stream_id > 0: + return state + + if circuit.stream_windows is None: + circuit.stream_windows = dict() + + if not cell.relay.stream_id in circuit.stream_windows: + circuit.stream_windows[cell.relay.stream_id] = flow.stream.default + + circuit.stream_windows[cell.relay.stream_id] -= 1 + if not circuit.stream_windows[cell.relay.stream_id] < flow.stream.lowlimit: + return state + + circuit.stream_windows[cell.relay.stream_id] += flow.stream.increment + state = send(state, lnn.cell.relay.cmd.RELAY_SENDME, + stream_id=cell.relay.stream_id) + + return state + +
      [docs]def send(state, command, payload=b'', stream_id=0): + '''Send one RELAY{_EARLY,} cell through `state` attached circuit. + + :param state: a state object (see onion.state) + :param str command: RELAY{_EARLY,} cell command (see cell.relay.cmd) + :param bytes payload: RELAY{_EARLY,} cell content (default: b'') + :param int stream_id: RELAY{_EARLY,} stream ID (default: 0) + + :returns: an updated state + + *Note: returns an updated state that *MUST* be used afterwards.* + ''' + + # We build our onion + state, cell = lnn.onion.build(state, command, payload, stream_id) + + # Then, we send the encrypted payload. + state.link.send(cell) + return state
      + +directory_request = '\r\n'.join(( + 'GET {query} HTTP/1.0', + 'Accept-Encoding: {compression}', + )) + '\r\n\r\n' + +
      [docs]def directory_query( + state, + query=None, + compression='deflate', + timeout=30, + **kwargs): + if compression not in ['identity', 'deflate', 'gzip']: + raise NotImplementedError( + 'Compression method "{}" not supported.'.format(compression)) + + if query is None: + query = '/tor/status-vote/current/consensus' + if not query.startswith('/tor/') or any([c in query for c in ' \r\n']): + raise RuntimeError('Invalid query: {}'.format(query)) + + state.circuit.last_stream_id += 1 + stream_id = state.circuit.last_stream_id + + state = send( + state, lnn.cell.relay.cmd.RELAY_BEGIN_DIR, stream_id=stream_id) + state, cells = recv(state) + + if not cells[0].relay.cmd == lnn.cell.relay.cmd.RELAY_CONNECTED: + raise RuntimeError('Expecting RELAY_CONNECTED after RELAY_BEGIN_DIR,' + + ' got {} in cell:'.format(cells[0].relay.cmd, cells[0].raw)) + + + http = directory_request.format(query=query, compression=compression) + + http = bytes(http, 'utf8') + width = lnn.cell.relay.payload_len + while len(http) > 0: + chunk, http = http[:width], http[width:] + state = send(state, lnn.cell.relay.cmd.RELAY_DATA, chunk, + stream_id=stream_id) + + # TODO: proper support for RELAY_END reasons + state, cells = recv(state) + if lnn.cell.relay.cmd.RELAY_END not in [c.relay.cmd for c in cells]: + candidates = [] + diff_time = time.time() + while True: + if time.time() - diff_time > timeout: + break + + state, new_cells = recv(state, block=False) + candidates = [c.relay.cmd for c in new_cells] + cells += new_cells + + if lnn.cell.relay.cmd.RELAY_END in candidates: + break + + if len(candidates) > 0: + diff_time = time.time() + + if time.time() - diff_time > timeout: + raise RuntimeError( + 'Timeout while expecting RELAY_END: {:.2f}s out of {}s'.format( + time.time() - diff_time, timeout)) + + # TODO: proper support for incoming RELAY_SENDME cells + cells = [c for c in cells if not (c.relay.stream_id == 0 + and c.relay.cmd == lnn.cell.relay.cmd.RELAY_SENDME)] + + # TODO: proper support for concurrent streams on the same circuit + if not all([c.relay.stream_id == stream_id for c in cells]): + raise RuntimeError('No proper support for multiple stream!') + + content = b'' + for cell in cells: + if not cell.relay.cmd == lnn.cell.relay.cmd.RELAY_DATA: + continue + content += cell.relay.data + + if compression in ['deflate', 'gzip']: + http_headers, compressed_data = content.split(b'\r\n\r\n', 1) + raw_data = zlib_decompress(compressed_data) + content = http_headers + b'\r\n\r\n' + raw_data + + if not content.startswith(b'HTTP/1.0'): + raise RuntimeError('Unexpected answer to query "{}": {}'.format(query, + content)) + + return state, content
      + +
      [docs]def zlib_decompress(compressed_data, min_bufsize=32): + data = b'' + buff = b'' + part = None + ilen = len(compressed_data) + olen = 0 + zobj = zlib.decompressobj() + while part is None or len(part) > 0: + buff = zobj.unconsumed_tail + if len(buff) < 1: + nlen = max((len(data) + ilen) // 2, min_bufsize) + buff = compressed_data[olen:nlen] + if len(buff) < 1: + break + + olen += len(buff) + part = zobj.decompress(buff, zlib.MAX_WBITS | 32) + data += part + return data
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/http.html b/docs/source/_build/html/_modules/lightnion/http.html new file mode 100644 index 0000000..04716c7 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/http.html @@ -0,0 +1,296 @@ + + + + + + + + + + + lightnion.http — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.http

      +import collections
      +import requests
      +import json
      +
      +headers = {'Content-Type': 'application/json'}
      +
      +import lightnion as lnn
      +import lightnion.proxy
      +
      +from . import polling, websocket, ntor
      +
      +
      [docs]class channel(collections.namedtuple('channel', + ['id', 'guard', 'middle', 'exit'])): + pass
      + +
      [docs]def client(host, port=80, *, io, prefix='http', failures=5, **kwargs): + base_url = '{}://{}:{}{}'.format(prefix, host, port, lnn.proxy.base_url) + + guard = None + try: + code = 503 + fails = 0 + for _ in range(failures): + rq = requests.get(base_url + '/guard') + if not rq.status_code in [200, 503]: + raise RuntimeError('Error code: {}'.format(rq.status_code)) + + code = rq.status_code + if fails > failures or not code == 503: + break + + fails += 1 + + if code == 503: + raise RuntimeError('Too many failures!') + + guard = json.loads(rq.text) + + except BaseException as e: + raise RuntimeError( + 'Unable retrieve guard at endpoint {}, reason: {}'.format( + base_url + '/guard', e)) + + handshake, material, uid, path = (None, None, None, None) + try: + code = 503 + fails = 0 + for _ in range(failures): + handshake, material = ntor.hand(guard) + data = json.dumps(dict(ntor=handshake)) + + rq = requests.post(base_url + '/channels', + data=data, headers=headers) + if not rq.status_code in [201, 503]: + raise RuntimeError('Error code: {}'.format(rq.status_code)) + + code = rq.status_code + if fails > failures or not code == 503: + break + + fails += 1 + + if code == 503: + raise RuntimeError('Too many failures!') + + data = json.loads(rq.text) + uid, handshake, path = data['id'], data['ntor'], data['path'] + + except BaseException as e: + raise RuntimeError( + 'Unable create channel at endpoint {}, reason: {}'.format( + base_url + '/channels', e)) + + state = None + try: + try: + handshake = ntor.shake(handshake, material) + except TypeError: + raise RuntimeError('Invalid ntor cryptographic material?') + + io = io(endpoint=base_url + '/channels/' + uid, **kwargs) + link = lnn.link.link(io, version='http') + + circuit = lnn.create.circuit(lnn.proxy.fake_circuit_id, handshake) + link.register(circuit) + + state = lnn.onion.state(link, circuit) + + except BaseException as e: + raise RuntimeError( + 'Unable craft local state with {}, reason: {}'.format(io, e)) + + try: + state = lnn.extend.circuit(state, path[0]) + + except BaseException as e: + raise RuntimeError( + 'Unable extend the circuit to middle node {}, reason: {}'.format( + path[0]['router']['nickname'], e)) + + try: + state = lnn.extend.circuit(state, path[1]) + + except BaseException as e: + raise RuntimeError( + 'Unable extend the circuit to exit node {}, reason: {}'.format( + path[0]['router']['nickname'], e)) + + return state, channel(uid, guard, path[0], path[1])
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/http/ntor.html b/docs/source/_build/html/_modules/lightnion/http/ntor.html new file mode 100644 index 0000000..96b4487 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/http/ntor.html @@ -0,0 +1,213 @@ + + + + + + + + + + + lightnion.http.ntor — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.http.ntor

      +import lightnion as lnn
      +
      +import nacl.public
      +
      +import base64
      +
      +
      [docs]def hand(guard, encode=True): + identity = base64.b64decode(guard['router']['identity'] + '====') + onion_key = base64.b64decode(guard['ntor-onion-key'] + '====') + + ephemeral_key, payload = lnn.crypto.ntor.hand(identity, onion_key) + + if encode: + payload = str(base64.b64encode(payload), 'utf8') + return payload, (onion_key, ephemeral_key, identity)
      + +
      [docs]def shake(payload, material): + payload = base64.b64decode(payload) + onion_key, ephemeral_key, identity = material + + material = lnn.crypto.ntor.shake(ephemeral_key, payload, + identity, onion_key, length=92) + + return lnn.crypto.ntor.kdf(material)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/http/polling.html b/docs/source/_build/html/_modules/lightnion/http/polling.html new file mode 100644 index 0000000..3c00278 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/http/polling.html @@ -0,0 +1,303 @@ + + + + + + + + + + + lightnion.http.polling — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.http.polling

      +import threading
      +import requests
      +import base64
      +import queue
      +import json
      +import time
      +
      +from .. import http
      +from .. import proxy
      +
      +
      [docs]class worker(threading.Thread): + def __init__(self, endpoint, period, max_queue=2048): + super().__init__() + self.endpoint = endpoint + self.period = period + + self.send_queue = queue.Queue(max_queue) + self.recv_queue = queue.Queue(max_queue) + + self.dead = False + +
      [docs] def close(self): + requests.delete(self.endpoint) + self.dead = True
      + +
      [docs] def die(self, e): + if self.dead: + return + + self.close() + raise e
      + +
      [docs] def send(self, cell, block=True): + try: + cell = cell.raw + except AttributeError: + pass + + cell = base64.b64encode(cell) + self.send_queue.put(cell, block)
      + +
      [docs] def recv(self, block=True): + payload = self.recv_queue.get(block=block) + payload = base64.b64decode(payload) + return payload
      + +
      [docs] def main(self): + try: + cells = [] + for _ in range(proxy.jobs.request_max_cells): + try: + cells.append(self.send_queue.get(block=False)) + except queue.Empty as e: + if len(cells) == 0: + raise e + + data = json.dumps( + dict(cells=[str(cell, 'utf8') for cell in cells])) + + rq = requests.post(self.endpoint, data=data, headers=http.headers) + if not rq.status_code == 201: + raise RuntimeError( + 'Got {} status (send)!'.format(rq.status_code)) + + answer = json.loads(rq.text) + for cell in answer['cells']: + self.recv_queue.put(cell) + + return + except queue.Empty: + pass + + data = json.dumps(dict(cells=[])) + rq = requests.post(self.endpoint, data=data, headers=http.headers) + if not rq.status_code == 201: + raise RuntimeError('Got {} status! (recv)'.format(rq.status_code)) + + answer = json.loads(rq.text) + for cell in answer['cells']: + self.recv_queue.put(cell) + + time.sleep(self.period)
      + +
      [docs] def run(self): + try: + while not self.dead: + self.main() + self.dead = True + except BaseException as e: + self.die(e)
      + +
      [docs]class io: + _join_timeout = 3 + + def __init__(self, endpoint, period=0.1, daemon=True, max_queue=2048): + self.worker = worker(endpoint, period, max_queue) + if daemon: + self.worker.daemon = True + + self.worker.start() + + @property + def dead(self): + return self.worker.dead + +
      [docs] def recv(self, block=True): + return self.worker.recv(block)
      + +
      [docs] def send(self, payload, block=True): + self.worker.send(payload, block=block)
      + +
      [docs] def close(self): + self.worker.close() + self.worker.join(self._join_timeout)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/http/websocket.html b/docs/source/_build/html/_modules/lightnion/http/websocket.html new file mode 100644 index 0000000..749d42c --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/http/websocket.html @@ -0,0 +1,317 @@ + + + + + + + + + + + lightnion.http.websocket — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.http.websocket

      +import websockets
      +import threading
      +import logging
      +import asyncio
      +import queue
      +
      +from .. import http
      +from .. import proxy
      +
      +
      [docs]async def incoming(websocket, worker): + cell = None + while True: + try: + if cell is None: + cell = await websocket.recv() + worker.recv_queue.put_nowait(cell) + cell = None + + await asyncio.sleep(0) + continue + except (asyncio.QueueEmpty, queue.Full): + pass + + await asyncio.sleep(worker.period)
      + +
      [docs]async def outcoming(websocket, worker): + cell = None + while True: + try: + if cell is None: + cell = worker.send_queue.get_nowait() + await websocket.send(cell) + cell = None + + await asyncio.sleep(0) + continue + except (asyncio.QueueFull, queue.Empty): + pass + + await asyncio.sleep(worker.period)
      + +
      [docs]async def channel_handler(websocket, worker): + for task in [incoming, outcoming]: + worker.tasks.append(asyncio.ensure_future(task(websocket, worker))) + + done, pending = await asyncio.wait(worker.tasks, + return_when=asyncio.FIRST_COMPLETED) + + for task in pending: + task.cancel() + worker.dead = True
      + +
      [docs]async def client(worker): + async with websockets.connect(worker.endpoint) as websocket: + await channel_handler(websocket, worker)
      + +
      [docs]class worker(threading.Thread): + def __init__(self, endpoint, period, max_queue=2048): + super().__init__() + self.endpoint = endpoint + self.period = period + max_queue = max_queue // 2 + + self.send_queue = queue.Queue(max_queue) + self.recv_queue = queue.Queue(max_queue) + + self.send_async = asyncio.Queue(max_queue) + self.recv_async = asyncio.Queue(max_queue) + + self.tasks = [] + self.dead = False + +
      [docs] def close(self): + for task in self.tasks: + task.cancel() + self.dead = True
      + +
      [docs] def die(self, e): + if self.dead: + return + + self.close() + raise e
      + +
      [docs] def send(self, cell, block=True): + try: + cell = cell.raw + except AttributeError: + pass + + self.send_queue.put(cell, block)
      + +
      [docs] def recv(self, block=True): + payload = self.recv_queue.get(block=block) + return payload
      + +
      [docs] def run(self): + logging.getLogger(websockets.__name__).setLevel(logging.ERROR) + asyncio.set_event_loop(asyncio.new_event_loop()) + + asyncio.get_event_loop().run_until_complete(client(self))
      + +
      [docs]class io: + _join_timeout = 3 + + def __init__(self, endpoint, period=0.1, daemon=True, max_queue=2048): + endpoint = endpoint.replace('http', 'ws') + endpoint = endpoint.replace(':4990/', ':8765/') # TODO: work same port + + self.worker = worker(endpoint, period, max_queue) + if daemon: + self.worker.daemon = True + + self.worker.start() + + @property + def dead(self): + return self.worker.dead + +
      [docs] def recv(self, block=True): + return self.worker.recv(block)
      + +
      [docs] def send(self, payload, block=True): + self.worker.send(payload, block=block)
      + +
      [docs] def close(self): + self.worker.close() + self.worker.join(self._join_timeout)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/link.html b/docs/source/_build/html/_modules/lightnion/link.html new file mode 100644 index 0000000..fd6d2b7 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/link.html @@ -0,0 +1,407 @@ + + + + + + + + + + + lightnion.link — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.link

      +import logging
      +import socket
      +import queue
      +import ssl
      +
      +import lightnion as lnn
      +
      +
      +
      +
      [docs]def negotiate_version(peer, versions, *, as_initiator): + """Performs a VERSIONS negotiation + + :param peer: ssl.socket instance. + :param list versions: target link versions. + :param bool as_initiator: send VERSIONS cell first. + """ + if as_initiator: + lnn.cell.versions.send(peer, lnn.cell.versions.pack(versions)) + vercell = lnn.cell.versions.recv(peer) + + common_versions = list(set(vercell.versions).intersection(versions)) + if len(common_versions) < 1: + raise RuntimeError('No common supported versions: {} and {}'.format( + list(vercell.versions), versions)) + + version = max(common_versions) + if version < 4: + raise RuntimeError('No support for version 3 or lower, got {}').format( + version) + + if not as_initiator: + lnn.cell.versions.send(peer, lnn.cell.versions.pack(versions)) + return version
      + +
      [docs]def initiate(address='127.0.0.1', port=9050, versions=[4, 5]): + """Establish a link with the "in-protocol" (v3) handshake as initiator + + The expected transcript is: + + Onion Proxy (client) Onion Router (server) + + / [1] :-------- VERSIONS ---------> [2] + | [4] <-------- VERSIONS ---------: [3] + | + | Negotiated Version + | + | [4] <--------- CERTS -----------: [3] + | <----- AUTH_CHALLENGE ------: + | <-------- NETINFO ----------: + | + | OP don't need to + Link | authenticate + Protocol | + >= 3 | [5] :-------- NETINFO ----------> [6] + | + | Alternative: + | ( We (OR) authenticate ) + | ( ) + | ( [5] :--------- CERTS -----------> [6] ) + | ( :------ AUTHENTICATE -------> ) + | ( ^ ) + | ( (answers AUTH_CHALLENGE) ) + | ( ) + \ + + :param str address: remote relay address (default: 127.0.0.1). + :param int port: remote relay ORPort (default: 9050). + :param list versions: target link versions (default: [4, 5]). + + :returns: a link.link object + + """ + + # Setup context + peer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + ctxt = ssl.SSLContext(ssl.PROTOCOL_TLS) + + # https://trac.torproject.org/projects/tor/ticket/28616 + ctxt.options |= ssl.OP_NO_TLSv1_3 + + # Establish connection + peer = ctxt.wrap_socket(peer) + peer.connect((address, port)) + + # VERSIONS handshake + version = negotiate_version(peer, versions, as_initiator=True) + + # Wraps with socket.io + peer = lnn.socket.io(peer) + + # Get CERTS, AUTH_CHALLENGE and NETINFO cells afterwards + certs_cell = lnn.cell.certs.cell(peer.recv()) + auth_cell = lnn.cell.challenge.cell(peer.recv()) + netinfo_cell = lnn.cell.netinfo.cell(peer.recv()) + + # Sanity checks + if not certs_cell.valid: + raise RuntimeError('Invalid CERTS cell: {}'.format(certs_cell.raw)) + if not auth_cell.valid: + raise RuntimeError('Invalid AUTH_CHALLENGE cell:{}'.format( + auth_cell.raw)) + if not netinfo_cell.valid: + raise RuntimeError('Invalid NETINFO cell: {}'.format(netinfo_cell.raw)) + + # Send our NETINFO to say "we don't want to authenticate" + peer.send(lnn.cell.netinfo.pack(address)) + return link(peer, version)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/onion.html b/docs/source/_build/html/_modules/lightnion/onion.html new file mode 100644 index 0000000..1703e86 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/onion.html @@ -0,0 +1,457 @@ + + + + + + + + + + + lightnion.onion — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.onion

      +import cryptography
      +import hashlib
      +import copy
      +
      +import lightnion as lnn
      +
      +
      [docs]class state: + '''Handle Tor onion-encryption cryptographic states. + + *For now, only handle cryptography as an initiator (as an OP to an OR).* + + TODO: add support for __init__(link, circuit, initiator={True,False}) + + Status Condition + + backward decryptor provided initiator=True + encryptor (none) initiator=False + digest provided + forward decryptor (none) initiator=False + encryptor provided initiator=True + digest provided + ''' + + def __init__(self, link, circuit, early_count=8): + '''Build a new onion-encryption state from a link and circuit. + + :params link: a link object (see link.link) + :params circuit: a circuit object (see create.circuit) + :params int early_count: first `early_count` cells will be RELAY_EARLY + ''' + self.circuit = circuit + self.link = link + + self._inner = None + self.early_count = early_count + + self._last_material = None + self._reset_digest(circuit.material) + self._reset_encryption(circuit.material) + + @property + def depth(self): + '''Number of inner layers in the onion.''' + if self._inner is None: + return 0 + return self._inner.depth + 1 + + @property + def early_count(self): + '''Number of remaining RELAY_EARLY cells before sending RELAY cells.''' + + if self._inner is None: + return self._early_count + return self._inner.early_count + + @early_count.setter + def early_count(self, value): + '''Setter for self.early_count.''' + + if self._inner is None: + self._early_count = value + else: + raise RuntimeError( + 'Unable to set RELAY_EARLY counter from the outer layers!') + +
      [docs] def wrap(self, inner): + '''Wraps an inner state w/ self as outer state (see lightnion.extend). + + Usage: + 1. A one-hop circuit is build with stateA. + 2. A key exchange is made through stateA to get stateB. + 3. Then, call stateA.wrap(stateB) to properly wrap the onion. + + Usage: + 1. A two-hop circuit is build with state{A,B}. + 2. A key exchange is made through state{A,B} to get stateC. + 3. Then, call statea.wrap(stateC) to properly wrap the onion. + + *Note: should not be called explicitly.* + ''' + if self._inner is None: + inner._early_count = self._early_count + self._inner = inner + else: + self._inner.wrap(inner)
      + + def _reset_encryption(self, material): + '''Initialize stateful stream cipher with cryptographic material. + + :params material: shared material w/ {forward,backward}_key + + *Note: should not be called explicitly.* + ''' + if self._last_material == material: + raise RuntimeError('Unsafe! Do NOT reset w/ same material!') + self._last_material = material + + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives.ciphers import ( + algorithms, modes, Cipher + ) + + # Tor uses AES128-CTR with IV=0 as stream cipher + nonce_size = algorithms.AES.block_size // 8 + zeroed_ctr = modes.CTR(b'\x00' * nonce_size) + + # Initiate forward/backward encryption/decryption (as OP) TODO: add OR + self.forward_encryptor = Cipher( + algorithms.AES(material.forward_key), + zeroed_ctr, default_backend()).encryptor() + self.backward_decryptor = Cipher( + algorithms.AES(material.backward_key), + zeroed_ctr, default_backend()).decryptor() + + def _reset_digest(self, material): + '''Seed stateful 'running digests' used to authenticate payloads. + + :params material: shared material w/ {forward,backward}_key + + *Note: should not be called explicitly.* + ''' + self.forward_digest = hashlib.sha1(material.forward_digest) + self.backward_digest = hashlib.sha1(material.backward_digest) + + def _clone(self): + '''Non-recursive clone of current cryptographic state. + + Whenever it is required to rollback after an error, you can use this + function to give yourself a clone of the current state. + + *Note: does not clone inner cryptographic states.* + ''' + + child = state(self.link, self.circuit) + + # Clone digest state (use of hashlib's native hash copy) + child.forward_digest = self.forward_digest.copy() + child.backward_digest = self.backward_digest.copy() + + # Clone encryption state (use of python's ad-hoc copy) + child.forward_encryptor = copy.copy(self.forward_encryptor) + child.backward_decryptor = copy.copy(self.backward_decryptor) + + # Don't forget to propagate the RELAY_EARLY count + child._early_count = self._early_count + + # (note: we don't recursively clone inner layers of state) + child._inner = self._inner + + return child
      + +
      [docs]def core(state, command, payload=b'', stream_id=0): + '''Build a RELAY{_EARLY,} cell as an onion core (plaintext w/ `state`) + + :param state: a state object (see onion.state) + :param str command: RELAY{_EARLY,} cell command (see cell.relay.cmd) + :param bytes payload: RELAY{_EARLY,} cell content (default: b'') + :param int stream_id: RELAY{_EARLY,} stream ID (default: 0) + + :returns: a tuple (updated state, cell) + + *Note: should not be called explicitly.* + ''' + rollback = state._clone() + + # Send RELAY_EARLY cells first + relay_pack = lnn.cell.relay.pack + if rollback.early_count > 0: + rollback.early_count -= 1 + relay_pack = lnn.cell.relay_early.pack + + # Compute the cell with a zeroed 'digest' field. + cell = relay_pack( + circuit_id=state.circuit.id, + cmd=command, + data=payload, + stream_id=stream_id, + digest=b'\x00\x00\x00\x00') + + # Update the "running digest" + rollback.forward_digest.update(cell.relay.raw) + + # Write the "running digest" + full_digest = rollback.forward_digest.digest() + cell.relay.digest = full_digest[:cell.relay._view.digest.width()] + + # Encrypt the to-be-encrypted parts & build final cell + cell.relay.raw = rollback.forward_encryptor.update(cell.relay.raw) + + return rollback, cell
      + +
      [docs]def build(state, command, payload=b'', stream_id=0): + '''Build a RELAY{_EARLY,} cell. + + :param state: a state object (see onion.state) + :param str command: RELAY{_EARLY,} cell command (see cell.relay.cmd) + :param bytes payload: RELAY{_EARLY,} cell content (default: b'') + :param int stream_id: RELAY{_EARLY,} stream ID (default: 0) + + :returns: a tuple (updated state, cell) + + *Note: returns an updated state that MUST be used afterwards.* + ''' + if state.depth == 0: + return core(state, command, payload, stream_id) + rollback = state._clone() + + # Retrieve the inner layer of the onion + rollback._inner, cell = build(rollback._inner, command, payload, stream_id) + + # Wraps the layer with our outer layer of encryption + cell.relay.raw = rollback.forward_encryptor.update(cell.relay.raw) + + return rollback, cell
      + +
      [docs]def recognize(state, cell, backward=True): + '''Attempt to recognize a RELAY{_EARLY,} cell. + + :param state: a state object (see onion.state) + :param cell: a RELAY{_EARLY,} cell object (see cell.relay.cell) + :param bool backward: is it backward? or else forward? (default: True) + + :returns: a tuple (updated state, bool) + + *Note: returns an updated state that MUST be used afterwards.* + ''' + rollback = state._clone() + + # We expect the recognized field to be zeroed upon successful decryption + if not cell.relay.recognized == b'\x00\x00': + return state, False + + # We build a copy of the cell with a zeroed 'digest field' + cell_digest = cell.relay.digest + cell.relay.digest = b'\x00\x00\x00\x00' + + # Update the digest state accordingly (backward or forward) + digest = rollback.backward_digest if backward else rollback.forward_digest + digest.update(cell.relay.raw) + + # Check if the computed digest match the cell digest + if not cell_digest == digest.digest()[:cell.relay._view.digest.width()]: + return state, False + + # Update state iff the digests matched + return rollback, True
      + +
      [docs]def peel(state, cell): + '''Decrypt a RELAY{_EARLY,} cell using provided `state`. + + :param state: a state object (see onion.state) + :param cell: a RELAY{_EARLY,} cell object (see cell.relay.cell) + + :returns: a tuple (updated state, decrypted cell) + + *Note: returns an updated state that MUST be used afterwards.* + ''' + rollback = state._clone() + + cell.relay.raw = rollback.backward_decryptor.update(cell.relay.raw) + if rollback.depth == 0: + rollback, recognized = recognize(rollback, cell) + if not recognized: + raise RuntimeError( + 'Got an unrecognized RELAY cell: {}'.format(cell.raw)) + + return rollback, cell + + rollback._inner, cell = peel(rollback._inner, cell) + return rollback, cell
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/path_selection.html b/docs/source/_build/html/_modules/lightnion/path_selection.html new file mode 100644 index 0000000..4814d83 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/path_selection.html @@ -0,0 +1,686 @@ + + + + + + + + + + + lightnion.path_selection — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.path_selection
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.path_selection

      +import random
      +import sys
      +import logging
      +
      +import lightnion.descriptors as descriptors
      +
      +# Chutney launches all relays in the same subnet.
      +# So to test the proxy with Chutney, these checks needs to be disabled.
      +check_different_subnets = False
      +
      +
      [docs]def select_path(routers, state, testing=False): + """Handle the path selection + :params routers: list of the routers given by the consensus + :state: + :returns: updated state tuple (guard, middle, exit)""" + + logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) + + routers = [r for r in routers if obey_minimal_constraint(r)] + + state, exit_node = pick_good_exit(routers, state) + + state, guard = pick_good_entry(routers, state, exit_node, testing) + + state, middle = pick_good_middle(routers, state, exit_node, guard, testing) + + return state, guard, middle, exit_node
      + + +
      [docs]def select_guard_from_consensus(cons, descr, testing=False): + """Handle the selection of the guard node + :params routers: list of the routers given by the consensus + :params descr: list of descriptors + :returns: tuple (guard, middle, exit)""" + + routers = [r for r in cons['routers'] if obey_minimal_constraint(r)] + + guard = pick_good_entry_from_routers(descr, routers, testing) + + return guard
      + + +
      [docs]def select_end_path_from_consensus(cons, descr, guard, testing=False): + """Handle the selection of the middle and exit nodes + :params routers: list of the routers given by the consensus + :params descr: list of descriptors + :returns: tuple (guard, middle, exit)""" + + routers = [r for r in cons['routers'] if obey_minimal_constraint(r)] + exit_node = pick_good_exit_from_routers(descr, routers, guard) + middle = pick_good_middle_from_routers(descr, routers, exit_node, guard, testing) + + return middle, exit_node
      + + +
      [docs]def obey_minimal_constraint(router, exit_node=None, guard=None, testing=False): + """Checks if the given router respects the minimal constraints + :param testing: + :param router: router that must respect the constraints + :param exit_node: the chosen exit node + :param guard: the chosen guard node + :return: boolean""" + + flags = router['flags'] + router_address = router['address'].split(".") + + # check that the router is running, valid and has a recent version of TOR + if 'Running' not in flags: + return False + if 'Valid' not in flags: + return False + if not router['version'].startswith('Tor 0.3.'): + return False + + if exit_node is not None: + + # check that they are distinct + if router['digest'] == exit_node['digest']: + return False + + # check if they are in the same 16 subnet + if check_different_subnets: + exit_addr = exit_node['router']['address'].split(".") + if not testing and router_address[0] == exit_addr[0] and router_address[1] == exit_addr[1]: + return False + + if guard is not None: + + # check that they are distinct + if router['digest'] == guard['digest']: + return False + + # check if they are in the same 16 subnet + if check_different_subnets: + guard_addr = guard['router']['address'].split(".") + if not testing and router_address[0] == guard_addr[0] and router_address[1] == guard_addr[1]: + return False + + return True
      + + +
      [docs]def in_same_family(r0, r1, r2=None): + """Check if r0 and r1 (and possibly r0 and r2) are in the same family or not + :param r0: the descriptor of the first router (the router we are trying to see if it meets all conditions to be chosen) + :param r1: the descriptor of the second router + :param r2: the descriptor of the third router (possibly none) + :return: a boolean""" + + # check if r0 and r1 are in the same family + if 'family' in r0 and 'family' in r1: + for f in r0['family']: + if f in r1['family']: + return True + + if r2 and 'family' in r0 and 'family' in r2: + for f in r0['family']: + if f in r2['family']: + return True + + return False
      + + +
      [docs]def keep_exit(router, state): + """Checks that the router is not a bad exit, is not down, is stable, + is valid, does not run an old TOR's version, has an available ed25519 + identity key and has an 'accept' exit policy + :params router: the router we want to check + :state: + :return: tuple (boolean that indicates if we keep it, new state, descriptor)""" + + logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) + + if not obey_minimal_constraint(router): + return False, state, None + + if 'Exit' not in router['flags']: + return False, state, None + + if 'BadExit' in router['flags']: + return False, state, None + + # Retrieve the descriptor + state, nhop = descriptors.download(state, cons=router, flavor='unflavored') + + if len(nhop) == 0: + return False, state, None + + nhop = nhop[0] + + if router['digest'] != nhop['digest']: + return False, state, None + + if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': + return False, state, None + + if 'policy' not in nhop: + return False, state, None + + for rule in nhop['policy']['rules']: + if rule['pattern'] == "*:*" and rule['type'] == 'accept': + return True, state, nhop + + return False, state, None
      + +
      [docs]def keep_exit_with_descr(descr, router, guard): + """Checks that the router is not a bad exit, is not down, is stable, + is valid, does not run an old TOR's version, has an available ed25519 + identity key and has an 'accept' exit policy + :param descr: descriptor of the exit candidate. + :params router: the router we want to check + :param guard: the guard in the path + :return: tuple (boolean that indicates if we keep it, new state, descriptor)""" + + if not obey_minimal_constraint(router, guard=guard): + return False, None + + if 'Exit' not in router['flags']: + return False, None + + if 'BadExit' in router['flags']: + return False, None + + if router['digest'] not in descr: + return False, None + + nhop = descr[router['digest']] + + if router['digest'] != nhop['digest']: + return False, None + + if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': + return False, None + + if 'policy' not in nhop: + return False, None + + if in_same_family(nhop, guard): + return False, None + + for rule in nhop['policy']['rules']: + if rule['pattern'] == "*:*" and rule['type'] == 'accept': + return True, nhop + + return False, None
      + + + +
      [docs]def weighted_random_choice(list_of_possible): + """Choose one of the candidates at random weighted by their (avg) bandwidth + :params list_of_possible: list of descriptors of the candidates + :returns: descriptor of the randomly selected router""" + + total = 0 + for router in list_of_possible: + total += router['bandwidth']['avg'] + + r = random.uniform(0, total) + upto = 0 + + for router in list_of_possible: + if upto + router['bandwidth']['avg'] >= r: + return router + upto += router['bandwidth']['avg'] + + raise RuntimeError("")
      + + +
      [docs]def pick_good_exit(routers, state): + """Choose the exit node + :param routers: the routers given by the consensus + :param state: the state + :return: the descriptor of the exit node""" + + logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) + + # Go through all routers and check if they meet the conditions of an exit node + candidates = [] + for router in routers: + keep, state, descriptor = keep_exit(router, state) + if keep: + candidates.append(descriptor) + + if candidates: + return state, weighted_random_choice(candidates) + + else: + # TODO: see if we select another policy here + raise ValueError('No exit is suitable')
      + + +
      [docs]def pick_good_exit_from_routers(descr, routers, guard): + """Choose the exit node + :param routers: the routers given by the consensus + :param guard: the guard in the path + :return: the descriptor of the exit node""" + + # Go through all routers and check if they meet the conditions of an exit node + candidates = [] + for router in routers: + keep, descriptor = keep_exit_with_descr(descr, router, guard) + if keep: + candidates.append(descriptor) + + if candidates: + return weighted_random_choice(candidates) + + else: + # TODO: see if we select another policy here + raise ValueError('No exit is suitable')
      + + + +
      [docs]def keep_guard(router, state, exit_node, testing): + """Checks that the given router has the properties to be a guard + :param router: the router that must be inspected + :param state: state + :param exit_node: the previously chosen node + :return: if the router can be kept, the updated state and the descriptor""" + + logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) + + flags = router['flags'] + + if not obey_minimal_constraint(router, exit_node, testing=testing): + return False, state, None + + if 'Guard' not in flags: + return False, state, None + + if 'Stable' not in flags: + return False, state, None + + if 'Fast' not in flags: + return False, state, None + + if 'V2Dir' not in flags: + return False, state, None + + # Retrieve the descriptor + state, nhop = descriptors.download(state, cons=router, flavor='unflavored') + + if len(nhop) == 0: + return False, state, None + nhop = nhop[0] + + if router['digest'] != nhop['digest']: + return False, state, None + + if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': + return False, state, None + + if in_same_family(nhop, exit_node): + return False, state, None + + return True, state, nhop
      + + + +
      [docs]def keep_guard_with_descr(descr, router, testing): + """Checks that the given router has the properties to be a guard + :param descr: descriptor of the exit candidate. + :param router: the router that must be inspected + :return: if the router can be kept, the updated state and the descriptor""" + + flags = router['flags'] + + if not obey_minimal_constraint(router, testing=testing): + return False, None + + if 'Guard' not in flags: + return False, None + + if 'Stable' not in flags: + return False, None + + if 'Fast' not in flags: + return False, None + + if 'V2Dir' not in flags: + return False, None + + if router['digest'] not in descr: + return False, None + + nhop = descr[router['digest']] + + if router['digest'] != nhop['digest']: + return False, None + + if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': + return False, None + + return True, nhop
      + + + +
      [docs]def pick_good_entry(routers, state, exit_node, testing): + """Simplified version of the Guard selection algorithm + :param routers: the routers of the consensus + :param state: the state + :return: updated state and the descriptor of the guard node""" + + logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) + + candidates = [] + for router in routers: + keep, state, descriptor = keep_guard(router, state, exit_node, testing) + if keep: + candidates.append(descriptor) + + if candidates: + return state, weighted_random_choice(candidates) + + else: + # TODO: see if we select another policy here + raise ValueError('No guard is suitable')
      + + +
      [docs]def pick_good_entry_from_routers(descr, routers, testing): + """Simplified version of the Guard selection algorithm + :param routers: the routers of the consensus + :param state: the state + :return: updated state and the descriptor of the guard node""" + + candidates = [] + for router in routers: + keep, descriptor = keep_guard_with_descr(descr, router, testing) + if keep: + candidates.append(descriptor) + + if candidates: + return weighted_random_choice(candidates) + + else: + # TODO: see if we select another policy here + raise ValueError('No guard is suitable')
      + + +
      [docs]def keep_middle(router, state, exit_node, guard, testing): + """Checks that the given router has the properties to be a middle node + :param router: the router that must be inspected + :param state: state + :param exit_node: the previously chosen exit node + :param guard: the previously chosen guard + :return: if the router can be kept, the updated state and the descriptor""" + + logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) + + if not obey_minimal_constraint(router, exit_node, guard, testing=testing): + return False, state, None + + # Retrieve the descriptor + state, nhop = descriptors.download(state, cons=router, flavor='unflavored') + + if len(nhop) == 0: + return False, state, None + nhop = nhop[0] + + if router['digest'] != nhop['digest']: + return False, state, None + + if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': + return False, state, None + + if in_same_family(nhop, guard, exit_node): + return False, state, None + + return True, state, nhop
      + + +
      [docs]def keep_middle_with_descr(descr, router, exit_node, guard, testing): + """Checks that the given router has the properties to be a middle node + :param descr: descriptor of the exit candidate. + :param router: the router that must be inspected + :param exit_node: the previously chosen exit node + :param guard: the previously chosen guard + :return: if the router can be kept, the updated state and the descriptor""" + if not obey_minimal_constraint(router, exit_node, guard, testing=testing): + return False, None + + if router['digest'] not in descr: + return False, None + + nhop = descr[router['digest']] + + if router['digest'] != nhop['digest']: + return False, None + + if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': + return False, None + + if in_same_family(nhop, guard, exit_node): + return False, None + + return True, nhop
      + + +
      [docs]def pick_good_middle(routers, state, exit_node, guard, testing): + """Choose the middle node given the exit and the guard node + :param routers: the routers of the consensus + :param state: the state + :param exit_node: the previously chosen exit node + :param guard: the previously chosen guard node + :return: updated state and the descriptor of the guard node""" + + logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) + + candidates = [] + for router in routers: + keep, state, descriptor = keep_middle(router, state, exit_node, guard, testing) + if keep: + candidates.append(descriptor) + if candidates: + return state, weighted_random_choice(candidates) + + else: + # TODO: see if we select another policy here + raise ValueError('No middle node is suitable')
      + + +
      [docs]def pick_good_middle_from_routers(descr, routers, exit_node, guard, testing): + """Choose the middle node given the exit and the guard node + :param routers: the routers of the consensus + :param exit_node: the previously chosen exit node + :param guard: the previously chosen guard node + :return: updated state and the descriptor of the guard node""" + + candidates = [] + for router in routers: + keep, descriptor = keep_middle_with_descr(descr, router, exit_node, guard, testing) + if keep: + candidates.append(descriptor) + + if candidates: + return weighted_random_choice(candidates) + + else: + # TODO: see if we select another policy here + raise ValueError('No middle node is suitable')
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/proxy/auth.html b/docs/source/_build/html/_modules/lightnion/proxy/auth.html new file mode 100644 index 0000000..3cb3796 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/proxy/auth.html @@ -0,0 +1,273 @@ + + + + + + + + + + + lightnion.proxy.auth — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.proxy.auth

      +import collections
      +import nacl.public
      +import nacl.secret
      +import logging
      +import base64
      +import json
      +import os
      +
      +import lightnion as lnn
      +
      +
      [docs]class material(collections.namedtuple('material', ['pkey', 'secret'])): + @property + def public(self): + return bytes(self.pkey.public_key) + + @property + def suffix(self): + suffix = base64.urlsafe_b64encode(b'auth ' + self.secret + self.public) + return str(suffix.replace(b'=', b''), 'utf8') + +
      [docs] def perform(self, client, data): + data = bytes(json.dumps(data), 'utf8') + client = base64.b64decode(client) + + material, msg = lnn.crypto.ntor.server(self.pkey, self.secret, + self.secret + self.public + client, length=92) + + box = nacl.secret.SecretBox(material[:32]) + data = box.encrypt(data, nonce=material[32:32+24])[24:] + + data = base64.b64encode(data) + auth = base64.b64encode(msg) + + return dict(data=str(data, 'utf8'), auth=str(auth, 'utf8'))
      + +
      [docs]def filename(auth_dir, filename, base_dir=None): + if base_dir is None: + base_dir = os.getcwd() + auth_dir = os.path.join(base_dir, auth_dir) + + if not os.path.isdir(auth_dir): + logging.info('Note: creating {} for private material.'.format( + auth_dir)) + os.mkdir(auth_dir) + return os.path.join(auth_dir, filename)
      + +_x25519_footer = b'-----END PRIVATE KEY-----' +_x25519_header = b'-----BEGIN PRIVATE KEY-----' +_x25519_openssl_asn1 = b'0.\x02\x01\x000\x05\x06\x03+en\x04"\x04 ' + +
      [docs]def genpkey(auth_dir, base_dir=None): + logging.warning('New private key and shared secret generated.') + + pkey = bytes(nacl.public.PrivateKey.generate()) + with open(filename(auth_dir, 'private.pem'), 'wb') as f: + f.write(_x25519_header + b'\n') + f.write(base64.b64encode(_x25519_openssl_asn1 + pkey)) + f.write(b'\n' + _x25519_footer) + with open(filename(auth_dir, 'shared_secret'), 'wb') as f: + f.write(base64.b64encode(os.urandom(20)))
      + +
      [docs]def getpkey(auth_dir, base_dir=None): + with open(filename(auth_dir, 'shared_secret'), 'rb') as f: + shared_secret = base64.b64decode(f.read()) + with open(filename(auth_dir, 'private.pem'), 'rb') as f: + header, data, footer = f.read().split(b'\n') + + if header != _x25519_header: + raise RuntimeError('Invalid pem header: {} vs {}'.format( + header, _x25519_header)) + + if footer != _x25519_footer: + raise RuntimeError('Invalid pem footer: {} vs {}'.format( + footer, _x25519_footer)) + + raw = base64.b64decode(data) + if (len(data) != 64 + or len(raw) != 48 + or not raw.startswith(_x25519_openssl_asn1)): + raise RuntimeError('Invalid key encoding, expected asn1:'.format( + base64.b64encode(_x25519_openssl_asn1))) + + auth = material(nacl.public.PrivateKey(raw[16:]), shared_secret) + with open(filename(auth_dir, 'suffix'), 'w') as f: + f.write(auth.suffix + '\n') + return auth
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/proxy/forward.html b/docs/source/_build/html/_modules/lightnion/proxy/forward.html new file mode 100644 index 0000000..b11c5df --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/proxy/forward.html @@ -0,0 +1,594 @@ + + + + + + + + + + + lightnion.proxy.forward — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.proxy.forward

      +import asyncio
      +import base64
      +import logging
      +import signal
      +import string
      +import sys
      +import threading
      +import time
      +
      +from datetime import datetime, timedelta
      +
      +import quart
      +import websockets
      +
      +from quart_cors import cors
      +
      +import lightnion as lnn
      +import lightnion.path_selection
      +import lightnion.proxy
      +
      +from tools.keys import get_signing_keys_info
      +
      +#from tools.keys import get_raw_signing_keys
      +
      +debug = True
      +
      +formatter = logging.Formatter(fmt='%(asctime)s %(levelname)-8s %(message)s', datefmt='%H:%M:%S')
      +handler = logging.StreamHandler(stream=sys.stdout)
      +handler.setFormatter(formatter)
      +
      +logger = logging.getLogger()
      +logger.setLevel(logging.WARNING)
      +logger.addHandler(handler)
      +
      +logger = logging.getLogger("asyncio")
      +logger.setLevel(logging.WARNING)
      +logger.addHandler(handler)
      +
      +
      +
      [docs]class clerk(): + def __init__(self, slave_node, control_port, dir_port, compute_path, auth_dir=None): + #super().__init__() + logging.info('Bootstrapping clerk.') + self.crypto = lnn.proxy.parts.crypto() + self.dead = False + + self.auth = None + self.auth_dir = auth_dir + if auth_dir is not None: + try: + self.auth = lnn.proxy.auth.getpkey(auth_dir) + logging.debug('Auth dir is set.') + except FileNotFoundError: + lnn.proxy.auth.genpkey(auth_dir) + self.auth = lnn.proxy.auth.getpkey(auth_dir) + logging.debug('Auth dir got a file not found') + logging.debug('Note: authentication suffix is {}'.format(self.auth.suffix)) + else: + logging.debug('Auth dir is None.') + + self.retrieved_consensus = False + self.consensus = None + self.descriptors = None + + self.consensus_raw = None + self.descriptors_raw = None + self.mic_consensus_raw = None + self.mic_descriptors_raw = None + + #self.consm = None + #self.descm = None + self.signing_keys = None + #self.signing_keys_raw = None + + self.timer_consensus = None + + self.guard_node = None + + self.control_port = control_port + self.dir_port = dir_port + self.slave_node = slave_node + self.compute_path = compute_path + + self.link = None + self.channel_manager = None + self.websocket_manager = None + + +
      [docs] def prepare(self): + guard = self.get_guard() + + self.link = lnn.proxy.link.Link(guard) + self.channel_manager = lnn.proxy.jobs.ChannelManager() + self.websocket_manager = lnn.proxy.jobs.WebsocketManager() + + self.link.set_channel_manager(self.channel_manager) + self.channel_manager.set_link(self.link) + self.websocket_manager.set_channel_manager(self.channel_manager)
      + + +
      [docs] def retrieve_consensus(self): + """Retrieve relays data with direct HTTP connection and schedule its future retrival.""" + + # We tolerate that the system clock can be up to a few seconds too early. + refresh_tolerance_delay = 2.0 + min_delay = 120.0 # 2 minutes + max_time_until_invalid = 900.0 # 15 minutes + + host = self.slave_node[0] + port = self.dir_port + + + # retrieve consensus and descriptors + if self.compute_path: + cons,sg_keys = lnn.consensus.download_direct(host, port, flavor='unflavored') + desc = lnn.descriptors.download_direct(host, port, cons) + self.consensus = cons + self.signing_keys = sg_keys + self.descriptors = desc + + #self.consm,sg_keysm = lnn.consensus.download_direct(self.slave_node[0], self.dir_port) + #self.descm = lnn.descriptors.download_direct(self.slave_node[0], self.dir_port, self.consm, flavor='microdesc') + + self.consensus_raw = lnn.consensus.download_raw(host, port, flavor='unflavored') + digests = lnn.consensus.extract_nodes_digests_unflavored(self.consensus_raw) + self.descriptors_raw = lnn.descriptors.download_raw_by_digests_unflavored(host, port, digests) + + keys = get_signing_keys_info('{}:{}'.format(host, port)) + self.signing_keys = keys + #self.signing_keys_raw = get_raw_signing_keys('%s:%d'%(host, port)) + + self.mic_consensus_raw = lnn.consensus.download_raw(host, port, flavor='microdesc') + digests = lnn.consensus.extract_nodes_digests_micro(self.mic_consensus_raw) + self.mic_descriptors_raw = lnn.descriptors.download_raw_by_digests_micro(host, port, digests) + + try: + # Compute delay until retrival of the next consensus. + fresh_until = lnn.consensus.extract_date(self.consensus_raw, 'fresh-until') + now = datetime.utcnow() + delay = (fresh_until - now).total_seconds() + refresh_tolerance_delay + + if delay < min_delay: + valid_until = lnn.consensus.extract_date(self.consensus_raw, 'valid-until') + delay = (valid_until - now).total_seconds() - max_time_until_invalid + + delay = max(delay, min_delay) + + logging.debug('Delay until fetching next concensus: %f', delay) + + self.timer_consensus = threading.Timer(delay, clerk.retrieve_consensus, [self]) + self.timer_consensus.start() + self.retrieved_consensus = True + + except Exception as e: + logging.error(e) + raise e
      + + +
      [docs] def wait_for_consensus(self): + """Ensure a consensus is present in the clerk, and fetch a new one if it is not. + """ + if not self.retrieved_consensus: + if self.timer_consensus is None: + self.retrieve_consensus() + + while not self.retrieved_consensus: + logging.info('Wait for consensus...') + time.sleep(1)
      + + +
      [docs] def get_descriptor_unflavoured(self, router): + """Retrieve a descriptor. + :param router: Router from which we want the descriptor. + :return: the descriptor of the given router. + """ + + descriptor = self.descriptors[router['digest']] + + return descriptor
      + + +
      [docs] def get_guard(self): + """Generate a guard + :return: guard node + """ + + self.wait_for_consensus() + + if self.guard_node is None: + # Use local node as the guard. + #guard = lnn.path_selection.select_guard_from_consensus(self.consensus, self.descriptors) + host = self.slave_node[0] + port = self.dir_port + + guard = lnn.descriptors.download_relay_descriptor(host, port) + + #nickname = guard['router']['nickname'] + #fingerprint = guard['fingerprint'] + #entry = [fingerprint, nickname] + #guard = lnn.proxy.path.convert(entry, consensus=self.consensus, expect='list')[0] + + logging.info('New guard relay selected.') + logging.debug(guard) + self.guard_node = guard + + return self.guard_node
      + + +app = quart.Quart(__name__) +cors(app, expose_headers='Access-Control-Allow-Origin') +url = lnn.proxy.base_url + +
      [docs]@app.route(url + '/descriptors') +def get_descriptors(): + try: + app.clerk.wait_for_consensus() + desc = quart.jsonify(app.clerk.descriptors) + return desc, 200 + except Exception as e: + logging.exception(e) + quart.abort(503)
      + +
      [docs]@app.route(url + '/consensus') +async def get_consensus(): + """ + Retrieve consensus. + """ + try: + app.clerk.wait_for_consensus() + cons = quart.jsonify(app.clerk.consensus) + return cons, 200 + except Exception as e: + logging.exception(e) + quart.abort(503)
      + +
      [docs]@app.route(url + '/descriptors-raw/<flavor>') +def get_descriptors_raw(flavor): + try: + app.clerk.wait_for_consensus() + + desc = app.clerk.mic_descriptors_raw + if flavor == 'unflavored': + desc = app.clerk.descriptors_raw + + return desc, 200 + except Exception as e: + logging.exception(e) + quart.abort(503)
      + +
      [docs]@app.route(url + '/consensus-raw/<flavor>') +async def get_consensus_raw(flavor): + """ + Retrieve raw consensus. + """ + try: + app.clerk.wait_for_consensus() + cons = app.clerk.mic_consensus_raw + if flavor == 'unflavored': + cons =app.clerk.consensus_raw + + return cons, 200 + except Exception as e: + logging.exception(e) + quart.abort(503)
      + +
      [docs]@app.route(url + '/signing-keys') +async def get_signing_keys(): + """ + Retrieve signing keys to verify consensus. + """ + try: + app.clerk.wait_for_consensus() + keys = app.clerk.signing_keys + return keys, 200 + except Exception as e: + logging.exception(e) + quart.abort(503)
      + +
      [docs]@app.route(url + '/guard') +async def get_guard(): + """ + Retrieve guard descriptor. + """ + try: + guard = app.clerk.link.guard + res = quart.jsonify(guard) + return res, 200 + except Exception as e: + logging.exception(e) + quart.abort(503)
      + + +
      [docs]@app.route(url + '/channels', methods=['POST']) +async def create_channel(): + """ + Create a channel. + """ + payload = await quart.request.get_json() + #if not payload or not 'ntor' in payload: + # quart.abort(400) + + logging.info('Create new channel.') + #ntor = payload['ntor'] + + auth = None + if 'auth' in payload: + auth = payload['auth'] + if app.clerk.auth is None: + quart.abort(400) + + select_path = False + if 'select_path' in payload: + if payload['select_path'] == "true": + select_path = True + + if not select_path: + app.clerk.wait_for_consensus() + + try: + #data = app.clerk.create.perform(data) + ckt_info = app.clerk.channel_manager.create_channel( app.clerk.consensus, app.clerk.descriptors, select_path) + if auth is not None: + # TODO the proxy pack the ntor key in a tor cell, this can be done client side. + ckt_info = app.clerk.auth.perform(auth,ckt_info) + + response = quart.jsonify(ckt_info) + return response, 201 # Created + + except Exception as e: + logging.exception(e) + quart.abort(503)
      + + +
      [docs]@app.route(url + '/channels/<uid>', methods=['DELETE']) +async def delete_channel(uid): + """ + Delete a channel. + :param uid: channel identifier + """ + try: + channel = app.clerk.channel_manager.get_channel_by_token(uid) + except Exception as e: + logging.exception(e) + quart.abort(404) + + try: + await app.clerk.channel_manager.destroy_circuit_from_client(channel) + await app.clerk.channel_manager.destroy_circuit_from_link(channel) + except Exception as e: + logging.exception(e) + quart.abort(500) + + return quart.jsonify({}), 202 # Deleted
      + + +
      [docs]async def loop_signal_handler(signum, loop): + """ + Handler to stop coroutines. + """ + + logging.debug('Signal handler called.') + app.clerk.timer_consensus.cancel() + await app.shutdown() + await app.clerk.websocket_manager.stop() + + tasks = [task for task in asyncio.all_tasks() if task is not asyncio.current_task()] + + for task in tasks: + task.cancel() + + await asyncio.gather(*tasks) + + loop.stop()
      + + +
      [docs]def main(port, slave_node, control_port, dir_port, compute_path, auth_dir=None): + """ + Entry point + """ + + #if static_files is not None: + # from werkzeug import SharedDataMiddleware + # app.wsgi_app = SharedDataMiddleware(app.wsgi_app, static_files) + + app.clerk = clerk(slave_node, control_port, dir_port, compute_path, auth_dir) + logging.info('Bootstrapping HTTP server.') + + logging.getLogger(websockets.__name__).setLevel(logging.INFO) + asyncio.set_event_loop(asyncio.new_event_loop()) + + app.clerk.prepare() + + loop = asyncio.get_event_loop() + for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT): + loop.add_signal_handler(s, lambda s=s: asyncio.create_task(loop_signal_handler(s, loop))) + + loop.set_exception_handler(None) + + try: + loop.create_task(app.clerk.link.connection) + loop.create_task(app.clerk.websocket_manager.serve(loop)) + + app.run(host='0.0.0.0', port=port, debug=debug, loop=loop, use_reloader=False) + except Exception: + pass + finally: + loop.close()
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/proxy/jobs.html b/docs/source/_build/html/_modules/lightnion/proxy/jobs.html new file mode 100644 index 0000000..2e10fc8 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/proxy/jobs.html @@ -0,0 +1,665 @@ + + + + + + + + + + + lightnion.proxy.jobs — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.proxy.jobs

      +import logging
      +import hashlib
      +import base64
      +import time
      +import websockets
      +import asyncio
      +
      +import lightnion as lnn
      +from . import parts, base_url, fake_circuit_id
      +import lightnion.path_selection
      +import lightnion.utils
      +
      +
      +
      [docs]class InvalidTokenException(Exception): + def __init__(self, token): + super().__init__('Value {} is not a valid token.'.format(token))
      + +
      [docs]class CircuitDoesNotExistException(Exception): + def __init__(self, cid): + super().__init__('Circuit id {} does not exist.'.format(cid))
      + +
      [docs]class ChannelDoesNotExistException(Exception): + def __init__(self, channel): + super().__init__('Channel {} does not exist.'.format(channel))
      + +
      [docs]class LinkNotInitializedException(Exception): + pass
      + +
      [docs]class LinkAlreadyInitializedException(Exception): + pass
      + +
      [docs]def dummy_random_gen(): + return b'Dummy random data.'
      + + +
      [docs]class Channel: + """ + Channel + """ + def __init__(self, token, cid): + """ + Channel constructor. + :param token: Token identifyint the channel. + :param cid: Circuit id corresponding to the channel. + """ + self.token = token + self.cid = cid + + self.to_send = asyncio.Queue(2048) + + self.destroyed = asyncio.Event()
      + + +
      [docs]class ChannelManager: + """ + Channel manager + """ + + # Cryptographic tools to generate tokens. + crypto = parts.crypto() + + def __init__(self): + """ + Channel manager constructor + """ + # channels identified by a token + self.channels = dict() + + # link and main token set later + self.link = None + self.maintoken = None + + + def _cid_from_token(self, token): + """ + Extract a circuit id from a token. + :param token: token from which the circuit id is extracted. + """ + cid = self.crypto.decrypt_token(token, self.maintoken) + + if cid is None: + logging.debug('ChanMgr: Invalid token: {}'.format(token)) + raise InvalidTokenException() + + return cid + + +
      [docs] def gen_token_from_cid(self, cid): + """ + Produce a token from a circuit id. + :param cid: circuit id used to generate the token. + """ + return self.crypto.compute_token(cid, self.maintoken)
      + + + def _gen_main_token(self, rnd_gen): + """ + Generate the main token used to produce channel tokens. + :param rnd_gen: method to generate a ransdom number to initialize the token generator. + :return: main token + """ + if self.link is None: + raise LinkNotInitializedException() + + guard_id = self.link.guard['digest'].encode('utf-8') + secret = rnd_gen() + maintoken = hashlib.sha256(guard_id + secret).digest() + logging.debug('ChanMgr: Main token generated: {}'.format(maintoken)) + return maintoken + + + + + + + + +
      [docs] def create_channel(self, consensus, descriptors, select_path): + """ + Create a new channel. + :param ntor: First part of the ntor handshake provided by the client. + :param consensus: The current consensus. + :param descriptors: A collection of the current descriptors. + :return: Response to be send to the client + """ + + # TODO: Currently, the ntor is provided by the client to be packaged + # in the proxy and send back to the client to be send again to + # the websocket. This need to be simplified. + + if self.link is None: + raise LinkNotInitializedException() + + #ntor_bin = base64.b64decode(ntor) + + cid = self.link.gen_cid() + token = self.gen_token_from_cid(cid) + + #cell = lnn.create.ntor_raw2(cid, ntor_bin) + #cell = base64.b64encode(cell).decode('utf-8') + + self.channels[cid] = Channel(token, cid) + + if not select_path: + (middle, exit) = lnn.path_selection.select_end_path_from_consensus(consensus, descriptors, self.link.guard) + logging.warning('Middle {}'.format(middle['router']['nickname'])) + logging.warning('Exit {}'.format(exit['router']['nickname'])) + response = {'id': token, 'path': [middle, exit], 'guard': self.link.guard} + logging.debug('ChanMgr: Channel {} with token {} created.'.format(cid, token)) + return response + else: + response = {'id': token, 'guard': self.link.guard} + logging.debug('ChanMgr: Channel {} with token {} created.'.format(cid, token)) + return response
      + +
      [docs] def delete_channel(self, channel): + """ + Delete a given channel if it is managed by the channel manager, do nothing otherwise. + :param channel: Channel to be deleted. + """ + if channel.cid in self.channels.keys(): + del self.channels[channel.cid] + logging.debug('ChanMgr: Channel {} with token {} deleted.'.format(channel.cid, channel.token))
      + + +
      [docs] async def destroy_circuit_from_client(self, channel): + """ + Destroy a circuit corresponding to a channel as if the order was comming from the client side. + :param channel: Channel handling the circuit to be destroyed. + """ + + # Send a cell to the link to delete the circuit in the relay. + cid = channel.cid + reason = lnn.cell.destroy.reason.REQUESTED + + cell = lnn.cell.destroy.pack(cid, reason) + cell_padded = lnn.cell.pad(cell) + + await self.link.to_send.put(cell_padded) + + # Destroy the channel. + channel.destroyed.set() + + logging.debug('ChanMgr: Prepare to delete circuit {} from client.'.format(cid))
      + + + + + +
      [docs] def get_channel_by_token(self, token): + """ + Get a channel by its token. + :param token: Token identifying the channel. + """ + + cid = self._cid_from_token(token) + + if cid not in self.channels.keys(): + raise ChannelDoesNotExistException(token) + + return self.channels[cid]
      + + +
      [docs] async def schedule_to_send(self, cell, cid): + """ + Scedule the data to be send to the correct channel. + :param cell: cell to be send. + """ + logging.debug('ChanMgr: Begin adding data to sending queue of channel {}.'.format(cid)) + + if cid not in self.channels.keys(): + logging.warning('ChanMgr: Channel {} does not exists.'.format(cid)) + return + #raise CircuitDoesNotExistException(cid) + + channel = self.channels[cid] + + if channel.destroyed.is_set(): + logging.warning('ChanMgr: Channel {} is destroyed.'.format(cid)) + return + #raise CircuitDoesNotExistException(cid) + + # If the cell command to delete the circuit, + header = lnn.cell.header(cell) + if header.cmd is lnn.cell.cmd.DESTROY: + cell_validation = lnn.cell.destroy.cell(cell) + logging.warning('ChanMgr: DESTROY cell received for channel {}, reason: {}.'.format(cid, cell_validation.reason)) + if not cell_validation.valid: + logging.debug('ChanMgr: Invalid DESTROY in channel {}.'.format(cid)) + #raise InvalidDestroyCellException() + else: + await self.destroy_circuit_from_link(channel) + + return + + cell_padded = lnn.cell.pad(cell) + + await channel.to_send.put(cell_padded) + + logging.debug('ChanMgr: Data added to sending queue of channel {}.'.format(channel.cid))
      + + + +
      [docs]class WebsocketManager: + prefix = base_url + '/channels/' + prefix_len = len(prefix) + + def __init__(self, host='0.0.0.0', port=8765, timeout=60): + """ + Websocket server + :param host: host on which the websocket need to run. + :param port: port on which the websocket is listening. + :param timeout: timeout before closing the connection. + """ + + # Time witout activity until channel is deleted. + self.timeout = timeout + + # The channel manager is set later + self.channel_manager = None + + # The websocket server + self.host = host + self.port = port + self.server = None + + self.cell_sent = 0 + self.cell_recv = 0 + + + logging.debug('WsServ: Websocket server prepared ({}:{})'.format(host, port)) + + +
      [docs] async def serve(self, loop): + """ + Create and start a websocket server, then wait for it to close. + :param host: host on which the websocket need to run. + :param port: port on which the websocket is listening. + """ + self.server = await websockets.serve(self._handler, self.host, self.port, loop=loop, compression=None)
      + + +
      [docs] async def stop(self): + if self.server is not None: + self.server.close() + await self.server.wait_closed() + logging.debug('WsServ: Websocket server closed.')
      + + +
      [docs] def set_channel_manager(self, channel_manager): + """ + Set the channel manager to use for dispatching data. + :param channel_manager: The channel manager to use. + """ + self.channel_manager = channel_manager + logging.debug('WsServ: Channel manager set.')
      + + + async def _recv(self, ws, channel): + """ + Handler to receive a message from the client via the websocket. + :param ws: websocket used to communicate with the client. + :param channel: Channel correspondind to the client from which data is recieved. + """ + + while not ws.closed: + try: + cell = await ws.recv() + + self.cell_recv += 1 + logging.info('cell {} recv by wbskt: {}'.format(self.cell_recv, cell[:20].hex())) + logging.debug('WsServ: Recieved cell from channel {}: {}... {} bytes.'.format(channel.cid, cell[:20], len(cell))) + + await self.channel_manager.link.schedule_to_send(cell, channel) + + except websockets.exceptions.ConnectionClosedError: + logging.exception('Websocket connection closed.') + return + + except websockets.exceptions.ConnectionClosedOK: + logging.info('Websocket connection closed.') + return + + + async def _send(self, ws, channel): + """ + Handler to send a message to the client via the websocket. + :param ws: The websocket used to communicate with the client. + :param channel: Channel from which data is sent. + """ + + while not ws.closed: + try: + cell = await channel.to_send.get() + + cell = lnn.cell.pad(cell) + await ws.send(cell) + + self.cell_sent += 1 + logging.info('cell {} sent to wbskt: {}'.format(self.cell_sent, cell[:20].hex())) + + logging.debug('WsServ: Sent data to channel {}: {}... {} bytes.'.format(channel.cid, cell[:20], len(cell))) + + except websockets.exceptions.ConnectionClosed as err: + logging.exception() + return + + + async def _timeout(self, ws, channel): + """ + Handler to send termination cells in case of a timeout. + :param ws: The websocket used to communicate with the client. + :param channel: Channel from which data is sent. + """ + await asyncio.sleep(self.timeout) + + logging.debug('WsServ: Channel {} timed out.'.format(channel.cid)) + + await self.channel_manager.destroy_circuit_from_client(channel) + + + async def _destroy(self, ws, channel): + """ + Handler to destroy the specific circuit. + :param ws: The websocket used to communicate with the client. + :param channel: Channel from which data is sent. + """ + + # Just await for the channel to be destroyed. + await channel.destroyed.wait() + + + async def _handler(self, ws, path): + """ + Handler to process a IO on the websocket or on the link. + :param ws: The websocket used to communicate with the client. + :param path: Path used by the client. + """ + + if not path.startswith(WebsocketManager.prefix): + logging.warning('WsServ: Attempted to connect to websocket with an invalid prefix {}.'.format(path)) + return + + token = path[WebsocketManager.prefix_len:] + + logging.debug('WsServ: Begin handler for channel id by token {}.'.format(token)) + + try: + channel = self.channel_manager.get_channel_by_token(token) + except Exception: + logging.warning('WsServ: Attempted to connect to websocket with an invalid token {}.'.format(token)) + return + + tasks = [ + asyncio.create_task(self._destroy(ws, channel)), + #asyncio.create_task(self._timeout(ws, channel)), + asyncio.create_task(self._recv(ws, channel)), + asyncio.create_task(self._send(ws, channel)) + ] + + done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + + #while not ws.closed: + # done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + + # # Conditions to continue or stop listening. + + # # Circuit destroyed -> close websocket. + # if tasks[0].done(): + # logging.debug('WsServ: Channel {} destroyed.'.format(channel.cid)) + # break + + # # Long timeout -> close websocket. + # if tasks[1].done(): + # logging.debug('WsServ: Ws handler timed out for channel {}.'.format(channel.cid)) + # break + # else: + # # Channel has not timed out, so the timeout is resetted. + # tasks[1].cancel() + # tasks[1] = asyncio.create_task(self._timeout(ws, channel)) + # logging.debug('WsServ: Reset timeout handler for channel {}.'.format(channel.cid)) + + # # If recv is done, restart it. + # if tasks[2].done() or tasks[2].cancelled(): + # tasks[2] = asyncio.create_task(self._recv(ws, channel)) + # logging.debug('WsServ: New recv task created for channel {}.'.format(channel.cid)) + + # # If send is done, restart it. + # if tasks[3].done() or tasks[3].cancelled(): + # tasks[3] = asyncio.create_task(self._send(ws, channel)) + # logging.debug('WsServ: New send task created for channel {}.'.format(channel.cid)) + + # The channel is destroyed, and the connection needs to be closed. + + # Cancel tasks which are still pending. + for task in tasks: + if not (task.cancelled() or task.done()): + task.cancel() + + # Delete the channel and close the websocket. + self.channel_manager.delete_channel(channel) + await ws.close() + + logging.debug('WsServ: End handler for channel {}.'.format(channel.cid))
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/proxy/link.html b/docs/source/_build/html/_modules/lightnion/proxy/link.html new file mode 100644 index 0000000..6691d73 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/proxy/link.html @@ -0,0 +1,593 @@ + + + + + + + + + + + lightnion.proxy.link — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.proxy.link

      +import logging
      +import socket
      +import ssl
      +import asyncio
      +
      +import lightnion as lnn
      +import lightnion.cell
      +import lightnion.utils
      +from lightnion.proxy import fake_circuit_id
      +
      +
      +
      [docs]class InvalidCellHeaderException(Exception): + pass
      + +
      [docs]class InvalidAuthCellException(Exception): + pass
      + +
      [docs]class InvalidCertsCellException(Exception): + pass
      + +
      [docs]class InvalidDestroyCellException(Exception): + pass
      + +
      [docs]class InvalidNetInfoCellException(Exception): + pass
      + +
      [docs]class InvalidVersionCellException(Exception): + pass
      + +
      [docs]class NoSupportedVersionException(Exception): + pass
      + + + +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/proxy/parts.html b/docs/source/_build/html/_modules/lightnion/proxy/parts.html new file mode 100644 index 0000000..4bd99fa --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/proxy/parts.html @@ -0,0 +1,230 @@ + + + + + + + + + + + lightnion.proxy.parts — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.proxy.parts

      +import secrets
      +import base64
      +
      +from cryptography.hazmat.primitives.ciphers.aead import AESGCM as gcm
      +from cryptography.exceptions import InvalidTag
      +
      +import lightnion as lnn
      +
      +
      [docs]class crypto: + def __init__(self): + self.binding = secrets.token_bytes(32) + self.gcm = gcm(gcm.generate_key(bit_length=128)) + +
      [docs] def compute_token(self, circuit_id, binding): + circuit_id = lnn.cell.view.uint(4).write(b'', circuit_id) + + nonce = secrets.token_bytes(12) + token = self.gcm.encrypt(nonce, circuit_id, self.binding + binding) + token = base64.urlsafe_b64encode(nonce + token) + return str(token.replace(b'=', b''), 'utf8')
      + +
      [docs] def decrypt_token(self, token, binding): + try: + if not isinstance(token, str): + token = str(token, 'utf8') + token = base64.urlsafe_b64decode(token + '====') + except BaseException: + return None + + if len(token) != 32: + return None + + binding = self.binding + binding + nonce, token = token[:12], token[12:] + try: + circuit_id = self.gcm.decrypt(nonce, token, binding) + except InvalidTag: + return None + + if len(circuit_id) != 4: + return None + + return int.from_bytes(circuit_id, byteorder='big')
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/proxy/path.html b/docs/source/_build/html/_modules/lightnion/proxy/path.html new file mode 100644 index 0000000..7a653af --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/proxy/path.html @@ -0,0 +1,452 @@ + + + + + + + + + + + lightnion.proxy.path — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.proxy.path

      +import multiprocessing
      +import threading
      +import logging
      +import atexit
      +import base64
      +import queue
      +import time
      +
      +import stem
      +import stem.process
      +import stem.control
      +
      +# TODO: replace the whole content of this file with proper stuff!
      +
      +default_nb_worker = 2
      +
      +
      [docs]class worker(threading.Thread): + def __init__(self, host, port, barrier, path_queue, batch_size): + super().__init__() + + self.mini_batch = batch_size // 8 if batch_size // 8 > 0 else 1 + self.batch_size = batch_size + self.path_queue = path_queue + self.barrier = barrier + self.count = 0 + self.finished = False + self.dead = False + self.port = port + self.host = host + +
      [docs] def run(self): + ctrl = stem.control.Controller.from_port(self.host, port=self.port) + ctrl.authenticate() + + first = self.barrier.wait() + if first == 0: + ctrl.drop_guards() + ctrl.signal(stem.Signal.NEWNYM) + self.barrier.wait() + + circs = [] + while not self.dead: + if self.count >= self.batch_size and not self.dead: + for circ in circs: + try: + ctrl.close_circuit(circ) + except (stem.ControllerError, ValueError): + pass + self.finished = True + self.count = 0 + + for _ in range(self.mini_batch): + if len(circs) > self.batch_size: + break + + try: + circs.append(ctrl.new_circuit()) + except stem.ControllerError as e: + pass + + fails = [] + for circ in circs: + try: + path = ctrl.get_circuit(circ).path + if len(path) == 3: + ctrl.close_circuit(circ) + self.path_queue.put(path) + self.count += 1 + else: + fails.append(circ) + except (stem.ControllerError, ValueError) as e: + pass + + circs = fails + self.barrier.wait() + + ctrl.close()
      + +_cached_tor = None +
      [docs]def get_tor(control_port=9051, socks_port=9050, msg_handler=None): + global _cached_tor + if _cached_tor is not None: + return _cached_tor + + tor = stem.process.launch_tor_with_config( + config={ + 'SocksPort': str(socks_port), + 'ControlPort': str(control_port), + 'PublishServerDescriptor': '0', + }, init_msg_handler=msg_handler) + atexit.register(tor.kill) + + _cached_tor = tor
      + +
      [docs]def emitter( + output_queue, + kill_queue, + control_host, + control_port, + batch=32, + target=1024, + nb_worker=default_nb_worker): + + # (shut up stem) + logging.getLogger(stem.__name__).setLevel(logging.ERROR) + + barrier = threading.Barrier(nb_worker) + path_queue = queue.Queue(maxsize=batch) + batch_size = target // nb_worker + 1 + + workers = [] + for _ in range(nb_worker): + workers.append( + worker( + control_host, + control_port, + barrier, + path_queue, + batch_size)) + + for w in workers: + w.start() + + guard, middle, exit = path_queue.get() + output_queue.put(guard) + output_queue.put((middle, exit)) + + while any([not w.finished for w in workers]): + new_guard, middle, exit = path_queue.get() + if new_guard != guard: + continue + + output_queue.put((middle, exit)) + if kill_queue.qsize() > 0: + for w in workers: + w.finished = True + + # (cleanup is useless as the process will die, but do it nonetheless) + barrier.abort() + for w in workers: + w.dead = True + + try: + for i in range(path_queue.qsize()): + path_queue.get_nowait() + except queue.Empty: + pass + + for w in workers: + w.join(0.1)
      + +
      [docs]class producer: + def __init__(self, process, path_queue, kill_queue, tor_process): + self.guard = path_queue.get() + self.process = process + self.path_queue = path_queue + self.kill_queue = kill_queue + self.tor_process = tor_process + + @property + def dead(self): + return not self.process.is_alive() + + @property + def empty(self): + return not (self.path_queue.qsize() > 0) + +
      [docs] def get(self): + return self.path_queue.get()
      + +
      [docs] def close(self): + try: + self.kill_queue.put_nowait([None]) + except queue.Full: + pass + + try: + self.path_queue.get_nowait() + except queue.Empty: + pass
      + +_default_tor = None +_default_socks_port = None +_default_control_port = None +
      [docs]def fetch( + batch=32, + target=1024, + nb_worker=2, + tor_process=None, + socks_port=None, + control_host='127.0.0.1', + control_port=None): + + global _default_tor, _default_socks_port, _default_control_port + if socks_port is None: + if _default_socks_port is None: + _default_socks_port = 9050 + socks_port = _default_socks_port + + if control_port is None: + if _default_control_port is None: + _default_control_port = 9051 + control_port = _default_control_port + + if tor_process is None: + if _default_tor is None: + _default_tor = get_tor( + socks_port=socks_port, + control_port=control_port, + msg_handler=None) + tor_process = _default_tor + + path_queue = multiprocessing.Queue(maxsize=batch) + kill_queue = multiprocessing.Queue(maxsize=1) + process = multiprocessing.Process(target=emitter, args=( + path_queue, + kill_queue, + control_host, + control_port, + batch, + target, + nb_worker)) + process.start() + + if not tor_process: + tor_process = None + + return producer(process, path_queue, kill_queue, tor_process)
      + +# TODO: check if this conversion fingerprint->descriptor is safe? +
      [docs]def convert(*entries, consensus, expect='fetch_format'): + if expect not in ['list', 'fetch_format']: + raise RuntimeError('Format unknown: {}'.format(expect)) + + if expect == 'fetch_format': + entries = [entries[0]] + [node for pair in entries[1] for node in pair] + guard, *paths = convert(*entries, consensus=consensus, expect='list') + paths = list(zip(paths[::2], paths[1::2])) + return guard, paths + + if expect == 'list': + pass + new_entries = [] + + by_identity = {r['identity']: r for r in consensus['routers']} + if len(by_identity) != len(consensus['routers']): + raise RuntimeError('Unsafe! Duplicates in the consensus!') + + for entry in entries: + fingerprint, nickname = entry + + as_identity = str(base64.b64encode(bytes.fromhex(fingerprint)), 'utf8') + as_identity = as_identity.replace('=', '') + + if as_identity not in by_identity: + raise RuntimeError('Unknown entity within consensus: {}'.format( + (entry, as_identity))) + + router = by_identity[as_identity] + if nickname != router['nickname']: + raise RuntimeError('Mismatched nickname: {} vs {}'.format(nickname, + router['nickname'])) + + new_entries.append(router) + return new_entries
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/proxy/relayinfo.html b/docs/source/_build/html/_modules/lightnion/proxy/relayinfo.html new file mode 100644 index 0000000..1aedf29 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/proxy/relayinfo.html @@ -0,0 +1,207 @@ + + + + + + + + + + + lightnion.proxy.relayinfo — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.proxy.relayinfo
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.proxy.relayinfo

      +from stem.control import Controller
      +
      +DEFAULT_PARAMS = [
      +]
      +
      +
      [docs]def get_relay_info(port, password=None, params=None): + """Retrieve some info from the relay. + """ + + if params is None: + params = DEFAULT_PARAMS + + with Controller.from_port(port=port) as controller: + controller.authenticate(password=password) + + info = controller.get_info(params) + + return info + + raise Exception('An error occurred while retrieving the info from the relay.')
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/signature.html b/docs/source/_build/html/_modules/lightnion/signature.html new file mode 100644 index 0000000..6f7a34b --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/signature.html @@ -0,0 +1,347 @@ + + + + + + + + + + + lightnion.signature — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.signature

      +from Crypto.PublicKey import RSA
      +from Crypto.Hash import SHA
      +import Crypto
      +import binascii
      +from Crypto.Util.number import *
      +
      +
      +
      [docs]def verify(raw_cons, keys, minimal=0.5): + """ + This function verifies the given raw consensus + + Note: TOR does not perform a full PKCS#1 v1.5 signature (RFC 2313) as mentioned in the TOR's reference. + The padding of the data that must be signed is done following the reference (see subsection 8.1 of the + RFC 2313 for more details), however the digest is not wrapped into the data structure described in the + subsection 10.1.2. This is the reason why RSA is performed manually and the module PKCS1_v1_5 of pycrypto is + not used. + + :param raw_cons: the consensus we want to verify + :param keys: a dictionary of keys as retrieved by the function get_signing_keys_info of tools/keys.py + :param minimal: the minimal percentage of the authorities whose signatures must be verified in order to accept the + given consensus + :return: true if at least the minimal number of signatures are verified + """ + assert 0 < minimal <= 1 + + nbr_verified = 0 + total = 0 + + # split the consensus and hash it + raw_cons = raw_cons.split('directory-signature ') + cons = raw_cons[0] + 'directory-signature ' + h = SHA.new(cons.encode('ASCII')) + + # get the signatures and the signing keys + signatures_and_key_digest = get_signature_and_digests(raw_cons[1:]) + + for fingerprint in signatures_and_key_digest.keys(): + total += 1 + # get the RSA public key and verify it is valid + key = keys.get(fingerprint) + signing_key_digest = signatures_and_key_digest[fingerprint]['signing-key-digest'] + + if key is None or not verify_key(key["pem"], signing_key_digest): + continue + else: + public_key = RSA.importKey(key["pem"]) + + signature = get_binary_signature(fingerprint, signatures_and_key_digest) + padded_hash = get_hash(public_key, signature) + + if not verify_format(padded_hash): + continue + + sep_idx = padded_hash.index(b'\x00', 2) + recovered_hash = binascii.hexlify(padded_hash[sep_idx + 1:]).decode() + + if recovered_hash == h.hexdigest(): + print("{}: signature verified".format(fingerprint)) + nbr_verified += 1 + else: + print("{}: signature not verified".format(fingerprint)) + + return nbr_verified > total * minimal
      + + +
      [docs]def get_hash(public_key, signature): + """ + This functions performs RSA on a binary signature + :param public_key: the key used to compute RSA + :param signature: the signature + :return: the binary digest of the signature + """ + signature=bytes_to_long(signature) + m = public_key._encrypt(signature) + m = long_to_bytes(m) + + # Compute k the number of bytes of the original message + mod_bits = Crypto.Util.number.size(public_key.n) + k = Crypto.Util.number.ceil_div(mod_bits, 8) + # Prepend leading 0 bytes that encrypt does not return + m = b'\x00' * (k - len(m)) + m + return m
      + +
      [docs]def get_binary_signature(fingerprint, signatures_and_key_digest): + """ + This function encodes a signature in base64 pem format into binary + :param fingerprint: the fingerprint of the author of the signature we want to encode + :param signatures_and_key_digest: the mapping from fingerprints to signature (and the signature key digest) + :return: the binary version of the signature + """ + # get the signature corresponding to fingerprint and convert it to binary + signature_lines = signatures_and_key_digest[fingerprint]['signature'].split('\n') + start_index = signature_lines.index("-----BEGIN SIGNATURE-----") + 1 + end_index = signature_lines.index("-----END SIGNATURE-----") + raw_signature = ''.join(signature_lines[start_index:end_index]) + signature = binascii.a2b_base64(raw_signature) + return signature
      + + +
      [docs]def verify_key(actual, hex_digest): + """ + Function that verify that the downloaded key corresponds to the hex digest of the consensus + :param actual: the key with the format + + -----BEGIN RSA PUBLIC KEY-----\n + base64 encoded key split on multiples lines ending with \n + -----END RSA PUBLIC KEY----- + + :param hex_digest: the sha1 digest of the key + :return: true if the key is verified + """ + raw_key = ''.join(actual.split('\n')[1:-1]) + key_bin = binascii.a2b_base64(raw_key) + key_hash = SHA.new(key_bin) + return hex_digest == key_hash.hexdigest().upper()
      + + +
      [docs]def get_signature_and_digests(remaining): + """ + Function that get the signature and the hex digests from the remaining part of the consensus + :param remaining: remaining (without the part that must be hashed) part of the consensus split by authority + :return: dictionary mapping the fingerprint of an authority and both its signature and the hex digest of its public + key + """ + sign_and_digests = {} + + for r in remaining: + if r != '': + digests, sign = r.split('\n', 1) + digests = digests.split(" ") + identity, key_hex_digest = digests if len(digests) == 2 else digests[1:] + + sign_and_digests[identity] = { + "signing-key-digest": key_hex_digest, + "signature": sign + } + return sign_and_digests
      + + +
      [docs]def verify_format(padded_hash): + """ + This function verifies that the hash as the good format, i.e: + # 1 byte - [null '\x00'] + # 1 byte - [block type identifier '\x01'] - Should always be 1 + # N bytes - [padding '\xFF' ] + # 1 byte - [separator '\x00' ] + # M bytes - [message] + :param padded_hash: + :return: true if the format is correct + """ + # Check leading two bytes + if padded_hash[:2] != b'\x00\x01': + return False + # Find end of padding and check padding bytes + sep_idx = padded_hash.index(b'\x00', 2) + for idx in range(2, sep_idx): + if padded_hash[idx] != 0xff: + return False + + return True
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/socket.html b/docs/source/_build/html/_modules/lightnion/socket.html new file mode 100644 index 0000000..bc26ed2 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/socket.html @@ -0,0 +1,398 @@ + + + + + + + + + + + lightnion.socket — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.socket

      +import lightnion as lnn
      +
      +import threading
      +import socket
      +import queue
      +import ssl
      +
      +# TODO: Better network handling?
      +
      +class _stat_peer:
      +    def __init__(self, peer):
      +        self.peer = peer
      +
      +        self._kbout = 0
      +        self._kbin = 0
      +
      +    def disp(self):
      +        print('Traffic: {:.2f} up {:.2f} down'.format(
      +            self._kbout, self._kbin), end='\r')
      +
      +    def recv(self, size):
      +        data = self.peer.recv(size)
      +        self._kbin += len(data) / 1000
      +        self.disp()
      +        return data
      +
      +    def send(self, data):
      +        bytes_send = self.peer.send(data)
      +        self._kbout += bytes_send / 1000
      +        self.disp()
      +        return bytes_send
      +
      +    def sendall(self, data):
      +        bytes_send = self.peer.sendall(data)
      +        self._kbout += bytes_send / 1000
      +        self.disp()
      +        return bytes_send
      +
      +    def get_channel_binding(self, *kargs):
      +        return self.peer.get_channel_binding(*kargs)
      +
      +    def close(self):
      +        return self.peer.close()
      +
      +
      [docs]def cell_slice(payload, once=False): + cell_header = lnn.cell.header(payload) + if len(payload) < cell_header.width: # (payload too small, need data) + return [], payload, True + + if not cell_header.valid: + raise RuntimeError('Invalid cell header: {}'.format(cell_header.raw)) + + length = cell_header.width + lnn.constants.payload_len + if not cell_header.cmd.is_fixed: + cell_header = lnn.cell.header_variable(payload) + if len(payload) < cell_header.width: # (payload too small, need data) + return [], payload, True + + if not cell_header.valid: + raise RuntimeError( + 'Invalid variable cell header: {}'.format(cell_header.raw)) + + length = cell_header.width + cell_header.length + + if length > lnn.constants.max_payload_len: + raise RuntimeError('Invalid cell length: {}'.format(length)) + + if len(payload) < length: + return [], payload, True + + cells = [payload[:length]] + payload = payload[length:] + celling = False + + if once: + return cells, payload, celling + + while not celling and len(payload) > 0: + new_cells, payload, celling = cell_slice(payload, once=True) + cells += new_cells + return cells, payload, celling
      + +
      [docs]class worker(threading.Thread): + def __init__(self, peer, max_fails=32, max_queue=2048, buffer_size=4096): + super().__init__() + + self.buffer_size = buffer_size + self.max_queue = max_queue + self.max_fails = max_fails + self.peer = peer + + self.cell_queue = queue.Queue(max_queue) + self.send_queue = queue.Queue(max_queue) + self.recv_queue = queue.Queue(max_queue) + self.sending = b'' + self.recving = b'' + self.celling = False + self.fails = 0 + self.dead = False + +
      [docs] def close(self): + self.peer.close() + self.dead = True
      + +
      [docs] def die(self, e): + if self.dead: + return + + self.close() + raise e
      + +
      [docs] def send(self, cell, block=True): + self.send_queue.put(lnn.cell.pad(cell), block=block)
      + +
      [docs] def recv(self, block=True): + return self.cell_queue.get(block=block)
      + +
      [docs] def main(self): + if self.fails > self.max_fails: + cells, _, _ = cell_slice(self.recving) + for cell in cells: + self.cell_queue.put(cell) + self.die(RuntimeError('Too many fails, is the socket dead?')) + + try: + if len(self.sending) < 1: + self.sending = self.send_queue.get(block=False) + except queue.Empty: + pass + + try: + if len(self.sending) > 0: + nbytes = self.peer.send(self.sending) + self.fails = self.fails + 1 if nbytes == 0 else 0 + self.sending = self.sending[nbytes:] + return + except (socket.timeout, ssl.SSLError, BlockingIOError): + pass + + try: + payload = self.peer.recv(self.buffer_size) + self.fails = self.fails + 1 if len(payload) == 0 else 0 + self.recv_queue.put(payload) + if self.recv_queue.qsize() < self.max_queue // 4: + return + except (socket.timeout, ssl.SSLError, BlockingIOError): + pass + + try: + if ((len(self.recving) < 1 or self.celling) + and len(self.recving) <= lnn.constants.max_payload_len): + self.recving += self.recv_queue.get(block=False) + self.celling = False + except queue.Empty: + pass + + if len(self.recving) > 0 and not self.celling: + cells, self.recving, self.celling = cell_slice(self.recving) + for cell in cells: + self.cell_queue.put(cell)
      + +
      [docs] def run(self): + try: + while not self.dead: + self.main() + self.dead = True + except BaseException as e: + self.die(e)
      + +
      [docs]class io: + _join_timeout = 3 + + def __init__(self, + peer, + daemon=True, + period=0.01, + max_fails=32, + max_queue=2048, + buffer_size=4096): + peer.settimeout(period) + # peer = _stat_peer(peer) # uncomment for extra statistics + + self.worker = worker(peer, max_fails, max_queue, buffer_size) + if daemon: + self.worker.daemon = True + + self.worker.start() + self.peer = peer + + @property + def dead(self): + return self.worker.dead + + @property + def pending(self): + return self.worker.cell_queue.qsize() + +
      [docs] def recv(self, block=True): + return self.worker.recv(block)
      + +
      [docs] def send(self, payload, block=True): + self.worker.send(payload, block=block)
      + +
      [docs] def binding(self): + return self.peer.get_channel_binding()
      + +
      [docs] def close(self): + self.peer.close() + + self.worker.close() + self.worker.join(self._join_timeout)
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/path_selection_test.html b/docs/source/_build/html/_modules/lightnion/tests/path_selection_test.html new file mode 100644 index 0000000..11817bb --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/path_selection_test.html @@ -0,0 +1,250 @@ + + + + + + + + + + + lightnion.tests.path_selection_test — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.path_selection_test
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.path_selection_test

      +import random
      +
      +import pytest
      +
      +from lightnion import cache
      +from lightnion import consensus
      +from lightnion import create
      +from lightnion import link
      +from lightnion import path_selection as ps
      +
      +
      +
      [docs]@pytest.fixture() +def get_chutney_consensus(): + """Get chutney's consensus""" + cache.purge() + lk = link.initiate(port=5000) + state = create.fast(lk) + state, cons = consensus.download(state, flavor='unflavored') + + dict_cons = {} + for router in cons['routers']: + dict_cons[router['nickname']] = router + + return state, dict_cons
      + + +
      [docs]def test_keep_exit_works_with_suitable_router(get_chutney_consensus): + state, cons = get_chutney_consensus + + keep, state, descriptor = ps.keep_exit(cons['test006r'], state) + + assert keep and descriptor is not None
      + + +
      [docs]def test_keep_exit_works_with_reject_exit_policy(get_chutney_consensus): + state, cons = get_chutney_consensus + + keep, state, descriptor = ps.keep_exit(cons['test002a'], state) + + assert not keep and descriptor is None
      + + +
      [docs]def test_pick_good_exit_returns_a_router(get_chutney_consensus): + state, cons = get_chutney_consensus + routers = cons.values() + + state, exit_node = ps.pick_good_exit(routers, state) + + assert exit_node is not None
      + + +
      [docs]def test_path_selection_works(get_chutney_consensus): + state, cons = get_chutney_consensus + routers = cons.values() + + ps.select_path(routers, state, testing=True)
      + + +
      [docs]def test_obey_minimal_constraint_with_one_router(get_chutney_consensus): + state, cons = get_chutney_consensus + + assert not ps.obey_minimal_constraint(cons['test005r'], cons['test005r'])
      + +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/test_consensus_chutney.html b/docs/source/_build/html/_modules/lightnion/tests/test_consensus_chutney.html new file mode 100644 index 0000000..f3c00f5 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/test_consensus_chutney.html @@ -0,0 +1,213 @@ + + + + + + + + + + + lightnion.tests.test_consensus_chutney — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.test_consensus_chutney
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.test_consensus_chutney

      +import lightnion as lnn
      +
      +
      +
      [docs]def test_download_unflavored(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + + # Downloading unflavored consensus + endpoint, unflavored = lnn.consensus.download(endpoint, + flavor='unflavored') + + assert True
      + + +
      [docs]def test_download_microdesc(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + + # Downloading microdesc consensus + endpoint, microdesc = lnn.consensus.download(endpoint, flavor='microdesc') + + assert True
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/test_create_chutney.html b/docs/source/_build/html/_modules/lightnion/tests/test_create_chutney.html new file mode 100644 index 0000000..df14e24 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/test_create_chutney.html @@ -0,0 +1,223 @@ + + + + + + + + + + + lightnion.tests.test_create_chutney — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.test_create_chutney
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.test_create_chutney

      +import lightnion as lnn
      +
      +
      +
      [docs]def test_fast(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + + # Simple creation of one-hop circuits with CREATE_FAST cells: + # - no public keys involved (only exchanging randomness through TLS). + # - used in Tor to connects to the guard (the first hop) to reduce load. + # Creating 10 one-hop circuits with CREATE_FAST cells + for i in range(10): + state = lnn.create.fast(link) + + assert True
      + + +
      [docs]def test_ntor(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + + # Retrieve cryptographic material through fast circuit + endpoint, authority = lnn.descriptors.download_authority(endpoint) + + # Perform "ntor" handshake with authority['router']['nickname'] + endpoint = lnn.create.ntor(link, authority) + + # Attempt to use the "ntor" circuit + endpoint, descriptor = lnn.descriptors.download_authority(endpoint) + + assert descriptor['digest'] == authority['digest'], \ + 'Descriptor digest: {}\n'.format(descriptor['digest']) + \ + 'Authority digest; {}\n'.format(authority['digest'])
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/test_descriptors_chutney.html b/docs/source/_build/html/_modules/lightnion/tests/test_descriptors_chutney.html new file mode 100644 index 0000000..997d7eb --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/test_descriptors_chutney.html @@ -0,0 +1,226 @@ + + + + + + + + + + + lightnion.tests.test_descriptors_chutney — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.test_descriptors_chutney
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.test_descriptors_chutney

      +import lightnion as lnn
      +
      +
      +
      [docs]def test_download_microdesc(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + + # Downloading descriptors + endpoint, descriptors = lnn.descriptors.download(endpoint, + flavor='microdesc') + + assert True
      + + +
      [docs]def test_download_unflavored(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + + # Downloading descriptors + endpoint, undescriptors = lnn.descriptors.download(endpoint, + flavor='unflavored') + + assert True
      + + +
      [docs]def test_download_authority(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + + # Asking politely for our OR's descriptor + endpoint, authority = lnn.descriptors.download_authority(endpoint) + + assert True
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/test_extend_chutney.html b/docs/source/_build/html/_modules/lightnion/tests/test_extend_chutney.html new file mode 100644 index 0000000..0a4b8d7 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/test_extend_chutney.html @@ -0,0 +1,255 @@ + + + + + + + + + + + lightnion.tests.test_extend_chutney — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.test_extend_chutney
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.test_extend_chutney

      +import lightnion as lnn
      +
      +
      +
      [docs]def test_circuit(): + import random + + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + + # Download our first hop's descriptor + endpoint, authority = lnn.descriptors.download_authority(endpoint) + + # Download a consensus + endpoint, cons = lnn.consensus.download(endpoint, flavor='unflavored') + + # Randomly pick few nodes (!! NOT a sane behavior, only to showcase API !!) + further_hops = [] + circuit_length = random.randint(2, 7) # (random circuit length to showcase) + + random.shuffle(cons['routers']) + for router in cons['routers']: + if len(further_hops) == circuit_length: + break + + # Skip our first node & already picked ones (no loop) + if router['digest'] == authority['digest']: + continue + if router['digest'] in [h['digest'] for h in further_hops]: + continue + + # Skip nodes that are not 'Fast' and 'Stable' + if 'Fast' not in router['flags'] or 'Stable' not in router['flags']: + continue + + # Skip nodes with old Tor versions + if not router['version'].startswith('Tor 0.3.'): + continue + + # Retrieve its descriptor + endpoint, nhop = lnn.descriptors.download( + endpoint, cons=router, flavor='unflavored') + nhop = nhop[0] # (expect only one entry with a matching digest) + + # Skip the entry if digests do not match (note: double-check here) + if router['digest'] != nhop['digest']: + continue + + # Skip if no ed25519 identity key available + if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': + continue + + # Keep the descriptor for later (to build the circuit) + further_hops.append(nhop) + + # Create a brand new circuit (to have spare RELAY_EARLY to extend it) + endpoint = lnn.create.fast(link) + + for nhop in further_hops: + # Extending to nhop['router']['nickname']: + # - remaining RELAY_EARLY: endpoint.early_count + endpoint = lnn.extend.circuit(endpoint, nhop) + + endpoint, authority = lnn.descriptors.download_authority(endpoint) + endpoint, ncons = lnn.consensus.download(endpoint, cache=False) + + assert True
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/test_hop_chutney.html b/docs/source/_build/html/_modules/lightnion/tests/test_hop_chutney.html new file mode 100644 index 0000000..0280254 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/test_hop_chutney.html @@ -0,0 +1,206 @@ + + + + + + + + + + + lightnion.tests.test_hop_chutney — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.test_hop_chutney
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.test_hop_chutney

      +import lightnion as lnn
      +
      +
      +
      [docs]def test_directory_query(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(address=addr, port=port) + endpoint = lnn.create.fast(link) + endpoint = lnn.hop.send(endpoint, lnn.cell.relay.cmd.RELAY_DROP) + + # Download the full consensus without compression + endpoint, full_answer = lnn.hop.directory_query(endpoint, + '/tor/status-vote/current/consensus', compression='identity') + + # Download the microdesc consensus with compression + endpoint, full_answer = lnn.hop.directory_query(endpoint, + '/tor/status-vote/current/consensus-microdesc') + + assert True
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/test_link_chutney.html b/docs/source/_build/html/_modules/lightnion/tests/test_link_chutney.html new file mode 100644 index 0000000..c2bd048 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/test_link_chutney.html @@ -0,0 +1,197 @@ + + + + + + + + + + + lightnion.tests.test_link_chutney — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.test_link_chutney
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.test_link_chutney

      +import lightnion as lnn
      +
      +
      +
      [docs]def test_initiate(): + addr, port = '127.0.0.1', 5000 + + link = lnn.link.initiate(addr, port) + link.close() + + assert True
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/tests/test_path_selection_chutney.html b/docs/source/_build/html/_modules/lightnion/tests/test_path_selection_chutney.html new file mode 100644 index 0000000..1dae235 --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/tests/test_path_selection_chutney.html @@ -0,0 +1,203 @@ + + + + + + + + + + + lightnion.tests.test_path_selection_chutney — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Module code »
      • + +
      • lightnion.tests.test_path_selection_chutney
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + +

      Source code for lightnion.tests.test_path_selection_chutney

      +import lightnion as lnn
      +
      +
      +
      [docs]def test_select_path(): + addr, port = '127.0.0.1', 5000 + + # Download the consensus + lnn.cache.purge() + link = lnn.link.initiate(address=addr, port=port) + state = lnn.create.fast(link) + state, cons = lnn.consensus.download(state, flavor='unflavored') + + state, guard, middle, exit_node = lnn.path_selection.select_path( + cons['routers'], state, testing=True) + + assert True
      +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_modules/lightnion/utils.html b/docs/source/_build/html/_modules/lightnion/utils.html new file mode 100644 index 0000000..b3148cd --- /dev/null +++ b/docs/source/_build/html/_modules/lightnion/utils.html @@ -0,0 +1,416 @@ + + + + + + + + + + + lightnion.utils — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +

      Source code for lightnion.utils

      +import lightnion as lnn
      +import socket
      +import time
      +import os
      +
      +
      [docs]class InvalidCellHeaderException(Exception): + def __init__(self, header): + super().__init__('Invalid cell header: {}'.format(header))
      + +
      [docs]class InvalidCellLengthException(Exception): + pass
      + + +cell_cmd_to_string = { + 0: "PADDING", + 1: "CREATE", + 2: "CREATED", + 3: "RELAY", + 4: "DESTROY", + 5: "CREATE_FAST", + 6: "CREATED_FAST", + 7: "VERSIONS", + 8: "NETINFO", + 9: "RELAY_EARLY", + 10: "CREATE2", + 11: "CREATED2", + 12: "PADDING_NEGOTIATE", + 128: "VPADDING", + 129: "CERTS", + 130: "AUTH_CHALLENGE", + 131: "AUTHENTICATE", + 132: "AUTHORIZE" +} + +
      [docs]def cell_to_str(cell): + return cell[:20].hex()
      + +
      [docs]def cell_get_cid(cell): + return int.from_bytes(cell[0:4], 'big')
      + + +
      [docs]def cell_set_cid(cell, cid): + return cid.to_bytes(4, 'big') + cell[4:]
      + + +
      [docs]def cell_get_cmd(cell): + return cell[4]
      + + +
      [docs]def cell_version_get_cmd(cell): + return cell[2]
      + + +
      [docs]def cell_get_len(cell): + return int.from_bytes(cell[5:7], 'big')
      + + +
      [docs]def cell_version_get_len(cell): + return int.from_bytes(cell[3:5], 'big')
      + + +
      [docs]def cell_pad_rnd(cell): + if cell_is_variable_length(cmd): + cell_len = 7 + cell_get_len(payload) + else: + cell_len = 514 + + if cell_len > len(cell): + return cell + os.urandom(cell_len - len(cell)) + else: + return cell
      + + +
      [docs]def cell_pad_null(cell): + if cell_is_variable_length(cmd): + cell_len = 7 + cell_get_len(payload) + else: + cell_len = 514 + + if cell_len > len(cell): + return cell + bytearray(cell_len - len(cell)) + else: + return cell
      + + +
      [docs]def cell_is_valid(cell): + cmd = cell_get_cmd(cell) + if cmd in cell_cmd_to_string.keys(): + return False + + cell_len = cell_get_len(cell) + if cell_len != len(cell): + return False + + # TODO: add some checks. + + return True
      + + +
      [docs]def cell_is_variable_length(cmd): + return cmd >= 128 or cmd == 7
      + + +
      [docs]def cmd_to_str(cmd): + if cmd in cell_cmd_to_string.keys(): + return cell_cmd_to_string[cmd] + + return 'UNKNOWN ({})'.format(cmd)
      + + +
      [docs]def cell_version_build(versions): + cell = b'\x00\x00\x07' + (len(versions)*2).to_bytes(2, 'big') + + for version in versions: + cell += version.to_bytes(2, 'big') + + return cell
      + + +
      [docs]def cell_version_is_valid(cell): + cmd = cell_version_get_cmd(cell) + if cmd != 7: + return False + + cell_len = cell_version_get_len(cell) + if cell_len != len(cell): + return False + + # TODO: add some checks. + + return True
      + + +
      [docs]def cell_version_get_versions(cell): + return [int.from_bytes(cell[i:i+2], 'big') for i in range(5, len(cell), 2)]
      + + +
      [docs]def cell_netinfo_build(host): + tstmp = int(time.time()).to_bytes(4, 'big') + if host == 'localhost': + addr = b'\x7f\x00\x00\x01' + else: + addr = socket.inet_aton(host) + + addr_len = len(addr) + + if addr_len == 4: + addr_t = b'\x04' + else: + addr_t = b'\x06' + + cell = b'\x00\x00\x00\x00\x08' + tstmp + addr_t + addr_len.to_bytes(1, 'big') + addr + + # padding + cell += bytearray(514 - len(cell)) + + return cell
      + + +
      [docs]def cell_slice(payload): + """Retrieve the next cell from the payload and truncate that one. + :param payload: bytearray + """ + payload_len = len(payload) + if payload_len < 7: # (payload too small, need data) + return None, payload + + cmd = cell_get_cmd(payload) + + if cell_is_variable_length(cmd): + cell_len = 7 + cell_get_len(payload) + else: + cell_len = 514 + + if payload_len < cell_len: + return None, payload + + cell = payload[:cell_len] + + return cell, payload[cell_len:]
      + + +#def cell_version_slice(payload): +# payload_len = len(payload) +# if payload_len < 5: # (payload too small, need data) +# return None, payload +# +# cell_len = 5 + cell_version_get_len(payload) +# +# if payload_len < cell_len: +# return None, payload +# +# cell = payload[:cell_len] +# +# return cell, payload[cell_len:] + + +
      [docs]def cell_slice_old(payload): + """Retrieve the next cell from the payload and truncate that one. + :param payload: bytearray + """ + cell_header = lnn.cell.header(payload) + if len(payload) < cell_header.width: # (payload too small, need data) + return None, payload + + if not cell_header.valid: + raise InvalidCellHeaderException(cell_header.raw) + + length = cell_header.width + lnn.constants.payload_len + if not cell_header.cmd.is_fixed: + cell_header = lnn.cell.header_variable(payload) + if len(payload) < cell_header.width: # (payload too small, need data) + return None, payload + + if not cell_header.valid: + raise InvalidCellHeaderException(cell_header.raw) + + length = cell_header.width + cell_header.length + + if length > lnn.constants.max_payload_len: + raise InvalidCellLengthException() + + if len(payload) < length: + return None, payload + + cell = payload[:length] + + return cell, payload[length:]
      + +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/_sources/index.rst.txt b/docs/source/_build/html/_sources/index.rst.txt new file mode 100644 index 0000000..cf5dbc0 --- /dev/null +++ b/docs/source/_build/html/_sources/index.rst.txt @@ -0,0 +1,29 @@ +===================================== +Welcome to Lightnion's documentation! +===================================== + +Introduction +============ + +.. toctree:: + install + +Lightnion is a JavaScript library that you can include on your webpage to let +any modern browser make anonymous requests. Lightnion uses an *untrusted* +proxy to interact with the Tor network. This proxy converts between protocols +(Websockets to pure TCP). This repository also contains a Python Lightnion Tor +client that we have been using for testing. + +**WARNING:** At the moment Lightnion is alpha-level research software. Do *not* +use it in production, or for anything that really requires anonymity. You are, +however, more than welcome to experiment with Lightnion. Please provide +feedback opening issues or writing to the authors. + + +================== +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` \ No newline at end of file diff --git a/docs/source/_build/html/_sources/install.rst.txt b/docs/source/_build/html/_sources/install.rst.txt new file mode 100644 index 0000000..e50cd8d --- /dev/null +++ b/docs/source/_build/html/_sources/install.rst.txt @@ -0,0 +1,2 @@ +Installation +============ \ No newline at end of file diff --git a/docs/source/_build/html/_sources/lightnion.cell.relay.rst.txt b/docs/source/_build/html/_sources/lightnion.cell.relay.rst.txt new file mode 100644 index 0000000..a42094d --- /dev/null +++ b/docs/source/_build/html/_sources/lightnion.cell.relay.rst.txt @@ -0,0 +1,30 @@ +lightnion.cell.relay package +============================ + +Submodules +---------- + +lightnion.cell.relay.extend2 module +----------------------------------- + +.. automodule:: lightnion.cell.relay.extend2 + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.relay.extended2 module +------------------------------------- + +.. automodule:: lightnion.cell.relay.extended2 + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.cell.relay + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/_build/html/_sources/lightnion.cell.rst.txt b/docs/source/_build/html/_sources/lightnion.cell.rst.txt new file mode 100644 index 0000000..867233a --- /dev/null +++ b/docs/source/_build/html/_sources/lightnion.cell.rst.txt @@ -0,0 +1,133 @@ +lightnion.cell package +====================== + +Subpackages +----------- + +.. toctree:: + + lightnion.cell.relay + +Submodules +---------- + +lightnion.cell.address module +----------------------------- + +.. automodule:: lightnion.cell.address + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.certs module +--------------------------- + +.. automodule:: lightnion.cell.certs + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.challenge module +------------------------------- + +.. automodule:: lightnion.cell.challenge + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.common module +---------------------------- + +.. automodule:: lightnion.cell.common + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.create2 module +----------------------------- + +.. automodule:: lightnion.cell.create2 + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.create\_fast module +---------------------------------- + +.. automodule:: lightnion.cell.create_fast + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.created2 module +------------------------------ + +.. automodule:: lightnion.cell.created2 + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.created\_fast module +----------------------------------- + +.. automodule:: lightnion.cell.created_fast + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.destroy module +----------------------------- + +.. automodule:: lightnion.cell.destroy + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.netinfo module +----------------------------- + +.. automodule:: lightnion.cell.netinfo + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.padding module +----------------------------- + +.. automodule:: lightnion.cell.padding + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.relay\_early module +---------------------------------- + +.. automodule:: lightnion.cell.relay_early + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.versions module +------------------------------ + +.. automodule:: lightnion.cell.versions + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.view module +-------------------------- + +.. automodule:: lightnion.cell.view + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.cell + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/_build/html/_sources/lightnion.crypto.rst.txt b/docs/source/_build/html/_sources/lightnion.crypto.rst.txt new file mode 100644 index 0000000..cbec368 --- /dev/null +++ b/docs/source/_build/html/_sources/lightnion.crypto.rst.txt @@ -0,0 +1,30 @@ +lightnion.crypto package +======================== + +Submodules +---------- + +lightnion.crypto.kdf module +--------------------------- + +.. automodule:: lightnion.crypto.kdf + :members: + :undoc-members: + :show-inheritance: + +lightnion.crypto.ntor module +---------------------------- + +.. automodule:: lightnion.crypto.ntor + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.crypto + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/_build/html/_sources/lightnion.http.rst.txt b/docs/source/_build/html/_sources/lightnion.http.rst.txt new file mode 100644 index 0000000..fec8299 --- /dev/null +++ b/docs/source/_build/html/_sources/lightnion.http.rst.txt @@ -0,0 +1,38 @@ +lightnion.http package +====================== + +Submodules +---------- + +lightnion.http.ntor module +-------------------------- + +.. automodule:: lightnion.http.ntor + :members: + :undoc-members: + :show-inheritance: + +lightnion.http.polling module +----------------------------- + +.. automodule:: lightnion.http.polling + :members: + :undoc-members: + :show-inheritance: + +lightnion.http.websocket module +------------------------------- + +.. automodule:: lightnion.http.websocket + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.http + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/_build/html/_sources/lightnion.proxy.rst.txt b/docs/source/_build/html/_sources/lightnion.proxy.rst.txt new file mode 100644 index 0000000..1e24624 --- /dev/null +++ b/docs/source/_build/html/_sources/lightnion.proxy.rst.txt @@ -0,0 +1,70 @@ +lightnion.proxy package +======================= + +Submodules +---------- + +lightnion.proxy.auth module +--------------------------- + +.. automodule:: lightnion.proxy.auth + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.forward module +------------------------------ + +.. automodule:: lightnion.proxy.forward + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.jobs module +--------------------------- + +.. automodule:: lightnion.proxy.jobs + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.link module +--------------------------- + +.. automodule:: lightnion.proxy.link + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.parts module +---------------------------- + +.. automodule:: lightnion.proxy.parts + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.path module +--------------------------- + +.. automodule:: lightnion.proxy.path + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.relayinfo module +-------------------------------- + +.. automodule:: lightnion.proxy.relayinfo + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.proxy + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/_build/html/_sources/lightnion.rst.txt b/docs/source/_build/html/_sources/lightnion.rst.txt new file mode 100644 index 0000000..c159b71 --- /dev/null +++ b/docs/source/_build/html/_sources/lightnion.rst.txt @@ -0,0 +1,129 @@ +lightnion package +================= + +Subpackages +----------- + +.. toctree:: + + lightnion.cell + lightnion.crypto + lightnion.http + lightnion.proxy + lightnion.tests + +Submodules +---------- + +lightnion.cache module +---------------------- + +.. automodule:: lightnion.cache + :members: + :undoc-members: + :show-inheritance: + +lightnion.consensus module +-------------------------- + +.. automodule:: lightnion.consensus + :members: + :undoc-members: + :show-inheritance: + +lightnion.constants module +-------------------------- + +.. automodule:: lightnion.constants + :members: + :undoc-members: + :show-inheritance: + +lightnion.create module +----------------------- + +.. automodule:: lightnion.create + :members: + :undoc-members: + :show-inheritance: + +lightnion.descriptors module +---------------------------- + +.. automodule:: lightnion.descriptors + :members: + :undoc-members: + :show-inheritance: + +lightnion.extend module +----------------------- + +.. automodule:: lightnion.extend + :members: + :undoc-members: + :show-inheritance: + +lightnion.hop module +-------------------- + +.. automodule:: lightnion.hop + :members: + :undoc-members: + :show-inheritance: + +lightnion.link module +--------------------- + +.. automodule:: lightnion.link + :members: + :undoc-members: + :show-inheritance: + +lightnion.onion module +---------------------- + +.. automodule:: lightnion.onion + :members: + :undoc-members: + :show-inheritance: + +lightnion.path\_selection module +-------------------------------- + +.. automodule:: lightnion.path_selection + :members: + :undoc-members: + :show-inheritance: + +lightnion.signature module +-------------------------- + +.. automodule:: lightnion.signature + :members: + :undoc-members: + :show-inheritance: + +lightnion.socket module +----------------------- + +.. automodule:: lightnion.socket + :members: + :undoc-members: + :show-inheritance: + +lightnion.utils module +---------------------- + +.. automodule:: lightnion.utils + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/_build/html/_sources/lightnion.tests.rst.txt b/docs/source/_build/html/_sources/lightnion.tests.rst.txt new file mode 100644 index 0000000..f9fcfd9 --- /dev/null +++ b/docs/source/_build/html/_sources/lightnion.tests.rst.txt @@ -0,0 +1,78 @@ +lightnion.tests package +======================= + +Submodules +---------- + +lightnion.tests.path\_selection\_test module +-------------------------------------------- + +.. automodule:: lightnion.tests.path_selection_test + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_consensus\_chutney module +----------------------------------------------- + +.. automodule:: lightnion.tests.test_consensus_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_create\_chutney module +-------------------------------------------- + +.. automodule:: lightnion.tests.test_create_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_descriptors\_chutney module +------------------------------------------------- + +.. automodule:: lightnion.tests.test_descriptors_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_extend\_chutney module +-------------------------------------------- + +.. automodule:: lightnion.tests.test_extend_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_hop\_chutney module +----------------------------------------- + +.. automodule:: lightnion.tests.test_hop_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_link\_chutney module +------------------------------------------ + +.. automodule:: lightnion.tests.test_link_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_path\_selection\_chutney module +----------------------------------------------------- + +.. automodule:: lightnion.tests.test_path_selection_chutney + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.tests + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/_build/html/_sources/modules.rst.txt b/docs/source/_build/html/_sources/modules.rst.txt new file mode 100644 index 0000000..95d6d08 --- /dev/null +++ b/docs/source/_build/html/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +lightnion +========= + +.. toctree:: + :maxdepth: 4 + + lightnion diff --git a/docs/source/_build/html/_static/ajax-loader.gif b/docs/source/_build/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/basic.css b/docs/source/_build/html/_static/basic.css new file mode 100644 index 0000000..0807176 --- /dev/null +++ b/docs/source/_build/html/_static/basic.css @@ -0,0 +1,676 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist td { + vertical-align: top; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/source/_build/html/_static/comment-bright.png b/docs/source/_build/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..15e27edb12ac25701ac0ac21b97b52bb4e45415e GIT binary patch literal 756 zcmVgfIX78 z$8Pzv({A~p%??+>KickCb#0FM1rYN=mBmQ&Nwp<#JXUhU;{|)}%&s>suq6lXw*~s{ zvHx}3C%<;wE5CH!BR{p5@ml9ws}y)=QN-kL2?#`S5d*6j zk`h<}j1>tD$b?4D^N9w}-k)bxXxFg>+#kme^xx#qg6FI-%iv2U{0h(Y)cs%5a|m%Pn_K3X_bDJ>EH#(Fb73Z zfUt2Q3B>N+ot3qb*DqbTZpFIn4a!#_R-}{?-~Hs=xSS6p&$sZ-k1zDdtqU`Y@`#qL z&zv-~)Q#JCU(dI)Hf;$CEnK=6CK50}q7~wdbI->?E07bJ0R;!GSQTs5Am`#;*WHjvHRvY?&$Lm-vq1a_BzocI^ULXV!lbMd%|^B#fY;XX)n<&R^L z=84u1e_3ziq;Hz-*k5~zwY3*oDKt0;bM@M@@89;@m*4RFgvvM_4;5LB!@OB@^WbVT zjl{t;a8_>od-~P4 m{5|DvB&z#xT;*OnJqG}gk~_7HcNkCr0000W zanA~u9RIXo;n7c96&U)YLgs-FGlx~*_c{Jgvesu1E5(8YEf&5wF=YFPcRe@1=MJmi zag(L*xc2r0(slpcN!vC5CUju;vHJkHc*&70_n2OZsK%O~A=!+YIw z7zLLl7~Z+~RgWOQ=MI6$#0pvpu$Q43 zP@36QAmu6!_9NPM?o<1_!+stoVRRZbW9#SPe!n;#A_6m8f}|xN1;H{`0RoXQ2LM47 zt(g;iZ6|pCb@h2xk&(}S3=EVBUO0e90m2Lp5CB<(SPIaB;n4))3JB87Or#XPOPcum z?<^(g+m9}VNn4Y&B`g8h{t_$+RB1%HKRY6fjtd-<7&EsU;vs0GM(Lmbhi%Gwcfs0FTF}T zL{_M6Go&E0Eg8FuB*(Yn+Z*RVTBE@10eIOb3El^MhO`GabDll(V0&FlJi2k^;q8af zkENdk2}x2)_KVp`5OAwXZM;dG0?M-S)xE1IKDi6BY@5%Or?#aZ9$gcX)dPZ&wA1a< z$rFXHPn|TBf`e?>Are8sKtKrKcjF$i^lp!zkL?C|y^vlHr1HXeVJd;1I~g&Ob-q)& z(fn7s-KI}G{wnKzg_U5G(V%bX6uk zIa+<@>rdmZYd!9Y=C0cuchrbIjuRB_Wq{-RXlic?flu1*_ux}x%(HDH&nT`k^xCeC ziHi1!ChH*sQ6|UqJpTTzX$aw8e(UfcS^f;6yBWd+(1-70zU(rtxtqR%j z-lsH|CKQJXqD{+F7V0OTv8@{~(wp(`oIP^ZykMWgR>&|RsklFMCnOo&Bd{le} zV5F6424Qzl;o2G%oVvmHgRDP9!=rK8fy^!yV8y*4p=??uIRrrr0?>O!(z*g5AvL2!4z0{sq%vhG*Po}`a<6%kTK5TNhtC8}rXNu&h^QH4A&Sk~Autm*s~45(H7+0bi^MraaRVzr05hQ3iK?j` zR#U@^i0WhkIHTg29u~|ypU?sXCQEQgXfObPW;+0YAF;|5XyaMAEM0sQ@4-xCZe=0e z7r$ofiAxn@O5#RodD8rh5D@nKQ;?lcf@tg4o+Wp44aMl~c47azN_(im0N)7OqdPBC zGw;353_o$DqGRDhuhU$Eaj!@m000000NkvXXu0mjfjZ7Z_ literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/css/badge_only.css b/docs/source/_build/html/_static/css/badge_only.css new file mode 100644 index 0000000..3c33cef --- /dev/null +++ b/docs/source/_build/html/_static/css/badge_only.css @@ -0,0 +1 @@ +.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../fonts/fontawesome-webfont.eot");src:url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff") format("woff"),url("../fonts/fontawesome-webfont.ttf") format("truetype"),url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} diff --git a/docs/source/_build/html/_static/css/theme.css b/docs/source/_build/html/_static/css/theme.css new file mode 100644 index 0000000..8daf2c9 --- /dev/null +++ b/docs/source/_build/html/_static/css/theme.css @@ -0,0 +1,4 @@ +*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.7.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"),url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857em;text-align:center}.fa-ul{padding-left:0;margin-left:2.1428571429em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.1428571429em;width:2.1428571429em;top:.1428571429em;text-align:center}.fa-li.fa-lg{left:-1.8571428571em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.wy-menu-vertical li span.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-left.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-left.toctree-expand,.rst-content .fa-pull-left.admonition-title,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content dl dt .fa-pull-left.headerlink,.rst-content p.caption .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.rst-content code.download span.fa-pull-left:first-child,.fa-pull-left.icon{margin-right:.3em}.fa.fa-pull-right,.wy-menu-vertical li span.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a span.fa-pull-right.toctree-expand,.wy-menu-vertical li.current>a span.fa-pull-right.toctree-expand,.rst-content .fa-pull-right.admonition-title,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content dl dt .fa-pull-right.headerlink,.rst-content p.caption .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.rst-content code.download span.fa-pull-right:first-child,.fa-pull-right.icon{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content .code-block-caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content .code-block-caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-hotel:before,.fa-bed:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-yc:before,.fa-y-combinator:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-tv:before,.fa-television:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:""}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-signing:before,.fa-sign-language:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-vcard:before,.fa-address-card:before{content:""}.fa-vcard-o:before,.fa-address-card-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content .code-block-caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content table>caption .headerlink,.rst-content table>caption a .headerlink,a .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content table>caption .headerlink,.rst-content table>caption .btn .headerlink,.btn .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content table>caption .headerlink,.rst-content table>caption .nav .headerlink,.nav .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.btn .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.nav .rst-content .code-block-caption .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.btn .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.nav .rst-content .code-block-caption .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.rst-content .admonition{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.admonition{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo,.rst-content .wy-alert-warning.admonition{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title,.rst-content .wy-alert-warning.admonition .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.admonition{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.admonition{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.admonition{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 .3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.3576515979%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.3576515979%;width:48.821174201%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.3576515979%;width:31.7615656014%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type="datetime-local"]{padding:.34375em .625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{position:absolute;content:"";display:block;left:0;top:0;width:36px;height:12px;border-radius:4px;background:#ccc;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27AE60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:.3em;display:block}.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:before,.wy-breadcrumbs:after{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#3a7ca8;height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin:12px 0 0 0;display:block;font-weight:bold;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a{color:#404040}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980B9;text-align:center;padding:.809em;display:block;color:#fcfcfc;margin-bottom:.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:gray}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:gray}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{width:100%}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:before,.rst-breadcrumbs-buttons:after{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1100px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content img{max-width:100%;height:auto}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure p:last-child.caption{margin-bottom:0px}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;display:block;overflow:auto}.rst-content pre.literal-block,.rst-content div[class^='highlight']{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px 0}.rst-content pre.literal-block div[class^='highlight'],.rst-content div[class^='highlight'] div[class^='highlight']{padding:0px;border:none;margin:0}.rst-content div[class^='highlight'] td.code{width:100%}.rst-content .linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;display:block;overflow:auto}.rst-content div[class^='highlight'] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content pre.literal-block,.rst-content div[class^='highlight'] pre,.rst-content .linenodiv pre{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;font-size:12px;line-height:1.4}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^='highlight'],.rst-content div[class^='highlight'] pre{white-space:pre-wrap}}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last,.rst-content .admonition .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .section ol p:last-child,.rst-content .section ul p:last-child{margin-bottom:24px}.rst-content .line-block{margin-left:0px;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content table>caption .headerlink,.rst-content .code-block-caption .headerlink{visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after,.rst-content table>caption .headerlink:after,.rst-content .code-block-caption .headerlink:after{content:"";font-family:FontAwesome}.rst-content h1:hover .headerlink:after,.rst-content h2:hover .headerlink:after,.rst-content .toctree-wrapper p.caption:hover .headerlink:after,.rst-content h3:hover .headerlink:after,.rst-content h4:hover .headerlink:after,.rst-content h5:hover .headerlink:after,.rst-content h6:hover .headerlink:after,.rst-content dl dt:hover .headerlink:after,.rst-content p.caption:hover .headerlink:after,.rst-content table>caption:hover .headerlink:after,.rst-content .code-block-caption:hover .headerlink:after{visibility:visible}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:baseline;position:relative;top:-0.4em;line-height:0;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:gray}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}.rst-content table.docutils td .last,.rst-content table.docutils td .last :last-child{margin-bottom:0}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none}.rst-content table.field-list td p{font-size:inherit;line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content tt,.rst-content tt,.rst-content code{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content pre,.rst-content kbd,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold;margin-bottom:12px}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-weight:normal;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child,.rst-content code.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}.rst-content .guilabel{border:1px solid #7fbbe3;background:#e7f2fa;font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .versionmodified{font-style:italic}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Lato";src:url("../fonts/Lato-Regular.woff2") format("woff2"),url("../fonts/Lato-Regular.ttf") format("truetype");font-weight:400;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato-Bold.woff2") format("woff2"),url("../fonts/Lato-Bold.ttf") format("truetype");font-weight:700;font-style:normal}@font-face{font-family:"Lato";src:url("../fonts/Lato-BoldItalic.woff2") format("woff2"),url("../fonts/Lato-BoldItalic.ttf") format("truetype");font-weight:700;font-style:italic}@font-face{font-family:"Lato";src:url("../fonts/Lato-Italic.woff2") format("woff2"),url("../fonts/Lato-Italic.ttf") format("truetype");font-weight:400;font-style:italic}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:url("../fonts/RobotoSlab-Regular.woff2") format("woff2"),url("../fonts/RobotoSlab-Regular.ttf") format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:url("../fonts/RobotoSlab-Bold.woff2") format("woff2"),url("../fonts/RobotoSlab-Bold.ttf") format("truetype")} diff --git a/docs/source/_build/html/_static/doctools.js b/docs/source/_build/html/_static/doctools.js new file mode 100644 index 0000000..344db17 --- /dev/null +++ b/docs/source/_build/html/_static/doctools.js @@ -0,0 +1,315 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var bbox = span.getBBox(); + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + var parentOfText = node.parentNode.parentNode; + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/source/_build/html/_static/documentation_options.js b/docs/source/_build/html/_static/documentation_options.js new file mode 100644 index 0000000..d28647e --- /dev/null +++ b/docs/source/_build/html/_static/documentation_options.js @@ -0,0 +1,10 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, +}; \ No newline at end of file diff --git a/docs/source/_build/html/_static/down-pressed.png b/docs/source/_build/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..5756c8cad8854722893dc70b9eb4bb0400343a39 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`OFdm2Ln;`PZ^+1>KjR?B@S0W7 z%OS_REiHONoJ6{+Ks@6k3590|7k9F+ddB6!zw3#&!aw#S`x}3V3&=A(a#84O-&F7T z^k3tZB;&iR9siw0|F|E|DAL<8r-F4!1H-;1{e*~yAKZN5f0|Ei6yUmR#Is)EM(Po_ zi`qJR6|P<~+)N+kSDgL7AjdIC_!O7Q?eGb+L+qOjm{~LLinM4NHn7U%HcK%uoMYO5 VJ~8zD2B3o(JYD@<);T3K0RV0%P>BEl literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/down.png b/docs/source/_build/html/_static/down.png new file mode 100644 index 0000000000000000000000000000000000000000..1b3bdad2ceffae91cee61b32f3295f9bbe646e48 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6CVIL!hEy=F?b*7pIY7kW{q%Rg zx!yQ<9v8bmJwa`TQk7YSw}WVQ()mRdQ;TC;* literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/file.png b/docs/source/_build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/fonts/Lato-Bold.ttf b/docs/source/_build/html/_static/fonts/Lato-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..70c4dd92b068550ac526c46e8368d9b68de37bd2 GIT binary patch literal 683116 zcmdqJ30#%c`uBaU;T|^%DjF%uW>Qo@awt?Z1XNU1R8(*TMJ2^VMa3Bv6Nk(k(##A^ z%hGD&6giZcmYJEQm6ZdPm6?^5l@+qz-`ao&%kw|a|NlJC`}w?Y=X_n$wXQYX>t1W! zYh7$&L{tm^Nb>2L+`C_mjan|5zmyT{{b1LA{o_7A{=x{d00amyof(e%7dr%(;uV-3|TzNWV7=5j7V0yo7KH!Xa7XbMt<= z+N%iR8$>O-j2kuS!7~@?3?S404AC3+W=|NI5wXsCh^Qax+ahUvMqW;h$7-;U zAIum(YQ)0)g=Cg`5!E@GGhuSBdjlOteUP7=Ig>`^l)h+(p#FfKC)GEc9seV1QTlN2 zm|v-Zq1r_~(tca0-1k~%Zv3nJ%{T3Qb1h^o;+`BRj>y72684-I!!|2*N#X$3r127<_Ab4((*K4sPwCF#Xibo*G<8_P0qO# zTzpR4olIBV$ZIL(xzm%AsEDZCt#>buq&26W9)6-tat_Ew+z#rYYqW{?p-o~i)zbze-kUZVBWRO~*OQSB%*oVK ze&h)!X*y)OQKWQHBkf&!M3rIQOSQBPBs3rQFLFPHiQnlSy&tub6KIAwLh<5Fiif|m z45v8$E;W_K)Jz@&PP#{C(F|5b>8zX%Km3f-a94cx~k(^k-$XHr{*=u4v^ z(?=nGq*U!Nb%K8+7{#8YEO8fQY0pwOeJu^vb5Jj!eM^1C{pjaHst@A9R1gYkf&kDG zEC5L$4wzsd7z+9^zw#-S{vmJ|SF!=_T5uMq_!q!oP@t92Ao&O-h$|R@pORCXPhGSD z)D>xc`9b$o_7ly9KLzyC$52o1PgBHlO0p8Dr``;22L4my=T3OWs2Zo0@ILN^7^lGf z9ynfod{&K9<$A`X8kbdIOsesCC)9YX4#wY6cGEKscfkMttud&^VRh7)s}9DTcAPrm z84T0HXsb5P{fjQ$ZdG^vZt_LFN6QveL%mz7-txW5cj#?urs}EcX11qz!%gw}7Vr$p zQ}0U-`f>`zsyZ4ysHt_Dnri*2sgVHxiOTm#y-WWFqb)Tvq9Gscah3mekgoE2pArzFqw ze4AqQZPZqukN0pm^~c<#=Bw#)E)A2zC>Y$2I(HFG@eXgsJhjI&PJ(z8O_n{#Priaa z^d%GN@uCHu_hcF`Pg0z4VP4r!wd8P`pxYD+I*Cu+<$5@c(_5k+oJ`fXEjvtc3i%zz zRr?B1$C_p;ak-T4QgzgFz$tf`*&i&enA^3}h_l>3Yb)J9>D{P<-UeY6mq@+L8MMhf z2miO!(1?W2Gw?@KsMeNxn*HJLg?y#dK>H57N)d9Sr>&jD_ZSP^Dv-aRuh9QuA%)20 zXk$mPgM|JV){4jBpNzSFC|vb!!7n-bA_?!(Ui86773s1Ob=K!X?n{K9rn|Lwp!+yD ziRXC|?@9vvzhnLx>HbJgq6X-X?qIdY{R?xB4{h_zjhAU0=Aj2=Gq&0|t74u3!M@4HC6h zlq%Zdxy_(1vH;Kg1!^F>Q?zV_`L{pj_YKq%B!l)K8q@`GAQtoj@t`y43q~neFKPjr z!msis0j1|&Pzxye`$6|ge^>2OtOq5YxmV5O~zw>cO+XHq2wQk~lDZgAnRrr=0f%Mh@uKU9Zw<@giF+<;veZ)KTi2Rb`H7DlIk1Xo9fZq-AFZm!(rSJcKN9SR9P&e#A2qFpl8pfCD|C7EwZJp= zlLc(5TECF?1M*%0q41vpsyqq#c+6kfVi!G$wEgCOyf+n$hO2m>D$M&*f1XBt*f1K* z=TRR%l`?o^xHG{N8YgB_HhYUkvlAFE>DW_D$9&=>O+n<&f;*zJY^jfov>==3-i&1iqQt*{l$Jy&28F#TB99y|0G|h=JF}X6ydo&OyQU}dYDOgj*o%2fiK>N;}oX- zK!)y3$yzP))tCZv8O1~HDzZAu@zPLh0HDfMl88R- z1f8>GxZ91rg6fAZMpx==%%IL@0(I8%s1fGVAnhgv>-(@TX^lCfE!NDYlz~0TL=XOC zXYgJ4T=<}G2ae>t}Lo0`lJ44`Hv}0ncbZWa^Wl{Xuomz7`^nnuu)7 z@58Ys`JwE)@g1W2`dvJ$;p8XkPz`b3UB=Ji{k}p0cus>+A4OZCV}9vEgV{tH#4b}q z;f?q@SZ@U8J;dYPP869G!ClmZA4J-Du!I_kFpS4ZbT^N|x-kiRnNg5Q!anF4MXc-|` z{48;w_k<_nd+HhJdK9cgJtn(%dUQ;$*vqN1+3(2P!R=!2l9R8c#(WL-gKAD3gn18p zI_AdSayd0)Kf8ZIS~U71gY8Ax$065;`e8mRk!`62`=KFh1q}pgyanFn7FdhU;JE_y z&sP2&ZCBuVE&e;`hj9J_zKj0`-p?5d)z50q)q>DRlQ5Sp#+X=4x_%gb7xouVQ+KuZ z6VG8xJx{GPZ@jzPD8?|+pOYzD=DNSp)n0BT{A%yxMW)sh<7Jn-Ozgy%%)vL?j}*ft zt=4-%XFTTL?bt{Dj(K`7G3@~2j)RL7q8Cs@d|PcYeneUx_H|RSHz~o~9|5^s;zl=W zs69`;H0V=b}CU#%^Akh=`){0xknFuX%y;w#KWhamq1;?{w+nDhP6 zZ`j{y?;~v#;x41jURYBb;JpbZTV|5fUV_Yg%!3WlKlLCRfo};Q)8KcIK)=tB$S?h| zr}!N%=1Q^H{k7^((UYc&t=PAXBn^9sCVG8Jz}bf(E?}M-g#Bj#WeYqyF zAKgvewM?vUlPMMZCH1Wxj&JpTaD$BP^tw5b`soL0pI#Gf<*ro?>=cRq19SD zYN6Fd-pWKej;^N@sb{o_c4Pq!92WcnP498M43oiQOQ`|otEP)rx$OB zJ$F0os~@FZARhaxIM7vm>%O4QQM6z24Kow_ne{YK3x>M_{oUPjJ`$=8#UAAZ;_#fc z@z`7M@$B{MVtpD7vOofe28p0G#&j=f06$8@{${vbiE%u-;`;z=%ouqX^LNGf!gRQc zfpV9ECx8na0!l{3PXj|#82!-%RR1pMhVOzz#0^({1=@gtKz$$h0rjn*zB4+4W{_U%_$-x{O>^=y>>E}&gyxG{7@f@TOefva>T@?x5Z z@SXCiZ=73s;aBG#{e4BcE z_DHXyuaA8lME$WZ?22$taUZ@P=VDJ1NWCy_zW^Qa&JdpC6F5Ii5E{-I zPh!kgd|%YXH-n-R-m|xXI;UI;rhyz#Sn0y={;C4?UaCA5XPIm%#^pJDlU&BRTBXa^ z<1F|(=!tR*;T}c>{sgljSD~l8vfR3u`<><|m`j#n&8qkY{7&mauUFLlX1UVC18F+e zRKmAQ2M_8t{}Fs^3=|18RRRBKxD)V9epG!&ROYB~RsB7Eq|S0ifsO!YII3@` z2T*gCI@eL@YVN|C?LLkEo(TULpwi;-P5S}j7om;6R>rA#l~>6hg$tcZzk4QJb>5<$ zODptoqUX7(XIJ&zr_POT|JGa~zrcK;D4-9KZyeYR7C^48HiT9w5LWfC4!&JIXVW9J z7Fbs+&*%_01pI=t$!9#@G|yvxzlk~hA$7BaEW5IFX3XI)zY!o?Tz;>%Kaqv+YMza_n&f>>Mu_{)!Eo) zwU5%&eFEMKgp;u*P4~PbF^I!=i8}Z3oc}*eTh*8s+pxwSr4sDn+v84Pt~#4icM=|% zBRD^fz#RqJ%j2*obCOhhH?@ZoAK+Py#COvVR1an3irEw-4j|tmoM~GW&)VV)>;=qS z*n6ryqGxZLO5VH)&b?b>|6i#GcPHZ%s;)qd35DwGzUVLY9qkEw&J}PDpxzh6JzM!q z*Q;-E?3bos5B~t#H$ybXp7}E29_nTk#^on)zX!^_3)HD}FiF+MIc`n=?U_Sh~i}IAE%2T>jIZF4h z6_f|UeGaI2wEgBlfOGeoS(PsQWhg^&6Ll+p75k-4)xjQk7{dPm@!b*s4-lV#_hX_0R{j28JeU8i{-_*}A5@M-xVOIxSX*%Srq11& z8uvJ<^^8L`9x*OGHVcz4P&;O`C~TZTE)qXTs++Xr-T65uZUFO>0D8Pe4|RUP%NRio-1s&Mag zpQVk#dHKJ&>-ulU=iRz9YlyrSm{qBxK3rZc{9$E$^*gqIpGVcPvYzVR*h3fhw^}H^ zD->+TGtj z{q9qLiyL_>T#R+^j(Oce&MB92&dqCbj@y8r!T+r+aJNIafhSMpojAU^dfW-mx3c

      sTyz@!rywr4tG1m)vU<#U&~h9bz;xe$NdG)HdX`N z)w|oP`_D?ha(jb~h@&CzmVy^<;NzxDlW({OO>%r@Wpx5BUgftj;%R zcUAa3^bc$!s?o2S|5m)mc0$=t{3meUuFl+V<0JPQw}q>0Fw~j)|1Ontld|Qw6PmK` zs1EMcmA%I;YL>rs%U?ZS`D>Oxr`5c<04#xDf<0j0EqU90O~P*E-+{C8JKo=W;%~Tn z|Ci}^%6r3IitqZr>#VEvD7%#^u$T3m&3oL5*zYM@mcMht{k|uz%EqPY{9d_709-Q| z?%!+;{_C*&5!oDPVpVyRKMG^5DqQ7Omq8qdZ4LIL74|i1@BbP2`@IC>Joo*|HefVR zHUTYekGo}?qwI6;MD;dS^W$8y;_jj?_Ph$v^&XHkMrb3e&tsAtEX4_=ivEO zAHx&ezk1G15$Cz?^mb1(y9+b}XUPg3ca&BB3b%S#`2#&N9U-fzlr@&%ELO3Y0&n^M9#@@f|cE(imSC9Ws{#S10OToKgd1!_^PS~IQJ80}KA3;|(NR_rnI_!`BZvlG+j~$b;U#f1yRDIv5 z?3vWQ%wxZ#Y?!K0_gJu3^4KcDu1S24`3?3+I_!`XxXTZL4Pt~SsI*B^c1hKNjZ&3u zlCnL*UA4#7NZBPZ*m){jP@JKTmfyR};SR$Y@-W2D!2Q(>9k!jYqnaapac*=6aK}1; zx9({(Tj;GRj`2I?8tD?`Sv|{yX?C-B<;_xnUbqg|d;U z&YkRKD$X1shchu{>+*MC+v2R`_H)kvseO&IwfUEgO~qNNI#0dL-Uem1P*mC7ApM71 zRM_4q`%;%GRgS-UsvWIEAwNslsFbqilexfGv=+ z2U2il6I2CkgOq)c0`1cN4eHFZ%4SH}EGeYA_x12P&U2ML%3<8WPj(lGcz3LL+x@+W zbk7i>leudW5%To0BY+yI;d z2P)!KTKOS874JCis?{8Ty|KquM(w3=*7Oy?okkU&I~8@WavSQt6yK+#)Om#3pQ|$o zBOCici|(zwUw}zB0Uk!o6XTB%dc)QvRHS&4|Mm|~mHrq0<2ZSqK@ZV{b>!Y#QkeOnuR)Pq?3ui5wOWY zUQ~l>k~jYPpcd7pI#iGDBHV0IeQH4d)Q}oc06FPF8igBzX#^V$3Z!5Pp~ln%_H@lD z95-MsD2kq@dvMp=3Vm@O!TOfkQw(*Wj&wi8QYXs6t=U9Ue|zDgVlrqK?W5P|4SJJ~ z(p&U49i!tEN+;+YdY4YpDSD6Irw`~feMo2MBRWeT)2H+aeMaYKGUd|(DxfJemZnlW znuB|(xzw4u(JGSUOHa^RT1Su5LMo*VR76ivA9|AFa4&t4f~YlZqi1P7ZKTb#nl4ZV zjUcQUw1ZxvS8*=ihQ?494W=QKMuX^4+C=B+2t7jcXgH-)Q~aewE{&t1G>o337il-W zKznE>y-X$a3hku>bda8>{kZ=+Oou3vx={NzIbw-eCN_za@*%BG&HEdAH9X$viAEb6{Si<%pkYAgfSv&Z1JVKp2Mi6E z9k4s#NWkfU&jNl7xE@gM^l=6`8#|+%t)1)HCx2HtT0CCh`$-EQ@l zC#pS8DiXP3hA2RLmW!vwDOrg2P{SGx%h8^q01EI6a0Vm>Bv-a)ctC!@-hej)J_X#PIA^pds;YKI@>y9(4Jw=9A~bx$XQa^o_f{V(=)JN;DW#vx7t$+?YTRsQDuA5 zgEBqsafYOaTnTaC)}H4>k5_BY)bRB1T(sw|XPsydl{-D{VHhd5{)1&p<$u5T|2jr_ zzZqH;qug(k@V{==W2*e6I4Q39ue3*%kLb&y(l<-56O}%5ap=WYO3!{ivnuV&D;L&Z zIC}xNreBn(xG&mWm~;V_3`C!g{2VtprJh^ii&+~*o$ zh29sMsPM=A)xU;kUeWhg&OFE2Lq>?v7&{&^qK#q3Zp*2p?3NC+&g&BXO6pLJ<28M2 zHd3)fH5=C)QS*4suf56J_Kx&!=^f`ig2+4Hd%pKW-ni}ZUgEvXd%5>X?;92J-oI72 z>R<04ys!C~KAxFRg?+HY@$vPkr~L5MR$=9O{J7Kl*MC0#K9%KH#QD_oL4AE%`b6X3 zXrEY5?EklCLXLR|^B7j=h3p7svu>Ej;xHer$2>jVcvZkGj9;)-ghwjs=4<)%)V;wy^h)U4CddDF!!FtOxPOp@26@8wyv;- zbl%7?_ZTB!TlP79Z#-dsY-}*k8XL_|jVH}djHl^m<9YhUc)|R}c+tFUykve$U(&C} z4)bf{lvUe!->PGLVEG!St-8j?%$F{)y2dY73*)*KW&8^J`mb0$<2Q;lYgx_A+E%Pt z*NS6zn+>dProYvlzF`gYK&=OT&FY&?tyHtQHOOpcrP-g-W#(_Twnmt3tdZuuR;HTI z&EeJ(Gs9YDrdvzRENiv-fVGCMutw%s>oIexwaJ{sg6KOIY|hey%-Pmk<{ayoIoEpI z%(sryRo2{GX_cBAtncWE`J(l^>9YPXU$SnnK>iZXw~M)p&*Q~>K3~9h8ryjRU&wdy z-TWcGh!^t3w3#pAOZgtYOiSSp^Ovn2yo4|3kJtk^{*sF~;g9lH_)5Nyui~rue%qg) z<_Gv1evm)L8}l%}mapTF^H=$L{u+ORZ{Uac>--FVk{{+D^1b$X`vU*S{@8KCankXw z8Ds`qeax0-D=Wj8Y#uertu|&SYl6AJI%yVI@0km&Q|3d~`{p9+1OA4QYrbhrG2b#) zneX$B{D^VJs%PG1#p`wSyUaK%$MJ~vr}l@j&3MlI%J|T_i$BGS%m{0+G17e5SZSUz z2UrV?spd&zn)$AA&@4AzHE$YjD+XJN_GY{_-%POPnIo)K=16O$S!jJ~F19`~$60I5 z$ySkL1wU$hW(D(2{7t@@zr~;C$BaDlnDLtVtJ&F_Xm&ALm|d+&W}-FOeA@bnzs-;H zcbFeP!QVBe8%5?hv!OYSpXBd39^_1d z3n8S?gf0wW3QO4bTHz30qK2p`yoHabC2EU0!dKLFtQPgeUBXY?E$WK~!e2BLjYNQO zia-%0f<=f36^%s`5hj}2M?^Ex-2Om>iwF@ZS~%7^)`=)_k7y}ciPoZxxL4dKqV)vP zR+4bzZ9oro{>`&~^#9?tnydjQ?H|;C-cj7H^4Ev0(;%(|~ zgy`M$2D+bqw_aZy7w_n;^w#2pcvqZ+opQx4BpExBp5l}?Uc7I6*|qJv950Cv#A$Ix zd?-E=AB(ekckNUAoc5V^PCKt%&@LLGdP}3R-blYkE7d;NzRD#r^Brz6l2 z1}-3395;k<;WvnI|X7>2k81A#>$SIYrJAUyIA;dFy_AzxYyI zGKYzuj7{RA_(6QDUDsRaQN}J~H+#a~$<~?K#-GMtW*t_@7PAfZKKo_+0RE16G@ENY z#`4*GV<%g{3fMw>FMEhBGDD3|&9-c*nQA;`PGQT~a&s+vggweuvQ=y~Tf-h>YuV#$ zy;;IGvLd#LJ#AiLTi90ijQtLKmThCtv+dRx_M%l_e#Tz1uCik5E4GvEW_#FP_A)DB zudsdW06S=YXI^Em+DF-bYn|2HYGrj`&#@g=Q~Q*C!up==l5^x@_9S~v&Xr4KzFaEj z$z^iBd{{1!%VmLl#BOM>V@ucz>|y4z->^TD3*`#=kbG1wk}Dm@9q-6Oxk`J)amaDl zanx~4TcJHFuFF92s|+%ST8r5{wpsip@%I=qMBI>}dUHKk{2?2QKV=i~mkbkSvZ=T! zn~8GST)1VpBpIQH>micKNb?2RLUI`;g}g^f*-~nuWU+ved-|R#7X<0{hvR}8)NM9Kz z>q^*7%LI9sc}e=o&hl>AMb?*HWdoTg{be`VP^iouSR@MVx?(ZDrk3LS<6*H}@1S?o@7H7XPI{bpM6A%`#iM$F z?$qzq?-MKaXuYl8POQ?~>oH=rSR)>Dyr=cICt8cdTCvXj$o$eGE5Pci4X_4S=~kij zsI}3t#yW3Zwr-lo9gk`QwNx$5e%o=-iqzYP$E~wsy?DZAVuN^6Y_v7;lx>J2eAjKp zm(UimRXih}72Cvf;(4)M><}-A7sX4$C5pvPu}kb0d&FMxvRz-4h*!iuvENbPSj1;J zmKeQ_WTTJK*XU=YIHo(6IhGrbn(rCw%+to><{4wX`Ju7dykKlGFB)6TQsWu(bKPHW zXgq6vVZ3hsZX7mm7;l(=7)Q)MjicsY#(SpQ_{j1z&RHSGc`MYoU^UiLttQ4reUQnl z2$Ng)nSNG+dAHTstZ#KO8(B$afYsASs2wQp_-`zZq!_F}KVf-K{BR4{NHKWKA>EtcB(v>mf7KT5gWA9x+E-E6g!^nmOKj+U*2m^@>ofBa>zuj5 zx?nzPT{Kr&pPQ?#FU&R8m*zU_Yx8mI8*_{Gv$@my)7)kKW$w1htT26ub;%|b^PrJ!zG{p&Uo##w4;d58*Nq(Wurbkm!8+*+k zjF-(HjS};k@rwDAvCsV3*l+$~95AmNWmaqBrWJ0sv$D+g)&pjYHP-B4jWau1+2;M$ zcr(^|(7tN_W`A%0ZvSB4uz$4wu&>#Fn)9p^=6vg2`zQM^`)9k%{>8p&U$@KcUv0O! z-ul)ovVJf(Ti47@){k~8`#!sk-PUexN89(>?Ti`59AlP|Z_G628ncagc27Im?rrzA zd)a-AH;uQAW5zqiTgGvFpgq`5vxnNL_7HoJJ~YW>DDZ>roefy}i-iU>Dg>*iYF{+MDbEJJ=4iLv5!WVh7oc?HIegonrU1)9vB*9DBAk z*P3ImvRB$q+neo9c4s@@?rO)`UF-xq(O6_GH5MBW8->O)V~Mfc9%+xUN7)b9nRb>v z+8%3sXZ&b>c*A_ICR@`vtq19chQ#QFe2?g&kqvW8ZIg zw7c7}b~n3&-NRUD6c`JP`Nl)qEN!m#pf*XHX=mFb>~VI6J>GcNIAMHiTsE#~x!PoH ziapQHw`bZj?78+Vv!+?Y^fDdz{f(*GH2X1ojlIHt#GY?2uvgoUnmf$x=JV!r<`8X$ zHeH)&zhrNzRZ3bLQLDGmd@yWBxop%eV7S_^13uevY5lzR@mg-)dL1@3gCQL!I9-!F;s6 z+RIuA&Vupr9PV^c|J2TDPG^r2s@bQ9OYb)*)z!LzD=aO2v~x-SR2L7;c*VqV>By16 zBN_w-x+u*>@xci@ah?*N9v9(a;Vx(T=m-}NcV;?Whmu{g@t~by%#QCovUA_Tse!?P z4VI)jUCGI*fv(uJ22NMB@kQSeu>e7PaTzYUE zs-Na!=@Bj&9*lZ9GmEtmaZZ&|QMk*Fcggh5F3~IyvGL9&&Lz-X9HoUW>64nC+#sWG zT550_(qj9iBB6n5P-UqRE-l<;#5doG!&FbV=m-YK1*3a|<1$=)#Ap{AiLzZ1Vr+Vv5=l?+RL~6HX*ejpb6m5)TODnM-`??dg%;KvRY1K%)194{ z1ZSv+;OQl5pnB5fY=BBu)zT$GgEJB;ig2h$kAAV61xC2M!izcY?8?kYh;Y>iM-`k- zmsfmuRWo>k6#P zQvcMzKQ2}eeJMhdQ;XHOLv!Pn;PIf?8qETOk*&(#pdwvm!N^sqX=q7T)W2&w9>Z;& z{cj#YF@6#$7@ZXFqK-QmW1i<(I~)g1ymLyb%R4yE+1ce#T^Eeu66Z`u@q2uH8150` z;+CWr*V3E2CN^&ngl?*Xw$*MP;qnbHX3DLLepYV1@M59dyTXg5a{a=KHRawNUaTv( zet5B=+y>#rrgHtmi!J3g3@4XY^Z!9b8lfT$p&$SiQLYmeQEnhAqTC=Y-)8b%m)x)hyiAw7IJ(27Gf2 z)vg#)cO3D-8PUONrui==FkT{D;kTXvtLJLo%*E~zK~fvz_HN_Iw8=x|AlR7g2p>FQ;U?UTBTJB72sF5XzwPm5Dil!>Vh<)Osj zE_k)@6mNe|@KUqp74tBUPtOc?iTI36%q=`VqXGQsX?QXJo+krU!cq|2B_p~)FiPlx zp#jHJ3iREf5L86XWfE^U`d-68(*B_p8Z(eN)Kdxki$$P8aA4ZM%EBnQSM`AtrE85V z`ye<5U2~r&+GXPHbvnBQcU6U{rxoq#GSz^}9;KAjNM{U|Emh;nNGSVPm+PSjbwkpv zg|Xs6{c~`o2Uk8B)G@- zThVx$|B8;e744C(%6gkjhj3Tx=2a=TDeV~UYSVlP#*i8;OYl1WqhLIiNLMqIf4`@@ z)BvpNT{XCZ@m56QC8?-mEG7#~(6>fvReS&QQ0#iAf$={XeX8Hoyb==}-5{{q^A1d_ ztYatD8C9Jcr`jK=dR|qrvK_aY9FHc~t#~=H7~?&x6X}Y=yO{8A;yYumWxjP>_dupg zxT_VMuBz8MqhFm}ux3^DQ)0Lpj;^lg)^6cDiDKdD4i8hF9^pHgCngCVPfSlG(+Nqv zl#KH9Rx-+ytYnm@kCN#CPhTaYJpGi6@}wvk<>{|v?uTc9l2M+4N=A87m5lPFDVaEU z1}Pck8LVWKXNZzfo}o&nBRs>DjPeXuGRl*#WRxc(+;#7*ZXTfmu6BqX>G8FPFVi!g z5FLZSsBqVPx1>j_fJb_a$ET#TJU%7*K)5UVmgra&@Q9A{_>^e2$EQTchr8O|5`9nw zJfagkJ|&vt@hQ=X;kzu!MdylXC9b*49OV)r$$4t2!C$%(Hp$2OVhh5SV_L4*7UvX` z7Plv{H7w7mnexZl?ad};h`Wv<&B}<*`aODRxxeO#u;LDS!}P$4)o>S17DQ^q9i&+N z4=6r7i$!Kaabp$QXXfL_lwu1Xw}Lj3oCj z|B}@9K(;b`o7{=pHEJh3I@eYF8f0bFj=`;jCBii1GHgY*z=UKL{=yiyu|^mu1f}@v z*=+!SS7e2QQ@F3q1V#Ae$V7lUVy_{%c+bau?Iqm1X5p4J3Y^8C;vXQGAOh&D4Lx;m zr|jzl%DqNZ4|lMBAw+j46V;C)YJhV6HxM<1?ncqz3{k*3qQKSwX+e+;N+k+5!4{&B z0-{jFg+i|JWumZU_ACu)-qAak!jI7f6J>UrN5qUb!Lwjo6A(AM^diz&ft9|hLol|;B>DPHj$ z0DZAOAO=7-R)tY^C&+e!?oOyrr&D;xuK9B28R0q)Gs}OC?f`-4@Tqxv}+`EjD(vR3$783Li#A^9GwVIhtZdb#-xJ- zL|M?2g?tYnJQn`3NFRHhXj~XT{J673<58FK(DfkU&wwRS&NiZnQACpvpBqjz1%2Zo z3+^GJsn9buAD|DWL2eq_HSGpbUOG5JG~EQrU>$(|8OSr!7a;#k)M=IzU3r;k71CDc6RkmbjjQsfDp1ziJp6nu z`ec0$(S~TEC(jaXEF~&3i8ev^X0-ij=-h(3Y=z7==-hSV2#L?8MC$bWd9=%XP3 zG9RJLk8{8|qO<7$?k71*;iFL_Z_`=MzM~oFlppxnH9J%J>cb-@O3z z-^eBU!xulAkN|Gr??MS6?q&`+hIPgXptl_5yHh-NISfLKug0%o`Geh9*oF|(GKuN< z>vSDyMl85S48OF%tRw&#+Xr9~w9gQ8AkJ})m>1-|4iT%dg;>oM#Jmyb1Gg4z5^L=s zRy&ngog8e>oZu3%x*=dSv3fDY?n0bjB0&7zxy0&2e*+V2BZlr_{-=mFgumf6VvV8z z%5^4yEyMzm9+(A6hy{g#-Nb@Zz*%A;s6%Keu_pfD2(hpY#F`>s(;`qttQqRm9P!~M zfbNJ(#3D}+Yf(rnioh&l_nhy*K^ZyG0QqtX0rKXYBQ_B_Cx!#GVd5ELlb~nP5P-5Lq3p>>pBxL; z0i@?f0qD*xBQ_-oAfE@+Ysyt(Q!@e5r$YbK>%^v^%xP!w)8LTHJ3wr@7l4lG$sh-u zAU4Avq=0M0X6AuY#Ad~S6~tykeztN;iOqq`oGrxWN{|G05X*;LK6K1GMr^(xKwamf ztObXN6{Hhe7)9)%B4UeH6Dte@X!~N+aj7r3MC{>YaE{n=$ge&jNQUC2(0P#EE-vRj-LWsSXPwXX>UySN><%Owj!Mc&^~_ZyJ^3p&fPh?OJWy@fbzt~vJhoM#dj>KAs4 z@at%a;1qG)McgPPZblKeAd9)2JFXJZK)hB6@!Cnm>x2{cT}`|$ z+`1*i>kR>A#Qh+9cOLQj*~A+hAnt#Ic*7&a8=(wm81cXYfO-UNAs*}t@`;C}5D!J! zp;w7FX$_7M4}%`;;W_4I-W+i_cI1(M#9N^J7KZ@z-h(n)A*~JcM?CB4vrz$B^E%gTM2ROm3dMkKs|dV1Jtp1E1TJuc_)x?R%OXA;I?_?6bjW9*t{JO|k32&> z^91oxsK;nOFbkj#W6}Z2%0l>o1ma`EiI0X%nA9# zbDRL}ndk#hheRtzaARg}KBZf}TY=;1co0kX@2TeCY||4`%|Dzr2Vz<_W$6 z<*!8E)yRwafj@SP_*&#$ca8Yt$n!Yd_4xqhKY?bNtFF0^lv;u{Hb)} zMbK9S|E6$og80*t_*Teoy-NI<65`Kh6W0?_elH1XGbh#x}wA>?~~H}S(rKLWi+ zpzr7n;%{vreoS$l_}k}*AD;!z5Pt{xPYfact}pSEDC3kLNG1M0_yA>pkV*XXI^t)b z^TRCSANhl`#6L#RD#FGu<1r--|=!6g!~8x$;s1kNX583}U04HB5k zgysu2kic!U&{vZ%&X6##k+80luuDid3ISxj3P{w5AyG3HK+ZcGoF(A{`C5>#jX2*F z5_Q*+sFz9NF2vs*MWVio1m-j0Uq+%4!U4z^h`33 zlZf^Q2>`m<9wE^_i9`(YbjTvn(T~Lai2$;lP=~nIB;v1eJ1O zM0e!r4xK%=kVq;d(Gw&m0`zAe`1`>ffI19>-ZYdo2s#H7xJ+WmB@!9Xk#UT~hz%r0 z?uQ%F1r9S=g+1eBGN2+)rcAv-CG z#AGKpL?RbuPeGYeAu|nSp%%ONBFU25Dt(w4{7s|HViSr6dXvEkoF5SO<3<>i#&~$D#Z26`+j7dX%+(8GugA+2RQwfckFm0;uzb10JZkyD~n|&C39EY=(}_H%L5<@}G_cXy4O?Uheqh*aoguunqa28v>4ycpmk5J^?`g_AG#Q?J&V55-&ox z3;K2*Be5$NTqUs^GP}2t*b@d&?q2BM3)z=fkidRbl;nT|B(Q#nSF$T9f{U{Ep?>?4 z0c7^WzaRMz_<|Gw|3T<~4fzfwka#_s#Nm7rZ{(6Vl1k!e42d@p_a@4E3o>s(&s#_S zdmKakj-md?4v}~p<-a|P#5<=*e1JN909~iU0qSrj6I`m`BPR(DCrEtUn#9>HBtAi1 zK1KXzAprT$?I3X;b-jS_Mf6LlB=NaP;tR-M$|mu35eXcFh;Pr5_zq=WJx1ck1QI`` zkhq=%koWo)fb?ITU;}{O-=OC=$o*DW!S4wFz5<*faRY6+fwUXTNc@ouN=f{g1K|FZ z4xp18Ot>;$+$;${d)1;~TnvJ*EUQx2WwQD6u_Ipw(u(GQlzc-QMR&`h)@Ksg(e(k*tmU zby@?I>wAD?-3=t`A*~+t`$7J0$ltw0Jmcl$@}vGbl!gmpxjtLkPeXE zNdoBVg!aY3AD0AB-?+1&jAT6O5RdfuT!8ra5|Rlht24^!jPx$cNOp|{d0+!L18$H^ zM7cP-k%>r8bOFS5^9Rt?4Z6Cayly8*cJ~61?Y;w?BH6qQ_MK&ICjlD(m)cM@0)j)AKrlc6gax{^}?bR?tR$(Kp?fova?iL)Tt2Ri#8 ztq=0_xkj>YA}9cm?I%Gj$N{^-b&@G4GX=7^XOR74Kp{9qa)2)w0?v>eh6SO-c;4n}xz4k!UPNDgTY4uCR}L&HHXKzJy^!(su- z8;m(nH26^BR$qC6|1<4%b$$>v-88|?4B6Lnf892X^ zll%bECglUxHIh?N*3?-5;b~p~`KA?sVFa4XPO`uAbuvwnF)O}ualgGxLJ^!b&lk00?0c% z5oCiEU^mG*F`$g(+%SML=c4U%p<^y|%)LZ1AG-6SKq|-wTfh;L^Hu}M%tJZzQO5io z0OjEORxU^aIiLtYwm<@uTd<7eLINmb;Te*Pya4hpLcYS*pa8(XI31LdT;d0k0c4gO z0yju5MO~I=fg%7M%S;dhP~I}gJnRH0XE}5)hx-Uz?D6D^Sg?cSqtLn17px<>3iVo* z2dT;C4%uF5lme~Fe9J&9U@qc5y6UbQjpJv zGHt*s71yalM6e^RV*qfP2u|Rgc8UmYl;b`?1dkffPXsT1z1xZ41HL}s=x+xcAqYt$ zLeL7>O@t8Y3Zcw&JkKx!Rudr;`7%*v7{6hZ6Ml;bS;(7(Ig>R?jy*(}j5bV0-IGre zVM;Cld8Z=pROFp{gb34cJq`J$9VNo_1OUpPzMlx4rGVFn(1rJ1GXV#Q(5(XCeK(%> z;C;^)z)2#^$OW7x!c5R-=5`|V;@zwe5&En|n2r3iHv>K;!W=xGvx^9Gfz#YBz|%yS zrv?lFjuW9D>HBd#A9?4WCIZ%9VF39D(8fVL$9gI(&LzTJ^}N{Mg<>bYWw2%C}rszM@M4g9w5 zBEmK6h_DT5wofI(b-RgheLdhyBJ8-A2shw*C+fZtX?7vcO(_2+lzlVqZ$bK7lZo)X zy+pX}I1zT^diR?|xMK?u?rbB%_tD-xDgfTyg}UxW{(BA(0Xnj9-%KLhkNY3IMufe` zi15H(B0T6K!hY2M&;Su0E(M$>!Xqb%@F?;;wwef!*AwAj0$@22z_*1bP}dV^&yyPf z$p7RCz?VdT4ODpQR=`ofdqjA858yc96cG*?0hIt;AIA0JPl@mh>Ns*Q5uQc4&$SWZ zd9?9)lyemL9L4=nwDl;;e_=KeUOYyGmvR3x?q5c}mxqY(!+rpszk>9yY$3w&r-|^R zWB}g3in?BXlL-G42J9xnYr6oS65+?CfE@s&{fP>Iv_JI$P~T7S?57_R;e;Jf54aa_ zng~C`Gw^-k=X;585_wL}27F0`U(5uc{x?wn8ykr5%cDei6Yt+_2jKcw$$%~Z^8O0t z{2F!q8tH%I1MDZlTeyGgJtDk~yuU-*cbWn365;pji13G8z-vVK->CpRd$%7jM1(&g z%^y+LpOEK0D*$D`Uk|{uKcmbKknh7TBK$=KI7oz#@ciTBM1YM|_{2zrzs@AW-w0qk z5k3tAz9hnDM~U$HY$AMtJYT#?guerqe*m|yd_*|yBEmoIfRjY{8fAZdj0oTK6JZEt z3?bj}2_is;70&D;B6*XD+({zxUlI}Pf+##qMDZXIrDH@??;v8_Od`hPgfY#hL`-;( zh>5QeQCkW)K*S_F;5ZSJ_Y+Z<3|I#^O+@_>A{q*bXle%_op~1#tuDYxBBmgX%?iM^ zJpq7pcGO|t0zg{(TSRma0M0UUAio3Y9eD0|lZZ~Fcb*_(S{Gn50MFC#JZ*@GE+3!` zfb_0=0l?GsDG}XP0G_*71CZWxgoxf9fTscP645t6M867fnuvkjfMY}qB7JBb5z~_a zNT0Esh?yuq6Lp1=KFbI|S=mUF0~+L30^TEH-WC9U^TR|e0R9EQvEVHt7Ulx*t`PZ) ze1H=~ES?Ggp2fhi6!nz$15j640$>9GY0FV|Im)PL1KbLDhlsEPikvii8y@#fP9@Os|#gx z9U)>5-u2pv*mr=4bFD<27a}5bDsld1B7%2|3-CK&1mHb*x4868BCbTem+mFvT9mzR zI}z98_wv_>xDjpMg!|3667eduVGFLW!MklIhmD7M0^- zM0^?b{1D|FM;^$s;{Ti^;%i9rlQ0o~iuWhpBI3``w%4Z;@#nb!;CgZw5q|-E-vFM! z93bMGTZs6pdx`jKz;9*~@vV9yz8xasZ;}4DUlQ?mNdJxsfHL0MOT^!!&fm8K_7m|B z!1I4+0)WrEc>jNP0P6fB?%#6}@qHiQJtF=Y^?rc*K0HRmzo3qf2w)um&p$@GkGBJm z?^GcXKS8~pAkSZ4BjVqV6Y;YM5kEgl#4lAu{5$IYM=24%8X)3nl=n}x^PhW(_%(jN z{*Z`6tBEM@CK5SHByKN}_z#IBbP-8>jYw+zLMD~stwhoo0eG+Zl1K^50q+q>>jP{C zyh)@a7XZ(bP7o>iRwC(8o*uu3lSDF}B9f^daD+(aN&w2X>;Sw=Bx@VsX(FY(L!?yH z4S7>?Bm))`$*Bea2PdATB>)Z($)y6!1e_p}dpnUlb|QK4%!~A1l<#W;EC=iXpdLQ~ z6auCKRs(JYJWZqk@&xcKuoo~yq+mUfLY06WfVYU0j_dS$iIf4zv;vSf6ZnQve%4ID zJ4DJxp6oA)l!G#IhlrGSoJjfoL@ICr@V=;-NX5ug0z69&0B{Z2RVwuX(5}*Tfc=0| zL@KibW&_?NQaRq2A0tvlDPRlWQzBJX0+6;!4Hy8Rtm+8h2$5=x0N`EoA(0}@fc=1z zM5@gNpq^T!sdE8P7Gzv$9LgPs_w^{J9(6Yq0+s`SVmc=a45(hT4`6J_?|dGBr_%`yT|<}9S`!*3scXQPbS2Z=NX_|4fuq`B(=z+oPK z`;o8zIFaTf-+bUP|6L+oG8HgHqy@_X$A~mg2>?C|k$)j@8^rzK9suxPg#3$u+oDrM zT8#P@pCr{Sz=ch!v5%)JD-7Y-ab(}~y*#YZ_bh8ft z9B!EjI8CHmQP*uM0MhP8-aB!9r;T9S0U;{8u#b3g_Fx50988SFS67yo=7*9wRXEd7 zO$+j!oXLn!4Nz||P^~H|40t_S&g%&p3ah!;OWbC2)U9)u0RC2X)4ayz6VvS(`Pp8< z{E$wxq!(nR|ml@t4&Sx+GtRI+Y%7=4Q-(R=jtpd=yDVMac53p zK^a2*dSWFNkx~;S66&XfQ&X;&s9~v43%y7wO(T+2)dY-Gog!7Ks#Odl9s5g;Q`<8s z&Kxu;Fcvl7B@PXb&!fY#J)bKd`cruL^v=XW-wE!2Re9fN==Y{4dv&Ul^0J@H3w}fU z<+oDZ3`Oo}K~I3;hi?F*pML@T48(=K+|`ka1j?%zg(RHVq~iOCAm9v4LVy~_QJ{uB zIJDVlBqTlPbsJsAG>ZwD^=`G=m|386M@I!GsW3J;FU5muuBb4Z^ZE<&i!n$taYoJO zJAZOzrL$(vIGWLT&GAk0$27V1lB!f^WPX$U*{`p=Ve|I)g?+{SJG%>dJL)Xs&dl7i zBEqegyL^@HSvjpm_UHPSte6cNPB`-^cI6+&S(y!yI`k~ZQz~$cgjW$2PZo<5_8+Lq zM5W?7fqg?08bdn?rH!%}^Ynf4nZt7iUZCPVcmI8Qk2=MiP#_raGT4c!w6+{&;E+(RY z@1P9A{G}44v9yq+>Lwb;5d!%`tsbv#PHjD?`;IwVF373>jyW%^)A${8URbC3JLbHw zPV0Bfd10Nl@0jz#I$1}4mtHx)&PdtCyE2Zk5{Xb)Wk<)iB(*eQe2?@f+rY*CA}N&A z*OiwQ6=Y?4-FBPFpyF`4d~-Yoy^wE?&dgv*HuvwweF0{OmL^drb}TYx9|)Edb2n?< zF1Ne6HN5MC`=|f=xsZUVGwF|aCeCW}*7g*qH+e1MM@cDqM~ddkgtb4U-0pulLv*X= zt%%Pxw-$Pe14fNzf`xF5hY1gWhb7>Q-L!~ZVN{@k!c7(C1@`U^xqT|NC6gLCOmQqn z`6{zsV2p`fS98JxgU9609~gd{3qC-##|Gt7HESOlls}*;gAc8(;eL6K{EuUU!oEc> z$^W=#?F&~o4vCFdzks>Q_-7vK){vYC;#UcH5coO}nkG^~h%)qP=ppcPJk=15!qO$I zGt`8dW1z|#-bBBaMeeGh<-)#SNBK2MJzIVpNsk1^l&_j5V3knHujX0NI8lieEwVO_ zl&oXra?asD%Ad1Rr~YR6DHMu7N?O4?TfjSWNlBzoPdOR_-_NC3e;Q#~$2omCubwe{ z&=Gu-=M_5Q@Lhv96b^YrbxNk6amKT((#bJi8O-L-vdZET9fn911OTCB=|6WqA^+b` zmkz!{&5w57arNS?3Hox6yRKt?-J(a=*EL;vczOG#%ELAXeRoGkYm8GSA75#I!G|$!x~Sp#$)~G2;V1QO|NQFQI4zTAawYHeix$_Dl0C*VqZb2 zC^@MGy&VYBY)D0nhV-$TK)#;dm{OAQp`4PL?Jly?e|(aglPoVV9khdpfj;Ba=1jjbMd)K( z-Ov*>@eh9(lUIBhH$f7JctJtd9{dM-FIG_|u0R%G#kkGIx=be4foEAjLt2dwKtr%9 zMBBtn>IpJlhI=NlS}4C(=g?}MI{JuOZ?frs`U%g=t!a@!Bu#GQRiFG+Z!_uC^a-xZ z)!_9vxOjJxUd?^o!|$_IyM|6wRPZJ4n$)2lVIQZ~Ck_36%=pCl-w`ut97QckYKuE1 zSwT&yJDV2i3fP1hMTutXQVe}^lsgIY;f%hTN)d; zys(zBOvW(Tm;;VC0Y`kFhGdg6G8i$qQ#chwt56V!_i5D}gyP25gFeieG*FN(!{n%G z8nep9L{f00RHVQJS{hAub{#yMqB|0oo*oSOeaetlm_H~CPL)XwW5m1?HY_Bp2u8Do zDw>Q?h>lQZTZ{(tpPbm{Xb%p)vT9R|5*?L^W^0=H+NTCqeA822!c7?1!AQd2lAASr zwC}PpWXT9E47q4RKlL1p5+`S}J|$WDN5A~>zEy|o_>3Axqy_sULx0R>Wa1#(ex?qf zAMN1KueTm_f*A3s6vk;NFdSq*b|Xb^z+c#F4;%e#^#Rv`VKQFgM6sbM4y;hs$<_+2 zK#=g56f(L_MN<-%j$KOA;we)?&dn1kKDXeDCs)=uC8y8{F}p=*hS&iufe9RFggq41 zWi)Er+2u)c7b(&;WnzcI+$=>rTaw2NK(&APis;Hnhi>XTb@Q!XJl5Cu*cZ3ne5%t` zI=H)U_8o&|WrKIj?%O?BI=XT`*EhKAMx zOxq>|hoPh(wI%GptY@9?u zKyQ3UAyQEVebGh1dl!xuCL2Ger^FE)K6$j3H(V|AT~7qbaX`Ms?}bGJDyqb(_}BDjRp@bL$$exqNZP zq#9w7wE?ec)*W2A`K>n9Jtjk1AT2d_T&SQvH;`G@xv6LFBUiMf<~L?u zsWqhMr!TprtU1pUD(%@eZ_;h68{4s;3S)`jwAFpEHbW+21m~xrRZPH8mPF7&g5_AJ z6Byl@tf+Grscw!akKT5NeLLVOqm8fC@~te z36e-sXo>($!XK4Pbc$w>&4d&kG-mFDiI-2!qKQ+!|A*^${NejkXkym1%ik`Xb!VSdjh;Y4f}I3wJA|gF34)0zVHcAOc&46@uIfxo z@oL_Ji3YlMnpWe`(JAU2&)dUCz7Y0#QipbCE+{QskjbyK1itP;+jP)-{b*Z=(a39t z5QSQ}==#iv1)^qSJ=GnP zBK({bA7qMm3}LG^Y#8z>Wri&p#w&V0+!DNw~!~@%@mwC>SpLEq7E%^ zOfdOTYo&OycE~F@pC{xWXPC>m@d? znb>+xPw`s$%i+&H@uq93+TztFddyVPggt-da)(cHx%?WBO?HIa{DHPi`X_ThX+Hv6 zR9jJ>mRa%8{Lvwe0W)oMTx*Heq%%gxwNavw9gCQthvB`|Hf-bm_RZ5;4fo-2wy%|orB|s zlls7+6)w??bx#!W=|qSwtm&y(VZSvgTWG753?rtf?nr7zIyh5SdSOPP*X>BPnhpAR zH3`uWQ_#_W;PFtaFr~mvN=7ZMcwDR)T6KO%>P1@KWHj?B-hjp&9N#{pq;_e0xN7IA zgI!Z9CspP-Z9Yx-iGTL&oLeBLwJj@Jd{b9og2~n5E%NETjROtkD`r%xDi_SNd+n+E zN%vPQyt#9D-JK<+j|!<7rS95NCbtzpw$y`0_4r=S4A|@rG6PIfT_qLnXZjDbD-{v7BuZ*nq%dNk_AE}MVmzh1Nc)l!I7uR%aaz!?xk-Zo9Tiy`6_JJ2 z@?T_bLFP!!cdZmdDq1HDC>l-dQpJRr;M6J5*rrdJF?Ghow#J4?by-PaeonT}W49Ug zNr{>`QcvrX74xBD5r;*=i4o6?;4qe;-vYtW-cy~^dr^_6nj#gtPLU(1N0i(UCRFP> zZ(CX;B$#x=4{5JoQa`=aZ}Mr!rOz8&TDateDrfiLx~lQ(re@hHW?g&u(lK4!{qmYs zw+71|mcNG{_D^WYn^x_kZ!TPwNT0Cgx2p8xHa)%E?l;BVa=p!EvrNsc4JOYWD4vjK z3A8L}3QTIL%}e9G3kK7CX&43_9bFSzJBN=7Y1x(ThKRGKzk$BI^|HK~O>hrzWc``X zR2jnSSRX><@u+B-#6x~@IygaPq8!9{jD|5!aQgqqXkc8Vrb&Was!W4sW}D?YMV?cZ zmYAUWFA}wI=w0{ug+ScktD{AsLy?9Fp{X`PJT6-(H3Uqp5Jc7BO9jxi82w{ihRMa0 z0xzS#F4}#VXY0SJzI{&jjq{7ESKU7^cT#Ohibiy#(4wZn+>Ci8Wiuk4<-+U3hw3IY zUj5wajVEquH+b@#4K_1Bxwb+sEKE=D+&1f>+ZFyb4qw6BtI`vExi1nQhInDaY~jFJ z*wg@v9}z#;%or6vKovGDA%n1)@Eww2%tPS`1-v09q(Fy1M@Uhu*CV4c%1sz&=DRgG zf6SNPP*6L!*5$36RZ-EB@3%OUn$l-4SW?`#e^X2CrspnO^=Jd1u1&T$EIC~pCr#em zndR_0EIn)lHEsXVrWG&W&_2E)+E#gw($;b0$>^xiG5d9KetaB6uUgnF*|<3G8C6CG z(@wH3Fn1D_Kt?Us%}olMmEb6o#!H||!Nt>q&r-N~#^l2)F_No0V!`2LRk_)j>F%_c zJ#-u$7k8dLlphh_*wDZb8LOCF%oIw0p!Gyep;LDaR>g=``)$;%KhTpntJPcEU7X(R zF^?EQuTJRLdSq3UnmreiyS+6of2{SB&BF$at-oU)TA}l=jwG4j1aa6ol>muW#TG9{ zRYz2bW|ItKs#%$NSh2*B70Z3zdpJ+9OpVUZ7K(vovB8e)PD@F*rCZDfU7Un3wOJwS zV2K*LLa{N0*~JzmT{h?z^_=jt@)Aw1#*W_NsXOMERIk2&{`B>^U&*csi!qnVN_!$6 zNAbk0dA{-tOXJq#n^qp*)d7RF^XvRW5qw{-AR}Yi)!jWCCwbA{I`&0L%q1VbleXay zTXtw{A_Yg*79wIsVP#Rn2unI8H0Hdy^qo>F(F$qdqoPsKP!( zFnkE3XBmEUYFT2eoXeTBcg;AfXLzd^Zk|_J*;$)sNyFT_WZA0XMMt(ztiR%!b&J>Q z=o_iUQ&jruwT~_<4Nh9s>bHCBvDtO~&$cam_S*I*)-TVU7D1#1xCMHea6b}WB59;F zQk0woQ!RK3Q)JE>ZB;5V4MTuLnwTlNT3}XUd?!q23i!>;09~L9X45KK5FO;O-eRrN zat3-Pl@ZM20Z)bN?l|Z!?r!L%(n?g16FyE{d9jWu%x^~PhG;Gl7;&?;OgtGdB zL(fFoT$LH4FHiF1+p$T{2)o$?d^2x%Bw0-*b-teCq}mKDxNN%H(WEdeIj{yv z9E4ONh`i7T?iXo-qYq+MbT){hva*b4D@zWjgHt!ui!aP}(Hz|o$E1mnil$BMozy$N zIa2L)TP?aIcwNhAnMRozW{cZoJnJb6LPK_rYROD0hrN@Dv(X<~n5}{iHR58WOqFC2 z1uPdwKdW1nM}tK(<26-_Z<$tJk~^Y6U-9gk)dyCVcD9CclidZLiQQF8zDJk&s;BhM z%SkUtt(aBc&|mA6|B_vwWto9LOICvl^1#e+yv|ncYP)=Tj>h3jb0qNbDaE}l^_%;v zvRdaBHO+OH8p|wsxtY3*9kbdl@67(@MW^2!4@at{Iz2VVV=(y(xJy#P)&92b?lxa_ zR*Etw*F#7?4L)old68^<@rW8B6=Uc#NeApTCg@<6DheAOn~2Gafxvt=W8@KLon}p! zbnCyW+%;$FRh?O1P49{<&xfq>qq4@b1vgF~Ud7!oYe9MbFhm=U%mzc)Bm5LSZDH1Z zOf|k!Vdp9gX>_`xln`QMN(D4E=>10MWnLW}(bQuR8+83?YO`gQyIo}&DJdCcE_ZpR zO~rj9gTZFHO4+kgJY&D*j0atf|JK8k$TQnEn?7gjQtIJH>RJC)v=qccJT325a5cbk zUl_@YhXWdlBd}ElV@(rGa2$$(zTXAB#}hCupT}lJh=IZHj~d@bJdaF#W4@3Jo8g_X zvBz8KisNm5e}OZRHLAir+JFkBQNJ6vrn?|6eydTFPG7pMd@$kW`Fk&P)--QC|ugFeuB%MhPru|WV*%LCklj!vS zb!2GeueDBR=~u$*LysmJX@$uwU!7%53Rz^WA%$+WXk{jH<4?g&OjTsczDN>Gyd)F0 zE3PpSB6veoWi_)<5(3tSWu7rKFo-Be!?;n_g%QTreD-COlZ8nbL(>!pxTBnmi96Mb z$%Xw7sW~=EvAB;JueawWC8t)5n~*(cW16*j`kcIJTY7T7nm#2^n`b{grMEo{c21-i6`30;L}ryWr4a1{oO z=S@70K&Ho+gxD8e)5xT#ByUl$Vpg(dWhjs6_zW|K?|E+&vC3dFQdpRc_$DcoNdq;A zqoM_K{Y9k-gAzTXFhnyKS^50d=H{)>uUvI>YfH=4qpLPwe);CBHf~hu$8SG=8FK)R zzwY?@%Z_g!KXliDefu7J{DB7^#f;25^OS0~YChzqFsvLaA_fOJ>vu6|VtyBT`c!`ZL_2pgF+#`_EMEsFbvBFu&HJ<6I2 z-wS^z(!d(od_{>z>kVcYdhV=iWUbw`v^2q#;xexvdc#H6l}^6;daB)gU7CD-3BR%7 z#kH*c4ttK#u9JSz@bYDh4CSqQTaq-qXYE8Pdk)Fu>3u6E$s$_G`cS+LeV9usNdx&E zaHjF(##i4Cc3=)f9sH%MV%K49MXlUH{_`(g(SCkwXess;s zm21|mT){_}?cty`?;P91sBAlDV9vnESY6Q9vv_2@?mNIe88bA%&LBUb%7ER;j5Xu- zD5rxfdBnsJ?IH(LRYv%MVoSg>*oZO9^K}s6S`V_oor@-F8BL_v6C!7oo|sVr1&yX* z_5>@KOq#o_}UJnjA#-b1i>I`G83E3QDF2?Hn7Eiq%3ec(_%iqYwBv;`pTwNP=JbZ$SSTVS>3+*&W0up*3BqpJ*iKO)n`{Hsv2VIk(Z z{_~fi=zCCwEkjmfb^H9I%aA!bZla-vV1RJ!>DJ#Aa0=SIEj>+{$$}v{sluKfDG2IR zT&j2V%!O&s>hV>ftVsIscD7D3+jS0jSQU#fWj-zNuW$EhVN{RxX?cS=;JHu-M{Pyt zNa|<(SxOw|s6&f86>rw*(~BE&TBc++_4ESKqJca5i{|%Ea+YbF7E5|@OKG?!-H_Qd zqi;r2X8xR;`UW2>=gX55jVZ?Je0P>7)sRbDgsOA96s0V=*=k409#MhMDNou%JN%f*+4D17^ce z0v{+G;E*yYG#%IvE=&RKcvL_~s_uwEVW$;AzsHqgA&s;#8Xl?`3lZ7sj7GOIqv1L3 zK14yYNN8p#5*4win&Ymybl*U3u%f;qm_NR2e16U18{4ycri^!%$Ad^2`H`%e3B~Pw z?Zp{2Ej1aI{D~!3Z~Llw`wxYe>MvPSP(HajJ0r{C&dn}t9h@-j%C4-lq-w3qsm{x( z>1imN94RQS&TvDnz3=-&x%^v$PhQo+Xy!p&((i>z;vvf;@o}J+3lXtQeqsTlY@~8a znTEhmgJ=>p5|A!tDp3L}z-aKEK**({fS8)mbeQ#{$+{y5XpTB8bjeAHqKbH^hgpOK zPoO9o{1tVQDUohb8#l~DEQpYvyynJ*M*9PWg5A6s!PI}vNw=g~^l=)kdVKMY$0+y@vt0Y{;$wI6xk3+qePC3%7zdKnOKgLTqm2R z@Q*M`GbPqn0flUC`MHE$pk?^AdHg`iT$` z(H|;qc=fCWW%=Bnzmc;hyNVzt4%|4M+rj7`2i?H}9MAJ(0xt!lm>+YjcQNKrj5}fX zi?1eI;^VElpGdxxSLB87syLf*_?_ID+1WF5IiJz?jjYf?k64ca4E8XAA2VPXu{i@7ly_~y(EN^-I@iZY9Qo>4z!I!$MONcu1Q zkTJPuj3bguwWeqitl{h;cSe0)s%PrX#W`7?u*YdKq^Q$MubEiZQ{$F@6)1OBv}Ni2 ze2doXGdhj&=FFOOcSEV4PbtpQ>b0hXvVt66ZC9bZc}1$DgVUN)lU*rjYYSh+y(Jt` zbgzs^kVWoLj%uq zZ?HXO_|lT}koLwK>|Xs>!r@fg7fD7curWXrQO-w7IV>I$1)&^--%@6{jU#HWVoy~qIFlZE|3lR-jdmbjtBoH>OrXGMOxZeC zb~H8vC3DM|B3^}EG?_}-jHjis*o@*D$ix+t_m(`8l&T)Y#}nfd7OL&q2j2fs*cUG? z6B4Dwgk_>e{s?7HR_*0}A>0>@#=_#w!X-J@rP1}fiU&chX1y*cFxH=C&A^2Z7ib$t zDpl8T?+Lpxrh>#0F|tmiSUwQhKcU6T_I<>rRMIYL%;Td~tw+?Jg+zR2My8lM#? zC)dZXLuPq zBp;5F*8w#Hbt9f1feeVU>x6Sg3Mt_fx^1>oFuQ)XmXY3xWu0)SiNRmUhN9kZ2RGs zNg0WAjZTy1$pcw)FWu2~KpuW>eY0Ii&?h`F?t6bbFrZDdDK=h?Tyf@eWv@jXagb}G zR8$rkL@cs+L-gW^m=5wW%3SPii!zGYrml;lvwU)SV`Ef#L*jKK7g^?f1}Y67uo;YBL78 zSUpD6b6a#kU8D+T`iPF8i@byrA~s|$@-mw9TQFxiFT@;A*`~w85Sf6uharxB0p45D zF9y;c#ggrHRhoYmx6wyuF&cfuQbk7ZqE$Q{T|CG3Co^PEKYuW7KYyg4zkrYM1n@zB zO;_j$bi7aja}pV+thcefs1S{=P{E z_T5pHlNivXOul4wxg!%62b49H-$hr85@;PO3z9hElM(HK605mDFo2j?k5b&kcq~yO z3N-k1NhzW<>5&IfpvX4NjVTiJ0)E`Hz|X7s1-r(`>sBb$P1{hX`jFKiQZ5UPL0Z($ z9Yg&rEv`Y=USd$a4Z8NyKGoYuZ8JqvQ&KBGL+8-!e~oL>MR29r--;{B zx4jCcy)jJB*4;xk(O>b0p(lw?C3B4CMbzTN_Eu4X_F{%&)B~~G6|cKat4~h8P8aX$ z;No3$M?hQT{MeSPwV!epYFT(PXucd}okCf9l%;27Q4=;pQl|dE%>_LRnh-s82E}P~ z*Q=A_;*!+Y>oh1Z!zHf{XbYXE5>41bul?9rqz!RmJJhY)_6WRd20Q&V&81_Iv zk5R{i+DM0b`J!mLa2&(I$bf=| z;jg(@m@}M`#}S6`Huw0y%kwy&G4yNh@yC@sYvJ)c{_pdw6()TB)JUFY`M3PcGwV@L zadeqYU^+U19e^(|`H z%A8K`pg-r6Q09p4I0c0=W=m-6#S5P9D5wvH8Va1wf`(AAzQDmv2{sfs90d)*;5ha> z4w+lzbpzv< z#_QC4d~ZLu>UDYL<2W=zCyrbB=Z`+!xbd@(-d|ZK>MUud$K(}26ZMp!p5L8QPa&r; zuNvxvtPcN3FqbKFm$2pu?=vF;8_P@GUB@MtstnT#L}pQ*6xU=vb-q2 zC{w3r)^h`bmx`3#Ps)CUsFneHgA&T6^j@?R5%P|mG)@E@j(DG+D66R{OVlNXXIww4 zNTbtBagE~>5)(}6Wj;uKCR~nhjFa>_P0_6DXM~ZE-dQ!_#tBt9y|eoA+BWv&Elo5e zh+Pv(=J(Ca3DlQl#B0(^>-{-1`{tLlb%_ba#3gy%8{6{wX3b(9J%%2=htd!|d6piK z#NfpP9iU>Vl-N0CUMe%(g{gerTNE}WHg_ojJrc*&)kca6vNMa)m5?QvSy;m}m54Vq znr#h>Zsv&28<;Z`gA7x>qDk3)024wXo;sHtEgG%H6e{=m%0nhxwwy~2Mm~CH&Mbu* z-FZtAji5%GLJfa?X}Tspqoh8dP-6n9VMtt>*P~FQH;0iCBmqq>;TyP9!YS-VY>gOl zGBbi+m~3^)iE(O`7DEOjh8YXaGCeFIP`QzF#6ZRPAH~FAvKl`0YfDj#pG?tae1iGQ zN?>*br=S)k`V{j;s>Vvh+@EaOWnxMYlZP%9M2%B-cf~z=ufgxVr~DpWnnn`V2$IIB zk3RJT@Ko*fbrR9OhKL2f)_J1NxW$8?eEo? zwXTdKtgRjLU8)k{?Pw%g5{pDjR>KSIgBzV4gTTT;*+~K{ehNI9xlIu)Y4n+b(cQ!f zb4D|GX8lGOeN-tz{H)HP7#D)z1|3>^*jaOHYnrXj=c}{1{H@~~T+XmvD=%@y9?47i zn@lh^P?v`OB^iIRMM%=d>zx79Wclu)ciAJ}MdwEQX9Q=MBqI%Han4IeJVb5=hr?bP z)f9*K2-soGVm@n>J-MSz5XJFgb5*4YA!<6-j(8j`^zH2cGmBa~gCi|MA3?&dVrM%2 zi>A?AShHOX<6Hf)R;IPyTEm)6Z~0fv9X>soQ6fGuNsz6q-Sk6E8dWI4sag9u(sgDV zf2VK=ae-Z=E>hDBZ};?xRaTgT{cw7t*B~a1-N>oJT!ldi$=J4J*wP#8bFwl*?ldp_ z?=ZZHjQPZ3)WM-xnBHik&++ZT^F0!?st7Qc)9?kciHx{azEI~pNgRopnUvg7KIe{TJ`p7Q$2P#eAL@_#UErH^K7Z$BS;8jQa8lRQ^L2XWWa)*0?yc_Gz^%Bdo zb2!Re@@Bo28)ox%KHaHG=iz~1G3Epg>ZR}?s+PfH0IS;+SjKonLigcT*{Vvo*8jw9 zz?~|s{-5*-%bSblbhf$1Tyxu-YbR{%&b7PkqZiRRIl$jYYtZI+0)J*46Cl_YZW!yC z5EvzFJc;*3!(qYZ(D)pxqcvu=FT)>Fn}vPyyL-YpIpICj#q=kX$FcKAnEr%oNcESo zVNEWh%Ta7rB*T;#&tY#1+i=OMiJGoaQ9=Tx3FZW|KACE$2HGXF8o*bEeZ2R<_Ed>J z-Vo6h!Gc;F@mLX-k3(OSvldwFgck*l#!N7?o8mr3G?XC3u9+<4K0g)g8El^jM1t5p zCF~QauA-!>xw<)=;rFIFvVu6D=e*mArkM_#SZSz21*kyq60Xtvn5d^%r# zRqt3Zv8!zH9kc5%TQJqxdSg@Tw*HE*&y?iRZG~62mULCQS--=#awbV^5iTL^(7I+v zdQCV@tCR9^jQ^A(XhPM9eby=*g$8kw#PM8Qp9aedjc0L|kg)_&6fjr?u@gshiLH}6 zDCz0ym_2!Rb7N(>V)wBbbg)^s;{&#!ogXuX4IO1Js+0vsjGjjp4LFJJvQbR8#aKp1 z&oQe;T2+*(u?^ZK1|`A>@`Y+&!=R~ROIuBEO`4;;^U_^k_fb$G(U>at6h^fjeh&GHSAjvRf_>@5?odUfl#c?Uk)w)dY8PSrX5 zrlbUGcm4F0zoPjsE&9n5w+>eHJ#psVMbBS1>E7h@`T}Ybi)Z4D5f-fhsS7q6(S~uH zfe4k^G(Hl4_RP1ar3N2ZiXQz2uBM#)#xbuq=nspET7Y;R7ssfL<1P?TDRp88StE9k zMa? z&yUz7h?gvM3CG!Gt4gBIKNhdVj<-{(Y{sO?rH`!Yzkg+QM>=m)EzJcdL_)R%5VbptgRX$)9XCzdg37`7f}d zqE%e=#|LMJ+m~N=cW39l*RSXZhdWkWe=i#gs?o8KidctM$O2y-ieMuQlTVpVJqK~` z5@sIUV*-g&3vqo!jjb&zwX$hjk>xQ4VjiNi2FU*?+gX#}f0Ruz3I0bpVkSdladFr5 ziEYKL#pBc6mT*Qmzz$P^@b)izRlxd<0|BCvjl}@_JeJ*&V>Q^JCDZ@I-lQM@hSoj* z*vvWRH0`0EW$Aatr=*m071sK-3GVXjMcgm{qs}}jKhIxz&BpGnX^BCb{4+O|v`Kg9 zJo&D)oU|myV<+>iLLb&bCkZgSR~mepuscBNW;z2~IMBWl7O#YcS#Zq;zdtIu6!CAX z6GcHAw^eI2-Ex~|w;^Or*X`Eac8l4ll|R}0$PZLE=)HQqPj^NaH~aw2o-O~%@2BB8 z@*CWYIGt^WoJW6-Z+VgiK8gEUi8TqbNFhAI3K|VH!B|A32~4@lflB9_YhqIj(otGeU1R!yrVc;KO6ZcvJ!yLi>4 zT_-kOtFb2F6rfoRNqgjsR4o2xbdatmonIgX)cg zPZcAM;z*3jWGqlS+TDtCFadq^ZD|p|eNNh#)A2i%%i=t~Yq{)9hi^;Ucn%KVn(Q1@ znZpS#O0P5Mbq3hZcLB;pOnzBUX+!pUPnDZl(OZ`pPFRQP-^x>r%&gYn+TXbh>Wuo1flu=k4^fvEY(OA9ivE>QW zZ=XSLPR*+edIp!snAEj_w9<+Bmbm2EO)HWNX&D*u^d(bK_x1&CH?15mY_bN9>pF{P z7>$Nhdz?JiTr_p#tll4NoFv_1338hPWnovMJg8m8eHsP?z85MN0p-b z7`vYf=_8S(d_ywkd!F9`1BJ3ZD(Y2c`|?;MG)77EL?dM|C{$Axz-DDIu!sb#rh z8r8#ng2QPwb#=5#w^)PR|6cQegZqB+K_*L4f-U8$xsa>NNNuD#35MYO00%2R_H0L2 z609KDN6%IeD0?I8hA1imbhXrM@dsd`Gy6U4oN5CzL@U;UsIC`Kls)Wtjxt#$hrnEh z8yJ?{Mb$i_#Qo_Ri^^6WSUu^Ac`d2)yfroh%o^?mm(V*xPWjQi3}17A8=qtkS%>P} z)j9STxd%OYr)E8L#rX8bzLFZf%4zneYPYTXWUe*z!@31wb=-hHkY@P4+L2Y2j>t-i zGlPhV**`p_EK(c~UPc?iDdS<;C8}9*R8Yg=Cy2d@w%!D#0B!QPU1^FXL>G1^YgoJ7 zijnV}aB0Nfv42d$D#E{OsX<=(x;IPnTfHq#ZPmYxBaKeVE2vR^nbycJpN{@;m+@IH zyKK$E`9`f-^h1k(=$F^^T`T{SO4l;`KjvZ@@LdFai_jx2kw$F-r%J}rk1QavH%>XB zFG<5eahw*f#uk`+{mXyyx8*rvo6fIT8Lu9K)ADezJ5l{%*}PALCbxjGVD+O{g-QYXGp z_-lhYw`f_lx;(gI!p|lw4P=YeKhfh+f8ox6Tb($(|7V3iqr2sSWSloc^W`7rX3*VP z#gnLULBLPzLScE3-j?T=kKtB6l~pqFNy_{$Xn#KTdQ8W7WO10^dWL08zVqc3D_*&=<4pF1{^Fu}ZCP1u^NNc5CuDQK zd_n%pVFWEu%L^}3GrN*MdhxE;*XQM}fBml5FPke@qi;0Aexf6uNSX%WZ_L)iB9&Mt z@Y9(!gvZ&XsmUyi8^_)kmVlbf0Zef?y2<@9_46n7-ZZN?kv{uVsv3ItS-v%|_%W>{ zCdDnHYroMw%V>aj0Mru(4RT3-Bqxl}JDiGyI6jmgi*IHdkGW~kVX(J>Vvn@Zkeo=c z)lUiTjCm0xNXP|{{xSQQ^%5I+M&P|lDGr?x&* z(pjG7ESZoSZY>YR>xv7mN}7J$uj)At=Y;j_sDqE8{FJmXs&k&3>ue<-gl~rjK(~7U!+`j#( z{w4RXo9bMW*{aiLR(6!u%&JKuoMvPE!c>jpnIA-4fr$hoK5Qm} zYYAscu-HXHXJeUG0^87WMkBa~ayBtegisuZ;3dooMhp1D66)sfIc&3T`OWa%DFMO8 zJ^Ima;^Z27gmd3$bjbJ6Icb)S{4Mg7aqYvmvN6*MdZ&PIWHLUUE^q=n)LAe`?czAm z8FoShnZf!*!O5|2WExB%z~t<1FxZ9yA&*C5hjcQLn2(+>HsS;*QEsE;h80N)8r=K` zb(7>(g>&0iKDMT^W7m&X*RNkR!`EgFrWB5w5vd<&@Lqe(g2i{P<9;Gk71haa80**F z*SqS)ZR70-rdsH61zh1tOCoEw2EyEn%D6|YhN>QI&?_^a4RN+31X#vc9A4;sK@~II zv$X_kCQh}3PYG13qN;jh{O~)v>cXeE9KGK%Ji+3@k=?l!#&33e^Hd$4GMmTpAWA|X z!JDdbV{E38Ja)3S!d%&?gu4K?xwFfhGQR@;aLBKmx`~>`8d{>xx)>ItTt_*|i@RCp z)aI|NYu&ZHq4}!AOP4*dahxTi(k~y<)o1>R>-W{oC}yYLY+O}2E8^zzOd+GoUAXZ3 z19KkUJic+$!G+`2EgLM9LsmEcc|~u;<45|-t_aliF#M^EAT#cM&?y?vp@d2*6pF@k z1V`gJ_Sq_e3;8;0Rd}!|-6>29#Nv&5$$nK>^*x+O4tp{j0E81du+B$^XfN{!FyEF3C&OgD>br(HI*<^Y6KDo}n+D z7yUKdb>0JD#F1<1t^67O0C1ETXOCgaB8NsCo0vI>yhmgda1y3pBirggyQh~`0ts5c^Z5h6|NS!$9r^g`Yf>zE|?WUQzEY8l2yk`ETCyo3$oO++8Vt zs|LrBCYe&=ZnKAM32FW`dC#}KiPGYB@&DAN$)ynbSFHQppz0U&ucu!gOqJ?0Bzqwd7q6fFAmaXafzS# z=7N6aQKtN7Lm%KMfkoj8M*%C>$ft12<+%rq9?kP+t)xS-ZsS3DoNdZZZ9dbD$2I?T_y157GR{8SR zp%3^JKoh-uztNX?H+C2#Ywk<*8TZpovX_q z{#$4|{|)yI%&OHZ1()5Aw9KEkB`NNV}eN3Fg|U zz_*ecgep2rh&mpH(p0x{UYpaIo;O<8v43SUxpIF;-RQiu)7ds}B|aHVCP(*=k9d+5 zakDvIk@UEe6vCYp4!CQhR$C4y!k43fL%1ajS!v_{zhNiwbE zb%ot3Rhu0Q`Ayj=&yLl?C!&j%uWMR$|E{*dyZ-y0l~5Unu77#wy6Y=>f6MYzxU-?W zSm)5)n_55IZp`;52NDAp^anSKb)L!+{k)t1<(< zv>X=tV%w?r%GTVqJ=~M>CRZO?aM5L0e=hTw;&-ZbSRd7Ko04L{h-NaavB^hfCVrwU z2z?4B#lKS6z4>!P!6ku0K;nDsjSFjCs;dgSwp_DF{;Wj$O!@BSJJ(hg8MYvVN3_<= zuRArig+4HDrkEaU^?Vjb&vRbf+dok~hFe8-++rktg4ZD)0VL!i^zwnfT@tS2*C3B} zlTI(HbXxupvR1!5{?m7aLr_8-rpz0$;kd6msC>)h_ys}lfB9p zPJdSr00Q24s;@vNEE#`NSAc%T_xFzPe|woBq8ENHyr+*)3eMs)4=Yp1trCH(t2v?1 zM-CkEg#=Px66sHhk!qz%y&X5LsGh4Gta(~r z2tg{r5aME;aU;Tl5FRBReaV2A#j0cCDQ!8@(2=*De0mbRP9;?P7<65JCKF$I)4Jr+ zYNy7nFADeu2d6^Wxpgv--3!Za-P&X{pYJvltYp#(cR4o49>mU0;9LRqDJzb`Lc+p2 zd2AAX4^W#v222;$aTv0A5B3Fcqa^tfG7kj>AW(%>R)ItdA#;S(M+AF@fGp1BOROsm zLy{}$dYAMzsOV&tltgdo&KL4^_JY{jhQ;^p?HjoIrHl5waHxC9a(;!OyZmS4*ZJDl zv^A~ojfQ*HH8rj23M=l`dy37r)CCW1-}uatc>{pe+4SQ*{M$DFX>arTo=CKBZA0t& z?qIZcEr`TO7l8goCLdRFom_Xi!v^0q)EER8O=xcNeo*5AkOBt)98g{5^YUC%Lse&W zXKBP+>8k{CehFW~pf%<3NRV&RD6;`K5yr8hRj@EYVsTlP#~lA%yZ-4&|G}f%AQeBd zVZ$T)JGX5;da(bXRw)0w=7uT2_wL^7vLrJ^2W^r-zj{DYJ`Aod* zp^FyZw6&>e>rIOQq&l6YrSO}&^A2?M9avFQv*JKs-=(89-?B!M9#1W0v(|b%$%s{WpfKS5`l;_1 z1|2VmS50lcBJr|?H4mH3Vb|1r**?Ca*vt>3VInbG!+F$@@(u*#-8{n+t}f+|LD$BiV%aqSIl-Z2Nn{98pO)Zd zr0OpT#6;+)s~PtiiXH)Ezz38;GMV57?6qeEvy|X9{yXLOr*xYa}7QhcV^)wU$ z#Y!B>SHWC4c^)Qq_^gj$mRfu1In_u$t`~MDfblCGxSS_uITcf$B7fk)%l2HfZOfXm zoby5c!0G9>pZ$D<{(nC|iZ9olcgf_5Jb)AV|J@O*Kl>5H$_$+u7Jn+f2brvz>xazV z-&PT@7D8r6i7eW}Ry8@`96T(L0U27wDqB(Xkz^ZWrG%nYBz_;MBaa-GT`gR;^zfSY zu-+1>Eh%Uk>kRf>_x82?D^Deod0xG#=Aza$S1#~w*uQ}np1KY#)6rt7|Na27;h8g1O$v24<>TPI`)NPI@!rc&5ui7k z0J;T~Ac#;RFmn_tL?nU*Oe-IJ=jmoczg}KcQ{Mt&)I{|T+*fn-t&c_JeqlM9=vOnX z-+8QGL?lb}VgU(vU$a`vi*Q&dL_{3SLbu&kTZ5_xk)Yq>w$<6|*oz8s=OusId*-wE zpuUXs9&+4(auv*(vviN!u#9z?r-|gyzHM5cLwp2t0?&}tC+>aVWa3I!V;$A1S$hUJ zK~B%KKez`W+ErtJP|PNN#}3Jpb_gsM9NE8tx1z=x(rnY^0IMd9ODGda2-Qp&RLW%n ziwb$(Y%H`D+4us!fSgdkZKb_3=R5i)-vI*!_8)DQPkcuq-ce{Pq(ISG-{GAxj(+af zAh##oY35Z3v*I)=%??QV)87Pd+SJkTyxZlpV@$KYCx6C!=Ck*}evN&D;ft6>auv8Y(OG@t4+I3`)$w6g-Rb~Q~WwxSr!mlhobN-#q53*Lp`l#_=niM^*<#Z@_Nd2vVD<5XFs!|gU=;+r3yPkrBv-eCemCz>tjKw*AVS{xlhKUbNZae z`ed9)UUPWBvF3P#q`zR#Kz$(xqeO36ytlhO-P~B01QPZ@*#NylJ9RGDKFoQ?eD)4_ z6zC=dy>nF&#h#2(cNz`zM}THlYf3(6H{<=3WhmXSB+28(0={Q<#VB>51*o0a&m)*= zl%jGw1s+h7VRsmq^!l|BPwgeYD7&8r}11LoOMJg zHlkEpsF(;NPt7?ZcAlj%JvePleHhd0v#(K0c5RAz zO#z=TYVyJHK4s5PW`mKc-ORX_G6q+&OXlCES=fW<>MgbE!R#P9tv;K@PMc!4X^&(9xGs@ zqK79(6`(a69T{5C)79KK+h}w&nu&dQYT8)lZQ}TbnPZ^<#z~?yoHk#h#n$8U#C$~Z zXIE~b`r5SdNQh&N6N8%moK~w@j{FZ+lR@6cGkTy?@YyLyH&49$ti;bUtFTJYRqykr*u~-Mlk&qB7VE2$z z%V!4t-LujU;xUBj^smvf+u{@G|J2V(^j9+aE9)y!@9iw~Gya-0|2>TUFQ@ZUh_{ze zrR7Bc+zN1}W{!e#lUi^`&>|4SXEwr|Mfmj3u|bs35+EeLsk(CZA<)^B_7LMUIb-N& zW4Le19)cZi>fWJnL=6bmXj*y;81cl}rxE|DpOWUENMEw3zn5f~nZ(nT4LRmJ*zfm9 z`v*JTkNU1`|DQp842KwfSYDy$@!P4aNH>7k_=y@NDqyu~^F*CWM{+fg3y>>`xi}2z zX$|@#Js!VPkL*NspV=$-i0;rSdQ>Q;_K3iFUet*Ir=0AO>1$te z3z+tYi3J_#n1zR-s|iYB4lq$B;AF2DH>^-XgUHrwvQP0O>l5-f)Iel#5{)D%=k`?^ zDRBe2FOT)6p1_ql0H@F2MRup+S3gqsX&(Eyr_lTL>3jgb13V8Jvn(M*vDjF9IPj2J zr9ri6+zRXl#l3i-{s6x52I=Si6~P{r%_`Zhl;w_8Bs43AuswE;%^7(C zX*C<_5;ar;FckDP`_3 zZce&D6kZFuC>=M4u1UOhoXy$VWa(NyL6;MBIfKrC*E1Jg>Xu&3taCPdn=EY;b7tga-F^yX6Z6IPRSsSKjIIl3u44)9E)_Nw z9nZW;iY8|(Fk6c(J(F_#x_6%rw+v;VG^KA zMG4FZ^1qQ$fMsU`8HbDlaesgr1q3J-oOlE7ygUT#YEBg8YZQoMsiT-?p2E>XKDlUi zs~3G3_*34GpXJSp{LD9XB|7|nUjJg{%cr^*E}Z`(MMYq3L*tqdh=3&+$UQ0}_J0#% zbRuRc{wOz6z)JDcgrj4zvaByYIFbI2$O-}@qPXT`-IuJa?Y-o|(a{I@_tuVH(mnpi zSk-@5t*=^f`}s{fUgni|+`%hezM$#++efQ5RJ~taI{pW~s$l7%M_2EBczY_f{o$Rf zA3e0RAoEUT=-Pa>_o91V+HTelk#PDbFfEFj~^wO6UtnLdt?NuzaKr7G6Mt{fwqaM9Ma0 zIZ0Ae%Cef#boO2;$!bQ^*?Xl#KHns*OkxG!p!ef^=DeOVL+5TdF{DpulkH4Otx6YR zej{8Y6b=Q90je4a+*S(zp|TAGEyYrdSkNGktY?ZeMWh(2#of1j+0d@Q$@aQ_LQ;w? zY_Bd%T|2U`FJFCWZM{+$e`wXNW8< z`5989TFnfW$cKQdBczY|iYektfrObFrNv-22>`P|5MGD^>{-+`zGxNr6GG%+UiZqj zZLefLczFCLCzKDT_kML-=2v`v=5M@x+gJCd6+z+9`7dYw_P_&~zrC_exV~@SONVXUpzvj%fqcnxC^ciVB2nLHKq(bO7-LOCJPhvB)>NJV z7JfdtqKfg!g&be2xMlnx|8Yho96E1u2`AT0Joayyoo{D0|9EoIFc|_O4j~C(E{yOF z!E&tuzt0y1UW;h`0{mAYXccn)8L1a6eZ^!ofo6~_|F5`^!Yin{Dd@yMNTE(rD5Q_a z4{^txcV<2qUy=FX&O2dTdxY1~U&^oEf9fM)|M=&W1^18Rf1iK%UGVu$nMe3PfEG7* z!HjhgC)UNrmV!~!D^e}v?2J0oB@nHVzrevTOUos-!STzsU`2i$wu!lR^KMErntFa{ z1e2%c>B%`>%>e&*|*JNQDyrsF3{3m?sl{6Z)i{f1w+K=>!p zKOTgn_Gj^(9DiytI#=+6JTy7Fy`>jo`!cPNMKEUHtx-e0G-*s&LzU#Pj`RRwm6vdG?onxpf4Fg~*YK)rP^YnA zbahnmEpMCS^ye@dS{8v-se!zR z6~bywL~KT~A)3fadMfiFU--tY?_Ss0bHfjBeB+IQ9sR*z-;TjIcrkNIJofjl1CMRo z`n7{SKL~ZNZ)qIs2w=guip+gLu6Yg^o?n)N2aRPAMIq8F`@vF#VP3;2AvDbRlvidk z{;R-q6lxXA{8m%uH|bAU7HFLEocH$vsR%H#WCb12WN{zP{#?(D=jc*D`*SnjNA=at z{@l#>Q8eY*pPT+ZfP_t*61r)zU73JCV{Wk8*_mOIMjE&6;-OS6END@9j0~*k!7_fC zblb9k<61-?S17W00~CT>TQN~74Y`QfJRJl>A-t6U2eK%0creAkp!0cszP`bD+oikK zMHc3J4fe*N^9OeyM498u_K!8R?SJ~BE8m;fS>QC8tGiaV)(QUckJmI>bt^hL=q3s*Q1H9s&Kqv`N7fU_a0bW zl+3NfKzlKUbMXMqMG>6}Sfs#1p)?{n46%5)`baqfZ$-W0jjonR$Fe=Jm{nnb+}io_Or%nH%mN?-E|To8R+ude_aFhY=xojH}`6X7GD>z`ZH^gD~C+7~ZLwJ#E@ zqw29Q{_rxzy3-FVxq5YN?by{z@cS3{ynfF{z1HOmo28-{fT74dg1T&GE{zQ4?@6+; zsSL)YE`)~G78j5Z3;~N+*vyaBjEB*5)qn#lkgtln8%|#ZoIXk=L+&Cssz$?Zj-Foi zRJp4m`w+=rk|6y_PfwAkOFG(-|Iyt(uVY?IQzeT@EAg)Lk=m9^aT`=>{iG%swf z_BevtvSxYsx)%PTJamgk=1%RK>^pWT&5gV?a>-BKESOYJk%9hNU_11?nL{#c5k3#tf{HL zCS>&#^_H&Ld_ijUqX+xj4}RkkW6)r-Bsbl*x@*glPA@;D()mf1ue{EcT7rKoJxRNw zR99?uTPsH{U%2?n<>l^x+d5j+9x3kq+;doWKh3?JWQp#1`Io+;Y2A7regiCT}700Z(~n0oo0b$6M?ol+@Ci+7?FQof$P#m7L-8txKRQbNxVP;mc-{E*t}vn z5)c#$=sXhzi{bvFYSAcwD1|^oXKzM^eCYRR%MQUev2dWQy8rXr7;&#*p;ggm#~uV zeFdL_C@J(*RayWou2l0~k|zbVY{+4&SWVh`HVhGx!igLAku9~hm0^Atv z2^HBu8hC{Qg#vgh6;HwOVGv((VhtD&?y`uQ^2;ExXGhFmSyW&j^!7%I9YuVeYvVVU zJYB6TFfVF2uOrZT=#|U1JbP%cecxBNeCty4hNa&**to7Qt|+cZFG-}=b@(HlE0tku znJ!*v(JGDZh;6C9wd%qlOR26Rarqt3ZvMir9vtpGcw+Z?$1WeZdfQzMSDyY+Y}IY& zhdQcVv4M3B{X6GHFh?DboBn`2rY5e7|GgwP<(KhD8-lb%#oV%gNH#^X5ZA(ACn`~! z7d3qW<+}~0cBLv$iEs{$h8bU(7d|T`QKq3JB9rucZqN4164vCiWJ5l;XJ@{bWaV>v zcIJB}kk!vNUXmw2+k4Y+GEAA`Nx^c~xrTunR$6(sWMRFerJ3h|e$&;`Ri9!mZMW6T z#P%k>X{KPw0K(+VNI(*@Bx(s7EJu1L_(Ir1h4-@pWozSx$1d;fy5jlWYrnF$)8-#P zsw(SS-`u>sz1mt*)Z6^P5(LcHUfS&(>GqpsPCKF>()x7IoziR70T|3me@5!C@ zk%hYlLoUC|I@&X!(>ndKY_D`3*j2SO9l~BMg$$_@-v>HXAACFM#!4rAJ3g6%z_|kf zA)wFA*M&tVkrf-6O$V7iBpL7+iQWTe4P|?V70bd)qv^G2AFs`fpQIe#hD*PFUFGny z)s6PnJJ+tbd1I<|_e1Ne7Pi;fwJNtAiPhVxV(aS~R;K;C#Au-&$*T=rPoI8XPVDVE z@4gGu>O3_+exhT3&*5+Ex%{nLhm8JePq)LOKs~=qZEb1k@@vMvdZ#p|yc;p5VQxLf zv~p>k4`WJ98AUe79V5(2!`3E#LLSZ;7_34PJIzjpPd|02-=54+7I~f3qh~qF+3}7w z*WL~KaDpwYC#@C2)*oDzx4Pj;5i(RKxH0V-u!mrCmO=1|BS4p|CdYd*^o z$(WznRBSTGEu|>(i;+&W#hxJ^r2PS`emBTF<0?yfL}iU9%OHm>{3?_| zcDbc8$Zi+PAfI|~wsD`eIP%9oo_iuNIC<>9$Qk>Mr(f2B3g-?_09n{d*!BiZKQh-J)2ve#B%JRZpXLRWGmdexYo<0KT{OXvg`Ao* z_+*y-W%Vd#>R=a*%wyygr;DYhMHFNplDpUr7|GcIU^suz?2?yTzQ3i5rG{~t+{I@c zh_O0}m#a?TZl--%GIPCiP*Soq5?D@Umhee3N8N#Yrjyxn`OAmTTdlkQ26w=4p{0LQ zyGLS;b5Oc+tpeZb{cL<|mN}Zrtm)vY%rk1bpU0S4HNjd`GiLUW z#aWRqcdcVXdj?!_v)9%rF?Fo-x%0QFTVa+H$&S4|w_9h-*?^K_cQq#(rp)d38SMt; zcFj^d>?`m)wSY4Y(6i$mB{TTlEOVB-_a{u>GZ^3m6P&)+W*iCotW2^0Qyi2zxFnl0 zl7l2Z_BxZ(&h6~X+!u_2P9MuGOFrw-o@+hX{NKf77zjmr~a#R?}|iT{!x>*$d`&Lwv$xL<|}g-YZQ)9C_#juBd?rgB+}wDokpDp8Mql^ndP2@lLKWWKEbx1WuVY=nb1ojZq3Nb zP3ccG+2<&?@`hltEf7;qKRK60K1aZn_H5p*pnD1EK9@cFX$CUqf;3$E+I7`uAKav3 zI@kJqs?koIQ|OZpMyQqbPZcU&pdvK>QbX^gzaURY;gC%4L{Kr&ye$EU=K?JLii4=fpxU zral5=++0toa!8!s&T;vE29O1ZstHk1dVc0Rn%INb^2UCc=aur)l3Z|{@UA;VZT@M5+y%D{TQ-x|BD9EV-Yo~b@k9fdx%Sqmz`4yQwu3BDxa@q3qh1Dl-5w)+q zc6UZL&3s=O{rJ^>dbi?<)_OhF;oZ6KYObIE#D8X>o|Zz-Yq5$Fe!)@Nyr&=clXLi{** zlEcpPh&%DvYaBHb31oRv0-1tanz={u@1Q*dtMGit<9)5Qv0}n)&GG{lmQ6cQ7FJT& zd*D+QkXg=ZYS=uw+*29y=}(rgx$FEuUrDjj8QHYCdgr2LhnAP|en(lO&s!h2+vD|K zUt^g==y$~NNkhzTk2T; zt3dB_b8bBfy82kv&QBCw_zOQ#L{SQvOXd(oKnkM^`NhJ1oSPzwXVvBBAxi;i#8ior zc`%tf6%7#%W|it))&Y8ghpH)sv-014)_=>%M?Kex-yi>=@5a)?meYS1p6&j;U)LmT zAlnVFHiiF?e7yM8&wZJl|3U5*bQ*>CflfI5U5d%KA&ZFD7l{UyVKPAy^Ow03b=3`! z^N-6or^s>QN|AG9W2^&t7daomU5s->N#AZ<*V!CK;2Wu0G0!={tWsY-5Q9aRgNZ4p za7M#)lv4n;g%I~=YnzSlLVzspdrD=9aj}puREo+ONM#@av?PlLJY^HHc*AVq&4D|s ziu5Jj^G9lj4=pdB#5Xk*1-yfU%SO_>YLr6xB5!Tj)Uf&HW#e})|NPb_lW9AkO-EM? zS2O10z`J3`Jb*lv7}nJSefr{b5g23 zJmS>uQ&eJq40F#)fdcw6Tmrp?`FUXei+N-yK)Rgv89#xBTaMH;0tW}*R3Nlq8w?UE z1-A_hlU)~my)3doJpxH_fGRyEW^YfKXE;4M&*3O#pF$l~o*P;q1)d_!qZmhUm>*_9 zsuIpE3j>)bb0vAvW{Eo`MAg~CPAjuvrz7_zq{}_kUtiW%YK-@;T)nb4UbFVr)!UwG ztk1XTS#9I~CGpxP9azjLZD@ATxmDf=z-SuXFxh+`XcY5O;Yr5JlT8g^F zD~bzI)ws3BSB{TM+eTVDE*fdf&kg^eeTa2A^Jmpk#2Z}(`K;4M@}zW2NWidc7}JHA z++bT6TS@e!s`8&IPD%Lvj8RV1Zk}syT(u5w#hN>|Z2bIKxfHcDDZt)^F}1AojHwgF1;c~aY-(;?bD-@9vxhIWwYRyV{V6ZP3Fe8L@?0V&iRSVPn9Cb$Fqh)F?3>Rzg%hD(|1bOPGtKG$#18#T(|k^wn%SC!??UIW zb5-ebS$#z<49WpvVMU0{r#pf!8Y!6C&e>sg7Qqx}=z9>E5Tzse5+v0~BUE|II?AoG z>L%$5a2Hsr7dD)FjqX(6nLjHwNOvmOv!81^Lo)Rsk02`Uwsd|zN+$SF7KU<$$#EM; z^enu)8swp&NG{5zs@p&t8d2g?8f+XlB?`k}y8-~wP{T{5 z=2WY4sH3p-yb(lF_2hxLa@G)Fg#e>eBea?x&`f;*EIQkMMYi+Ib3A9pX|6}*T?R4aU0=6u zTYuO5OmMp1yv5}DN>X%MuMmD{p0pdA9jL=FA;UMt9h3QQpESr^|C;#giRUGq0QVEt zMtKzbG6rSx{I}_?roQW0O z1vnF1#?qg7CZv+H*huF(2cK|S)b2?)^1@6#%xYe%KF?G*n1WCOBh&P0nm9hR4`5jn zUN%miBI9)3dX`gUkd^*ub)R~1< znVSxq+-@`a^eb-UKNg>Xy{a1LGZyx!$VN(ClD@%Y;3;`MSrcCf)=?>+hkx8=&&!YW zB?p%|yDwgeNN}IiY0}#@CDr@7s~6O{&v1^YC7vqL+7-7KTC6_bygp}BjbA7(^}}jy zD6EggybTM=GcR1AH@67dVx!hV0)W8vDQ*<{R5v3FI||x7HcJ6$1M`#OLM0m-8@E0| z3bNTFM^IJ>AGv!I(e8xX*Sw^~yG@oK7Hf6>`d9=mHg?~XVt&TOr$B+~c+fFT4`Z24%)JZu11xw<=dxJ& zw=_Ckfzj%=q$+Ex9DtcBGHGiZ4Gj&>sui74f9Hnw^qPq1&eLN210CH1g~f$MX-~+c z4)ttmZ&=?SD~;0l%P{^jjGt@~niFoTiP^7d^I>TwUxz&yq1C8h_W(t%^RJX>^GX)f zm3G&-eN9VhB1y}Wyb}^ev6#+dD<*!Z zxShX2bsdm!Wk02HTFjMN3M-?y{%vlftJMZ#V|^8zPxwDVM0^_l?=JX4@}D2*Zf`=OHjUFtr6`MdKoMZ8#rO#6b0|e2 zc@HRGtltyx=8)j!-{73f-@ zZd=*p4*T_He<)VvZ(j63NutebRhz?}#)@45k0*eC#i#8ZsN0lh(ns6MZGt+#NF#{O z`r2T3%4ZGNIQ(V0f{@#m(p&nfqU~k2@%M@fM1{eSZ_sH<_@NSqv!ujn_hP7+$3DgF zLM8T-8S@B>3(nG{sR=iUoW<7nq$6D(?<}`HQR1;i4S43`%pWbzlGH#PHAWVCgNCBa zP3TYH8Zfh>>UPYc75l>gMoZ@tJ=IN2l4OMV;E9)u0ZD8QI*W^)LBxuTE7roOF=}vl-;+VEj)Y(n^`?C-r&C^=UlN%k;%d4PKo|^SS$tCE^m%P*n1y>gLROnu6<#3QwT)uvPzYq5c`2 z`oDyaC)R`e2=9T>EV~{7{YOuzZXQ>m38O=?5a%y|@73~pkvWv1`mp~J20$&DgmRW| zyGNsRrE4mi^{!RbtJXZx>JC2X_8WagSV?_}%N41@KU>$*T6P7!^ure@D$HCf(bP|S z1n;zRK;%P~F^96L$WVdCD_MhEdf{`Sq!d{CxfW)2w{q5iIp|YSIY`M~D{<&an)+9I z3pL(>`goVTtBgcTpu`(1N%hAwPxC`wzo9sDi_CN8;r&Lg1bfPE%A4dl*@K6}mV3OK znl}P-sc&O*^Tz&Yw0~oBbwx#WO+|(HRH%1DTY6(}INZB2-L|1Olv&@^-{0BU-`_=J z#r-1uMd-)fm%U#!(mrFV8BK4t`cyb#o_4?VZ7;ScRo;aS@+CtYcGMd+(DgzL*62jn zCv-)TKv}3~BfDcP`qu>b0N$N)zX)6$4dbA}f*Y84JP;1Rdw>@*mB+&$N!dw^#}gkC zg!q&0zH0V*F!-uwyQuZt;Y5;O$XHrcV0MYe#s`1m@?|-^*RFSGc9~2+(iLe< zb!J}2oD#3Tk^c_XkK(?oO>|$Pn+mwQa+&9(>y;1!loR*neFdfhtE0r23?y5U0e8dF zI%i#?yeO(R>5D8jugzx*q*_t|M{+3DxZW*Bjd}T01x0W2r{dAhYG=N|s_WDiYH`CA z7>vcHP)l_HmC{Q+(%vosZC_F~VrR+s2;>}DXKmwAuALIYz_4-FW$m2TELalN8HRnT zlF=)!C@Lz-*8=1^>0O|>aYY}`8T8%8z0S`c_(*30`sY%s731%~ommPQjq38@?qYn4 zdL*}BPR^PBk6^A50E>(_Gp~fh{p`3S3PykWYcSUqtW=PJLPaB-T!PbjQ`2=YeUFj z3>n{-*QOZ6E(Tq6#}~2ssDKb*dyy@TT8h}jbxd;Zw;nlW(5pt28nIsM{NkfuJ7%z` zm#H)zDy#l(KQ|P-8uS}OhL;NUG@mitfj>l_I`mm6 zQlBPNj+cra8d2bu|DofJ|H!N?DE?nR=I;|%M@r6cM+UThBd<8ZX!?h$P-szivs#OA zfndLY?O18F5&pCZGN1OR$K5_t=2dmKkXNkB{6($jy?8I4Q*_DCu^NqeY%oUDn^bgV zUNi+=$Nx3oWOJL;-I@Qy)m)_0LoedF1m5>o#1$0NJWG3tgnc9fN>gi02!B0Z6t^xG z)rz9U)_Bq5fBB`VQ0v?#7KoN@PAyMUiGJd8KSk(A$LOZz668&!2*i&U#q=wR#QYI` zyy*B}ey#RuEEiiex;<7+<`2-f49dMi32d>2oFk2MgQDFCIpErO9IJwSt`PV>02|eePm@l;}wyr{-e-9Mjo$L&D8NSY*R;yhb&OF;Qtm5ME-*Hq$_CDlQTf1q6=l(? zs%Tk->aloljmuTj8;^C>IGr_Ju}Do#BvxHbviCE}^A%?G8up%2$ld`jy$iDUC%ubT zutSSG>X~56P+9rn)=;Q*ae3KLOYrJS>8+LgFHRZ)uG?-ZibloSig_uwJ2kJOe6ZH- zt{p6A1XNWCLgtjI_#+3(YY;7OiT|cptXartiJvnqDBlbQf;0D)H`xb%#RqGFRt z?~ZsZTv-{8#RXgDEmOdC{1tW@RaZwlsvM50j%cL4!r`cBkAx~KL(z%~{=pv@G_SEk z%GTg0&i5lYr>JX=y;hhHKMD3UI|&rG^43gwxMsnmVsc~fnv z+WRNH@fUX2pA3dy*xWQm;u!@(L|um-ab{V~+G%@Nh#>Hz#GNX&*-BIH5(IvzzJx+~ z_$%otsiU8D=!dsvE)(+3kR3vGJfHR%{Ar{Y$>;Q!E(q6H$*6aE%_xqkH!+ZK74wKR z#gbEX=yr4BgDZYOh0Cfs-B1ps1f?8&I<~=s{zo6V;f>< ze*Rz>Rs%x{;GED(2-i=}Jtrr&;1Vq3zg7HtE8+TmCG)|n+qS*R>%Ow%+YeneTABF+ zf&6Xz>b`V(AN>T#U&oKPJdpXzcX#gmE?@M(1ANhUcP3UH{mLub_PunZr{~B^`v~+e zi}%Osp6tau88~O!Mw%OgVk_+>u|CH2>C3z{Lq2v7;c`GdR(8Me332bQ0g#w^LhsdS z-TKUvno9p0Lf?l0hhlepbAA2h_~{!736aj!JgnpG_?2qOYpJR@s*{O;vsp#+w3Ohu zOA$qZs1jP=n9v6(0+cw&)1WLa@@nyzLa$Mq2t+AK{}Q)T-hS$NW&f$?|1K;We@r~~ zi(j0o|HUta^WUc)Y2PrcHZ_e2E6p5rr2uD@hJ>A?R9oYvJnbC4Puw73@F`!*?jGs` zIKuF25Z)W&jYXl-*Xo{$8E$Ae}0M$Hhp|!?c z4oS`EQ7CN6B9|reH*c9W-d`fzaO!!tiGL|mU1(7DkKa}|60e%?{jtSaBnrRPxqMN3 z=G!5l&5Cbta5q^1dS)q#ns&d9=%$81=A<2JKc=YR%q^;2Dl6osFf4dUxFMk}i;DpL z01u#wQ?Ew7H3SI>sBb_~Dwt_e=&vZZ>CJkZUhgQ*R|BVzVFM`D=0Fm7N#OH!$pn?z zwF16}Hf2QLs!+Up_sOTmVnY|-c6`&Bdrm&JYV4_#cb^&G+PLk`RjcmY)~Kv#+;+#R zRd;M_6jutHp8m~|6<@je;-!`RE3fdIzxLasM}G74CgH`?FONR3uZLG$AoT3Je{}Tz zy*Qh*iBWgY;hT3a?-wy*mKXyP|3xzKDG`kY0h|$$t&;vQe&udwlR|0;elNnLDA< zAs~W_fr%i_5}zn?K7qxa5Xl@^9m!T-+p9rf8lj31l2{FV<5E|1wJ0a=xd(@)Km(ZO?XgmxOD0NNVl4rm-D=dMctn(s($d5A7@3OGRENcfoIr}Q1b|C**no)v zZAQZOP@3i+^!gVqTM=7+$Bwq1OCMdg_KrkxQRSVrg2n>rj4*M>|4)2gQ&eNq#p}8v zRioXdf#wDIL(3}LOAS4TU)+l<`i1=s9p&SHtXdrp*7}Qql55kw?CsgP;BT&)ur<2u zb8D6#81&QL7Pw0?4=ZcL6F8?0+!bk^0h1V`NL$1k5DW^1l?4%T3*b=&)moH5A=&-G z0Z|?ENY`Hlu-#^9mY{29YBS82+r@MBsfw~tz}4Vx(B`4ywv%^C^A#c6jAWaGjZ@9e zzn~zAnT&uGSmBwlrN{ZCu=9a6CsR8g+jGHv8!9)i>%L$hlHPahmD4NLF(;lZ^>7X`*wC_?EK^-XKL!?AfgI#)Do z97^TCiBIfp%Bx4NZOTh;Ix=t1H;?qLdHU~n{WD+w*4BoR?cgt_kPD^5Im>-N@BqtC9}^o`6vzSR50haMa#^IrJpKmGTn%mDUU+nEoQupBd- z8Qcg}xCv7}LCFz=LOdgfSWJ9GLD68U@>VMs`r6ydW0e6vBT=$GO$#<-*6s;p4y%H$ z26B3NVDfGi6nBemkG^O5ShS-qHL`2(u8~yd6))_$_=PLG9)2t~kn)zVync0f&4%@* zM@qX!t1Cx3qweOFt#vCqg33R8O~t0-h}%<}Y8hCy|E|?rzIJ7A-xW`9dGP&qdtLj& znugWg5tX(m?{rt+&XI19v1!@vd94>Lu8It7qw@vb=gfzSoeVc-Al-{9@#+fP-9Cge z;@;-qZ{!f82-yP&tcXt=?qRA|bn_!^M;hKfKpxOg6QZG;E$<(bIsj zwr9Sn7{EPQ&w11C3fPDE9)}(5nWFj&0UU_k z^swnbNraf9Xi=!`)zR?E(WM;`Ps^&d(Tmz`6=kpF8H@9Ev3V`akB(OKA3nZq%bq>1 zh)pXzE2azG(Yi=z#l{OSJ<{E{q_x82ZtGcC*8Mr)r353T27^BsG&=j%UA1h-zr6mP zO@<w(;50tFH^@$L2{E9nMsl~LE?1J`P)qiiSt1k55vOnnYFIc`NMKQsdXB0n^!hD5yI|IakJ6S9R^>>w8otkqT7ovtYssxiN+PO-6e(W2W-=BCc^Sf`ZUj0qp{M-rN^o_BP zKThpAaq!@YJt<{>?T*Ly?R$JjE!{H|GnFSE2M_Im-q_ie@H5?=%@)j>6c8#!z<^oG zdjN(T=IVkRh#ONPT1YYhkS&nt}9^_Dfa2`iGxb>4)#bH}2uU3{eJ=#TDkH@Nutk^_sH zHx0&q{L{51Rk)cR&;0f~+gf*jWux%h5Re>&#?_s{Ch1J?KJ!$=xSYZL55#?m)--PCqgpDmuCb9TBIle9?|}IwG9y%ty-k zn4=2rjpql{9V+EBSD&9AqYnanY3MliV8yi)A^H?Uq2?(64VzH-Xf07Mgd~x(OGK zu(}E9`hGKbcx*v?O=0S~k-e;LLW5K{VPv6jWX`$?(9ED?qV@r2;ZUm>H4-U(28@Mg z1Vj18JXkn{S3)C$`-EaU1CV(vRwJ=Gvi>Ml?p6D5T5xw}>szjn>bovOS$8s8ESB1p z!lBF`Gk^Vft5R^7#(%bac;LzBo*Rw;eUA2hC+>|J+#5aIqO`UiJeThY1_YsV@M%it zG|~y^a25uI>sQx@5!MaEiMiLoaMzl(1Bkzno_%&eyuCLJMx$ z(P6Gy)Z9PcRoxN3yuMucS21nz+Y0?HOA|{Mz2bp|ucE8I#%-x>=`EdiJ-dU#dQ+gp zuC=tUzjk$O_2`g0xMxw>{Pv_d5g)~X(wL75%tt%ySZx7jyZ_XKfSysJclr$*(_^hA zhxc#1r)_1U%iAr}kLy#SKS=ajYDd}^E$h7Wsq^2GX!j)h;#*dqo%XV|s}?&$*PcK2 z`E?0!!3%KCs+2}V0YyjyH6u~a0D%tT9bHveYTTc41|U006)-*pfPzSTVybC13`M{= zDe5!P|AMwlp1o-OGe;M+?*8(|#n-1!o-E&u#FDh%-@3H6a=0}pbZ>ope@E{%uU<;I zC8?^+sIaXmkcl3Osf22X3gig3LL*xgQA^nE zS&&aTy2Z!BEqD?%N%ks+BTey4TVL;yZ|=V6n^zAky6Y#`3Ike`8xn=Cq{>(Q)P3Vu zU8?A=e{}b*7q6Yyd-Ub~m%esQ@5NfXxiIrWa?6U2;>VuIymAa{PcqcqkU?rWR4=cE zfdsWK90JKuJhu}kQqn{DzM86lUqO^*MZwwkwV3r`Dn@eQSWA~38Esxn8=1*bT6a~j zb?@e7t^W2azH!O!C%a`p-|_`pn^)`{OqN&@Exj??yhTAQjgdC5G2Xb~{2NxTKYsPX z0SZ(Hefl#e6%Q*i(3OyThBJ%YJH>X2{bq}g31%0BITRpao|ZfXlN5#QfWb}P3KS+- z8dJ2Fm1h1c)pj0TnC%-n{h1#rzE)DTHeNRV`<#1I@YB2?<`<>;U}*y1LX}^cW3j1% zffKZaxo~MY?juriWVL`av`DxWdbp%zGA&NeZ*nF2;<4e5n6}uU5(-R?g2(cWy1d1o zduD9Y7q=51-Ba0Lsdsu43ehq3ZJvFWUC><=rD+{P!cjKK$Oj%TnvF8*a}N^7Q!& zMunEIo+#~D9IfjR_yq??YXrf(@~S0~`PV$Z?aH@qS;%Kz;nTu`>%V>R$}b(=>|d|* zx~$6bW0{oV)n^CxE-C9>0a>&iV|o*O$&TpiO6bDzm=}0jEQeH@!yGF0>~O&16=Flt zDHN9+`RRSjm*4l(BfrKk%a-96p`&v2%0-K=9IZUPv2q3dwxSZ==Iz43wcp-<$!pin zV^s0;u6^y2{olTJK;UmXy^`7pIxpk`1|&8g zL?{x29H{#aB@;NwbcQG^R9XZG@~{Ji(ZVxJ3v^pCaeMnG8Zets_AD}WVDkFT3x(sM zaG0!WA*_=m+hBongdl_p%D~jHy-sfY2>-THr+HlMb3e;3cu?mGRQSR|aWqnQ-e8mU z7O_zC5Pg;Tr>C?wZ_FLZLu^vjvca_TC2zAeb0a#7Ik1;I5+2GJ-?6jtmIJ?uY+&^5dGw2mslfB^C0#l)8^xk*&p8Wi~ z*LFN!7msNc8x43n>a_ey>(SP%8c=y+J%RY?-Ys*E^kq0!S(l; zm46_b`=Ces4rjfW>rAKPVjJZ@mh~zq+E#>qB#Jd6jI)jPRI$(F zDk{v=!2aCJ_mVre9f zaAVBZ-4OId!g&RvxuoFPhQ7x0?;dMhGq1^FZJsw)KX%vojlGS}6nZRTL0%-{2{v>; z6Ybm3^x=n18~UQ|1=nnAynN?yu_x-#?#_%~vG=>TEOL~S^RV2p=$7y9y@FTl);gk| z;^Cc_H*ULTf#fs8GVMoP!ml_Lw@|98Kwf_y&?ES<6daJ_`?0S{G%dhi5(lm(Gu_N~ zkU8`5n2J;R6y(;R$P2ZC?`gOzU@N##xu4$|4`zOe^WUJnLeVJx2`wGaQBZe=vXRUr zh;az3CUd@2yrz_udLZ=zUxM#({0ic9@|RR{1`aiP2ytBa0usV%MmB5O4|3ovBg|j` zv1%Dv>PfOf@~X&YDq)6OyHg^Y-(n~!1s;OOVDQk-62tf}4c=0lB}$(}Ew)mxL3stg zD;~=H@)m2vqt|;PRvVh(G267iY2S4yZsxDV*o!$!+K4gK z>sp0y1O}-DKN=o6INz$&y2_1(Zcjk`(<7Ph9jVeqbdmmnh2{HPK^imU5i@@!fAMGU zm%n(Heg)>Md|aHYnS=WWxZ5b2gPEs1G4q6l%_6{esdwvLeyZ%H7IFLdq?1fj4Tltu zzoerPQ0^VC|NV_`T+vL({uzzpN8|Os8{F9HaI|h1RQ_A$K ziaPc`k4k47fAjW_GS7YdY>N_F8s-z^XqJN32BI`+gCC8s4tOACAjuD|DLCdiGkBaJ ziWcI3R2_$)Hasqqp^*GjDz1TV(27O`_8>Bx)N)Wv0bwkhltc{p26@@fig6G$xk`4n z;{Jl~l|NJ3ZRVpuiM?X{%F;F$A2D~w-pyR^ZYxU;2lz{lH!ZPe-g9;&?jFCprqhvm z&pzDvbpR|ZNtU;|GuMm9qQOk6%q5JCKjbRo-wZ~_e^Ak)H}tiP-ZSp&pxj8W~l}($DC2Z{r&r7U(>|npM zrYA1dE84TadO^zl-ukg6>%Aeb$#iAkQ2oa171A8 zgX|c#LhQlGfHNBV3?2sgoWMz4rwruTJpt33nGZybslqb;WBeI3zRBxU8dIfJTvFt* z7JWRbxGu4?t!{Pj^h5MF*v;O=MQ!zKC{9T7w{OSU@N$uKa4I$jc|OhXeh30%dy#0! zs}f;inPcNig!%ZVK3Cf8;9E?o@cWs4_RdK2k}!YiN8yAe^HzbgBw~M%N{K1@Tw(rQ zZ*=^{aE(sipC12WG{V1ccIs8*M?ejK<}~UfK){9kJYT{zpa3)FQnDQD#2>R%FJIf7wZyzquVd* z>g$;ANG21Nr9QigszEA$ocVKRcjh-wtqnNrj}}A*E`JV-wdg147d0V4r-uC9L3r+W zNtF6H4(w0~zda7l1XBdz5+4K)ccxKTVXijB=6fm6iCGCt$Vg)eVX;Ehp{i&YFA8ET zQJ>5>Ns5&3p6R2?xr@Zg-`)7el})|Z;3iVdI#R`*xSU#?j@FHX2s?f(dpXTD_^DSG zIP8Pqv1>687C6bqBw-45qEPTifX7`}P2<73sR1cZcLAFNKZH&JQkcjZiL*6Yk=9$S z)_~RTr!;1L)SFKSo6d1|(6pTNj~$=N7q7Ts^4e8Xg+{49qjdSUY#dY!Wk*Mq8Zla6 z7fl<_WL%ILCnL_)0d-&YB}_nuxUfi*jM4A2S|VXz+#g3+gV*Yf1~noq4l^T!D5f#j zhoDl<8XGhoTz&tZe(mXf+WtNFuUU1^?m?a6h;Cr_-NFxN3lJK=yJ7o%>(}46y+Ls* zwfVNOvD-GMCeAn63#Y`>5R+ktCwtdV#M9Jd{xW_;<^$!eS&0HX;>-s)iwH*Nd|dl; za^Ymj+if6TMJxh>5}CB!u(PM9e@Hv{d1ELZE*5duOHO<&7A{f>*Oiq!(i`YJ@biBR7S?D+aRa@r&kMS2udKRrp_H`_HOJgew?pB=iJI4RGbhLa~nP9Ml zPX*eCtBg3Hp!YA>Scl*{wR7z!;ExwbudT!dq-Pfy$)b#fScqCk-Sn4i*uq_>P~h_w z&ly5-FR@<=ET${p$}kjZ=TYrlH6JK?4i=`_3zr1S?fG@1;mq0(#bbWw z>HkaId%(9eOJraR<7RWwW8(<(M zSw2MXW@ja6J| zP;WB7=*U?KTQWFRWGyAw2$!Fgw5V&0>K?N{+30VL>TD^yi2l~dQEA+6^v2L*V~7!s&^C9278c7MNx!_ zrn0J#2^IONlmT~&$cdmKq%4M<2^BzSu}aC=oGXPSf`{ z2wDV9sH+?m0@@5D3PO*tNpP$oFoD?wM^+?c#*rqM%1z;pG`Qa(duI&kEqQX)h&?=# zvD%%1+@5FQ_gmA_6PtQqO{;up4t+$?yyDi*=_^_a42JZSp3Z;XeGer$w`k58mc92h zJJh{cMRn@zL9@JQ$mY|P_dqVPwiv(f>pdx+bY&`T4Mg>WlX(N6I*_l3XhR0zu z8Pv*z=QsLD!Q&2jx5qGb6LIcy@F4(W@H-P@P(d+U4eG&ecKEx;*x|FY7oDTT_uT!@ z=`*D12Bp(iP~BDBxqn5of<7`dS3YUYfsR;DON}elfQ?}F(lyIoqEyH3r<5-(T{P`l zxkil?erjYjo%P!Mqf3h9=Abyu9zhKi)KS2T_2HJD*#> z{<&R^jl0O}&PLeZpJJUpigjuM;}PDDN-(2!A5xRb`lhUJ^AS^;7F_zA z7|ehFJ29Q<=_y9PgI$^#rY;Qx^^LRF*Y@4Dq7nxPLH?8?2lc3{q!q&rSqGvgdIfEE zkrv}`L;!?(qLP_tIrTz=M8h4t@C%m!xz7TwfQwVz6r$m{5^5Ac`H0!e4SbYoWcw*) z5_XzCokN^p^x}Z?cXq4jfuFJ0C#~N%lbF-cR_6TANV|rIMGv4|Msf=S)d&a!Y>j$> z7~g?=Om<=J;&{Y-)MDS#=zxQnvqU(d=HM4(i;rSGA^aWgIdDVqX<+G#he_Q`i0xnf z`Xjq$6;RZR9m^xB-l6rV_h;;St5p^qynhvXN(-QAMYo|1!O?zqU{ty!eCGCwC!vJ+%3{ zP1jww{aWT(amB*DU6bcFZhvaUny0tbH{M4HpE*h?et3=Cx;a=(Uwr5I-A9ifIeh;k zn8PY?7oC{H08l6CnOKgV^LycLFL42v2;j%vArjYno_5DwfsG*|{xs-e`^xf52R3cl zG*H^OOugxCLk5o-t zwrA#wGuPKPZhn05=o=M=NL5EPHn$~oDO!Kklrpofq~-bFwqsMwiiPHW_pncwLq@xhxZ8T#t)$ zI_GX4$0SqVNZmI3mfmc2c5`vKv&>bsbZ;Bm`{9#qGnKxof~W4wD9bjfe3iNPF|@CG zX4KVKRj8EtODE^It!mDoo@GCpR1Lo~-66d{>NJKt4rum0ck1g^v&WAoC`wz6?LcG9fMEK zk6mAmA2XVm5v#zZW(?2z9fyYmF3(+lcf2%`UF8T0sP0!AJ#^ZVlLhjb{T>cbDp8#b76>hq?p@%$W14ZV(!36i?!j*+P_t1 z#Idb;_06}QeCS%q^-G1+@#Psot?qU^v*y*57 zusseZ<+pp-ZGn7+vNXi@1VWV6o59voPiJ`9--iO!iBPFhksqM0_1MwJjNwm&<+y(@ zh8BY#s2HxBjL3{LQIgdj62O;7EI~XxEC-lo#0p~&P<0kg7u?FQa~5&J3M0tvH-6rM zm_2b#ELxD4of-5aB8k7j3f> z92Z<%5%d?lh>%7W=ULLk1nh>r(Hn4cI4)_?l_ZkC+Ms`=Ydk6$-JaEB1E7wh{n{1yu1OYmEKb4C1?M5h?R zZ?R->GnBxK3Mzz}7)ZmHbrq}6 zQJUw7?m^qcOVBnFmHf*wTe4q&9cG(+hG^M|n61Yn5O_kKY+nW{a$gyTlG}QNk-2+&+4jqOM}P0hX;U>pz(+K@J<`3pvhnJ!yeo8f=xz4BY1P(90Ps24 zBSa2>C>{Z#Pn*=RB_O~U58MV(;2w>Y5(9FJ6S$5bUrCUTmtGPs*g1V<{$k=B4OV$`%n0zxk0ltp1d?*=yXMYCCnxt-pAQF7tHzhTh4_ zqC>u!o}rhZIbAFlBZ2H;pJQHRM22C*6Wgy3k%@&uV-m20e8>bcf|sbd+gG%K>}CX8 z5`KPxU2)+8wU5j^^$J^pq1i<3K>tv#n8+g8-xu)bC_4ya5VvTXOCualjwkNSZIooqA0+4Lss5Kz`{On@PZkWvO6u#9Lo}AX9 z4UC`A(O!(1M7cY|aRchIQzWj63r1#q6;Fm=wffl|O)w@`uiT{= z`dG1h&5GS>I!(Qk(KPRV>FSLy-PqiG<4YT_erb2}rQ2`Vz553G%(l&&xAF4H&A&td zZW@-9u#@m>#?Jj%>w=$oe%86g-jcLsaLWvC6U}4ZMDKCP6lOSalf~a}6IWCsJ|^Lt z?EVYv0nQi_wxAtioGEh{rNAm^ID<5~pm*@BCmkVT09)exf_Pm;?w{bo$$yOUu@Mr3 zfT%HCNuKqFT-;r{D?$EE;K5s`bv?;TFO;Zy#^h-}>wy$n(UfrIFuRXVWvV=WDwcxLFYga#uzo>(kX0~qX4vUA{#NqBut=xP1JLElQAH!ZHrm})y z#sq}scT~}I91h0A-jJyTnhU1}7ap_XmWu1WhE#05-zS}_HkIcU=?#kUu4-&iD`?mqy(Ux3Xh}hYSMNkG3zhG zyOScT(djfC-VNg#csCU#t>^IWu<-bW9l!fl--Te$&2ukM2b?LDx2&f++4GgH9<-~tR(@n0rjbX(BO6hmT-axl)$zz zNaL_=i`qQG1G)mX&2QxCw0Bh3_p-0h-YY12VI#X|WTVEMac5F^fD?Js0CO*m7m*8N zIMm~sh>>6h(H5j^NM5FDwFHLN+O)8ql^P`?P~(RHqf;k>(M02o8X465F->FMy)Y!Z zLfeRLg%vt#NT7Y(o+`YDYabU0d>lTGwoSmt)0L(##m7f?#c|E~@QO_t(+tGz!MWvT z?1LeA<06KISim#r`Tg+A&LDmN=9%RR&vQGa%;Q#TyuJVqD-gKR!wOF}A*U3E5G4qx zP7xFlpt?U&_vq@YpT54T>ADAJ6)syi5Uf$zm1dhOyCksi1~uDCJ+9rpEL7H>-A#0x?1O6I?gg-2CGHArNF;`H+c$pRA;!5)7Vvp73UIU}*YZhrJ*)xX>Eu2h zBY=>rFx3;T0I(K?y)wO4>q94(Z`V+dvy;>}F7%gXyRBxGO;r;dSh%!s)`QnIRb9t( z>+=;V^mXf+2e;n9_1@5tSLIg`M%~KiZ<)f8=^=}-=V^?A87H$>_@2ASA{xQd;ml4^ zb|mh;98mw72MG$tBkF`M!<9%#ZjkWAt;5(-Imix4-md%{M%s{Q0(N3NOE7hV6=1O2 zY4KToXug>M>q$x+hph8F2g0l+V8>YOj#~L6dF#e+&0GH6&Gn62zq@$RiK|;ue|SN7 z&xTd2Hf&h664r13{9`N1k~UYxng*09-)N6rp9>{*3g{8OQ;P)AI_SxX=iSQUq#)8NUrKjdZ%7S4K|w7VolS6#Y?7z z*&j4ap+c4{j>j7U}0Q|DPZ6iETZdmT3QU>Ct`8fI9P_ycLi)l%z(g2 zZd$S44Me!F{Jpr7|Gp=#z{Qc|jRr8{1drAJ# zS_TT8j6bHInJh}<&L;7AIYd+-UN(Yt15k$XO3omh#EnC|$DBGw5N|G~KQS&7^cYVx ztRB^`SOmrFtFM!j2Y0S)x_I%!ACXf>RY;V^{^ObNj~pcHpP}TJelWTtQG#Y>8~qOK zO%mIUkC8^`HaPz!ks0uKOUb1Pwa;5%m+v>H=S<(w+`M6WPP%!&+@3EItH9FEGKV{g z9ggCTusI97ZGdY;huy|3qi+&5eS@<1nj9MOR)gMK(-({N)_4tuEn5bGR*Hu|(R!=Iop@4^h3CyVl`P zh2Igq0Kb(A!C3^=z_JzqHbW2*19u5P{33CVp^?3jSwi4g4l6_0fkfW2dd?-1DC)0z zs)>7wNcdMhMaufh2T%-AIBBKD`MFTr9;;g{1sFWCaWP8DL*U04e97RVm~fXNyOwYy z$^_ZP5E%GQ_pJQ3?E}%G&UrJcrD=ECN=(oEeyd0=_4Kqwb-qHkDJ#WdW)2zyMNTIl za?0r}3K&JV$`$^$HLV@X+hWo3(2<6F+UVKEY^ts{Gpn??D$knlGf4Hii`yMV0h1|E z^<|x|8*F*o(I2=f5fs& z@3I#z{T$DOJTm;L*ep5=Ss;;u+XZRy)X8;7jKEI4<3*FY5SkDptx;Mx1}eplapzq-Eju3gL9va;Hi z@4BnA^YG54ZJBh+yHxe88+)>{X52Kes5@5UOOw0H@)px?jV)sSIZ^~)^wtkf3}jDP zapT=xUH9I!vOPPyedSH}e$2in+>$qSS!Lv|zEYS~Ls&v>_vu z^vsm7OiJR8k+UZsXA&KW2{{-?NJ!WO#1Vkiy5 zyHgu51=V-R4(>N<73{YZ2ARR`OSkz0rFEqNdvQn9T2>s^21Qy~n#GlA^E$aNY_ax8 z@d6if3rHzm*RVQe=v!3IT=q?`mkRc?Z_+bU)bkC90ctjB^%`TaI-1>5?35eqnn@{g zrB>-mH<>j0Abd$`A`Y(&eO@N`5o2c70o#fRs^S$&g&Z4zP~dVRM&ebL8L*lIj1=HAU|N3+$QK!#n2`gZ#S)_gF|^2vkobYr zC**_kgCSetTbA@YuRWMGr!X>*d1%ueW*hnYj!gVLEAvkB_gP!G*6*(i+wI{xzrQwY zqmM;rWggmikUWZC;HS}k{PdvNYED0N4JpdUKkY+|Sn@0AN;&x4R%WB18v3k&#Hs{f zz+D*-IGLY9m|w(EP^_~da20un*rgQ^WkllSpYdZ`@I^=@5RZI|e&!9QmtOmLZKc9* z&;=uPxvTfvspkTAb}da^=eM&zi@aAptuzaAp{}U<;m&1`ZJDaMb|vQ{ay_w@s&Qnm)69<=wNFrRrq(9BucrCxowxp2Hq4K5gRS zYzko<5(f}MKhgRL0T4Jj3E9ot7A`%#t0QgFmZvs)gMqq;TimfJ_5)4&&;?&GSXY=K z(NaG8PeW4%56#Kh;`bWz+KTAo8hOF|+g^Kpm)}ADzU36^HDK|(nZ=;aiciA|AY;Z| zk0PAcD7uMiVYcFb2>40Y;e8KDz++_uA&8dySw%+C@Na8ud93S zf}-aa^!G1Z*x$cEbiLB_#q}z^@QAGa>XHRFwokozUU6}Dk5rDcZA6i=JxjHrgqT-!W6aQQn9DTCS3l-41K!rMQ5e?5~#oI^Yt5NMj|se);DaL8Hvu^ z#7e(S&ugDKv%P)B3{IE!<1YJd<{DtFUlA`Gkzch~NpADle-;LmqowSQ)2=FI(9ExNTg z80@_ja*Hsn^af^`Kn}Tuw!*NHtqsdoB8I~Pb^7IxY5KIY%rK2vc5y%bdrPrxr%7ZZ z(KRS!FA@lU13f|Vt|KY{Kja*YCc+AH6&Ro#qR7g~@AE*{IL!t(2qB%*4WaPX^v2kK z6%P8riOapTnmSp~R%kVa;(@%nJf|$xWEE>9x1=?!I?8N}_HS*g7#!%%`mtOYcJJ6t zbqAZ9T7vGf>~u?RnagCNY17nO7L{`CsvdR;-$J`;&@Mi9EoZGFKGfJdK0|_&#~c` z0XF+^9`4$f0huvje>ED^60*M%wZ+}&y0D5dJz*hcigF1zJmE55^TyD5xk<02b@a8r zeM2l^=TNs&1=m^Z1cOXb8x%`{0L^wb`-k4d+y#amIMXl2$`PN=RFSzOT3kplh0*gM z6eYZyiL~)_4vAmu5^l@QXXoX0wlBPUajbd!*(H^$=5@O3HRZPOirR`k_Hf*^vhFIlfuX3~2(`ESR5lO~!5n<*E4 z&2*Yb{*FH&`Y^^@L@XiJO4_w<=cipMQvtM6I9rFZOHQQD+Q11^m^hHa0 z!?O)h*bRW|ewvB}|9pQYtmzj0{4EsI&a zHa*XH@dJffCl~(3Q)>2jZiQ7j6Sn+65Y^Iwe%8QWyExD9R1$w}5vP-Jz)eQ`!W1N> z)ju-&L`Q46zlasZliq0mf`_lJS#foLfBCXQy)zFltC-b)^@^ISA6{74QEXo~xM-aX z=25gcM`y}w%+G7gH6gT`qG;iPnd?pjGY>6p-7&kUX!efQ#fLJ3C)Uk8u(0SUSIOku zr7Kr1&7EB0qE~uKTLRv?u)`6q^9EWnw3lVPnXU5y+ptfA)-fHq^z}+&8Ck-O3fk>_%&b@ZrK~#dddjN8a+)p7IW~EeE{GZ-L)|BcpRgM!&BVym%zFdJ&aYhg#=Wy<-TTJMmFJHQ z3=1MXYpbf(bVnlHYpSZ&_C)Bn&ar1#y~;@WAVtxB#DVGe!ghZku2L50ufmN$tW{Gyv-%tf}n@-$>MfF}jwSqT^) z`f<6vN{o$!y~^1cV@+1hUY#`WfpyinlLt%Kr}FwTsnxJooq8knM69dCVUM-uWw(?B zQq_gwt;*?JPKeHyE;-aUW%o5}%GlEiWypKm)btp_`4=six3D-exzLgxD$B^RON|JH z7e%|OFup;wD~^6~d4$N(g|nl-#$d(KjI*k_CU(y|wyNAw+F7`D^OW7E=PkW&!!-NS ztQNHJ;+YwfO#bvp&CGc1qB_qFI~OiFyn%jQ zR35En-_+G^IM%oNd%K#gx#jMw+)ke}d-Brwx*fi3`g=s?3edlFv_pfrk&LkcL986H z0hx4N>d>#$6_L|)uEuK|YBjn=4=m0r)m=Q~$!FT##b&qh1jecuWf7l@|JZKYptdUt zHdMFlTT$1z_3X0ck6&A3%q;V=XVkS>|3%NssGeC!0&rc65Rq{gov#n*oUX`KM;6U~ zcyn|8b*HYX*|2;t!Ujw(;itqZ_Tu@gulH5YK-&t24fG%_@iD5q`o=)k(Q0t^*%sIemL(&)(Y~3ia=u-O?M;Xd=BW&HO9B=BEtX=_*4oyo-hbo*+yeFe2BT%N*+ zQpGJV4BbL}0x0Bow$t6{f0h7|aQ)ye$bj6@2)={TQ4y|rz-Z_|<%Bd$(M^=V<$d0VWGq5n!#oi_xm zYOqoRX$rSzZc1)rKP_{YOwI|`R+QMcs_p4l6{~%!pBVD<^NkrHm&2eDD~mgeu<%H` zi!g6f(e5(AS`e9#3F7Fq;{CWMOyHH&b~aY;kNSmv^6(^Ly3 zD2(RikZ=?Zn_4L-qspWsJxU%!h+z-^EdJ2UvksyoCliT6$n~zXxToA1E-tIcX$CAb zy{14j$sU%8RYs>il&5eZfn%W~&F}XFWRf(EN!=^Wt)D^55K+uq*=5o-l~(kWTJ^cD zMGiUg-@5p@buSrv-Y<*%D4R41(onKqbooj-iuLcy!zobPu`r;(g}p34QG=eu#^W6ul1Q29;QfSW^5^oFI85 zvIBn-7lvtNpGH}B8~eV|!YHW8kK86?e)v*Rcbe|lF}-RM^%nbUQ_R8snV-9A%v}@O zpCzb`R|Q4j(*`J^2$M&G5hDUI;t($pfGCFhI>;Zw5|el_;HWSi362Oux9EJHi~yX4 zrHDdIuz_)28AyURUPB_RuhvCp=fv*UYBRJYJ!Ou}NrUmGwZVusU1f0u9oh`5I+AND zFb-BxTd1czc}s+htE4@zY;I$qG}wgWyGouOu;v%Yr8a6O^hO+gn1w#r5DmBM44jMv zWDfXSDMGQIgRT;%#sM-DoF*ZTD#)ge%ToNDCKUfGe&6#%h6kB2L{bn$L21VZJqDQo z8jwh5H72_ZwMHLHH&=N*&1HUn!@TnN{CaO@=CQPV`w{lV!rbh#aDILfm1)kg>P)6^ zM@h85Av4f8r?hlg?B{AkC(S7>4MmDd__=9=Y|TW!v;xHaBMWUg)FEW4o!qgJE@0i@ zNv%NZ2{Po8i=5a2HFFo$95R6W1rf{0G#330fQN1Dj}_?%Cat#0hyIePQ>Rk@%=Va+ zpp6o)rGf6j8YW{{Bxs7)8>BSn9D+F~F@oS+$}e0{Eit4WgmKA*8m0v;S(y$ycB#C~ zqO2lBlLXBnf3(>D+pMw5s1*)f0*K zRAuy6MSTr($_o5hIic)8{?t^RL$9}MQ@nq6mUI*p_oU~n%xZ}_9I=+Hl{x7>#RVND z&Ygw+aCUasUr5#Vk_0abgH@3W-Uq=B>M*X8(N_{ZnaB&jW=G{^E`}O?hmwMS9Vh7I zLX#0BzSN6m*8>{2)=aeQ|8VZL)b6_3- z2OYkaZl<<@lZH6e;BzGsYw)V4kB}tErh$AK7=aOHF_CL7k(>uv?7~s%z!Oj0eC7gvW;yzymk zo%3?1)tZ{K^0OT~|FJ4pYPWX0O3EWP%;&ISK0^Ec4IKR&SSr-2uQOFBlEa2Br~eyv z3NU9G8Jmel$e!^=$f}7(2u18edOF&ljWWjJ=}Ju0S6LNPN305Kq4CSjijPLk3TevM z*cF8s%PD9}8R^d`w*POL10DZ~Iq=bcVh#}AseoR@jlTis5WQ~fIpnfUT6Tp^nlfKu zmnPh|&*^5A%bi2iJWl@2cG=K3+-2z_U$@H=*{(!8`q2)uMF%}R1KiRmX z|G~yZ;#&&ncC?l3TNr15@}0iqSxFDJhYQ2SCS>rATDs+n1Uu=t9H>(4rdUvbl5md#6uppWM<^RasUt zwrvX1HtbzD(6z#0`Xc(Cz>bJ(#tp)Cmu{plK7sF-3SI-}VG;Ic$Ti^&q|lNS%AZ0Z zJr|RP_@~phv5&G3Z=@)1iEmQ~l$QEik)v%R)iUJ9qtku5Z55*?Y zX@L{0Vd)va%S>biTN;1G4yVyXlnBCIMfeM&*EM2+Q7=`jJu!IG@22m_-FVjv>mOtP z^zvXq@Al&_EIm!7eYa0^@uV;%I(N^Eu6>J2=<^4=j;yU+x^Y&+iq_z=7b(TPi@yJ@ zU9%$_f5iUt);s;(`xX|L4&H{VEVQWvcyJHy%0q$@v?-jEk%BgXQXH!gB@Jr{-$KwN zxF+JfM}ol-go!)FmSnd3(~74p-FACN&HQTDz^Ts;s$F>wcU5VD=1109*W59!e$~_v zWiNNoZ$*~OYSGTQZ*5fpy-})`EqM9y+n1Dw+6K$!p1NamM6>v&sV+}RTUP#*U2}>G zH@>t-s*ni%Q}=#48AnPmASjc}W!?}VBh+bd-q2o(GdFmxhxx;;K1s4| zM^u#ox_P=e)%1ofY^>hb#O%6wb@TpeQ`B}oJ;gko-bFWco1@0JY$2^w_UqIXZI1PA zW1$(AC8=krpj@(oIX_wtCZ3of7#%>I;Aw!ML%@U_PaJeD#EjoTXs<5cvm-I zj|%jKU}_?8tt-P?F^4RdqTzG_q0_O>b2 z+{xF&9v2k>vr5Of$@zM4a(5sWR>IjrjN=sPo`a(QGW0|b8vI6ahBWmziCSXjZuU6c z)QRzYt2n26ZxeI##WhX)s*I=v!-+~ryqLd>21SMZn5B_@Q4M>Iq*LQU2>O$QC-z1C zqQPst4j~ilk6ilk-NJBWS)rpY$o|}&O^c$JUdF__sLVjEJ+dTx=?8ZSW8qmr_(VD~ zHj#Q(p`Ira^&rMJWWX!YiT(W48zG;G!PCJET_vofv)$~^gZ1|4vZye8_oW|4W(9>hvKDp2!|B%aK$Um{A;Ok7}pOZ@rEiX5`=#O6&Ba-@2LQ?f!)#z%VCyiYu zstm(<<5=m{`?bRTW0nVvu8dhcmzHP)hJ;8%2F@@8bcg6Y_~c>Tki4fPOEO^}L$*9o z65gEy+zFZJj4CHq;aoJgK4MrG$*{UKcBG(}DI}ufa=k*@Ru-LXoPJP(%)M4=suYQe zxpny+(Ld;3Nt7?260iYpWJ6C5eC4>mu2Hr`D0KPm!fb#H`6Nsmzk; zGD#xKB^I^TB$Y|!2>AmYA7l10MdAwFKU<*VH2?z0zC#jo`~2tvIsa01`#RoHS<7fUV5NB;YdbmU)|EjCwQidt{gG5a*jQx%HT7|7oO8>0i<( zKtm34_=Mh^*r}nnbymGPrO$0^&ivQ-PDvCx`L)4}l+5?Z{Gcu_SM|e*ewn|lUt=n} ztYhP98{e@TB?@g?qB?G_g!hQA#av}$46T|g&J`gla;Vqk0(eX0d6nJf~mPpv%T$ zq(#NbaV;7@ERT#dDY!#1v48m9X^M~>Qd$R)o0-?n>J<{ z@Ul;TA)Spj<)KZvU)LtAzVWN#E0c;-!ig!>B|}`ZdK)sGUZ=+DMzb2YW~s)dT1QMH z<^~}nK7(^GS^IhoKq!nA0RY21L`sH?gkm6hs1XBm-`w3D-jkhk=5(I)cI>9qd?IW` zFu>dpYFkuNR##V6vZyUYXOCpRrUelso$Qj9z(%&A4z(Om64BwDUV%OlPN+@T#hyfd z`J12SGFpFk?#_1i-Mw?>^xo}h-ytnwKTxMoDuqf)5B)H+d45S*MMYW3{N_xIG5SLP zUHsidUkq37i;!@Qi7FOO=*#`5_1%!8f=|(Jmk!aB4z;vw+8C zwdgclE|MH7hunXXD8dNEs=vH@BwaMQ59I^3()9ndZJHLM(z<8z-4RP8Aa-;ddH<%H z-#^kprG+{-{UXx8vqL!NCv;`*XyYespIuB1{b|d4_w@AK^WGNWoJ;p~?3{({jAV}B zb1RZC_W;Qb!y7S`T&x*!sz`d>T4AnIBw^KH z`Jq5K7%R;8O=rcl1F$Wc7Mqg=Uk*SH`ZM|p?QZ#_!RVk;1* zvju(60agSar4Xk)fzU%P!Em)`$32EKA*dJwM9Pqefmp=>&8AmfUUFiZt` zPL!DVo;W<(QB97|1)naD6!*Fa@(YeCN$z*0i6<6D!q-?$E$r%wuPC@sQ=1$Cq&Ayz zM}C^xS=-hfnYN`Hfpdn|^e-$fp#N}ES{WD}ftocvg`y#2XsR>n(-kk;JDmV|Bpx`; zY=-}-9Vet*!EJG+l}f=q7A;MYBljukJh{XP@jj@W<8i70=6erRLuG>?C4~#f8gGzO zQt6nH$p5xi$#ShQ#0pq`N&GGru*XMntXk3_=IVZMi z$7=QnBfa>!hJ1^cIn%C6Tu;q#6YhSvhtuXKXOU;#~)Fa`{`yadaR`w5fa_eH1 zU_Nq3K05x6XMD1{9D1VL)T-&XzqWGaYqw8NzP=af*-%@zVMZh}V?$l-2C&d>82dGO ztnO;^?bUU48)rn}yg~BHtPsp*zR!Fc_K#8E!3>oG74E>*{9?g+!8XBO!4bg;!D#_} zkK*oU&z^et_}z#0-@J44#x=_p&FP&!rMb4Es36ci{mA z63~=$og;7qZmUJn_%&zOIivYG>29e_qb$gab;PWjx0f!MG1bq0`jR0?G3Cn!my|Df zXj3iq;>yR?m5Wl9vQ0Kknz?vp745iwuRS)U;1YwBE{^r_DIs<1_Q&U8`H*(8hsL)n z$>jRqZr9+%W(hZ3xmk#nKKv-9Np#!5g1mu)(CX1oMKH`|hA#;akSq zgtv?tFm@8g>+tYDg%=qGHVN@*Kf!E>pA59#Wy8g}>yMp9weaHekDCG+ZmnHvQl>d< zt^&8ZX=?M5@LwO*d1yL&QbU8kabtG@HTC4GBHo^RTmxhEeNqBToNYuv?Ibng{f!?$JX@Mppg zFgCepOYjQwMm!4ndAn?IgdbF_dw6l{?$v$n$x5}%6lqy9W!2o~D~-Hq}nLV9@#O8lPKhQp%oD%{17iR>c+sNl+S@)e|t-JxIfg@^gf@&<}~X z!6rlbTz|iTLnU4NO&lfXe3cg@>Dx@|@$$=k?P$`^?wvu=y(lZ{Lo*{SuP-Y{CNQ~XOkwcH;C~_lHC@gBJefo$iYMiRe zGA3O&$?K@=rnK)!A_&UJ-7E1irHW3S5_hu1NB#tJh`yTpUIJMqp?L`wL!QCECr+KB z-29`|IXn*R<`lCBu{_RVEfCJRDivH$jK>Hb%%6FaOy z9m`6b*7Wza>c81c?`t%FL%(<&>v>=ZUX9{6YscaiM4skg9=|6#gIN)uMhs&zC$MHbN#{QgdPwc-T+?8GRAwvi`wMKcN9_%( zMP~@$XwP$NH10e*0Uc2mrDghPuQ&=c6I?S+*N#L80W*wK=(sNT{ zJ&F{uGOUu=^E0%fCoLhj7XAvJj>Gj1g<7JJsLL{eh;g!i3FRviRY!Bq<6{cc0oF_1FtMI?b)pe|s&61&0ZLYy41g%40Qr%tiwUO&Qyj!bwCG4SymA0xnX;M-I!`|P)K zj~qS1mB*~7cZ!=4U2}xL00n^3{*J=L&1{I`Vi*Z-LcMzu_2OL2ts{;Df73&!9v&KE zk5Gl|>qohDIlhft-H1$pQavd3zEj6?kFu|$)X}~WZiJNUOX3s=VwLB>u~YZq;n$C# zp=c@BR`yQxy>N8B8=(_WCYwfTrUY}@>*)UBzreFue46XC2xMv=QW?7|P!Bxmte#iv zYp4io*UQw5T%j==J=wYi;aN=~O`s|-B%(EXb$%Wx^BI(RHc_UL_%n<6eV)^h{E?lc zep;RFF`6|BIir@Z(}pV=e6{ncolkDe%UA0)v?!EU70`s5W`!4^AGF{Un@+D7K81DU zz&Zkvm8_%7&zb};;MugNGRoVtLsLnz*r}oH_VSEfIoW}{yg+si`$5j6LOV%5k37IO zTeLakFDUS5=I5jBR1up?{Sj>+(T}2pe$)|t2Xu1AAKWO=uym7kbdO^ zd&7e@?0@as$36Et_nZUcsv>KK#|J^t{$Q``|VSJ<8ASVytJP(@c73~{Oo;VnozZXIdIh^#`YUBL&b^(Tf(YLH9g zZH!w|21y*95q(ZleF8o3(0hi4Xd!#_#TSQI@Zn#0h?kiV`zrn6@H04BCwOHdY|9d# z#7)vr`8+;}pSvqH7Si6V6nwxkxch8==M2?|@Hq%HJ z$mt+s3dWNp5a42G=oK8Dhm%@d3{&&c9qAcWy+xTGv)$|=Z(O43x}3twjO>;|$3e_(`277|F1p7|sYage|udeie{C zCKLB&7J&<6>Ev`90c9ja{}N*dy(c0YG15Fl-_Yt5i_M&J$I2&{F4W*3_RX7bMjQUhtfp(lh?I&paQc?aGkUh=z`RdC zohO>VXYMDT5^njQnf=tS#gninC;5v>2ushwR$=Pbg*{asPgPH$Coj*#?01w*4Tsx{ z9oOdO=jWh#kZ&*3Kz||5{hIxi-}}HA5Mv9hplOT27qKO=d0WJ1xM}W<)BShPS-g18 zQUCOtm^YH&S;GXf4^uVy-B&mCtyt05aCJA)6N0ygeoto(zdELm=wZxA9lVY7k$q?H z+)qCteY}L{rVhU{<~e>W_VLgCZ10>;KAD4lFhl<(Ea#q+VV$N(;97#Y)LHTppx4H7y9GLqFY9TUQ!`x06il=a6sUm#vMC`yQ={iy9R1F!!kTy~B(5Zlld+Ot)Io6R#M@XP8F% zp!g<18swU{<+0S2a7#j~Dk%?Da;;e@tsL6Sy<8ICWHlaVZ^M7c9JI1o(q+T9aPuhT zVkQ-2VDOD%#^pp(E@Z4_`fj7BKmTS`)%l@|?91#cLtnfRU;X}{DFORCV|F}vf7hZ# zUH1p$*+$L>p_SPzT_*Z~%a?}t2nLM(lmtOMog$_}#F>B+EMR_ue97BK_dLSKTp;<| z=W5aRv*dgBYH8lcGhKYZ-?qq7g}cx~)^(R+_R<;W?_adh;Zd^+)lm&sPG0v=sW0 zq^h_tyO$)>gu;NLajZB|iOze36Jc(%~J5g+ulLQYu zo-Lw=cTX(JAsy6H27@#uBOYpOGgS_DAZM8aLCsV~u{E@$Ji8&^@+Xr|7bvi%8khmO zR&R6E$J3)B2d(rvKnqgI!alDp46fe0bCuc{oubsF>d1`=+SbnW&?a%czzwFE^o-X7 zCla#$$-+k*89Q1+HXFb%BavB+Zb=yXCsmm@rP!IKXFrn`W|~|UlR_)aF-BvBrh=Xt zzpJ9Vq(N~^qOpnV?Zs0g8OCrHLbNH0EiR4N86Sw}O|SATZ%wlp6Y&veG6R%WVt||& z(GCq5!K589Vq+7|I}~&HA!WKpt8tl>N|Q^Y^`tAs4z`MV?kZx z-u45zYqWof%Rh|1Hfi{g`;MmA3=%G6Ml3e7Is>k_u~24aC?_jRT#my9KaTZL}g42~1AeN>zd=qMv_F6{Gt5Lc^Hv~#Idl2!5W|4_ zp*T%0(;y&!es+GA$)Z&$v?(EDI1({sPbtrEl+P$F?(&FUl%_&BYRf8X%xt5&)-YP%sVRbyfX6lr#w$5lDAxUjd{r&E12G-b6`^SnZq<_P;dxd{G6`o9=l zJ`dVJ&Z4*`#JcvM)#X*00&~U_R)p^zU&8Z8zbTW$Uc`DcDQYqNS z`8is`3MIOCe~?`kb5K4CQ&cwHEI}% zvB=}lr!qRJE!F0dlhV~XS4Ng!DNjk6tT&?k z5{zFIa!hP1UXHnf$nfy+l+aVMMQs$uG^t``Y6)#pYavkoOHX*6i4VS{J#fh*wiso+EHWx*cO(ofsD>VTc9kW7OIN z34}3RL+!bS{aK<~YocA$ywMN1b^&W##4>`Duz6|)xN>&m%2`K7Z5g~W35^1tui#S9 z^NHgi`55k)_>`d#SSR@v(sWhD%Syc1FX51>%aSD83=ctK7ZN`MyaEa~7Le_N4|@gP z0pg(IRt#%MLHl!rha6cssx%|?kS8}MmgC9vaLFz`w2;n@IDJmNBg3K33TK(*a#@;O zo#nT5Ap{}Vuu6#>(63i76N@D(hh1mZ5Wf;_idZO-cx)y!Xu3kN1QDTi_6$RsM2yJ%QK=&VK-?dxhX8KAA|W0&F)I5^d4-mN@xC%>U8Df9(_?S^%O1 z@rfacQ!{b=Av_Y|VO&9oBtG;3`M2hcJc&rwTvpog5B9`O!61Bb%8Cku(O@Jy6YcPu z^sW?4KClW-yN|kx!ZL6rjtCO|K7c~hTQc)Gw8u-#wuld|y8ojrnNna(5lR%^yL7se z755L)^qwDVDYIA3uAwsPcfNETaBVe7i)oL~Z(u)p_l7;2cmIL;FHAzvoFg-ZQa$0` zqNzJ)g$w8H=?V9>R~u`Fd+%Bqr#G_Q8D&#Kxh+xa)AN?D9KiS^pPi@^e#%1WM>YeHO`hzsnAH52~q7SqjOIoAlB9KT$$c2lTl@op^kV?eTEB_1{%wzHgGJFBACq;^!=s0!42qQt7IrT*b4hK|X z;Z98Yo7^~XP^H~CqY{fiM9)Y;a$g6M`*s%(99t8wU4Kt+tY;EQ>nk^?7I(AkckgA{ zGjos&SaMIx_A+P7HNEcQaGu#CQX5QirC(QD#(a^?_glB^+|?Vux3!K>_d7l-u*s;8 zZ|pAtAt3cejb4h}#{DxP-$Xxr2>B-2CkI+iAulKbW{_N>7V?VpLl|9>EYtucMbTXt zLCAW7{|6U4j#7r8BGf#hAG#-gjWi8e!GI4LouKcr3Uo9^ia#9u zKKtqMp`TyA*ki{j#rFrMx1w zx1A$)XdH~NW^PT}NM=P)QusgvMi zpjND7(9eYLqD?XZ$^HTcHAI*snih4EI00x8#b=VjnB)0z(E>=)+r+=ZcQ37=x3CiG zUqjc69{6I$yVRXOrEYx(eQp4EZn5YYoEh^3jqy4ow&XgpP!P>$391*1DCD&sQ4%E2 z1n=evj;G&;+}2sXJb#`IR7hnSl5%+|?`R+iqPBTcomUmm9!XU}f>g#_*eU5JcK`PS zeG-k`Bs{13>yNvxA82yvowBLrd+xla^&lmDZt1}3VZlA!H!rA^UmD8q->vF8@%Ov@ zVY~cKe+U)?)r$FbGYSoJUu1uK?f`q~`4zv3&b_ItXGIIcie zL`e*T7r^#LsBt8O1W^rOyIq!xgsgEc7YWB{JuoX}v2jc};8W?D~9dsu2okZfx@{cTVnq>cC8I&8*_eu0m7O%|F;OdDoiR zLFN&=5{WA9;Tmt>obLxJr})F&Rlam@rYc3IUR~Q$XoxL;U|HFc84cy9B+Cjw`bkWZ$;X~ zo+W^{HAUN@PZ{i6_>|kX#(tXEyL_XY6~FX}E=q1%6vg$0+q95bD6wgY6T8$`J)hXE zyjo8nkld|cK#y)#;AL{hJeQgXNrn%mmZmTRhbrS0cdN!$O^Mr8-9Ep1@uM57>#uus zVehW;vt}Fh+t~V@hkNd3|M~pV!51mRqumFqC+t)zpRTr?`PW8UnqG@@RpZWQ*IfJJ z&IXr_lGyZzhMowN`m~7@_NtebSkldxZ&nx*diZUO%WaSy1#Ss5;x46JOu_{5xllPP zjGhiP2EA?6_*^9DR|-WO98(Ag=E8d{7$pU#N1vZI4?RtZtY!uE0CiAi(Ngr#3)J^7 zmeKt(i)Nu*N9{K#>2<<9wQlGTy-1_I^uo{~>NmECalax>LBg&O4j8>lbOPtvhj={$ zLIz}!f}Rlw&=>^%=Ti8PoOqXg1;TYg(OmWw|0~^>|B58RyW+1d|CI2$$v=SNR6^`t z$Q8!viR9_^Fr_T2nd>fY3N$Qf@`_GeyuYcY%b9JF<#%l$@zjoCytj%@3qpdYdD)g} zNhAO(4iGpzw4BO9Q@D>LiI3unG)jo*__UCGAgu36h&Z8^aCwXQKuHpq6Lnb7;22{q z^W_lepL+xej>?fZkPoOd<}n;QVAR62B?CPA1o4-^>+3&2n1!2bzsOBeN6rLR!`J9o$Il~r}qohFf5Z>t_E>r3oAL4r*b^lzhELv0I}{LBGYh0rrg=t2{ensMlhqbr#dm zc1Q{C%ZERf{1LKSAn1QWmx>^DFthmlK?VuQ5(NbZPdmiX;8OZ>=PYyL3nJ6}x56%x zn6h3-*w~bSaIu{Zvq`0pBC6Z}N8X#qw^g2L!{;1rw&hKhWG$9t$=YR0@+vR#BJaE7 zERMI>PU382-ykHAKu7|FHIz~yz(AlZEmH`kfl>;zWt-^~rY)VWZ`XNWrtLR$h60n8 z#L9Qw&pDFiB_Zwa`@R2s>12YXNAfw(d7k^Z@9Vzq>*mV&aypmYM7Sn5E5S~`6YKb>s4vuZ_MAw-XAn#ZFB-M9YB4YGUAZ&`8OP;oKD%;~=e4vmDFoxf7C4)v0qp6WPzkdb4FmvwQa3zo3MsV&d2rzcq7z?bZjUrytx}D?1n2`1#4n&u=9D z2>K1hpHl6{eR#ocUl+?LglJm^i!?=N$x78T;?itK4Gom7C{*a6qKX!Z5*B~ITY7&q zmh1ObltD=@>hk&BxoK&}V(UeVN@UgMbxtpi%+gww#`MxRXUvx7)?rIE~-S&xpKk{(= z!#8*Ac$3e0_+dWhtsR5i?aL$UPmG@bhpro6+qdtvo4UGgqJMAf!ki#>Qv4Uzw-Y|~ zb_SiC$(3R!{41_-50)^*11ZLU!lEK2h++~Y)EE~HvlWP+5@S$%lnA8QkkJ_MgwhZo zbSGD22E{|d6D|dxr1l6BK8}C1Ac*4Mzw1Z0v~=9|!`r|6-Jb1TE?3v~p6~KAaoJ)K zRNH|sufO8iLmfYKw@)|JO}033@24)5DKfAg3OEmSh!pP^>s_`3Z=yy{2~`#>aad{c zmvI=fd*L{b%Vxoc%t1s`NYIK_SI^*gY)Q!=lRZw{0wF%nkfr^{yWhJh7FfEk&xFdf z%^!8x;@{W!eS4nj+tuy5>z;q)H^fgWUifvx_WM_L->`YmnC-XB{4v7+t2zJM9`uvg zeig0&Hn<*mNj9##fvb|gSd?_SZ0h^z^}A1B-Bdey^`WaLYY%Mf-7;8f))rZ!6d7ESU;h*I?VO&o5bX<3u#%uO5g_O&}7|W*;u@ zC@+ZZIkk4=&{$(>Np*LXx3$!Ql4PwO_lHD_q84k?!a)}`7pso%K;#1{OZF7#=xCHt z1Zm-rOg0%D1jEh-ia>e7J(r0ca0YV~zHzqna85$~7(v&L2J zF$UFWEum2)0JUG9tHw2;e~n2DEcHFa| zrK6wU9Nqp}d?t6@b03|!;^q7II8^D!-QoE6)k8^Iw7gnvm^J_o4I<%t6g9}X8X>Y++x$q%Y>C3PY z9%)WunP#kFl(m!Zi9ilN%9B6Bi=i3HqpihbhGvZ&CWnd=P4HeQM%fCZGH*c4ntU%6 zb;8t$mLJ-c#!!)lX`RAfqggSCv~JOxg)h9})gY1ok$;re&x90DOou%2vA5$xKiRBv=kovh zHh@J4&`t@Sm0ZC=5EuTS9H_5An89WoqRJr^QWPvEWY$ky zuGI1H@;}qfmN)@Bm;V{27kv4{@hb?{A^JoqSE@&QM4z4&oD#8#X9fXF9&{VFDN?X` zW=yJSHhtOV_~)R-|jw7QSa5m-^tDA`)5vJ ze)G%B@yF8Iw%j&&;MF7Td#<`NSDvBE^*N2fzID}Q%c71wx)L4V`eXL|QG+EvB+a{x z(8A=rgUQV)$R^{A!Gt3!BhVdia$??7z;@9|EP?NPd7tTKF`+o`m-`upkNi!)B4yr< z=%(z3LjvQ2wqG`$%<()#AICdE`XWuC8XigmFYlc>#rNwquMc0{>+oQv>&DtjbB(6# zG-K8kQ}GLT?)?6#)#Y2iv@ia7b2cGJuV7~PIHJqSs@L@ejZR;#E<>Js7uOoYgcues#*!Fs^H`Zl`E_#Gl$xueEk`dYgCxe^HNEZaC zrK_OI3^SKN;Z&*w3Wu4f=jxrl608`F)}f{}P!&#Z+zYrQPW@acjoD~^9_m)*rQ!17 zubXZBzu$Rh0zLcAw#{!4dUpQ}+ky$Gt#!*+_9vh=3>OsRmi*)KKYsn&a}hI3Sw~==hjJne_E!IYgdjd zL$_pSG;BE9@s;@be_R>f^7OTD&ER~S`JAvFH;lL@{;Xmt)<-^0e{al1?yJXuW}Z0s zncqVb#Lj1gwLz~VpCCq-)|ywW%M|{}SwT>vSbEFZ_?N#I|A*@2)wmkUaPY%U4ba@JE zmXwLl64yvI#1_h4Y2X>B!*9m*5p+bT8Lp4#MKGmBE;;*Nlm$@W!e6AeSR?n&EhKK- zwqIzh1dvMtHu`#M ztDTMzbvPyJj4E-mN%k~^h6tdZm**p)O3pEB15B#VBpxCoFL~B!mY+n&mHOs=V^zH; zet6?eKRnS}y=s4J!?tCm7SDGIjoI0Gp@B`&%JEiDUUrr-{G_Ace^(6eiA6W|2SZD@ z$70)-hU7o*+BMc;a|~|2Wqj=;yPKMJKeBe@==wf;VfW;|{;J8^pv~0ek1T7cHW{ni zh9b@;Q(-8)_5Aa7V_i{8L4EgFZQE46#Zr&xmh&N>@j1+aGl6q~oCF7@;0*p1GpGb) zIZ}NR?5!af>Bd={N#Hq>eL zTddklQ*o_bM~;}>O8$VrsbD|f$GsXkH$_DmDtNu=N-Vtx%F2MF27Is z?}2NEf-{?;nXI$&% zRr0b@K?#Ifrp$mZ%Q7=~RWa{X`1OR_7vabgMKjtv)8J2vU_d7}95x$V-<~9lzv#&B z`6CI{Uvy;0{E?J(Uv%Vx@1*!+(UA+jlRSY%M=tnITCpCiLio?p$(M5f^F||!2`3QT z3tF}p`2aIc;(Sp$0)Ju}h@n>%H_q1NRUqn+Z)6L=WH`6!GM(=Max>C zpPEoIm8ICu0{d)7nz>XA?8pD($aOz?XmryH|8r;6+VPQqjCU2hF>`h0rZpoTXUD*3 zOXg&b;Qv9R)?&Dt~1gsbcScMw^SbO1I08FTw`4^$; z+rsH21ZIuQN5GgKy5cyl*}&PkNUXxB)4(4Q3dF`i|k0;h-7g29Ho zJdMVwb!5=qMS>sBu!B7a8Ojpr9$;i}P&e@oBvXHI{|8Qg_E!GQE$Wh@Ki&VW_>beC z#6OCE9RIQKYG$FXE&i8wU7`GLURz}T$xre<@ef{&+v95f6aF`^#;xwY;^W6ldPz6> z&iJjk1lU#e51^vLaYXe#N_(+`AU*r>EJd&VbJOhk#!`0ozc;?T%%jtB=ybD{#t-h=!Ac@Eflb=ozvT49l9% zREqMMaqFR;_W^{%GPvYhFESbiJ24m;DUSyLm8*nhq_jz*Tk?5hDa;408qhz60o(vV zPhI5ki|ZbMmbC8qtOO#ecw*s7nEAi?B6XMm(J0-)ON6+6r=U9w;=(i;gL!K*w@AC(oFaOuMch6@UF2=q41l&8- zE1TAy0r&3t_{_+b+{@?Q!K}%?hdn`B5@}Sghd!l@TcmL`2#06>U9j@m=Xd>tfBGjv z|EFV^NzD5xcqc3I85L(mo&&EibchxUO}YRwq=xn0A{25TQ4@`@6#;CyCLFpQN7X+@6lM4CD?n8+1e zs~9O?DG<5zM+3xI53TwY{E?TE8cxJzP`D?{pfcN?Rn$GQfVG#%bKI{ z%1S>}+eXI@4j`d|dA#s8=5a`x$Ct!;)FH+J0w&0LOr}B(N}Yn7$ptUtfKAM(l}%4_srAaO^h#@qN`Co$Mq6||gJs}a6(aoPi=zip52EEYE`0N>c{8zm7 z>zA0p+M01TgR&pq!*85<;j-qC=h`rbk19@bP26upqIpggxV>az7mW(EXxJW>DWGp+^U^RqC4lY@C{csS}Ji}ONvp2W%<~I-R z`u6REdA%{@9$8eE)!jyG8a=l@lzoCVZ3fDJeJn>0f2R-tlM*w{sFSo9i`ZETdkQ5% zrILj_UCbJA!@P>T0ZPyTT*QGpZxAVIHnO1%ekYteX0jBJ$52pgDK;4mBJteJ!z&|? zAwgCVsb~2HcJ?qT3$noy8Y`PD%hKCBmQF-g+y+Cr_tEt$50uV4DjSO1`?r<`rfVf5 z8Ju?21q>a>-Z-=yJG(l>?|Amp@-wk0|GkPpV2C#M5+|Dj`-P8W7Zj&~y|-~^W9oBYn51SF}Jq|dxLf%q?7V8{NTl_;ukXF`rR&-r|5BhkVh@hrHtAWtZrXp;-!@hr9&Ytn>&F|Z z1oC;iUZd4OiLWYB-#c;jeN&sBy{@zCy3?CZz29uAZXPVFooe?gGjq~q-|X5k+HTWE zSMKR+1i0hvxdM+2KF0y%Woxi*z1$%&s)r1!0#dag1i}8&4>IuwSPzPLF<&^sU?0VX zj*_K-JgA6m0t035%Vh8wXb{e+E`$>7oS(HRBIM%byk57~>twkC2&g2Cspz{`;RR{J zk^*N3&eoq;v*L!~;EJV7m!B|J^1rdpEz>&hV~g)nk(zRWQcMy4-P@-jYnw%8bc^pbGj8F!NngvN{5H(mTjg}mgM(R^~ zfRsAz-9xKumY^?7{ia(Uc&z`U-mA)|9=)n{D`JMF!PTy4z)&`I+xXOzcV0a`V2OVq zKh<16^RjQ<{=0^@UqR0d`zQ!sIm8_lBdiP;!1qkt3VUWQ05IYYcxHq>5EqbAN>lV4 zn1N>-PrN-wjRR*^h2sM|QyPhgWRZagynv8t+~CQjPyq=-5MvQoUMW&Rl_stHRC~;$ zccC@sLaw*)ckyo*`Sgw)e&w&Nf$aFF**06v+2Zj#)>f@7El5LqRHvi2SGXoi$4B+~ z@gqTFj?WO!)}ngfkR1=m{llNTA}T^^V^dhe7tUY!SZ>99)bNT}c1?BAfP6R4rNeuc z437y99+QLE62oapwzJ?P**l`b+s{04eT7a2g` zfL#Yu3OqCA24F+sr^sXpD>V9I$Q^WhD8H?(Mv8<|nxgS3gviTcws*OcqM}L;1I^bW?+o(6ZTK-MmlAdobwl?GzhHSpU?#BG1=_upN&UhiM z$ofixg65y~N$<|^QCQOR7J|+K+ao>`i0u}4c%!XW{z!4; z*~dwG8TZd@5Z0>?-3WguZc#0W?a2KqK|&Q&N}yjVhNVK}d;Y7E7w4gnoE@DamdJn= zSYwq+Owf}DN0v+c`p+1RsgvwnkOKh#zx_qhHU(<6c4$ir?Jwwz##l#PP`#II_oIs78V!8dli*!sfOX>`H_d% z?>vHa$M|Z*x`Zu-+Bf;kIPY-FXap+r0NQ+oyewiHT(hHL)t&1qOS&gkPjr_I^@iH2inTfVjGDTyUO9HlR9Ucl zV$DQ%P#b6oMY^g2Mz6khdqJp3Te4(FTWqqu%;WHs7L_*WOuDSx(b^7VZ(EutTElL; zx58xz7U@Y3X%hG1jNdE#T2YT(^-J-wgFen~QW4-)(6%lhK6&y5G49WX^wRN08f0 z=hD&_{7S$LiQkAdmR(-zb~_Qc0@|jmra~!dHDKBsc(8YH06{}upP%oZrukpBeSO86x^i~miUa}5|ZNFpjq0H&}x z*B~C7eF6KI=G;l>Ckp|Hvy9O_7Oao*-ymE zz=EOzyse23&HCCYzb5rFm|zoh$GonhLYozGHv~XJiWLg|8H{r0sS@j2NM2yhiEd>$ zR4QYW=f8jBotWb%iVe5ytQ_#?r8%;59QH^kWxCbbX+4qKa_>DRPVi6mZO_eHiwW%; zxHd7(YW3B@5baI)YR_Z8y11j_+^UH?maQOm3>Gtfk|%zWyweos7+bu=mli(?-6QDN zCub0wo0HhoDYP+sMv6=l?~jhY=x~RM;Mya-Kwy)W%>m4{0qQ-;G6-IbIaT}zYNzw- z--@sPna!T|^9(R3wd#}EWnF8VDhC2sU^E++peFvlxqyFAhL%J#|5;FNu~b|5n|MWKM7lY{>lb(dG5bG6+idt zMon1HtHgC(AAdmhMg0B}%1ru@f;BNjAGQ)cF)_plt0!B@KrLL(EIjXZdR!XTz?~|@ zct*!$C3Op_y=bEhLg!B5lXy8_Vt=W1b%W*hYa`vTf%#T-t*skX6bD~B+!C5Ru{Qp` z&LS6HiQj4V_B)$Kstz7E6d3X}lVm8n4?Q{Af5UVvlkeA6IoQ5L9$D6a>yL0(P)0(* z6=4@9G7>h>Gz5+)%GknGr5aq^mz)c z7PCgn{Qk;nw3!qqpQ1e_>SIK~Uoi_O5t<{25n1*9`*w&s6$zgd7=AvuyQ}D*->PVK zXUC%Gt&?p}D>Md!<<|adR)(MahdrA|#-9`HUi1HcWrL$e^PP;+-nI4jebu1M%Qt1& zJ;=H3Kq<1q-Za&8^$AVpU|Ul=*``uxN4H@Ps`>I*4ul*bI|bg8UgAAbM)u-NrrE6^ zf@usNp3h@SvZQ856RIZ0=$HT96s%v)Xz{x#YQLP(blsOVkb!&@$E)>~$Se8E6ZETv zJ%~jMn5gL|mh{S{`|i63HoUpCGZP)<^l7=Fx^_>vEvVlz z?pbNS^GdVP>^5WwKaxFL*6^Aj3ohN+GJ0&Jc_W4K$O63sS(#pbIy>K- z1wsw=C;m|OM`jO$+_h)&2`xo{Lr=zwMY?GDaROf=0EteN%NyCv5x(ScQ_~iA&=a(n zrCMbvBc(_bY&%3Wi7|_i$z&vcf%Jx`PMJTy=COS(imZH%aIN~D{q-Zw<@p4@t>3XH zvgM_l2imTGao^@^^5UU_$g-TqeP7vOaqH6`y2nyvkpsA!$+Ij z2SyvV-80g%x0Lr9t*bKB4O{MB8LczuBcpo`T(zcIHGSAPbk!F|H$AemC1br%7-|a| z#_`7xY_GpzzdD|tyNAC@(YO0}tEWy~(CXB+RtHDyf!ikgt{Dy$m{%Fh3XQqW-UlP6 zRvR=1LxwWj5*cYd6<*!|ExzR;;Sp0wqq}c(w9nNTG|l9PO59byuoYw}(=-9lVG#TO zB7U!|6*ewJ=M;{2xfXN*`1B}_!x05WEj9`4Hx>Ug2MceqP^pLO(&&6nZ;+AXQ|ZA- zD=8RZ658i)vB%e#z0kfq;YM#%hIsA^(6;i z94{9>kv-_B(#4<8j7{IrKl!EWdbCBMf=Nvt4lP&vbYs;>le6Dv;&;7*bEZ9hKk5eF zMHiwrZjd__v*z+jzNQ-JF@STFJ#(_IQXx$h^nehJ~m7I=v zS>%aPf9b?oRS^5^4*Z@NDW8Goy{k>yW|i8 zr?ZedMEl>6&!Qn(L)0k}J`#|IdAPFzR?~*jBtav~XnJIG3jBPQclHKqme&;Uyt!_5 zd(TEsx+X2pXYaGr*>lWU@e6a1Y2g7|#H_7xdVH=sJBMcxYQgsD-8ltWTD`lW-{&2S z`OAXYwj8rMzp`}H>mMuMHW$2}G3dj7w-tVuz%@bz{yZ|N|2H{!vfl>#rmLgdR+P6~ z``pf*&t2P6zISJ=&|*^c6;yS{v{QwBgJ-8y{&e%tIlky>l~@E zHJThH!R_a7Z`ruK#b#|;x~{QhqQ0P@b_{+)CHB-V?5QGdFLR#HfGW*21@P~zrhq-g z7X@NUxlNSSV)f0gIWOEOB}b|PvuYo74;fD(-rVDOGf*R(f0BG#Wlrt zC6yvo2`6Vx=H~MMDLS-qqfj_EhN}pYD=QpluIZ_YlLkAw<3Oz@SoUk zHZDNy3|I{m1A;7Q)WW-!F*PDef-^NDY%Qs_6ih)okW`PWFklbhvo@bctR9@V_$etJ z=9wwhP+~f<)cHN)+J>{w*7ng=raYgcx3~BObGH0B>f z{kWl`uQhtts3Q8;_l-Jfsp38k#P3n;fjr$5d>IJ3H z(p*+5S1F4T2?5U#)AdCN_nJD>)dHn4DM`}R3CD_n2nC-ZOUY!;8O2FFHD%x-63(z|okqp&lA}Tw6MAlD^*T+CO2Gwq zKg~B!DJ*uTC+sh9+_?uo8D!eFmzeN-L)rSqQ(F@AJG{U2Y~%gXbU(U&@=$q((rV;y zztnVNOHX%>bR2t~5lgDV@zwl0g#EtG($QV@?H1kFfc0K-vU#oyI6c}Vax1yVL_jE~ z1!*!Tuq3$-JS)cBkzV1YSETG274gVaO2PtA*#dl6&Y{oj=ER2Yn&ld^Okw$g;lT1y z1x*l6>Zh;*82pD10paZH>1>ZRIzw(p2`kvgil+K)iZoLzZ@nSKJm*wOF-wWI5al?? z(U*n2{kwY9T6MnH8$>U)Y*wbbyu4{;TZ6~hSQm*zthH*J!QhW{*OWB*wZ)y|Q{$b* z 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

      idpe6bfH> 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%0DK$!uDk3y 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 z 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

      hm_`HaQtJJ-BbPMF5C3Q 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≻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≠Kmp6+kN{KyNlR9qrGN)Q+ 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

      p z8S(GYEGD|1O_CKK8YRgj?RkY~r}7v(my*QG4gjEmrpguSX+rV~WuDR_L5zJuw7x`1 zgj66w>PIA?$4ZEOn1q!W4F|kyB~U)|@g(f|TH>$LazTMMUAukpTz7KBq6^;FiFDvn z(rQ$=%7JZWXNwpFy; zx<;lHE=6wIe1-+n>dMF$qLVfTE|BvrN$)vr<))GVNM=@&2id7wIxijUS;hduV?70E z2mmR>0xD#cTG`>&?H};$oP?$nzMn-U**O8Uo33r>s%mYN8;Fjk7&Js<*(=GeLo?HrWuK`zD{%q&Ph*Myc0HethN^RI<<4!Yj`RJg*1{%fXR$OW+dn%;6l$Cr1fqNSaQA$+~$`@ zJ6ps@{rgeu8Qul9sj15PrC=dmNIAc@LLnrJtKLCTrXs7{L~;G1;5t0G4D|_@v==W; zs9YFq@;C8pG90uIyep7Vb;bi%BNX$L=ZO%VlBi`vu%Z-$+ne3yzlm^pt$hH*?+_lU zRTjr^3_dCJlu9_FzwIpsIt4;yR1RMyjixv=Oik+Aa)Y3Zk<*c`J!9LyZfv~Qn7 zWtwvKqvK7TnPHo?qN!g0PH-u&QwyjWaD<-Kh<7xN%qa&2Np=!M*wABW9|@HqO!mCg zG$xA}7?^1Qk-X@lM_0B)nE%YDM6|{Emft18_OoHQ4p&)d?in4>H5GyUg%6~sxt zcE*W}bT}jxkl|><9FR?q;-FeG?*lt!_cvFQQ&TXw08DsmQkLD`>-hn9u(631tt`Mn zT|%L@q>doVBHUGD%z?}!`5bXc3*}oCDz0Ef?sk5szD(6QYC)Zz<{*kXEg}{JYI7<+ z%_|n2;+#zBNYZG6>JK+2dv(hFd4E3i)W7F0UvB1f5Lv(2l!q8KRcMfNEhOzxbh4N+ z@kTjxhkS5JS+KwLy~W_Uzl5X1@Y{B>4#4(zx+4{sMMH$kKSVR6F_Bs{s(PbGcj>_v z)L?y+*lq_kXrvO%+fAm=b$+$f4pcg>H=wm6P5m%33(TS_PAN7@(n6RXGH2;>VwHBK zl~W%MPXyOta^AYd0;osuoc~x2mgC4(9%XgY<7M&^`j_a79|5W5ZJUuLWaDD?^MBx$ zTLOLK)H!WdQI)h`%*IN(LiJjQ@ah~ycs--6Bieqa#vPjxWH`V-0n|Ay)^L4w@Yqni zuQaN;3@bv;mBQomyH#-vY49Zc0Ymsdfs>rxBwq@_oLq2&8U@q-U~rS0`@LAvIfuoO z=iZAsq6Y|{-e15!vkFB3md`HRkshYQq#H@5AfE*G#3%oBJq=L2Y6zJ9l*GFQ7fLC!%Zb!nojjQ~bWufit4Ay5Sti(9ocDao_mr_V9>j$`W^lN#^!MR*Uz^83<%_bN!WFeQG`8P`^S<#wYr{^w zx(2i<**yj7akuW|h$rdNU)Ph7Cfk_7@bL7Qh&I+rBn&r2Pyv9uH{XOuYPq)NsA)_(!|lj_`A$ zFgiWSE&x$9^ggDU;L3_?I+oe)aFg?XK!Fq{G)xFC%jWSO0Fyr>%kuyc&U3CJQ6^a* z#J}@T;i`boLrKt0LRMIS35~jGkle{{9mXcCPP!f64VRFCw7>;bZ(Q}Iv0kh<)eUzY zF5y*VV;*){6oUL|ObcM*->d;)$y*&6HaKzok=nM^3 z0#*>8DA3rPsUZxhH(z+$WAA90iSYLN{CIsipAHAT2x3k?q~=5fx%Ne~p*#{o2P(Q& z08S+^z48^Ruuga)i_g}>K$S>MNw8U!_2KWfsm^09;mKlE9>7>(1^29}G(-_wEpa+eajB0p9d&k3&$V5i zsH)8@%<&1a%xY*YntGYQ^drg&6lcG=OZcd1eg$)dO+jv4ia5Wn?=_1-$<@9#CRFuT znIa8{=Xv=#o6z;;)kVCjvU$3vPKr`UXUAK;@>MsN)r{H(MF-7vQn^R%%9E{ORhhH@ z47qWIGe9^ov}PWU7hTKLsDIozBB~JD+J?Y2q^gn1KzBKstY+>k?5|ea!cXAw{^q*6 z{(hq__R%;#3(t>F54Sfpim|nZ{*y`;6ScDgvs*>i1l&rsMs9PlYm0Rncr<7hTzu9c zH__cqbuh8DLd1Hy)*Y*=X``%@HpR=&@ICbF;J@!yazkhAYFBqFsQpEbj#%yYie&=@ zw_*itZ3JX9yFt`ODx!T^6Uqm|e^p;yTy9p&MuF=Q+uOV}4yp?F`?LNXi!o$kBewfI z6zGS9IZ2e3`eN};lw5dRlQ>I{_YZg1S52!+Vk<%OTG`lE9N6zdfOFMNDf?|~d5FxV zi_83pgvhd}!MW8IJHa`insKj_zpiOcjk&Hh4Hr*Pk6qmz8(|eG@wnH;rG9vI`L*vg zE2245FP+kD()w!D4uksQdmN4OZS@>aOQp`N-$LWGLPP@2N=uf8L~EP%y=G5LhPc~s z=H`kwyp9FMgqhNq$2fF#VyV!8Q^c0h1>=7G9C+-M2|9=3>N9Cl0wGyt*w^ZXr57iN z0tVYHVEp;<=Ytl&K)lt`^=(7%f{0`Q%%ZbZ;RGBI8uXkt4NNZZw%8jObILjLi94VgGISMS%{y(;iGGW>wz zbW0$eM>9*?&Bv`{WxO4A%cw)#TKNq_DHnprtt%X{)2t=#Xou`93WD!rs4m$YT%2ul zZo7&W+(+#j2VrlwNf@s5qe=1W+FXL=p^Rq6wzap_rp;hZDxH+9=<_z1k z1G{V2z+aV%=(Jfvy=fw@EqRpuG!Y%7YM0W9P!q9(9MGhwX~H_I*jgAnH`C!QUUHMl zFeM)27%FnmstBRI8sETZynHYj1>Vf;w-pY5&|M_k;?Ai6fU4eG0OT0V4}9%tnmL7O zFza5N_9*kiE$d*Kbhj!S3p=Q;&Q76?_J-xGf*faM@o`gMT5%{wHoA0KkLO&&4=s4C~ zWU_EZc~RuEaVALd%F)>>^WYnes;-ov=1f2j>@>S&TrM7amwQSP(4!p`4ki8pByn+z ztYCC5A51RyoC8N7S>nIw0nHhlHY9*)u9o*HerQ%dl~;Iq=-aOCI^Uda9m~AIqj9iU zad*~aypynWQeZ=J|D{fkBG->N@nwpAd0HOd`|#|SLW3DsOwW-{ikTx|JyKx+*xMM2*{aY z#ZL9K)YgLkIl46FEoO~0A*7i;NT+*%&>6`S^OJVry#!oj>CX5aGc?Fz1R-RAqOEn1Y zvL+~QdG5h3H+~Wsrcm%6n-Ya_{^nr~5B8UX{zw`xW99flk5TJD{?1_59bxyG)}&6Z zo1GU$W<2G*B&G~S;;w88e(s6TcXs*PmxueyDM~EC*JfWcXrxLGMSOm& zgu}p312uf}<#0dBpk(ut3z?G$+N@;Io^j>Q96}C9z_%c1YneXdT{9D}<--7IWt`P= zNI-sL3kmmTetJ^JJG}|tCF;B_Sji%o?+E^IMj0ffKnHh680KwV zX~URx#f7^}mZZZbrP)bSshK*_wR!zcjHClErzwT(vHA^IEmg|PG=aE%cNlf^F3r31 z=V$LLi*ylyzZe?8L z388jXusL`x#CQpzdK6O#fU*TR07|+LBSyi^E~Zn3q0`pcIL*2fOySiP1E- zTNRmro&b+8zMbNRHjy&JdWXdqdF?RYvqSoU7>e7tgufUwRuPNS6_)XDKiI6*415~T z$MuhcPmbc)MIc7nhhDC9zjaJ=Rb2_PLJ9v-(@My3e`92TAVIQ?Q+Q85l*t*7P$Xkk z>1-C-NYxXi4$SJj{4|wdK3#o&0C@B2@VK7ALmpBJ=GC!PZI6`LI|@-9H;r(|Zfc$1 z7o{;QW`1~31CCFjVmc`g6vt>8L(x$^tE(>_=|D>s-k)*_TSe1I` zCv+`_ZY`I8C!-y{ zxit7@SbCY2)M(z-ucxV7S>U`*HaEBFM`_#tvdU +ZY58D01Y>lL@rN1yL04bD2E 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 PU(U%VmZ(G;Q2zUWjonux literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/fonts/Lato-BoldItalic.ttf b/docs/source/_build/html/_static/fonts/Lato-BoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c0e84bc7942aeac19b88c3628409e19d7406c07e GIT binary patch literal 714640 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�Lazn~W%X*UQ>wj6){V!#X_nKlq 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%0A96e?Kj_3Q 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%0D-~aoil0x#Ux#s!Drb;-?_f)KJ`$G8i0sIU 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 literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/fonts/Lato-Italic.ttf b/docs/source/_build/html/_static/fonts/Lato-Italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e7a31ce36bde2885edb6927ef3753becacdcd640 GIT binary patch literal 693228 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


      ;0G(c;$%T7s537Imx+@60C-l7E39=l*&ib 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%0Dbw0yte#{e@6?eyKPn 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

      m0T%Gg-y7=$~uliKgZJ;I+T|d4XD`wy5OWwdT(c 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

      gfV& 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%0Avjp3JmR(d(0EuB>c$$7cRVcbGI4v zwlV;luLs(NB9HInRp`BO7T<1S#}x*lYjlSES5gR_Zb6eYi{_>0P(Qev&8GeZifeK8 z7XH1a;s>~1gt8O-vc$?;Ih1(~FaXS8fLD)-v&2e*(3f?<rkuh@7W;Fyjf{I_}cmT zyV1bV>eVc98n-F3i0T{hw47s@BIpqg)QUly8Qh=H@n|$>!t4-+*)6sxl2`T}d z3c9e91niM~lqbvV{-O*bIFP3{64cv158KJR5UyC{#6kqut~ z=1u|u^sFMSC{mh=5|&%W)|BYuS1xSkm2be-bB2T}U?Y3cfUVR%^c3Ph_Zn&y4H=Qp zL3Trt6Tl!U*NP)Hv(VZhxZ(S5Dc2PkIa6vb#JuVef}etb{vrcBO;xqIAGC`0<6#&6 z^S2uQ8VtQ5?RT|26lXlagVO8iq5^6G2?!A+RFCt41qRgCN)(q}A&!pL_2F-V(L66ifbd_9*2mx z173s&5h47_mF909&?wrFLyj~DFzcF%A(kl(05fu5jK~tnMidKj2n@+6jHbM3z_Uzc z*4z&&ljZTtYv*^r^_stv3pf^9i*|ItUga^!abbol>(R$J2k18osD$&(6UmNe8H`i? zuzZHWkuePnT&Fv#*bM?b7m+{dTvm66*0Qc)w@ko?3a~qYIwbl(79sDRsu83My`(l| zNFIv?B@C|lG(tW4aB)Eu)us(@I;$=I|7-VOL%XGGs*>SCXC5M6@A1+`net_W?kKyg zdIK};-aH%qq6ivNp`ZkVU`Yg`lS>hT={Ke)JTnI7jS&8GQuGC`lp#xB7xp_MveY;TPu!}G% zP>7;c=-AIQ$5h_Za)FCOGB*n8`3zZAuLMgO*VXgQsw~pjytq&vyXfA3_pcI`{x-5b zLVqF4GD9aUok=Q8#nORT7>I@mkwx}tTtrFAySU%8M`76y2Ttd?X;V|{)m+17Sz_w+ z-~8wIqx_6c4Qv*|zh2Jd_s*{9F^Gx2fix8}Huh;;X@{Z*pkwUI zZYPdTc6BarXX87B^vai^B`E5o$Lp0ATw$Yj9(#Ngfq*&gSl%6Mz`NJ;7RYt0GP_os z=z#Ml2^DayV}64VZMS&#xL}_r#PvOGfhWfG(@}V@D{XUsNha?qO>b5PTvd799WX%e zc6&uiF$v7N*0&GWRLh?BRIfX0zhF=1-|!&8V76aoaX4`c8uOZg#-GG^pveTRU+>}f zDeV!q0}kQ(S-H)jvu8lcVD}31U`cc@ZhIkL(Jd6;nDi=&x&%)ayj;(H&*Awg>uFDB z(;4il&E*%&*P7V&Gy`}CrV)nM&RO0MF89^*QJY2)jRbh7Ex}2(MjD%B2ICIOdqGZd ziiLe{FxOjE&J>GyLM-njC0U*P9Y)ZP>0!tQ(mK~+e!m&ob)Xp7z~YCGPC!7dcC{SV znJS#jlwsLp7&bdr8s28lq&zZAI8v>tyy=`Y8II*Dy&e?`zG}FG_{wo4Wt1>BH_#JhJ2~78IHG%# z>rrX246@zH$()seD{Ja&c`>i{PCDuPX%UXtkQ+~g$Y*`zMg%g0Ky7B-@84ZsoKEj= zPt8{4uB{>K4<5>SVH|Da#a^`bOP}%jayzS>X;Xtcw(+=6Zckx2SGu-FQng;S2p*{5 z=)XRqC0hmG$cv;`w4%isSsDgWV<{Duu&Y8Xxi{8T4l}0aa)$nPv>orVFM^4Q-Af1A?seM$v+C?AA z;}XWX4HqLEPQ4=FxWb;?7Px}vt$}cUHAwFwmstkSoXiCw$VZfWrI-5-*+5!NgH-{D6jMtc>FI6JEX(aUp2eFu2+EX zN5GF6-671i)VMXDyuIXAM3KUK73iI9Nch3q(+OBLI)}4F)G0bI7-SQO#_kg%EYlpT zw=&sV>dZb;XKDq}rujE~`lyG6EVkQr+agZYL~D}AGz36Kg@)#L9+GL3Zi zpB}(F$SPLzc@#+~Nl$?$H=7p04T4V0VCYI`HCGy+7v!ve%?r9S8cs7*@`{Jby0? zIZ=UZe+;s?>@PFk9s)#h#e%%a;gPA<&cE86J-abmo?RQOiYY!l@w;OD1f&G1YxA82 z*KK^(YNGRS%dFC5{z(JM#$6R@2lTe9lg6<#cbB80{r4iP<3o%FiWElXtTa5)$jF96 zSk(+)fv6MiMA|J!Mf>ZKp0gsBncsU*1lMYjl9yxf_uZLP(Mg$&*c0gWabuH-;b+EHv~ZdOFpFosi&0A$0Vc z2&7EHfa@nO!Shl!A{vh~_WwQRwdVipMaAUKWO;eC{C%3Yv?yQs@#?>tM<(Z8r=B{0 z@lg1@LxFIM`lzcWw@=aKQJViRDm_X11>?9xZQ2U?he%teNIn&FDX8Q6s0zTV@P9cwNA-r|IW6aOmM z_SwqUONQXm>c5vDriI~?KmY%eQ|#wGgRqpH5xSz>Xm^XML4!4n^sxR$LKvbCufK=? z2x|vm)mD+Vn~f+2wvq{6z*KA5kTV^1O-B6E#Uc`x*=Pi!h7EWFgFKVuKEMmzVD>qz zH;OQVfENK3q4Q`+1R=syH-AJ{#K!j}k&2b#zJB1alCE+8Do~4$4rYf5Id+%#A{a^+ zGjY+ywE%wMTvq@(RsG%}Ib-$lzoT;(tFJc{{P^L6`xh@9JGy(^{05ijjNm zPNLjk(kGsoZ{;2zs4!dfwe4%MgI;R+_`}`xYL*-n1p}k7XJ8{FCgKJ}d8PIm4-aBZ zrS?aeaO-Ro>F-?CY}MA~^Zpsf5ssmxKfyBh`gWvfn#~B| z4Q-scM1vg5lK&8}ec>td{J!9~H@hG2f4qHwTlvP-KF>A_dwLgohWC8kY7ZWMQr;5Z z-Ns&mf(6)+6oxbzx6-_9Ku<^zBsoU=sI$`zPM&8dbGwBM6$}{Cpy^exMwqYpZVn`(InCR---zffgZUPe&!x4D9xz1@90hD*wt^{PvpWUduvZ=Ip?B`8!Cd~wX zzX(Ql?bKO;@b9!oli&^=FGfe&8wsXC1V*RWM?+~+qp%bH+BA%AbjD5KED`|gX2Cw( z`yQMMC$YCPq8>*!*IZgJ+M&H{X-^L@HPLF1XaNTTDuP77?Z8@21w?RL)leI-d?ktP zy{J8}1|+9Z>_&UG$_VRD(!nl5p|c7O0jV%0mBB6`t3x|_8G+OrcTYvOM#Y#IeOiQ z%u2k(@MK%^+4!YsU|QxKO(*HpFYP8jOn~=qJ@i~Fv_Z5hsIV2UgD6=JC$?@ z$EeT{T$XF(u>P#a*afFXbCzGLyM;GHli1V&%;V!XZ ztvqpKE3YdC1VCvRq#1$6%KUpBShA4euq**2cX#>mqonw{hz7BKO{J2DfUyvy{4B=&XJybEs~MIo@>CG|7d=C z`hXqIbL?%a11}hl=AryzY6T2<_~X*OtQ1*8bZXY>4`Fe0M!|b2%;LGF?8l`uK$#LyTPar=@j?S>Uu6p zT4u0N@}_!zql4TytQL7{zPaf8Yp~|wH@y3{YuYhgA7D~k;;+L{PeN58t#{|iV4b9Q zDY=IaY!FnHhP0f+A}U8|njhjC(`beurO;8*KNW*YtKsx>Rpg5-8L~rX<;zt*yTC`$ z5<3JZ=4&HX;DZ|-Y3je{_bq|9%(uPPtUc2dz9}>_X>((3B-^~x)m)U({3d_tTv_~? zeD^bnW{Yso2HK*cyT)o!ZC!Hn#nD4_eGE3D){yPHvgeliIm|l7;aR%|b?U1Kxa*REhJQEM?+1GM!w93ccZ&@Qypl7G80}z zl}dZlQ6v&C)}3jWfG2(OK)c4&uh|01cd8&GAzPu8wRnUAhw^}cu0@xRVJu3g$kiLQ zwz#VJPm+xN>lz$x*VFN!XK0DaeVA0hVK~;O4}E&cwK^+ryhDwkk6c`lLCQrIz2rSJ z>QACC--$u=>2WfyR(|vC@yDkhH>>e}vNyEKs5+V(xf)L0A7PFkpD`T1%gU%^+HzJT zAv~jzzA;THedus+Q@`pr7F*Xfdj001HMYmlsNb+=DLt|zc}kyFH^a@Egsn#F)QcLH zw(6j6>1`R88Ty7)Rj`;b(>dG#!Yrl){qtlTaTVnS;Bv!Gg^;>G6v;!K-9xfpZ&n-8 zZi-V_RG^w&&_wfWbd_OWp>(3b=p8Ny{@|>Um(2zhxnRDpW%?eqp@S~jYYZYm9vKCl z&267|9gOcG+d*W=laQV2lD3vzArVc#XhRqqUC!k?ceRotf0!o@HC&Izrg=1TcY2*4 zwx{pI_r|bl6+P#Dz4wga=e3&7QI04Q^h*MJ-D@vc)k5B0O1L3?gN)TGadmFE@PvYE znc?&L|9Rs=s6-z*T8IDD8{we(S}c1+Zu$4+aBG-hFz=0MbstIA6wQsWGcjS+)1zAv zbMwmq1JG4S5q~xak2EJuiJ+f3zM%A158TV41tsiYU)iT-qB}DF^P^_S-LzY{sLrM< z5Jg+IS=zP~w*~^dByB`fedVVrXO3?EK%g~(-~%4zGY$BEvE>CaZbE$eVv$#f!YZ8r zvgqb~Jy3%3TLS_%Dz==gq5+vc4~)X@-UJPBuc?@pQ~-t-%2UT<@)L{rSa&?VYK+5Z zHP>&7Md-HE16emk!RCVOm*eGU)7N&{)LWujDT_S4!^9OvH*(u=CICcID$7ZNc&b@% z@WI~0Se7JHS6CqLQs+Wc{+HxpSCacxI$QpnxgKi6`gqt%grj{1**^;c(gw_ckfFh;eobqyp}Gv_}-5IaIl18 z**#HNW!fQo{6{Cx;MA=QiXiaf%rJbDe~ro<+*pc`^hYxFVf@iu)G;(PIjZp+nZHP{ zR4;c@-NYijdkCVOdvyWm#HgFq9bjC=CPeI6!kaFr;juuyJ;F17h~#wylQvbj5pnn- z@)gN0IQ7eaRrZ|X|I(FqBnbyGiHVT^+4R;+xICqY_(1ULdUo9vODT)Ia_iBkU8so6 zt12s5@H3|4%zHy+Z-jsc>!3I1FGUeRJry_2|aR zA+Wdkqma-w+Y%heD3#VIZ>dgq-TJ(O;yG8ZB_lCfuVee5KH;u1`hIwtNa;bNkaJ6i z%pd!^{JuN<7dS}|)iKiQuk^W;JZY+8s)elcD}ZeIR@flD{aSu_)>$SeX|&j}#L^&- zhTDb@Zk@ubIi>~C>G?`KVPIKrY1z4R7m=k?Q-c{s>H)9{JbN7%`l;#4j_~1ruU!hC zB4{q>AP|HF6c)C=Y$qlT<>A&@{A+0m@^mWOd-9|F}x31mvoCeG5+&`Q9tnA~DJ-F~}8HKpIdDRdhk| zJwufvFv3XZQh|bKR62MK!f0xoMlc@VF)EosUCX80*H&;8^y0yjn+Y_=L2vBtFV|q^ zKqI`{zbpTspNu4R@PBe*wBoWKPDbnM1oe{QVB}7H(F$ehm9lU51o1LRj}+m%o0n0v zv{h)sbP^@&NhYmUjEj-Nbo#!wFAo)}c47~yWXGBnf%oH5prJNV4nVPO=Pm~VFbOJ#Rfm9AySk%RGVZ0DJL8I9RzO=Aiq(^Bz! zyx@^e;xJWEEr$wn?s0cbWTZPI7`B-)cW(GoN@Rs+2s70!mM6+mg|-;)YMcp@X%}p` zm~C#(1n_ws6K)kQ`x9a+gz%}X>gUEsGH=jCmB^iy<8*O0;S zGQ%nbt_pN@fbCjioI*D%2N6zI zt?+C>>xv(I4PqBq!lRj1i?@GZ04?0>OtZ~*vis(7ed=fJ>-|NjE2IivlI}gXukjr7rxM``~>AnW3iIW z9dD}5O2M|gsa((W@#NU8M9R_WBpUmbY|#d?H5;yVw%Gu>FmmTbCAMRU194czE8ljM zQ`;AC`tbc{&5}(e=ZD)pIhW);7D>1*)op84NDRZDmJnu1c1O#!8`2S5Sx(?*5A}Gk z^MDh0{Km2Q1H57tbWQ$9T8FUjKmhWg=0vJ9&DurTN%gH%=cUimN*&!baEzde*U)1> za>0TmIBx(LT`#oEqxK@Gi((m=31h*v8^*$B3i8!C=<*7YxnBX*PaC1r2LAE5ke!oD z@h2o|-`r_eO_^apqvQw!Sos%oWsALuM3|D?-(`q2!!#Qo*Uv~db0~NauZ0Zex_OQGqmVZ&)xr)3C&|m1+p{}@HBJ+< zQJ=>YD2EPG2wn%Qeb9v*6O-d0_6RIe&OLDHfMve~gIY`O1K+Rl(#5?9kB!3=C|saF zyO?erN@Ft~P^cTH_y`^Z%KtUt&?>LyBRtDud>q!$51fD6x?bx)8!k#;?&0 zrUx?}ldWG{>E(m5Od-rvC#*^EY{h-1DPxvM!@*ldTfNrCn=>|`Nl_HI^XAL6VyE~t zC~DuGZO1Bq|RM&LdN%m>IJ}47+MSQA{7{7zSP{~7UJeUH1 z8t6Lo6Woa>25`)Ip@xXWH_S>;U$<)0pjY}|DD+Un z7Qf5hXokK?>t);~U|pRdjIP$Yk*?!BYwPshRzU_4L7p`SGS4#gsWII&fRd@ok{Si& zS6J1qczT}OQ-x#cCb0VW2l=Q$+NEUYRBaO-Z90;J#S;9*upWGNOK< z3b4ik=Yu>Z_#6)pk7jBSP;5c*YdAi1?rf-BJv+no+)+*yJc{=|F05-dTX{57uQ4BtRv=o;Ro89v~H!1p8dKXoc`1LULyHQ zT&bN=8TZoomy1+qhJLL{;_SZK?9d<}$33Kaq0=Kf9WfD?hravfjPNsxKtN)*G@OP& zRD@+z_mOWgS<(B14SvVx_;^5kqPW&4<@YE`)l5>QbuBhD{e2uQp2avW{;3BCw=5n6TCy3i|Aq{_mo4{@%3jkcsyt7aBC3Q68_Di)k;>Jg=v_r__t`V9IQLOkS=b%)M zJ96F_TE`ghky2S3B;>}Pi);J+;K&R;M~p77at>3CQ`|1#22Nik*DWXjXpUVOyOf^Y zpz6v4+<`J;>{0^kg1EyT?l~O!Aa-lKiYH~~hGs?qY*@aC;OVLJC2i%nWbd*27{d=Q zV!8bZQK0&&XK2_Bu3u0up%oYWO2T-Cd8u_jOOT-!(ZNcNa}3`$k%>@@ipzrjJPuN< zAd<`E__W~YfF``umSz*a{b|NrefBiAi124*tYbLqEI<13hr@27n+|!=!=u`CD$plLLo*#J z*>%~ioGeJd~w{#H6 zKx0d;osTTC6b@L3ot&;u{XW~PauVft;L#|mq&}bTWhG;;8`z2mcTsu;o6KG(GeM!u z)S`kYfayZYf5~vWjfp2e+M|Bgm6WXztG~s?FqVR|95LCz&^DJ;dR;1hpK^TE2j+lK zF`mfjue;3ej}%l4L6k`+oy$=VjOC@zDeqee#rwe6#`Eaq4@r(b1Sst6jYUzEATW)S zqWpClNZoaoJNSibFuzHQTzMq)mZ4`E%J@sVaTSdR6P2Bn;$@g-JpN=|=ZBL3Vc zUOaq*C^QWlEUhFjA7xfsHb>ce#l0;Mw(k|MdWlatu){&tP2i=E*d6{Y+{&6?N74fa z1jmu)@S*^jzu*DY5aHbg3PB+pxE>eq?fpCXwTtvSUmZx5-bwE=>73J~Cyxe@#!5_j zIu)42Hc6971xG!5v6-A{vjpR{@+RuzQ}7(a4o3k`zJozm81qwaW>&Do9g4W}@F)1- zmq&}JgseY<^U^`2H#t-o3a@KK*DtomMV+XTg`Esd0(WLj%E4oWp%$91Ia<{ZBxPu_ z#J&rj(7857e~MzcmvJ;4%He4AmL6h@+3qX)e1rq}4^uD$exkpGmG->|ja9zNrw6Qn{waFLzKe2ubJ=N@p4HXjG% zNhC>@e?yJKMYA=+r}p@^X(rDo$`0FvcFzspCg5+cqDgcy>Bc~((dk-aLdz51#)cG6 zmCXSMC*?XeSSilqMv_kYz=iJLJu@$7{yW8+KI3$;;Et-OOYrU zi>zqi>p8KNa1gTp@#X7bUCUyEl8!rN3nH-yGlU(qWzb_%2=i>Y*U|Kt+Y4^igR83K zCX(Eq@Jg>#GPSHgPQ}9UNuf@Gf>tE!vM4XJ*@%(35q9uhcwyLeIUP>$PUI>u9O z8%7^|hyRkwKD4fFz!bqNbX!>3RW6^5kY5tKrl1?8R$0uy{fT3Yn7EjaVm2Um?VJwN zIk$HZ_CwWGzAn~rXd1G}zA9eTO0$p_z)U0NM*$(wD_Uobw~^WnzVY3OWcjdi9yrK@ z)I*hSngro>U~U=s*Y9X4$e{w{T%JHdz)kSb^8Q+{6B?8x_tQd|)ZEb}LrD+Sj1*bA z@KGcQ9cB_Mp6Fa@Z?2zzv41?uRYk}7WmL<+5}Dl6ACnnk6#<+DO^hC#eR$iGidG?jf?Ze6yheMz3BN=}+)t4Zkd zE2vkaBv=x^{}>UFHn%p<2Z=FNOG*BtFJdvj?{Cv0g((AUfN=BJE(OP)lEn*YX~Od@ zpgn6vhsb3jRX8uy!-}TUW21BGtoFyx3~8i9-gUCtGHFy@Kv}|cEcN}cHhCQb&lD+;PE|1b;yT}NR?{pCAF_cYQabX0s)KrEE5iZn9r&wS7p~#;>4MP*%Gix; z)q-O3c;)QB`q72F7ElCg>z$~;VJFg}26amNE`jxN>Xq_R$6@qj5eKFK4Q@!H4tjZ) z3neJrA`fpWT2zipIQ_lxtT}A`VdK{LS3UCgZ8eL@hQ` z1AZ20^~nf*M2R6rd|%QE>XJ$y+Pqcc+-!-)#*{W{X%=&Xb{gGfuq}D)nsm}lq7EFf zzTOZ-i>^CgBbekBga>V1@J@c}{McdfG9!#AO-;UrGBIC?^Suwwq)8D{L>D3>(r+9` z25HlvzQ`rmfbhk#_cFv6EFF=r_z_`|#BKmteCN57sA2w7n`G?VWV}N*8la4hAsTWc6eslPgeOY#Gr%NP{Sy zar<{q(@AzLjvDQW$jZULPvf4Xrl1m74p<~|&Fz^e88(4FyUyDXWYIA06F@Js%|02x zy0PDqPYD)v`p-_*wHP_9ZK2lXOH$dgn$MzLS7z&J?UN8o?WICO%Qh-ocJKiN$Fpah zS?b(ZiBxp@Ihh*NhqzYi&_*@y`0Jh2smF8UdVuIBXG5U63kl0X^K;46l44v8(3Inc zR5aN+3bx&*!KG*gpQ1W#*ALZc1nE2I#3sK~d* zG5%*)1qm>(6YQ^sozBx)hgyQ zBcp$o$1ZCbpf5s6WV&Ta2Ge6vc9c}rN2Mtv>~Ja$%iBF~U8Qn4g;YoD8T3h6I;8P5 z(u|&y;e8(DA-Q*N(b2iZu&3YeF4cRwzcT#&`vZc&VVDl9D^Ctu)cIJ(+L5cE|>_H^u|4^JA zqC+F41ghs0kxRwy#WJP1cx2S^Q*!bZ{h*MP=C&O(nUkF<6`3ZZI=XSDp|otK;mwpb zgx*Prp>eyDJUO`v>@Txt#fJr^Y_Gw%mBPTH2BF~vNu=Pl5r90LSa`IN9hm)jYRLtb zxQ<&FylB_+(3yt-2NLkdS=MHigO7g9TlYF5gwr-nRSs`3>Npx zcD@Pl1}$$1$?m#~5VZd0hIr$h!S2Kt&D|4N6z@sjPMM1Iu0Qfc_ILrwI?jU^(o$jEsijw(#m z1@u`a+EbCwmPkMbH>3E3b}9LoMm4d%$dNsv8rMQ9}QUh_pa+v;d`9XX}0z zEvOm2fZ?Bfj0M0p$Qq~Tr<`=mkzyQKw-4aVbJU!{kTQ0%cp?71gBk$rRJuNQBZ?b= z(+4Ip8lLU+P^LO}*4ISy^tP=R*C6cPGAbaE#q6`@az^R7bi^ct?feF6_&49-G}|s= zbO}n1-FoN?WiK+cXC%%zkbAN>S>*u(>ZS7lv2dG@Yc*b*jgTaf8i(D}5neAO5TGG) z`)ai%DqW~gv(BeGZ?8xS5Iq+-bob|ULJ*ZuF2KAw1JphYmu_FM{9DYFCQsp8tT z=q)A~2Go_n6vp|9H_Z`4Y1F=8#G&qUB_Uq9DtiC&{%iX)OPuD91mvQlI5_XLYR=-) zTt29pv5Ae}Kmaps-+|KNm|lAu)V`73O($G3l+F}Kp39qOWG_3##wYa}{+J00Af6;c zp`T*&aj+0Gs?jJI!i~6pv1c!opoqj}_^o2M)i9|iJ)@#Udd2;-uzr={SV{9`CGBYD z2(deD2Uf*L{W%GkY5NXTeznMQ-7G@{XZ*`QsfAj!r~6bV4c}O&rr9B4vkc+an%Dwr z^yi2XtWPPCacn3HEZG)u8Cv?k5f(OxA~yGrEGR;n@f{IELl<)vML4KVO|-Rr_Q2A_ zu_QWu@B`+n7P12OEmcRn4yNY}qTV9d2r|4D94w+VB7@w>{sIPj<7z4tbr|jgb0s4g zC6)=36AJUuIt91qQ$!3DZ{Ar?qZy6o!F;}Fw%OCym8xR*C-1MeKT_tfHrVtZ#Gb59 zZRZ4l71th&bgq!B$Wq$~`NRd?jUUE0v7>8>3y-~(RfS)oOkLIfIGd1$}}yFP1C z>7`V}Bx`7$bP)wSW$Uoy#o9t$wD0r*8`922g?tA_f^<3QKz$XF81Cp^+KXCM4%Fd6 zhSzfoM8aRo72&%1gv7W=9A3t%d)-rCr|V$7I5=KuI@@Aow5eZ`LQ2b-^`HyYOKkkd zxB4%B5gOt>e#xuO{{?d7=@{n!TjPHqe5Rm%803Fp_|N3?vn#yq4&8Unw5;n|q{SK` z8Rsp(dF{A{Lzbs9(a=&}xU3O3!|s&RK8{Aurr(PEk#{|p@7|tAo0WAnDuq_KzC*I; zoiv1aN@|X!9IP3fpGzlp7Nys6Mdx4Uvq`&YePQ78j}9M}_fk!;9BPMl`PL*cTYejS`||RnJADo_S@Y@8BSfL*T@6XR)7w5AaMo{8C ziDMR@(OgkH7%9!++7l@0lNAc`ZaOh8`dCvhUz^M7;SfubHVepIJ}S{X1AMs5SNlyL z1ozB{w`qDAR)pwGZNv%(%s37b)q!;xtZnG~w8mCW4rv~0l8;OMCr#Du+Jvm=uVzj1 zhPkkbL8D?;*&ZC)mm@@Y+URE`u{BYhBBw50&~9CEO1TTMLrFdEiAS;)GV|r>oN~S( zp*8|ln`H9cW;V@F<>}iWhp3yA5xi;MCQpMknQjyd*D;rCA&)`SnO=RkJ$ME%zX&qH z)D&L=J^488a1%zIq?_nU6G}m2#$6)N`C*VUigNJ6S^`sV&Sok{88DXkYP-6KGFaD~ zqNh^5?55LKvmH<-c>V$Di%k~tQc1Ou@aR+^<3t)Hp&}+zCW(UqNl)BJMpCCF@TyU- zHxb5BUj-{IuCddX3MzuPGzgv&D6*5KEWMf!E?$jX+ZNZB4h((47OeSQlN(*CM>&)? z08I{7afU-(qO5?F%_vy?Rz>2R;@ts0mKDB}V-6qg68s*^RRYoAa}-Qqi$gLn*~+0= zu7YSSZ#fHSai5;=BRO`Omf?;SyaIFT+rkv}wVInjyg(dHyoPmdnDyYt`&9igGjG;G z*VaPVm!*F2R!1aKo?&cDq%pY^%+mm9-{H>>IOnV{4z(jETjMCl9acrue$_-{!%&nM zlHHPEIzM(4i(br~IEb4jCOzYun6Vi-7Iuf*yFj9!9ZWkJtj#e-yTj0;Ez>SSvf;Q2 zKEJJ7JsL9ZZri?<8*&HM7MU3Y8QCabpAaQg-9WUph7hOd03C0aM=)o4D4x_%r@+P}8j;Io@j zTAvB$$=oNv7Lj7ob!JRvi9oF_bL%x!U;qu`EB$+UegsD@wTEW~PQ80AInoCEKjVe7T5Ho>$DZwxv%UQn6>E!weVv% zV>zvD`RtE6?dGBi53sC+C5ke7)vWU&9qWx50{Pk3@7u3;fFqFGO}PUd-y~M)i}cmr z*Fc^X6pckH6Hm+N4UVDB>Jv->EHi(|B4T&F4651kgJA)2Tc|Q zO_hn_N5u;q?H?Ai=rE|YRsX{##$pf=fm1(D5Eq90$h=%&yj4j=-^ju_UrVKvE+irk9F;|U9wjBmY%{HkLsKVJ!CBShQqqoHhfN~yb0^Y zy{v(aq4E)BN4Q6~7NuBXmp!^qcQs)e5S8ajR>DXQE_NhV49T@<4^jPqeI=Bx!d2@w zN+ndm8)N+#Eq4CGrS2HR=w+YHi$XP?jUfGguBi+KCtk8|M?>S=jzVJvRl!^N71q|? zjssSbDUAUyQ`@_ACs-BP@t*LiORBhR%8 zyYNN=3i^@(FZpn5qnC^OU+CM%*~F3RGK?or_Y)t+EelUyM@sS?!uR2b#>nSIFim|a z{!M{g5uMNFrXMNofoPQ8=<#qoEq@)%hY zTLo7mSdw!@%!9B2nZ!fakX;%ZRy7wA>yC_A$n1xGpdQ-BfQ*KmSC1!Z>trb7YAwM) zFS*xAuy~7Og5Nx>{-tHtFv86OAs@{$C+OoWdm(b1>W%D58P9x?5RS^WW$;nly7+Pw zx$?u&>_wj^w2OA>$2RSz|IoA(OP&4pwmQs`&fpr)Py%2|X!7DS5AY z+-HbJ%IfP9Z{N7?_@Ej+IqqMdN{r?xB;0fl4nr|m8y)+2x1f&BZtGfni#qyTffo#V zmh>TnK%j{Z^;!T__aH(t{iC>JUm`i71Ybpt%2Ae*729||#?FqtjGZK@=L$U#V2IGY zkp(yM>$!XM4;>r{*b+ZAqfB9P!{52ck4O$)&w0GNOOtKRo9wTy5?M(90~l1du(BYD z&)&Kfs@0eZKwa>ssC*(y;j!SUNX+ESUc59H3(BLUEFvU=8K3s%CnqpOiQ}LrFdde#X$P-PxS8EZ@qp-x|~n-wB#$71*k5dPT-Z z(nQO{d9fskZRO=<6kCCMaKqzKx|b$fpHuY;*B$*|oK#4C62ODVQR{4~Wr?xfma(!w zZJ>u`hF=dyw@V zdeN9Uu*w0e6R?UC1X-Pm-acM$;0MgRgm%~NI`ly?eBk+m9v&P}&}z>PbYt8&rdRc2 z9q2Q{jHJ_#a8w(u@)oJCyhknig!Z=u`J|dv9chCe&j;r#3AXO$@s>`gZHNap>ttluR4|$o6obxIb{iI73vY9*3xLQfjn^+Ask|Y{OP)pF)b?rFU{Br6{ zhJD2&05*|!xn%G4R*k(ZHTM)0LvIWkh9g}`;nMKR%d6aYiNuS17>wk_)7@xqhgi$JZr;;MTaDw3xK;Tn^QWO9K)L8C+x& zjeaBOebsycQ-3sMqyy%yh|-A!hxXH_Pub7Q^wMnnAsgmz$c2Q>cut|dV9*8z#TPhB znVYVatK#(FlRzm^t~VlMMU6=QGv}$Jd9eUUDfo5B*upMf)mM{YztvRat-=26p)nTv zh&jZP(JQELR3k`L;#g%(-@96e^7BfFWaQsoQ~ot74TF!e;zEPsv6#o28%p_p1 zf(M?IehD&NY92r5_*oKpZi#7;=M;>KN`cD4(HJ`IXWsO>9WDQG^2-ME88&KeH8<7m zE>e19`7DWkU5+RU>nj&6rCI+TXZt5m9-8MU?Mh3itlGyjJxO9P)q}T&T9?{_*M6d4 zAzxC~&iBnp{Jb<| zRTJCZ*6~xmB9b-ob1#1dXk9Z=HjD!k=B55}+D_l4ulgYYoT8{VK$vGuAJg>5yPvZn zAqFWem&M@f740FTD%j?@t5~KoRj0>2oq_+tWvp~T9F>wfo%Wkn?S)Wq62bso;ARB? zFT;6EAQV@NA2!52tV9=2QW!NDRy5Jz#b@KtISch?SX*Cw1?UG;Lw>Oe+%^5^T271H zzhk1F@RDA=MN{5S$_op2pitbGn~?f?Ie!gGqVVuIa;P$r=I>Va2ROAo@zD>%X_oGqN5g8+fOwo^m zwabBp_vrC5h=X2@rkK=^py2o$c(3p!i;zfNR*LOrInv$_$HS2f&&{X$@~!9taVR*c zpY6x(?sV@7)d)#Km+DTx{0t&Lf0wJgUP}r*Vd?`CXe0_~UmAkH!21~|<&BXTWd_)) zk8W8Qn8n}3tNna^rVBO2l(@?ZX&m|s%FZ>rqT)b@-3qawT^9kFEd4NmW`^ECe^ife zmfM(xh)ysI==%JN&~b`Ci2Uw~t9}0%C(kpjh24f)+jIXKJKcKJ9Sksdg^u3&6mE|= zfe6_#*GZpd=1x5g+qx;!UU^UcZ(i8#rV|(EZ+7o5PpjqRVfxVT+Lj7}S4FLol0%I4 ztEVT<%=dP99z;Q@%?GqWGnAIJS}26e7> z1%<@jZu^>j!bYdi<#tU&nu5!*$r`wyj?U8dZv34F*F{m9u=~$;ir%rco3s+RW1*oO z?phhF^hU=j^GM__{yIOx(3z;;7e-cX*VrX@*6?L2pZa-8Cm@pA%kO+Bm|+OHkL;WN z)6n5nQ^;9Tez(EWLD$pyx0+c&ta4*3&p_^y5II+(BQ^?j7o{UK3$mSWo5gmFvv$Jq zN_J2Kp{*&%ad9#rj#zMMq;!CGk5X`n#6!`?__RqyPw$_EuNCyQ>vok0Z5+LOcL()I zhELjj&ypJ!7-n9#*wqauExR6j1n8R^$Z8Y$1P(vqfwrtz1dHCwD{R4cHE^iT?V+PD zy4FS#4ewv|mRWS<6?jAT?lwBS;dN?`?iL^U>CGUG1myZNF zz&-4w8!*S|yDS$;1QVD})c2X#3qk^^RK9*&1X_FaNfEEO8QfV@#L8X!j(FdL254sfZ9tBFS0eY>OlUb1ORL)U zQdNfZvUa;z5DDWxi&^`u*h;V|*Y;OkTz(13r5@N=e0>RT=4`x*XK($77s?OuA8SL; z75FZyzO;}5h+<5!Ra5_yTkkmyh{9)^6tjhf-q4Mok@1vJa%1B_+35TLrvn@|POh5b ze-1RnOufEw@dR55aer_e-#)Dtjjtf!2p#mteW;_7eYqxZg!ql)`gOq-DAT7KmdyGX zv=tf%>^@p4lErW_`SeqF`bJQcv(%>)SE;S;PS+kjAc_#)H{#7K2=BV}GXUxm9}F3( zw-OHZRBrN&Q^NQwH`>{g_|uZ%2ysZt`V4Y862flda|rG0GR4U|c?ce@5a;=z2y~p} z#XsZ_nnZ?NUgZ)`6n!_Q`zO^Hk}HwfY&UT}IIdbZvXxtFGns!@Xk|Y&^_h(7WJxSA zB`#h)p=z|3mQWE^#c5dvbP@?4btc+r!bOT*bq*vK*vZPDaC0)dkjoXkd(Otym;Eyx zJz0Ozo*tlp&=>oZ_|t9*Uk{i}2sAi0V}X3Nk^^wv-kHuC=H%|dHS-TkrvTCeR*97% z1+LPr*+Q)}H9S>;Rrv&VXbM(~!$OUz@}KBvW>8(Rf{Y7!FF@-6xA$Zl;%M=!Pm=^> zU_LP@V5JMPPHkICYCQO&^Oz&5iZ@A@)%o$|S;9E(97!>}ZnP~~3Q6DYl%p15lyOTk zjMPA-@gRefZD1_qwM7G%Ua5sl%74MzUc1$_bhRPvK8WLeYO&|=|LlfKy;ibPhAK*H zR*cwfkpNF>N7`+9^`4_}D=F=-|IR=CCOU7eGyX%5+nA3(Q>gpo=xgf~HG7!DV+l~t zqg9DaBzsvL!B|tO-rsNMvz`+gE%p-XAAN2#_2t}N4r6GW<@%~X zF`yvJ7=it0;{RQLw#@7wa;+*riUMp()~&Rh?gAZbkZJ+l36Cg2}d^(x`3;gN-4|l8O| zo%O`S`lKre$@b$#?-#)*S7Oio~%rqm68# zt)th5q^Lbyx&vv^2C9EpQblCsa5CGBJ*5DW*=N>!EN*1c(f*% za^?^~4gwn2$RtV`j+h0w7H<_HwnJZD8sBczzu@nDdwbdMHa~5D+H-#%Xm*wGB<_xB zjYmPQJ_u_bhggR-w84l~ooW>gBeblCQ`FnD=ltz2`v>;;Gr9vp7Bk?GBE$~paA|n6Q9lH~d)_?l?)zo#NP+W#7u2jqr5U+NAnTNg5bPyn z*Ln8SrBcf$!w!#Dz5YkL;oba9x{Gp_?{1^@(s3*TMO{fAz2N;6o5&1OmN0 zqHO#O(VN3e=*iI61-9DOr{)CS@s^K8F{Bi0=Di#=(rEbFU?@>;3$g zZx*|*T!dqfJ6{;9QTr(3dN(s#sT{C|tOed5RbtUBvI;XTVzWfth84pUHmEFF9!fSV zv9_m%=>-DVz@tGdTK>XR^1ggCU31#nM4v!I+Cecs7((Z!MxI{9AOGqf?U!dGmDKmB z+$gOCU|>*{l1$XK^|4V&M}>D?^b*5Lafb*!wCYjP@T5LbiVa6bsTlZMdOoAsEn3Tp zjd@$nr`W_pCZKBpc$ymv&+tE+m_lAbd=tc|>}Fshp1M1PEV z%1E19P)QC_Ay6T<+TI2wxExBElece5IT7;Aui*9bw8TM~68bfD)v6d~$>N->%eq=s zhe5?K!c+_)BEMGkHBLbtIUW$F-}UiuwVolf8sPNnlq$o}u7?1EQaNeN|TB7-PA$wspWi(^#*H9Dx=TeHV&2i02C&u@~w+u0bopFN~BKzS@rw zxTp7P1=*u##4bgC7(`Lu?y@fJLEfapeGxl!4?6Zg4>JCgY;go zWZm@jv3Xb~JFt(kkG=o5=J3#(8u^TfB33VIsT15gS3RsS{H*JcgWO3=3yCIw_GZm1 z*~1L0N3Qw$&zU*3Mcv$}7W+S+a_Z<&(cR53bgxQmI!4YlQ-aD zNejA$?KPx<&`XHwM)t17{U*TPQ z%J^WT>t9YG+uy*5d|m2|zSv%BV>9L({)>JH(Fzu_5>9d|N=TJBaXF~gTo!d8%VA70TG8gRs5jH+EyC`7dpn=d8{Vkn#h2mh-f|tt^SL^S z=dz%ZaQbyR!tuwksT+{xF=5~t!#?YCWkBnVlHWxdc_)uctW7@HwbUCy#eWgSE`o2I ztfpliGfJ)WXV%JFHKZVAr~8B?-Nr{j=9X6b6bZbmLgBfgY&8TMz-q0$4%G$)@#V;7 z##-RbX7K!`v^abuLB~ZbdZ7XQ=29QgUJ`P2J;cEb2onCHx8f46HwmCb>??yT{>-vL z3lcFeA+(HU9`goDV6u+ld3u5)DBWrETQp>E5YR%%p~a^12t;3_p;6o@FQ}$lYWr1a zR6n13l!{6>@r0?lhoUjCFLwkSol)*8fw+Gsvz{xHEMhRtm|_&9iIPkWA*d@gn8s*r zLwcd%M{y$;=|~MBJ$1%k?5K@Dj=>8MDTNI`=+Jms$I6OY5yH=r};(-b=T?F!+ zbFtnv$p}K|`&6mqCMF9CA~n)s(UN;~ zPRcP#XSOCN4Cm+40Muiv67}{CX%2a04la&(yg&Ny50;np#dn4-peX2-CA`0twSRHKm;R(g5IJJgX5oWGyNZ)nh>4{bRo%YbE zXm#wy2~|t0()PDO0#nj7tX6iaq)5`WvX{WT@aa$s$0cv-&DC_UVG4rsM8)$m5e_XT zqPqd+Sfu?t_p3%+K{jj)tJ{y8K16mHt-gGuoHFCk#$7jlryyk29GY3w{5at@DP6bI zBPi;6_18vdjq<8?7*8YgS9~Wk-06SYL{Izrn9GvN^zlabNM4UrXShtcv0|DuBh}Z+ zv=3O2hTr$d7*JKAktD|6`O}gnkK;jY5qrJ7Hc3CSa26cD3&hqkPgUybipOn->lKfi z5#C$bg!*HV{@`Nj$HTGe;v8RoSR7O)s~_n2@3HyTuD$i;QI)%JzTv+opC5E6d0hO4 zM}|qpDo0#G&KvSv6a;vDo1!3cI5`QT#h80Z3rkFtt+3P?jB}_8R}VDgcRakne8>Jv zSmN|_?yAFd6N#UPr*xe+!gnGD)IM1pF@yAp^8i1;81^lrDI?9Nt1dIzkbkkU2eL@&H9y_d`C~? zG%A&sAcw){O&@FVK4c{l{M3(GH6f5?Z$+Q@AL0G$AS-VX5EigZG+O<{I&5Q#qDI(lD+L^8TmAi8U{98yPbZG zZ~fQC(pE!Bq32Ri6DfH1Eyjz93Q@B7w6l^}Aw;vJ3136Qt!B`;SRBAc@rOoaeZ7!_ zSr^r|m}j8t$Xf>+5RnURocNN_3LADRZ%=ZWN{&VC%Y$$)S-BZ~|DvZR#8(2@6Hi~b zQRtUtDEt*!qRI9dj48arp@92k1V0^IOS7RyaME3f4KpGMr^52-m{|L^%u!+QmXS>s zD3if#z=D_6c<#_hUl8v%S9bXD$^V{!W%qnsSuE0HmcQIe3cGRgJ9 zLX^fQT_rF5`q1(-cj@lj+NuGhy72kKh5PxrTc%Fxhq)W1{{}x&3yVe z>;1KTbPvfBEDD2Va#cP8je{PC8ylhXPBQ^U77yZNtyBPnMLk2>0-Q4lBwd6FD*GQKQapC6+$x9_Tg$S zvG@cH36Tq26o#yqx8~mX%^5I|l+Q`U*1b^H9V_ptp9*@B?(!{|G{12&z_ejL2kXg< zLmflDyvlioj1$WI&{U3i02F9n{FgK$Eh?YS;?%wM35>H2L-HFnj zq3T6P?+>WVL$~8(i|=*yU^*AZiItB+ta&01uFSB@4Hzi3VA9GbJ=5jU+9%HDOdVfk zd5RC=!C}9a5q3mott{?t(dsCe;*)5dz*Ia^K=~y?sM*U_7qh*itYH1-rF6=3haf=a zafxoI)3-j9_dX>KI;qJDQ zjo8!vVU}rzUQqmw(S2}zrsgCuR-u|3OaEY5%{#4H3odl#BD2AqgyKBR*M|36o^1)f z42=_*u-uR>4TX%*F;V-e!V@Ra)k;T{QQd)a9nG?B07?uWCy_jf;5})*-d7&3(ve+o z_(=t`M%iAY7SGC<8L4Hjl!tGYM);Rc%i|o6rw_#4tuemLmQR+wuMwB&z4SGZ8U&zR z`Ot-4@0aEp^q1RKRf3HRw82Y?F68 z;|K|(em1D2az#v-UTktQT0at4&imcCo0|s8#fCFn#AiK1v#<)sNusVF)%a_n-35pL zx|)i}jZ`02Uy>2Oi)Un0{lO^!t-~m97`4t9zonjIXU8hQ$ zXq+7^G~0EvYj@g{F_aPk517;)*>QmoLn!Xh+mRb$^pyDjRAQCKaH}yC6z!5)fmgawJAi}NDE7{(YyN3 zN{8@xAq@ov=(DPBJHasm|IMOp>kG<;%5@MJBKHD@>0ceSJy8<4GUzx}}I$ zn!Jp~faZ$vMX{)?kxR@G+uR!ThYi#L4L%*=viB)v2QU_wp}t!@Gd%t#DfvWIYK~^I z$N^}6%m`kuI6L-weu6N{rHJR(o_RpEyj2QSQyjnkEni%RHl9ATcIxHxr`&K>1(YYO zr+n=kGb)7tUVKlf}mfH^!GwBcHme_kFU~I=wlq{w+^kCvQB}ckc8d zPd;TYE>l2Rz&h0!`R$GmlM3Pge^}V&UJ~lmvPzn@KVB>d8l<9}(!8V+W75SumT4&@URm-TH;?aE{a)SuVr+ z8b_xfh{*s@&x!u{8OS5?REQN<2x!Sm(uNNFU{Pa1R%!6UDjmMs3jG53WL_9|sQLr? z2Yr8cJ{f)7)0-L={R%Lq*qAt|n%z2}Nh1CGYnaw@+#JoUIrzoF+m+=d*j8uQwC($`*$PeH6GqU9;LM4DM{w_2`hJ&zCofl#TyS$wcMo7c znK1TX*=sJDS>(r&5p$u3LB^Veu!bC=$Bi_J#dyhA@yY}cc2Xd;nA_C`3c#&5f63xPQzstNA+K zUKrar*hg7wG!$4qoI!o`>Tu#+;nb3dQ|j4s4wq6zn-Kqahq|u(M5_k1H%H2@8oV89 zFnur;S7I9&ls7d;4Qu3W>W&XDkS)q*3S9%x2T6XBLt{u>(PlhBwSZ;C69aS5m~t=h3Bz-XdfFTN z!hNu?IFGUvEWTio|E6qwoA3o=M8?XChCC_~MSZs7Q1a9$c9qN`pEygsGzF`7H_aR& zN#h&bSv}p)ub0<`@yX@Qt;i+9=ZrXbd&T4D7iq%g)ICxnJ6o!RCnRs$APUC2lug)M zmqe!!t}+|JiL`P#WnG-E6yyB@+-_@Fgq=XXUXWC?3Kb8HggiC-<1BhB#C_L3aq?cswLxc+{i0~XAYaS9Esq}h+|qBePDw3+x((NL zHk|@g8`UvIuN98KRIuqSt`X!5%C1Roa}Sd(6w3F0f^kRUUQ6iItVDkfExR`hi_HH+tehxFCWt@&&!1}}hxf2|fDj;J{ z3@^nfcB$iaHgyoz=(L5P{M=(+Z5gA~%QFQn*b3xTCx!rEPRGSkYwEn1wkp-j7$-T! zPY8np0y+Rt&&oNdkZAxI-iZ)|X+~~2=mGOC*`?zmzs&qG(qoco7SxM*2$N^VdZ%92 zg`k~|nsZvSP}lr?UUXmT?Z_TVj|9Z9&i<|aJOUl-YjX?<_* zTCt-#rUf}PwaN$$UTbS@sgk!5SL66A!<=S~?;|@2IVWa4IPlx>?{fn(EJ*f(bggjc zB+*E;I4g46ZaI*4(K?hdPdEm}7pflf`b*$*P}_tkd;IVvw6s*GpQ$xJkZ6-$Ar7kh zC{jg3QgYsvNRqDJCT3vsaDm=rEYpmIb7s@~l;tL6F(cs}v$}o*OZB175fYtv@#SJ5 zgycx1^{tn3j-W+VDc;f8)6J>c@e9nR?OgxB30 zB75t(5hhC<*}kU7nSI5k0W4`XRI6UCn5VKG74lyb&j%(I)d>P3&S~~x1RE*ucU`8R z*RC{YXCAU@wIo)^vuoBmnMFHSSv8}vXow1-Dwvq0Gw+w1{PyPZ)zzzu)5D9942yzo zD30|F{-1=FU!(xyPhm2!yr4I&&tQT!NsF_!56o;`s z@;Fdd11y5ytM~M3TYjb=M@yN9SC^Kqsa0IR(W7@;bF0iRRBgtO($vtW2A(9pGN7#& zCH&FRB(=?CeD`sMNXiu zdGgpcp%K?-#>r`>N5mNPIi?x|vv*5xb`j`>X1I*U0+BOUm)NVX8=y=MG8C8lIFo-I z1dkexFkTGV|EkTJj#U>DyF0BgNq31=pGU7__qIMQ%qbPc@!24z7S({S)9_^e)aT`l zOL^HW4#7mE=i4}+e%5cPfGEFP$`F2uDvB_Orl*XegiOAT4Z%3F4Xd0dxK2ze_5uu5<11CUo!qc)JCP9xVQCbVO6TA0x9V_ zY&w%3#^fq(jtvIu&-zGJ3IHY^4YlEjNhm4Q;3=KcepK9gLpE>=)>7ZKFa?q1@oH`Vp+uBREfNPmOLQLUoDwQNWyf%rqlck#mK_6d~X}L1*>A()-n;y%9?%o zh-mHFa`Q~_GbJ~=CYvO`Y%*(fnm>gkv@PNz2Up#}qgr+Ddm?UjUT^I4%BrdUC2)@gx)+006`dRNO2#w`0FRvmVJ%NioWX#-fvSU$2?#N98*_U3lI zm^1j0#I|J`O0u2BG$({MTd~Xm`oIQ+!UWiIMoSU-fBTSw3u}3OjG-KIY%Q5H!ob8E zB81Yz=?1r!=2HHm{QTpO-+%ow?f}X!@#NKLpA@wE*ZAMZvSDkU@Nk@5np3?9*5vC7 z4NA$-{h7R|#~WXPx;Bs4J|O4?8~b&R{ZP_2q{?QmS0#@;RaK^VwpIHnX0Pck7zH(( zryyO3AGnN+4Qq-`;Nux2y^y#n7?-UaSFR;|RIud`VER>Qm3iP(I2OaS^TgNTczvHf z&j!7w72Ot9PrbBxzvQrHdqv*2Oz5*5a;IcMyQWPR1|c-jm0Fbrd|R4!llXa_U?o$S zW=BJkeZCLnTU6$dBVo^GgULa*=2}gff_Gxr+`P+r%@n`gW%k`>>4(NmGRctPG*vQ% zC{%W-gfKAKu!-ojjR- zguhW9zkUOyU_!dqV_~HH-@U?0Ng~TSR#->ssx1%H1w{%F!WXixXwU||kaY*-mwqlE z<1*_RxC#=QI={mo{`B?zakrR_hVslhuc51JZJkY-wBGX+u-DsB>6jxI`1lA7a|j?y z+10W^4%4s3Us;y(RJMF+UV5&plH!@aT%GIl7s0f#9C4^fMIwwGruoDg148p04oIi4 zT2^Ra2I2UtTEJ9^+LFHyl$omjGG7*3T{-SV7K`orm%GecFPF8;w*uEaAj=tiD!bGC z-0ko&FQ%wtQ*s(07~p zui5W@dwJgceE0M8|19L)@4P)55L=~g|B7VHS1#!LB{blJhHV3M?=&n!Ascy0)4`}4 zEdC^qwTsc3?%NRHGicEK6;2SYerVEsgYX4<4Hoo@V#$ZBK{SlTy_{h~P8EUFHJbe- z@RjD62pg2c;l~JWPnOqzo(>0<v0f2auUQ88uUUc6+Uwfk zy!=|%)Nel2?o_`ebbXmdD1lFk_|=9@YM7oSS~ng@m=_V~#$D zmi+1NkMK+K`t>E`opBxywl&=QoYFk1sRgVfcnMo*E7iAP0{v0lXSXsP3!8#Zh?cBp zV;I`j$LCx==vSWZHnWL^?N7_@gTS=)1zA4&5U0PN=2zy=6KH8`>v*)heF`s!LFxh) zN^1gLW_|7Ngjk|0W>9yNB(H0%yJ#ZTX*^o4ibNr$0O zdO3_zSFjaXPN2&y)GYbrFqb`B-w2-p>6?RKr)qdbYV1C}LnFwht1rqw+;*M*_j+5GeosS+qPApY7lxtMxus@0^h zlt9L%Jm~Acw3`=QE@m(IvsIr82Z;|ImQ(t6vPdQc9}WZ81*D@O*hT>h-nO5QmfCm- z_DFFarf!GIR^m9l{|}~&S)jw(6@%2G+vqpnM(xsU=`D0=s&1FkgGDWV0?DW0i-Ld_ zwYp$mc(n^c#;({v56@PjH{JPXh{}43w+X35!wdFX?=Mfgho!?HQoC=GAVA7?EpFM# z@(QM;;V^PtL6!yx#iN3Sx3Zr<)|=xaXh&g-rq{UEgfs`mMbL}(w}18LfBgE(QmBvm zshkh*-LlxlYX|b~UDIfh_OhpPbg;VzpcPfA+=<=fCqk$-Ir{Oc(I_OHt%eY3Ij)kU;wv5oe2SVjh;%8#tD8Oa;xZ;CI3 z_6gO+l^XOYeg>n{kF2m6$s6Zyu2*L{pvOiOUc^;!U6#Y*5EDcz7=(N`Ll-R$&>L7t zvgK&Fi-*hV2h-1rWJn6@V$myx4j4y{FD6x-sMmBc#`T-`|SZoMi^BV|sT zU-WA7IdaYD6GjqRf>{dMI{HQ4@;d~m8;LxnbT`` zUVCEJ?mi1vgiH0m<)cM0zDl;1yV#OTfXq>RPSoUX9W*@qpPForF97eo(}xzX44zWF zKBJexTYKCoMGKc-ctIAD(aUs{sSH)Tr_4hsVgSqvY}2cn>km7&jM=2uHCEPYnld`r zMpLdPa43*+c}YVgW+`av=of@)3g;w_0EDShsyP3&KNdd`Yzu( ze#K*QR@JBSJIyb>Rb@g_eis)!%e_eDovD^8wV`emBq*9NxD4SLmsuHZM>d=F%|8Ex z-Ti#p?-^@r4JLCch0$S+m6;lg+7nk71z1&^DK)aM*MV6?tFYD$_s%G6vEFl|C@z3Z z(U(l$tYu3bV><=|{qmd_@)=Jw0!G~=8Ypx%s>g#W2JHysEETXWtswHX!FpBh9K@m6 zHiJYftZx*l`bhb#--iFB)?K)Q3TH;6cwG}0&!G_Nau=x>*WxaL7p34)Ij*7mIA69h z0>QuYg&|-_-*<0YNAk|p|I2Hza*0y5QA1yWUb!3 zZW~E+Z5Z`kMcdNsbQ32Gdt?>T4kUE9G(Ud`~*6kcWh0+@jRBc$oI6rn(sX zA@=*bT>Xj96dii5rUsSfO6;ASY>X8iRII0lu#UCD=iA5 z1lz}7ahQZ}fGWPp==2KDi)#6OK9@MYobwd^G#qD#-+Ac+=&T?G)0AM&w5kqC7-td<~cndC_!0)z#w*T zOTWA=S+E)#5#uI&7Q+;q0torO@Ulb#J~_83@AMygXy}sb1Xe_?fY0=jvPc?OLJ^h> z6?H?&)=*oWU%Ks_Ct+!u^Ca<-U--TyGk|@lR${T#irma1I;;7759rb99^OnUwCmY4 z$~n~aH(--P94juTAGr~iBUC?M*Z6p7qT2Lg+yHV98nxD_Vx27;mFB(1SSczt|8KBI z!S7f7$o&Ax8}oca9~JNyY<+WhCH>NEoJlgl#I`Zv#Ky$7ZQHhObH}zlv2ELSZstAb zeCNCOx%=7s>Hh17s#UdCckixRm5&k*R4_JXlePq!FnaswLT4_w8AOLa!Hp6Nu_Q=& z3p$x~rpP11W5FvslI`B8l^D#<3DZ56=Bn@#`T@GwmWByvq!^8ER?h0*2Ka^TV*BBA z^%d?A$np5t@7Yh&&H^T2mX~6*a4d$k!jVRz_Q>1EW9O{U z3I=Fn<94XnB8iNs%Qu@61cJTU;zKpsG}9riC>(8nQ^3j>G`l9nRL2K|&DG)w!F)nD zZkquaG5-0b;t+Q9rwegbv|lG4xx|a5aghjP82Q_oLTVXYjO@`I7Pgh=C-~@iBbW6P z<*#9w4|K_R|7v(hy&OcCcCj8LeWM!m=-?41MnvJKq?jomB(ubojC!5V))=|se5n5Q zlJSC6Lo(**HP(^YMfkoDE#UJwxdRf!0)#>bjhfvMNNoN0)HO`PrBw&b`DxcE)D9{; z2$}Q8<+6(5vj`M+QPy9ZX0`}F)v^vn#Tqs>u>k$wifc^Q+wLe{=fS2|A&pST)ug6; z8IA)9WLJn5u)5kgIk~JL_3L_~WMV7tXUFlcimqT3_uxDT!8Ra)?+E~gRK0E{W;Wpj zJw#xe%LKn*_cjjla&TnEH&43-zV*X{%m_#+?Jr~;>RYjf!=!kYB04Gt1ZrhYu4bg$ zZz`!hnd#r&1~=ouBx;9tbAO`q9t$X!>OljdxjChT56<1(Rf!|fFP)d-gP5l?cflf) z;wNBnPW-E%ViJdvG?Bwo4XWv_*oFFWpXa5!&Nh@OmQdF^`7=e}HH`IE)8yP*$d6k` zmn~();l>~7IRQnavNF&1MIDRZSA_@%W%xNL|Il`8>bj#=*FIf9H@N@KedVl-j7~13 zsVbDJGM+}Uif^tI;2*}LHP2oZ(u}ONk9l16?va>`7pbz$+iaiR0;Zp4%!f9AxnN!p zgRKZIBG~7Qih2o6QU87D&G5^O8>91ZcZP^z*5=UleJZtEzTf79eZIMNBc@kW$WSk@ zr9aVgJQ`*p3HXRK{09XqRn52Q$u^d!27!-fLVe;MVgdf_SDw0{=z4otW(4<8!s?f3oK{EF$( zn<8aN68MH*_7q~cqP8L(E#QG1ytX1zN@HzLlvN!Fv%%}cQclvfU0|Gg3IIfVUWac? zc=ui26w{n_Soa|Lh8LF}OM|SA=hDTYu>EAp_)9*27)Zj@h{XQ7MC|$kyjNIOEUFsx zcLq_ZnGtd3VTJ8Ky3rU9x(k@-@++%TU}Lr{uLY%gYqu(yQJy(v$8J|P4``0@)C43D zsiFM3ZYwJ3DJvi?kkQFSf}+oBNwUA44@eH?*LxiHIL9G9b;#E*YC5H_P{S#{_c<(C zFT*_?blj(mOqeRNUX|g!t#<~a%OqLuMd?yRi8)IkY6WpbnVOF!?}v-Fs_=KfYz-4n zlX}d;u4PNh0<|Mw1WsXB_)+6(!|Ba{akjfa-h?{YCa`@my#!G6ai+;MSHBjS8N(I= zf-*OY%&05gVRIfEWKg}-PVwI#|6qzTEXsYBx zY>hF4vFk(;Y$S<=N#Whu^yH>W>8yMNV3~Ue9uR)jXFy)tuI7jPrSYdtjG@L)7p~c$}!+6aaaVeo6uhjxfQB1~hK^3X0y8!7zM>=+#l51;HB0lBOih9i+G8!E#T+#B>1=j9RxEbX(U{P<*uinVx& z!FX-jKW&SU*1lauqmI^ACV&Z@PSD2Ikv^1mIct7;t@^s9^s%~Y)n>Z)?(?2?JL3t3 zY*wg85Sou7r;t%Q-S=l<`lX!vTIX3Gv8>kduIQ0ULpxJ4)6<$q(o@TX$Oot^E;lJw z-n?^M1PMqrl+taRaXbi9Xk&L{jKQ1i`3ZgQ-Zm*vD+}?g=u0)3*LvJdW+=VS*?yBR zvlIWEuNEbz_$ow%akyoU|9rRic`v#Ev7pjne0X%U4icKQh(__%mc)pyzTakqP_-Sv52ZE}vzYC9 zV(qx}2mPD!;8vk5T3ekZFjR=f9_9Rw2sk@&+IfD3i1rUn-wfD5C1z6552uWx``wz; zm-F%QR>h7#hZnb%1}xQ1xY@)0SIH+m#OKEnLu>4ADk6a>JnqYZFg*S!>llCfEEVGI zM2zzO1d+z2RccsHSxTdUifUDqSG4lynVklB%X)sEH_=wnw(#G*;D&I9y0rK|J!uxM zm>o+Il!8R5ZK`+%eqY_TV2lx7CSxa>;?KRU+qhx%b9j5;j+kYVwY|?u?RE=->fAOr zgOCf+I5)1KjtUnp2*53@hK(&o^VmAwWRQv>TVKbSEjVURIN8!#F2ydL=JgVdjT=vrDc-l79~LA}=jdk40V~r~ zJFwHmuD&mhoFV%K&Grta)66&~etf8X`HsJ-UMw$;*er|Egp05fWSSUuf~a}N7=mFZ zPD5o=VvWd^yaYq_e08T?_B294UyM!J8az0YxRYmtnR)NH>9gra^o83N+RjI93_}G5 zJ^Q=TVz@FBlK-S@hD`tlMLN6iE}DBF+cT^g6iJR|2YeXD5G|_U#8y=batyIr*}u1T z7noN{GAd_WmwcC5Uf%-L&#C8JjqBrR-?PtANv6*qAu;f*=Wmh`J0}ndvOR4^`Re z=J$BS7?X(}+xtkzO#5<+I}8_aHqDKQ=7n%ga_;Mn9$2P7-7%HOAYGjA91Pul zD&jT%3z9+*8CUk30G<^gKRUtUF(BA;^Q4Zg$=dnHQA!mnBa}n4a))Bsc8NQE`Z6Fn z_~SitWZ*fr`i3wBZj^0CYs<5e&C_}NXlNQ^nE^4BbBp~>_*r-qf$yX4#@bYM=aYLq zhfWJy)LP)ZohC0(jH2rJ?T6c59!o7o<`zn#vNzK4-M&WOK&0L%LPsJ>&3CnTr6Ww& zeFnoeSr6GfNDd}m%dBFSwDXRGI*(mz#OM7(@AquNDixm3SMS}=3s0}L^2NP?Ypl;I zIoB&YAx9E`N38ydGz=9`u*Lu$#9}`Ga$koq+m7Yc*2z4IlUgr~gsmq98fhK!#tDtu z+Txp`I!RaSDG!&SuF35F7{V1PlWv``j$KurUYZ0J<&itq=$zvzUh&Ie`Wq!Y^hb1a z0GU&mN|o&9jKc~D5s;bOFCWe3e&Ll>?pIuVf zkNBLX#P8?Vtl0z$!@+FLI9httnxAJbS$Yzuj?CpPB4l2JVfK&3U}RP@fBsPXqL_B zXliDddE_KY>VAvQq5kTo(HF`9xizxkcuw)cB?4yNM~R$q73~ysG*2M|rCFuc5j0Cg zkT}GMpU|%})6`mCzbO_uwYA!=8?y8@-^hG5r(J5|7Acqjud2_Jf@IRSuQ3$Ch=3y0bXf|%CZ#2oDg zdB27Hv&l<zACILl8t8jaIy0a}2JNo&+%%Auj&-=+a_PFD1qP{??3SW-6 zWE577 zOg+K1O22>;VKDh8GtL&S>a=tY3NxUkIw`8-#DvtiX54jkkq3MzY!b$z5~kmA=lhn4 zu@t+*gwEdG%~3hY&d5&tHSAKveT~d4ni)Ts6pAN|TjbZvu979%bP1?u6w;HiXlH3~ zB`X1`XB7H(Gd}CqKe|VT7{R)(r#EYr{0*a1F@3Mkp-3(4l~K1A7~kAIN9z&EakYc_yQ3nsvCmCj zOY`*%tZm?jBG@Az0?Chk=-$!1v#l&!gYLjkNZ(9VEB{mZ5yl^;f9%lZD@-_wq{DC^ z+?x)ljh2MD!t-$=|5bOmQ~ce@CaI z0}|wA7C>TBEWy`RR!qO=H_Xhyd$Mp)<+E-$bdZ5S&vLnh7R``Ww3pcBsSJxq0Bafb zrnT`d*U8oeZ{~an)LpY_<+ULL)1F>u95;Iy2R+14d0|2(6%TU55NsdAP)_--zxUPp zi%hAG0mE4_kP@2vvXSg)j!X*RQ!K3_zeO8v1_GUY9cPYgdE{@8+xx-N6I@?Gru9CS zYD1%Nj(}?QQ)$_+NTHzzP2fThZ*NJNV(pevRs(q3g!mklJKZPxTN1|4RM{Z74>-xp zh00j846yBIr;#2@ZLRvOU#*fbIQD3bXc;Y)nd-%Lx}#mc14gR!fjkQ{Pl#f&iL&|$ zt}N$cDK8X+enhDe9Gcs_(2QtRGYTgMB&9^`khl8COkoh=qR@@G?cCj~D(6v;u!@>X#{?oRscY|>&g4@zFH}is$S65wH>aEfVSV4OcO~ebnefOeoBu4iAp|a6UsEL6n%C`cpXKZ|y z9qzHdixB4;!dOZoPv!AuV7@&B{?;Cnpu`aB%4DiSu=*lFG}x$TeJA4jEv5-n``TG2 zx3mLBB1e{QUWVNaY{Hxks1mfl&uq#uKT1c4CQ$dKuU6kD)#8Noj(V0rR&=P*fZ9ys z;2ysb{RIN_SX9TEWv0KWwIOb|TF7MXqAbES*bB22ghB+&uM=(}jiZ({wXyEy=S3y- zO~#$muNJH(^-hjZci}8BAlm|tR&8aPayF*TV0c3b8~SlDb*vUC{OK)?7MPe#uG4u^ z0T6krl2s>xPsb^Jn-KTc?_H+^G$n!>XO72Bg2N5{O;q0+AgrQq6v-v71GcN6=;K%S z3IT34r;(&0bbIe<3wduUMO)%KY~f44ycX_fBK`J@X5=^x-C@Q0`|3&~{MM7=JA1Qi zE4oFt5U|{Gj@S`3kR8nz8VvLn7inu8#=?t=rerAnj*vzGS2r>jpaH_Th&8J=I|l)YbLP78{0k#JXh8&R=jFU~fQeUlMgkgoQgvtvY5 z5F8fUZ&@vcUitA&ZLzg8Ta6M+QEe&z-aZy}+}4QC%m`XYHcsie`$36t7-W0!V_ekD z3YB397hgxrmafHw;51efA@-n$>OqG{uvV_NfyNwrm>&AtiiQ#xDw#DGf#vxwRfSBK zjIst5mCZp_`CnKe`^3!@Ni7+|<=oPpk;Ut@jBss^;YyML!+N`L@g!3Vv77^7HZp>1xlcD zf!=n7ubn(@4`x!AEO+X)^uI#I_UTlA`C=-YJ;2GeTksD}i zFgWitS6)c)b$4rIyBKBf)_mj!0il|a(t80+gW%h57qnd<*k{>bwcG$pd0}~9p3z(n zpxIEqXp?i_sl?eEz~j2Fg#;{Os-Js>=6=nsg1<{Z8%f3x?dn;#ZdK))UsrQSoDZ<& z08Zi{(EUqW&?=~6*{})2i46)tQ28EL`sJZWxj6k+sud!lm!VjQ$MrKp6){2qrWdPt z(*Amqgf;dysj41i(8L=>PJib#pKYE_PAs;o%e?rzR?8<;t$=V?F@vXdQU^A2m#MUu zvkLk={Ynps9eoSqeO4}I91tdp5oiKx`+I2|=o*#p+U(w3t0lZ%6@^2=6|x<$cAiG= z_tR2hw?Aj&D7e~Lc)Zng(UinsV3B+j?vsPCd9C#_-IFqSS7?+XR!FoY4WtTH$XN+m zK-*`ai+!ofHwX&RS&W-x3bS--3X>5tPWcq!S2FHppcZ-wP7SV0qH5xneF16nHwjRB z5FE$ML&vhqY>LtG5;_kOBaV+Nh!osXZ^D96@lg(iP~hkKTsxAzyQ+neDXV+-MFBqQ zsM=#LhyhO*kU8>fl303*e{Kyk5Oc3BKyYq{gya<6@hvO_*8{WY7QcOaUrEUj6)o0E zf8HnR^E)aQNbeR*-J;tDhY;y8>sh=wU$88$_r`SZdd$A?Fs!J9{G(!lUs8bk)@Z*V zBs*GPkH+q-ver1+_ zrdUqqyqB)wdpI?(T-j~s64St^i_k?g=y z0IwR9!HBCr(;_r?w4QM##Py3ytYm(rrKi2lLro^ysnHrHH?JRl3IM-MV;gyM5oV4dklzf3A?cNu%MM;0#!d1$6Zy} z?X{jE22Rig;ul};OosGMc1VOebCt?>HDhNfD~m2vUB6nWNVvL}JRzZ@%n6g*f4sBP zb(#hqrW6p7DDXLA1;QxjNW8yhwicjwOOZ3nzt;Z#cI|Kb#O2q9n28c2ZO!qDx4#L;f^XQdL`Mn_Z^N-5z%wG*+1|x@>Fm5Ze^XdVBR0i$ zrAwh6<4vl`lW{%a?{T{V)&=@>TEU58qUIFF%M!oU0p7&40IJ_>T{>a1(gTS#>aO{- zD1JNVv_5SK?Zu-}?LcwlzOYw9d&LHb&&s=VC(MZBO}qY(}_LHR1xTek=({s`i92^qesAn)(fc2ITD-+XUIAB|vCiZd;ru*!JuLJa6^9cn zg~6G~WuP%cVuM+z$8QurVEW`THB7Fq%SWn)Fgh3^jW*95MP}Kgl`8El3Mi`P0;LQ6 zZ}Rbq+fIMpLh>x#yI$20T(1DY1LSJ~gkU#|o;6-V3`^NtvTj)Pk;22N6b;|%h93S+ll?YM`lP9zmz<6TwO;S_pd{K_w;V(Po! zMqCoI#-x(v+g#W_N%Cv98>gf zo#D@`@PujMQDlMCYjdsvu>)@Yc5JB$on%Rb`*yOSS*Y(@2U}=z!~%1(6yr|p>&$V7 zECN&(<;B2jY}eB$a{*$s^HVzc%nvteE9BPrl{I1#aoh7^mlm<(21Q%RLo8UXbdokl zR#XGxJytL>e?e;EGnLhw=iu~YDWR8A(Kere|By^3^+_WgA^5Xp4gPU=CEAu4gt7`x*IRi3 z_4wnpeeVQ5nhF)-2eTnIs+h2c+-Sn)_wS>;)<3%96;f2Lh;8=F}({Zw$I4j}Zj!30vx z30g!j&%fy~cjW(;RF=n7Fv zbqW9G)wZ6_2bi{ab1l}J2g?GB`6OpB+;NdJ1r6T9z5*iZS1^w%g2oj#}1D8b* zjsYdS7}x~>N2i0-nsQOHq=q?GT6F-Rz%~m~Ge9g82-YrQ85L*t-_F!b?<~5cqUo%e z?>f*kPbns#0n~k_>e|NQs@$g*4{^&oTdG_FP)AFE^NneW;6?QDItjolnDKO`m~*AM zfR`G1^u)lyEbatx*==fUlO4t`7TPN#Ycg$|CBqZzdO4HYj8G33geU7=R%aZ{1x=8p zO1^T9wenbyDVqv5j?nF5cr$JaDh~@Hd3Fw3I3@P<#r_i}6KYNc`NG|Alk5FIBie@^ z##}WX{z{XTqyh6V``px#vpt;hDh@@}`du8=yT`fav@*OmhC_Iy`A!lS49{pGZp#mQ zC{I<3T^cXI5XLssb-i}-^CYyGz=gjmdu1rajWhY^K`7?%X2Y>XJvm?z1rYLJ#gUymQXO!gP$)kqE2ryw>Yp85Hh<+Y^ zr-R_sbakhJ-mGE-Qc@f<~!jbNWX7u^d5U} zJ5jZ;t4MRz&xwmyncew0{8%d~3WVT)*iGE&%uKYU@&0XO?x#eizt8wG2E7?%&f=(X zRZ3g=28F6&-g04c*u0PoFb#9ePmCr&$$|D5BiqW1y5R6Yjo;4;w97CY4Gk}xWMv}Y zwB>4aUHXN+_H&1LqGN#u&oMe(OMcm?-!SQ0OVwq0$4Oh;DC0<=3%i|+XneX>Mmg~g zGgDeuGKQ8LVeFqGdrw^B*a{JdPIz+~zNMsXZo6pD3eoe8!1eI;%M9jL`d z=k}!{+eWK77*{WqRtPe2VU~O2e|w}BdXKmo0eHwo%W^#76U24*)kXPe_iL)J?})#i zZxIBM)2tvd)&(>44aAcR!j21>$tuz2;iG=g(gNHmKMiE zc`>>SY2{^HaN|U5;o4v>t-|o?zQ+t(6mD=Le6t_Xef%{y1GVvsMXvsPW?jcx!6U&V zlZZ{qYN1WZcYs<*+GXofId{A!2uplVsT~WMD${DI81=FvZojj|OqrmY5Pywq`%pl$ z7k%ZxxX`1|4kGzzMkId)po|(hOyt-g!RR;ptQ`PbZGG3^tK`M{>;z2B>a%)NHOnl z3F4X|3P=Sf1+DVS06`w(NISy&mRHKH7+zoqisBK2mMz+8O|j2TZOj|&<1;u=DFs|K zMzCxplwkp2wQAmMurP%p)-5*BfLxhJ zARnfokia0Tus}_e!Pv7PI&XHyM2c>U=zJrd>jxVKN20jV2}DQDLtq!SV zBeq{k|3%t^CX3`Hc}(|yXP6QI55xIgFLG9R>YYzg8tTF;$g{6!UM{0Fj1z?8I5j8; zyLs}~J2~mS*dsThtG55^hKlD0iMK05g-Dx>a~Viw3jXTw9!ecyUWtQMNS~ILC%x9m zuCK@&q#lW4>Q&1p@la1s4hnE0Udo#3y$$;kY=ZSvm~pBjwxsK#4E9`31p|LXMATD= z_$ZX?@+^1!ULI0H$IfZ5s$@_nN{V~QV1WytNW=xcm(SSwi%nE?W#01i4=&f)UcK+g zg6dolC&KCjA>_CbjV+5VYN=U1&pAl-J2XdAx~t(4e0YGE()4w7lPBWa$oQ8f1N~;B zjH><;{}6nkK8_1|evbWd6+S?4+wbf5)u} z4twQuZW-pl&rlq%qIZa9QSf^0X+x+8Ix*fb+^Ek!U7bcXS{r-V)3Pnmy+0o0%MRG+ zBMNf*Oy;HdS*jt65_8n2HRh=u8Z8WuY7qbpZJ%O)-}jA2 zjD{&CA4Q=NWML`n$}KjQ0o%<@538T6iOOrQ7K2ZBZ19%+7`AKXWLhkOmr!WEwI5{G z9KDz=AxNGU4`BkuYe!jjBpkRi*ZvWDO8vx5%13HCU9l)UL*=rqYx^f75A7+qQ#Il= z(H#SdB+$;{mdowEZ4VYrXikSM$jjaHhf}|Y?A!C74*Qkq78TQ(lrgM#pBqTPmx?5|D$ZG6j*^8y&ZoTP}sxBodt@-Mj zHek{xMU4eI*r66eYfan0%pX3mP>cN9hs1X?I48uyBZ6A6lcd*qNfK;vIA-LC6e%Y7 zZKa~wgsl?rE2H*x6p4n11sa0pl3I2&g-YeZL7$Wj;b3-i;-y}vRwKAZ81fpb3HIpR zORMO~ApwCUeoV@WEq?WOv(qqgo>EG&RO9=t`^;rCIIH*!W*Ty-ubehfww|VAg+E9F zFr{`z9jr}jgJhs4AWatiBV1)K4ImTAQ)_!FF<7-gc9HmM$rBhHLkXjaU_P=$vD|32 zqkd5#84k8{-WN>7;3J(UjqkA!ggsgnGNc+COlZcc9VULm z4BRSo$kiZ8Sg3GGdU&pucj(`D#n89eAtO)&b= z3gL!)Fw3unjK2Rw6wR(4FdWS9=YsbsKDZK9Msf?$Y8dt)fvtmC5gD^_U2^VQ9ajINa zq){$SuU3>p{kaLnCX5!vsSlo*tjhB|oQhI~`yZW0Lym@54u*i1A5i0Mq#1`VCD}8v zi5^py}jN2mu>` zx7+SGMtUinq(MsgzIRf2!elc-WO2M?l;DCqK)qaugrW|FtnAa^4um}pT4bC7#F)xw z$n~#s>wA?7%Alrpmhia?2|W=)YnGJRO207e&}IRO z-!8pt>++7DUuJI|{2{E5uBLaq?a7!k+^>p)Jm}#&R$T}e&{mzT%u(f0`NXQ%<9zYC za}6R2Y1ySOm9oJlJ?f~-sbL|dX;PemPo2VNeZ_Qa;%Jj`39H$FtV2T|!X{c5ofRFIugHNbcJ@%>J1fc!%{U)XkU5hb z#K)bP*i`RDm2*herx)mbjE9POKfZF*Ba+2_ZMpd~J9}hz1yQb4uR3qD*K%Xi9q1Xp zzYsUFA1&&cjA~V{F;Pg$D-mGY`JfOCX%0O^#kSI4f#?CN)y7a3$?ife1EK}<% z#nuBF@|OIhxwThybBv*G*Dw!voK*J$!fQu=X~<&5GPj1AM3_T^Es7qYmiZ37K+Ia3i?!9 z@$pTC-V@Qv$UhW*mZr7ZoWre_OvttA2^m2xj-A}eR4B>YZzd8Gc4*CIrNaK&Kl!dinNDk)A}&9C0e(aZ~`Z?^PS zg>zqQ<-xp0eBgptKVIeyA>3nAe>&oxSx`k>*XWVuRnq|+1*F5 zD^Ks_Uv<;|Q~?L&9}Jazn?J(%>C2vijj)1iBTJ*vD(;{p!j9$%!}^Y)Y!rLR_kz=D zJ#ZtHW6XaoNlvi){lOg_d3&YhwHwb@3wjjPx3y{CyLd~B(rl7>qaq0pWIt&i5ElKk zHu)V=dd~l0>05)lbi(IAB#Sa9a{GltdkdEwhXh1EOKx^PW9x<9p%dWJaxO^1y6)tKR+eY%JOjB^~yE3XifqzkgPMpycWv#+Aq+oGumHg&H^v6tTWCzwOkWE z`$Av3O2R?E=hnV1H9mr|5IR4r~aj-u`8&FWNKMDYHI%1&p#b?nUPnZ$;Uh!t=oM~ z1Q#qM@0ZvbB3i1Pa+?dWyZ~!a0oor+xOzL}{ZwXjE-xgisDmvLbDLi>NXB@Ikj^Z{ z8=FUDU%j|lcC_bYea;%!N>F2N!*#%HUn+aE5F)QMJOoTFS$2yVIM{u5k_t{%>SWlb(|5ym&Vfv0zHSn<_5uR-(fS3P;_-5WsjcE+<&%0+qKn|wD-E5fSNHZ%Ho_(|(abN=ByQi^NKr6;6z@bqC18Rfk zHPVByVu_5=uu*ns#zJP~1@YCKH?c3;a5A?a%`2#2NlZwF3k_OpOq(dywL?CFl=&&k zic1xR%}vZATP&%uvv@P^#NuU(Um${h4@#mJ869|*a--@^cJ$N!T(3VqI{G`eogObv zDMUDLP*jlOPX((197#tDJ+hWrt1Qpk!K=U@2dBTS(z>9BXqu}K^mJvb2~`|y#h@lG ztYqZ00!vrW^|9cj@kv8tDCSn?A9eGjmRk)M>OSrvbWIG_zzofdKJ0sLX^tnOXPq4} zOC-d{isK>?@YDKCUe9=Kq=aOGXL_Jxa`SZ)#R*y5gylJ;$fOQiT($bpey3DnwU~ZT z@@m;=6BOAXmxb8LjvP^wYQ@QmIXTyjTBtE6o8Lf(>0e;O1d}0Wd4+`|J&yUR`2h-wIC43@jrQPK_h;F;; z6*Opv7Em=QaGBs*|HYthir7jTErm`@^EG2qdVqCKmtfimI_(V_wu_GrUg~D++|%At z*%6`X{5te9``n*Cnn+@V1x{$AoISOYQd)f1R=9s`v7I$`*8=$~Xm$mJojcMOyEgE@ zM@FOVnuA)3tuW{Hgcb?fwwfK^3?YGBPg4b0lYJ z4nl8brnZx{A3ZZE)z9Y`&OG2m`xjmrYoEYT*OWt?AbWO^o_9RJxwAe;ZY+o0o$MDb z#Eh0n$*OW#js6J_;@B_L{`NeYbF9i5d-?uluuImV+qY|!Cp!b8(O{V2&B{OzpQHcHPiNcuM-rk~@! z1|RjDnw~H7UiZn3wT<6RV_^K$7Ig1$)&AM2TmT9FUoUivZ9@8r>NCxX86*sgf;f`n zNd)rhwxqNWaHO56SdlrctV4<)$9Liq-HeEKiO-PX&}LF(5_x_`#nI%o9);#RqvbnG zo%yx5t&X5;HVzL{kq^dHvvT^fQhZ@`vC|dr1YN!9M6|-YgAW}OgGKiX7d)s1hw3M^ zKiN_pR;K@k#2zv*_-Rl8G;Ep16=&%!CU+RnZKOsP4-C4tO>RtXZw~ok_)&yYZu1o4 z;(OrwW<{KnA&O!H`VZ>A8$KqLFK*cN%us21b8GOzv=|y{hBBEo`U<}zSKAhyGLnxZ zDIP9RBt~)Ox;lT5_QbvoUPik(J{(M#1yHB~xNr>+j@FB%r+;ZC(?p=%L?NMjb1o?pG8Ci$+jOMadFXa2BaI39%Q&#K+ZSsry>BU7=fwv)L zso6XqW||tk!M_$qAYW|GGs}H+ROvkOQuB`ufYbll;3fMqvicDTi=uCU?(^W^9wENs z1OC^kN&!e39t{nKBfLq*H$(7J$<`{uslZ!qh{K&dkcmGxWDn~RNM%sV&@gdFnL7n7 z&K>)ED9DpUVC2=Lry)@nz(5Q2uAdY;o*?D0|8+MIkPXLWXH~13pCBfUDa}MNsn0Ao ze$0xmnbdj?T%uoYj7*PiVtRf4srymUHj@TX^jf>+)7jr}TfbEXHqzD4OkWB7gW7c@ zXAGqvy1YKXK>M%IikOZZ_)1a4Cx=JD%DS?S(ajAuSu(FOf66kq62#lIUMZ2B6?}y?i*7V7L7L zaK%AXB}dYx=tceRHV!w3o@FPx>Kly8m$Pbm`(f6>6k(I6f`XbWI#B89u z<_nQ2{o+M3Uq#gL7KRvn&$Up3~(a7nJ!qfq0(u$roYf~@)9s)UIp9bVe zj%I<);J{RFr)xKRL0=4mgUxmqn~ldAWgfA{8mTo7E)xx``l$SAv>rr6gNg=>bFGZM0HQl>l{qe-eWv5fp&xv2%jXr{CowS*|K$(ZS)R5K%L)d4#-Q0PWDM6+GG7K9ehlt0U^uwCeX ztrYcK=VJ*|iNcTSL;$S}ra8BDL|s&8PxV5u5$GIlehT1Cj&hhcgX$w;Ob}bd8~W(K zc!czbv5Eoi@29YT(<;5mm*7!heSPL=xO{K`y8A9MM$I;z11AY)&&U6x zj}py5c#$KL6S}=mNassfU8M7%YETt4(UFe~5U%9^qOAnW=?ZymJHN@#9dIRu;r=6~f9S0mSB$uvC`+CK(g_zFvB zb-3IgbRdeW3Mp2w%L&Mv&%j9h&OO2Ug4gA3qo*si1Sh~Cn+HELtIDN*Oavg(m1tE~ zK2BF_MUaJL zUJV&-oSJl&MQu|y6Y9dQUb}+IQxhh6j|%)K2%uhk#{geX&E^U|u)Yc!oyF;XeKP(k zmY|$l+W3-R&L?l4ZO+r>BIT>4A<;ooSAbNwDb}R8V1%yP6f0|*u4}&9s9&_4y6Q9@ zx5{{`#{4-92U|@NJnE};)Ga6#$Va1s$-tz0_2YL`UV`vxo1XF0Kvf$eCEux9Wq}BV z3(Jw!vG{2gNeAS=r*Nj>YY^AvZf`kU*?L2NOXcr1oB;!LgVO-}{%K?Lhsj^Ed~LVX#)TQO zhv@#SrzXlo{9jnK`+u+W0~Bkv#sW5l0B$Es&=W_EgEy(-}L z@9C6V?f=2LwWfd3Ldw6cs&H5^0!yuRObptkJ8@x7!fO^~M{8$9XRHfXDa{!p%2%sf zzBWF_^sDYXt?dGyAi`X*FnPaDHjgNLXM zg&<3gRgL)S`^x`p_CK?CjbSo1JhVLAh9B-do`zl4B%u&xBLA-~4mM&mHd=BRrDe8Q zE>gE}sVW+co}KaLGnY+fNzF+CW0ag#;?wa6$T9#TOX;lIZexH-)$sprM(vZ%x$ZZm2 zJ}Y6IB|9j$I(0Mk*_L3lcN(S_Fay93I%O!#D2?Q){g zM$&qQCV~2$)_!cx%g_X`!=M!NIar=}`+I|dmltLZx!FaR-r|swDpJi*`sCO)h*weH zDlh4O9hc?59aqwXH2-f)#<>H*pc%9(g)y`iZdZ!9=dZP=5gs~U%c7LDnKcEHkL_?I zF{zV=7=iE5cv{Pz<_i{v(Z%_Ps{uOQA$nBDNO+sj-viih`kK#JpyOWCe-7vC?$KTNzu*dH9K zh*L869PreG#PM5mTO51tJ@c@=Oow2q-gN{1i)?3G^&*pX874L4g>^j;xI}D~-Gs$0 zK>&c%a*0Q8&BC{hqQfn;Bx2Qu0s&%V$#JrFy4GUKSla^8lsNAV;>Gyr|1c=l3zFf+ zD_?<1r|G0S*z8e%Psp_vVz)+P1ZfQQU^gJph;HidtfB_+Sp6}@L0c~4ka3gmuJL?* zIN-6qU6M0&x4HkvV-*cKAFJ+_kR#Xk43M?GGdQ$A_#K>HIg0S83^>58n8AAUJyyP+ zl^|Ln`JfFq0(2QJbOJ?6E5Xm*Ma$jvIeD7Q>GO*X5qsBoKqrS4P%boJ4{%alZLuK$ z@kFh5FNwb_RBsMvN=H<2 zVln9w5cHC!Gzk5=7w{eaId&rI>=#m(jJTa(TIa6bML77GFLo0RoLRZMV(BZfFYvHJ zBD1FdEr8$>&-Xu#|0K+OV5#`=>o`6qGMqY>7KicUaR26b+q*xBZ`=;ahF1S<)_}x> z;)D3-Iat|FdKCnh#Aq=;Vd=03RF-H<*3vl@&72N^G5F$6mT##+(e_4a8KwCAg!l9; zU0YGsA5n_q!jGYITo{y#C#XIub8jTHv(ah)Ou5g^(8Lh!t?j#1Z6jH0RDG0HcQV3K z3WANUihd~PU323OIof{f?>i@25I9!>Qv+#9-+73os@^4+5_^?~Tv8kq6Osd5LH^Uja78>yKpBV*O26mR*qtYG3CiZaZt$A^#;V!($ zR~*u;gccq@x<^wGjQ}zWt6O$M^$!r)X^ohFDZ+w~8@(iP&_aSy;-4j$O(@ig?f@hX zxtTa^>RS2jDttH>$DM{q8>Hgl#fUKo-pieea*ne&z@DWZY%C6m-e)wFRo!pL@Neb4Jpc zq`7-v8bj$03i8(23R-X*K2vE@o2cNzlF%nVS>iwxZ)!g?cfuUZ+QPl{+*dsu7MJPS zwEg)e`wvIDC}|p@9}gP_<;cZIkoSG0U77g&?4&lwBEaP__ATOfcgr-fbQ950_Ie$1XMDsVdeG2d`z z69NSOv)$k+A9DCuM#2bK2sbF0I{sM;K-++*%zy}0G$_`H-T4RZUKPrE8f3USXnDcP z#Uif!dT}0vdluP6Zv}|o{K@hF8$Uq`m$G5K= z9LmtwyHV^~lOz~Lx|897(mjL&e2tA-Ci-MbfX4uAVlB{~Bv86_3V|a7+C?Eh>|^`0 zzkJjqT@_lx_F)VRWJyyV&9yCtE;_S++979GYt)3 z?*kTRs>OhfGp}0pz`dnK5(GlJp83aPuN6-F6_PI+0X?pkJNPHJ=Ydm)*zs|D(@7jC z3~Dit*q=e??~kEVR z$4A+;p>F8OZTzqo*cQ1iuiRx2BRieC@aq1CD@^>;QuM|NvQj5&X-*VN@d0ri?UGHR zQwB0Yr9S}8YH&>@RRDWZ{5a8v?eP7!#1P^uNorG{138Vvcgn}_`hMF7z(rGAO_FS* z&(O^nA4%Uu_z*53Xb>;MnG$Ilt~zAD`SMSfKz7;ai1?rVw=&=%HB=U3XT;~G=J z{NArkGWge>bZeP6mmv>sTJbme2?XuT=vuN3GoO<1NDNxx-{R7A6a*ndC;jygeaAw>NG@yZ za=n@slJAE`U3Lv{z`_F*HiI0R;=*E@Xcn5xd*$w5g^^ox9+kG^?qk{&3_U-q!P?HY zRBIDIVA^Xb3nJOY#gUP7e~$jdIka2zxX*tMJx5|*D?x(euQs|bj}e-sE;{~C_oY!(bx=W=yH;@bZ3udTf2yp{3BJg+1m`(7ngEK$&!*bJ4@e7g|Y&6)kF zCFRV*#yP#ZeKv>W$M+dj()ph-I7L+t!&qj?ohf`pQZ@(|)BWhvjY>UK=2RLz))qP_ z>wZREWFlMOv4F$<-v{SY`{y{;Z0{ZXD)2S+a|VmE$BX@DT_1iEk#P?PC$BG#p5X=R zvp9#pP|d0voiCmojDiAV~2gZ2I-+gt@ot&!?nztkfx){OFAEa`mlKbP9+|2d==J zONZE2e~kc8d1-k$VhPNRQQW%hg{oDr^y(A}j!DId?awKdH}8vUyM9b%C1ZM^V)CIf2J=IV${O?G)@C{8qqc%xK)v2*nyvV{3(hXu zzexxX!zStt6WfA5GgO6sBUyR7Zh;-tvVmWU=gvMD_Q1}_Vvpc~ss;CtNal9eo*YNA zno6{@+_IVfs`Z2>e?*PT@-#p(0(YHc*sU=uAsvHFeB-RdByY%|&V;6!{-949b{0VY z1@`ci1(|fDf^&$qAz(jpcZD1qVegc!m72ZtWF;?-M}ShWzjC9%I*(;WZXhBlo2+b2 z`%Q|{WG$I6I~r`3I`%-dCrm0%eT5_YkY}5{Ps~1o$d-f1)AX@9c0@Qj)fsVL+RGLp z39BHg=bK*-D({YPsNCHyw~gn1Z)Eh({7=h{f%Wk5P@g$bT<-^;-yZ4mD?gNW_oW~` zVIQHHH7`mqn=DZKl%0k*BVw*apZ5<5uE$cl9X@IsO2i6g>#+H&((l%{Ob06HWPcZq zIO+d}n{)D0@#R{92O6d*Ef$eQ?Ry(A(~XW!FK=^Ev6|$xytK@LOyzUX`@Tvxn@%Yg?ymXdHT``&AO3EfLCh3Zd}&CfX3KaQK>*ekd!t!r_4pz#U+P4 zLpbJ>Q|yQsE~i5GxVH;x@IeXoC~*vCf}>$tPn<)F!Imo#u{;v^JE*<{iPH_@*S5TjrBmZ>$3+Dd&@jLvw9`JK2MB?SXSk;VW!RCZn;M$ z9aOJj+r!h#bh8Rw#zDNcEpIoiV`b%)k}dr_=$_wy*!s7{59eUZX7z8f zc27qTY+IR!?r)EATwBzvb>jJuFgsifHhFRUZ#0IchgsUb(aVds3V*_PaXip+(SSFA z2KBeW^pu#Xh7#Kjk(ub;`S|(2-SqD|QFk0wQekDFivFoGY#i#4R{ijl^ueRgZFdM! z<;~K;Nj;r`=4P+?$)OybjH5ZqkNV>(sBV9SRV`r~RWI+oh@BODEuJm{$q4akJ$zJ^ zq}X|U4l@dP)Jd>2rc<9eFN{e;AEuj5ZMWf8$-d=)#%1n5D+kit0ZZ~I4c*;dz>;{A zxt1IRR)4IT6BaD*_)!^#+M{j%loU%BrtMxPjVzUe*`YgbyU1}3pYW!J1!b%iL zrbHcoier~(m8rK}y!LuOI^SD;-CmQR_pd~l-fku=nJ!2;+Ebp`I5&D9vjpm&8mG|v zrn`&c{6QuSbCgl?6Rkkyeb-8V#!4Rbeiam zMnCk#7&ENPw(?Af@a~SctdhcPv>V-#+v=s0)d68g^Am4TO4JxkiL$DE0S= zgg=manE6k0%zM$Rw|rL=_*E!L>jEj|c|+_{#v`n{ZZpgM!ok}RQ;$gIB@YA>7c@|LJ-m0XWRNAo&1AKx zObH)hiZN?I-Bi-kw?)8996M2?fqBPx{%6bB7kT7-uP7X!9B*1kA#c@YZmjA+Qa~0y zoYk$5@q(Lpv6z~7qA`iH?-%jj9;a+`AU&rc(Y%jI6hiC2~-M@V88kw5;7^KEw{!WOSUiVi#D}4r}ID7eihyTSR8&w@P*ltl8Yvno9wSeYnyFb? zS!r1=OcT?}%F2vV%Zkc8l$Dm16_w>-?cXfG(0rcf-Ov8N`}5h`=lwRPYp%Iw?zv~? zo|(l_5@YkWrLg5S3Z=x>1Z_F0Ii_Oss=gp&~t&6=8% z8&t3UV+da+YSnY{_?gqn_=l&+C`llCBWB9uu7qX|{nd8|^ufrb5lQVnf`0O*!+o7-@&@-gkhO;9p+V)#F z#y93S3N%!`s9);uIm$g6mHGIU{nx&==b2Lxw1|6ipg1Dq#p}a}>{qYszv^$#tB6;b zy#E}>RgB{UI*Zm=MFw&vQ98{;;x~>6JPSrr_GX2o5ox)aKU4;kyW%CvWo4$|z8dFT z3NFqP_axCp)DjlpU(TGQL^?=x-J|!tK9?05FS2Kx#2!^?;x}z0949$sQ);PVIMDi% zZuIc{rB$Q7S~QLE@-yv~i@{{X?V-`yAGDW8(q7S@0<@Nh7qr*tjx@yU-D$MKTuSM( z$QvFbzlKZ~ijxmhBkfgsQk7xWr68>)`O7oJhePEgu4Y)K#X@Dt3luu(R|aJLB0WF4HP~Dy>rSavJhYrGEMca5E5w4qghK zV<}!1&?^2Oh0Bq&SejH<520Xjj_OK-YKsEu#7|SE2&K`&NsEP(HHNGFis>K&%mDMj zVXz-EHR1jOzLH0&FRxFl#R3|{-lECeK?SUg=CM+muAQXmYzK{H&r%luoW_DIwv*CO zUK(#hnY=CKi4iD!B-{duXTQ-NXWKJ-VW6ttAhS_9)0m1xNj)`jXtRQVO3P0 zs|xy@_5j7|qbXafMZ2}$r0I-=vR&6HkhjLOa8f<>ZYjIva~1E!q{Q6JSTK|Ds=|93% z{;F<;U*+|t?T5}b)Y|Yv8L24a7<8(4HqG-i_!aHaMb@Qp?5yV{^^WpM6z+Y#>OIA~ zsoqIF8gxWokEYiAU24uhq6lpa-qEAfLLQ@V^o?-iJV>AxM$hthSGe#FG^G}N91Z5x zsSVsH-i_L@6%@uhQ&YSXLzt7|Sg_|io&bL+4H3B*N5+EjkVm@8gLh&G#*lElmyMB@ z$b-njm=*{f0o+Lj`-Q^sZoBZF`@u~H1L1E~;U5Hd4#)%_05v9j4xWHa9nc(fmA&!& z5-HHz&w67d|Cok)pXWh}(-%@NJ)OqsNi<1r!SfqQE750W$Zn|T07?=o@SgbLS>8uA zD&24iO!%AP{a#W&PV#$%rN0Pn#7jA1(ULY@v_ zIT#93fDf1eMuD*)1Eg!A&=)|#n7anag&1R=MR{GRpA4l=GJ$&W&C~_l0s4ZTAQU8n z!C*K@0z*Iwn5JL@s2k`2zsfri^aedZFi?31Rk$i|vUY?rG&hYwUDY_gNS{e}$hH)V z_j(GLg?VfjcmYI$Rh6zvhrbBz_YpV>)SQX;#S>XhWtc{l$D?mM(YKvmmsPlxVdP^@ z{V}W~3h7CC81Kce7&~94VOj*u1bNyc=u5l7bhP7ia?5-Wk2&=^_2>I3nh&LkA{Fjn za`A7dI_CfSe3j=iFQjmyYk1B~mH#Si`wFP%UTF{JcGd#;3yn5aVO52>Tv5qHW6dbB(agUBJG&D zfRZbi1Xqz$8Ro4hm3N|K))(uCQFxZav9_?`jsPjJuMgHo&(Tz@GrIGRSR=$@K66rM z1(7EY?)>ty@xDc4%uS$ZEsmnJSV}h!E!$O#8&j#$1#Ub_RP}uW3KG%Im;K& zPHhC<^=Y(C`@=I!jcvwJ^x-d%?^*9yGC+&QT!ZzV8r!rT^bFoXCJ#_Yxt^lrgOrAM zyR-Hi)`wq1mkaCaF&MX3p^vUoILbR2|j2b`|OyElyU<`>K3pJ3u@2Rda_d!TN0i#*%c5^Q|$?e(L!hHW)Gu z?~|H?f#4L(-h=;M?;3isK8+TaucbZZG8kjkSc|pt5bZmR7p3G|g;nsc;`ww0=;8qM z?FU)ZhrQ=f^ya~yKKv7^%MYQRZ&9>-8slYatWkBUqt@SW{lsoOhvn2+=AbRn?qV+H z<2OB_{7q^jO2|h%g1PTyjF%Hoj}92`8hiSRKgi}kc-vu^;ZMViA;5z%q8~LCzhnM- zgIZwxXr)=SRP)1}*_@_hO_Hk+SEvs9I@fz)-o&@1ID@`E61pZ}K23rBE2ur%B#Tdn zZRZhgfo}(lm5}QwUqXAoM#Hse^nni$cL49l2Fe1H#8Pkl!_Wp{qA%9TT`+&Vi?wza zJcC0t(p&C13c=dGlbDWYmyY?NCp8oGk?&8cjq+FFn<-hwVGVKtWgjKRU&FZl5x!HJ z!kyuzs}RWBjwZ5UG=Y7HwmpgXY8dmr28b8cFy|*@{CkjE@r_7(8BC`DQ5S7Eh#H|U zC#v<27>adMSFD>ZP&;;sLag7Odq^c5C(x zwPK;3y=)Kq%_^)Rm%#Q}G>Z4bJc%_O>K4wkq5q8M3cnZMO7mz6dy)d#KD199p7UyY zTh^hsu^yU=@9gnlEN?x2kKGFT&l&~qf;PjL zD=$zTj0bAW8;1A3F6Ozt+G7-e`8G|h{lqrZ^BL+Pf5-Ur2zAx>QV7;|3*>muciy$! z3i$Cpir=Wd7LNY14gKUn^sfwzymWPcTgZ#3wsxzV;(4=5H+4@$1tb7ggG?}Yn@4`!&6wt?8KTF>o2X$ z`z`;F2xc)N*z>J+((}G{l4I?qsPuc@H>cBftpW7@j&|=rnOZN;dF?^yU4-#(D#rPq z=o`Z@zAlA*S)MC$CH4khq(;VA8fs3YiN*{(i zBZ%Lkz&x33K0*EdPs7XC#%irRNyE6TJxe3B5=ueY*D>!;xv`(phVuCUtdR%6{<~-z zScUIBwRdv7f_c0hJu2p7E!~nbz(A~d-UNO5G>o0oXn=U#^NYTmvb1Yx>&bZL>*4po z+%^Gyq@#B)BvNaFHOd?4j~JJ=c-Znbjlf#JF_;79fdQa9NCq9`N0=inLx%(Fpb1!W zDV{%fRLecP-o}!9Gv|R2eE=F$1KcJ=8Zq)$f8djIAROHv^0T zeSrEt=nf)*`W{FC>N}$)WMe=__;1xS3h_$6`o0JQ>igr??~!!Gsqc=e`V$dW`r|+g z=;#WR?hbI3&JlbsEkRi2Rkme;O56IuUzxW#{K~Fd>!xg)36xzEKxLl#@K=8KsBa%t z&!M2Q93`u4Qf;8>q5P^1T(GGV=!`zJmNGFO)S`L{HO~@Vt*ziGp1&|RM)MIK4|l<> zhv%l&Wlb?wt%X}mV}x2G6?wnoT8RX_BZKkXH-g5A<}^YKK)3~^i)om5YI^(a1@ztS zcxMRDaWnQQM)J?Wi`a80|GtR8H-kcbznlkZpK>SI1Xh7<748PO>Yc23FIArMy-YR_ zee)!~NzP+Dt8n=y>@k;t{wTKq?sgb}ophQ9Ij5%#d5wy4BedtJt@#R#H)qoTSn0zwWQ}V9)X%%&BBPN`1WiFTDHGjj^UV-K&6qI^4zO&qcM~)hP8}^$+%` zHd1>zGb&JfII3Ny05xU}0&3h+3`Bj;p}h;>$G4(4ZM<+^{{ivqz2i!GoXVr}D*0dG zDxJ{p*#S2bl$Uwl`@Q#s_t{l`_o;8lo4++5kYD1vUy)1~koP`t-0Nx-s|}$|3WTBm zCh+a*-J71TbuHiL)3JYtxW#x@HL>>D=l!O+7vsGHIP8xK?E7H-oGfP19@Xc?MvB8Z#oPE6 z>mZ(>)!w}+oJ)9R_EQ@T^OUMD-nWg=*Fvq`)EZ8_h3~qq)X`XvH4w@WqtO=QsSoCX z_V{MXV!>EfZo)f`wI{}Y+q&Q?G-+VMueP;EUO?NwM2H{ZLj zfIR^9z98<^if8(S`Ub~(=}vqn&6fDy;@@HY{T?-j{5aqP-5l;E&=sJcdfirVaTewc zfzd;`(a1N5M|`?}V$$QYc-j9O%AY zy@E)D4_CzB2X`)*3Q)6a=p)L1^>R7aVB7VhSYJF=6|8}?5&j2=AB*^ZfcQ~}{|AU4 ziTHnj_!)@59sgT){KIBdkN+Rp@sBoE?f!3`%m1VHK%Y_l5q-$p7vbLgE?~S;XK!lX zJs2_;(p5iH{S^K3I{Ig2U%eLWUAtH8y&?TS^;Ol!k3udEsCP}hTYJDx#A67&`WgHc z@6q)}hyzy}f=|J6qAUC1CPJnLPKRlILk@vdFH2p$JRz%-<(_q8gc5w1ezJ5=u8 zdY0u4_au4S_}iR){YSYWmFH!i(OO?mAF#bVk7qdiz5Wj0uFQXvN7-0mr#d(G67RXJ zsq=Szx5V8N zZg@+0Kq{AVMzow1OK0T=E{zP=ph_c`DDu)w%fXz_+sZEaj?a zrq`_u-{g9lYJXgh2N7U3zOh@ujR7ui_^JnIMxL(a`TxCa`B^9SR3be;@krVNa8~ab zqs~7o{K_2(o<`hfpaX!crwky?QXkWCaH5PeJ zqn}_O;wHLzR^1f7HT}N|dwS{Jua5%*^zNR4aMM5{{4>B1Z+TtuU08%VR^<)UyE6P7 z($w9EzsauR|2tmYo%o-C{dTqIeiN^Fj@}fmyn|8Yyj$(B|5sFuL+UQa?a*+)qbd^T z>Nj!v`lXw~Rnt#jFOjFO9Rlyj)7Qhnr{Lrbd3>u#+#C5tdg(Vx5|NlluzJDyrUbQQwG_JX!8H3GOX-4gP%? zYxi5_n^MDn#N8sJ?$+=RD((fSwf`ePoku8tC5Ths5(=Yk#o5HUo8#2?g7#ow$JkO|gayg!zaC=nve-)>2rgf$gPYJiM2Y$wL0(=a$>z>cyzJ+taYU+#w?rN{x8BcGx`*<^?mw0w6Kl|D94)$JfUgUYY+*ST^JFqvu zik0FXLn+U}*6S8`JLD1( zSM|Qg?fg@*pD@ky*?*M#mwAz2>G0}Nx^7FqoBD7%&Wy&vHuP&=>SZR}Mf^|Pkth$( zfjb9xnFhjL$xA(d2z4&@KVf^7dmr!NOs)j`^f;Hh!9~yg5_dqnypOYmO22ZehLyh( z57HDBvPKWw9Z|$n^BewK!zwKSD0c>A6&3kp)jK;Qyys>&-{Yy8{;&KSkgq&#p~Ss2 zFTUmHU+N6(b_m={s|5D|>Zm(v{|(|^oT;hvrd#>Kd#2d}XB_{yN8>#cs=Q01?$b=A zk!%C*vUT!Yl11(|eyLj_RuWG`J5U zrMml~?!EN)9MY3K`Fhgz&EOvJEy4wG9{@`$!q4afJJH8S3#k47|AhC> z&Qs`@>h8|}66!7x_FCLL9Bw}LL~G)XUrp>i*2KN1nx0b?;mh!!FAqburY8#&mFLCY zX-&_o;5G0*&YAMP;O-F43IC6vsXIs&caPwv{BKctk4fEMy6Fy6)pa)RGpTi%y1!Hv zbjTg~-RAQ33Xo7FOIzQumUoV&gnyG2+zu67C*pPar?; z8mW6pcyIc9?}Bc}{?A^_9ouOV{}lHopM=acl!3dQYV5~7F1j7w`<@|`r?1CZG44-- zpY$zQ-&WyrZMs%6mGMuDY*Ni8tMQZ%5tTskpzR?(kIJ z<572cZrtZlcX}%C^{Bf&mG^tp9iPg3KI*Pd#eE-j=SQLL{Zzu#{hzAfE|9tpbmLBt zx))S&H;ChYkOKAc-VwTuTfV>S-M3bEmb}ze=e}MZ#(u84k5Y^|A;q&=kf#ssr*qNR zbDyY(I}f-Uq3$$r+-In~%kZD>G2Hg4TOFAGSnAm8kKm@R4UI_Zn)~aRGovW{Rp)_ zS9=mhHwxj+sRcHV)IU)UZ$``;Zh#p05Z3Y3@DG9V6mRk^|9SS7@a=<~2Gd+xMvLev zx|`oC}lZoF5 z*yJD|sz%kxm;9&()udWfhw4%Q)uZ|pNDZhVHKHJL(li>69q-vRi4rK7LMW7)P*ZA# z8+9&fNv$Z7o}kv$hT2kl>VPw`j<{zQLtUsVbtCjE%EqbL4DUIEn~Lx&hZpE2dX?Uw zx9ClJo8Fz=OSs8N+algdW^oHLv$Z4q%o9E>PhF&WEw@IX*)en zyXiUFL%V1%71KU?kq*$y_^rr(dJVrMIY<%IlX_EM>PG`8kp@zKN}^tPsInIJ5>ZRs znL-Mo{pXA6;w~{?EEg-qW8!_eOsiGBTSK3QM;blU=#fT$2GtH~7}O)Ef6(xt)S!_; zqk`rI?G8E=^kLBFK|ckR1zmUgIU75hI3t}=&Q8v*&IIQe=M3jM=N{)v&M$(s;99|T zgPp;RgPR0L1h)wu5IiP$N$|$tZH;+jy|HiOnvH8WuHQJQar4IEje9rFXgofIhxmmA zhu#@l7KTIJFrP5LF#oWCu*brl4J!#d8uksY#>6z4)O3MsifeX6-KXn69ef!V3$BM; z_juGVPgH%Jv_<5Ixnc?GvsyeMj>!VlhZ-b>*EYf5B)CGb5nhu2|H4yKC@iut{l{-?$b`xhps!l^~w18DeOEGogH@;za~1-f>0WUor9=VatqAqlpoLlxSnLvD;sj2X5QXX58*1)f#{EBcLKiKQn#xENG zjrNQ6#{PeMB;*)}FpjaeX(>B|(X0=~u{exJn=p>g$EcByU()Q7FJNRlgK=&$?keua z7&cb!kuPE;xeX)Ma~Oekk{VAXM$}yxQ+H!Dda+_O`Vu4Te(#9%3cboTjEo1p01`42W$Q48&=bdiOdYpgToX6t)8WIk{GVY;n9&7Ia|7R-0@e7lId`9faA7xBe>m+>rL!k6+F z_-?+8-@^-V*YI(^oUh<}_)0CAui|^He!Q5k=J(mdcp(qtP5J$NA78^?;%oUjzTa-Z zKja7a1N>#ao;Tsm_=9`{-^gF#oA|5zA-O4I{^V%ec#Y z+gNKJ=a2A1#tEyAS=Wl!Yw2~(I4j$6pZ1sbr?Ji0ZhmciWYy)5@-1ddYosyG+-s~c zkD0@)#l|f2ePg!yp7FAI-FU^kW_YX^EGash@zx?U!CGjJwbq*BtTkqV^_h9E^{F}8 zdeFSn+TtkWZyKLlA^b7^7Jr<-&7a_hja>7v@v8Zo*~6M)_B2|Vy{wsLZ|hF;3F~M6 z4nM-*WdXc|zh}%bwwNc)hURSkK0oSM&yN`o@~w8DanStT^tZb5C;4&yl(mXK%|GDZ z@$dOX{saG!|HLoxpZPERS6;?{vk&v%`5)R~e%Wfo|Kxx1EBq?I#;};!}K9YL` z35Fk23L%9ibYTcnSi-g+6b|7ds)_2tSNMq-$NVE{)_6NcxT8aqK%JHCMgNPKZMH|spM2U8yz33pK z^#svTbP}CyQyj2uyM}mKydqw;>)7=i&pLM4pW2^`*To_6hImuFWq)UXFWwf1vCilv z-l4umsNP2p)C2T-dVO(3ysNj>qeO{#PrQ%2#O14yB&JzeW9JwP8(r*8>5NdNN=s3(avgLYF}yRw6C>q^ild4 zJwqR_PjWDQvOYtfXmr!3>eKac4(Tu)w!_EaYxHpVI|5igeU3iYQQr~hXsE4qJm+va zf*p+=A&yW-n9<$n>S$s#)$i1E98Dd~94+)beV#twQA1y#=iBG(uZ;*jSMR0YZ8UT| z?+ACe94#HK9BuSLhSO-QFLl(>@6zvcG`GKTSdJh^JEOlbz|p}G%||*qIl4Gv9jzU4 zj(A6cqn8oy=;P??NOTNvBsqpShB}68NsbYYG{+dnSjTurmSeJGnq!6|$1&S+w`0Cz zA)CkMYYQA}^_F^sUCQoedB%AATcgPM)VORuVmGp<8=1xfY&c6X+-8wc%2JI#%sOm@ z8EU%NNV5Y=Gl#QLW{&wV8*Q#Z-=l{4iWd8eE!bL8FfE}1935$DY>tZw#x z@s&7djut-~kBQUbM{z+b(_870#tX)7_K>}cZ7`=8e;HTITC9NG%Qo9D*?a8+_#N>C zw!m1=^4TI|7hBAhu%-5kY#F=93^P76JF*pKit(s<7hB0zn-8-4*!^q`Tg%q52iSV{ zAlt|`nZ@i8wuL>$o-n^-TiKKBDf?aaG~33WVb59<+4I&C^K-V-y2y&Guh}lPo9$sQ zvc0UB?PD*o1MFqDVeR$HqJ+s<}a&Fy1$iS+|}LC%-=vWMBLa)Def z^W_S;P_C4V0ke#8D)E|rCHnY>@#BiA^NINp^7a;B*~V#OAnPyMwrjZR+7s|DP(IYWgDrDceg+b})VI z7wosBEu*DFc9cG{ldL8?%jz;l`pPb*pK+i0u2E=~80*XrjQ7o}(oc4E?039k@3!Bz z_t-~d4cW~uw%@n+*+rk~$w1j#HjsT}L)lk0lKo_mOq5R9-#%`?C;EuK zqMt|<{lx$=P$Y>#Vz3w@lEqLlObiz(B2|nKBSo4RB}R)eB3)#Nv5t*moX8a8#RM@? zWQj@Q4l!9w5mUu9dtd1Zu&as1c6EGdEEUUaKf9LgFYXZqc5QJlzNS{-`(u?@t#{G8>fQ8My}KSK?h}Q2 zytrQv(w%yHy@ObzN9!H+PGYUzS&tFx!~&o?+c19uynQkIkvC^^HxZgZ#Y%o7GHkv1lP3A|&*Gfr7e^c1V9 zaatc?GOMM@tqx{@m0;GhdYJXCo@OH}(G0Tsn@($h8Eg$Sn^;54rdG1q%o=J&SZQV} zYm^yjjW%0bW6VBQj@j3`%j{>(G83)YW~#N+9APapGp*I;cmfv)Kkr=)<$!h zwaJ`rJ!EEEo6Q;4!)C7axH-pq!klYuHSe~bo4;K>x#MCx@tAk)2wsW zua2J9qsByYpOIz0WK1&m8+VuojLGK9#uW1vW2*V8G0i+^OgCRMvd!0x8Ri?tO!JVj z$Na%~(frZaYyM;uo0p7z=Fi4U<}b#6^H<}5S!P_dqKs>n%j{%jnVqdkW{h=**~OY{ zcD1IM-K?o*tToNPX#Z~iVE-KN9$J}IHFt=DgnvYwT%*U*s?6!6XyPe(9jtQtE8|;x zrajBfv2*P^?b-HS_8e1~hN+pBDNWPVP20+~?zZMy^Q<{mp4s0_G6$N2%>m{h`yP9R zeXqUBF0fbH%k9^QrponZGi?lD#v_Zq8=0%N7I+*oaovnSf) z?MZf~on=q3?=ZeMelmVAel{)|my92cU+kysXY6hE4*O~QS$n(voZZ5Xuw8bf9d5U> zTiUJdZgy9@uN`amvAfv)jHSjBW3jQwSf=G^3$$t4Ozm!aiapkzY-iY0jrWWa;UGrUQR}W0p4CUT;5O7uxsPi|obrI{SWehxx4e zjJe%R)8=Y(v>EnJ`$_wGd#mj>lg%M^GrOtXT+7y`YYVkS+F~tVTcR!1mTC8B1=_vZ zaxF`npiR^s(ALugZIarBvQO(_dQ`Un_ z*c*CtZG*N^^Rq3jhE`LnrTJ^MwK|$Z^UfXZ8#G zm6fsI*zfEQEzI)R()P6j#HVtA94M3IAUW6?E{DiuIaCgl!?Dk~P^QRKIYN$ybt zEyu`o?W%T7yUt43n=*rcu3MbzHWzv|-B)+$e!7odU9X|n)J?v_v4)%6<`#EwKVE}Z z<37AP_r)D0iLcv7=pi{4fBPX*?cK?VGD|+JJ*{oiwrkI5&uTlg=d|awotj(QEGKEZ zv={J8s}?+5uWcpib~gwkXiAS%r?X!%RUg#Ptq&QI;*JV*H%m>Q;9Nd5#m&Pq z_LYVps+97=-FCcNruT4*7Qu*(cP@7>hvuS4Eo}Lq zl=P&)jKQfXA*o1<9g>2CKvkiNQd_z;m)nRB--XRoZ?otKhQx)Sc|+nd+eLya}f((UW& zmz+{0GZRun-POj22)Tt(y?KQyJt*EinHGUD9T!&MhU z$BQfSQU9ri|F~Hlw5143N-0wP4%LlYj>m&ytF;IYLAFYNV0pUAf}X2VQ&E#%u)kM2 z9>YzI{VyIt5&k4n2pTEgOnf7U4R94{%B|-r z(v@4^Rb(hP&{bqAw}Gq3Qf@;RxqZU_3qu;gkcLnY1VfbTgdxfeh9Syr3`3L~0z;G= z3PY3|21AtF1coTLDGX6=GnX^Q+f$pnP=CL4XFMK4x_W3CaNW&Rr)uGHHxG9=M~4qb zSM7x^b=w{vk`W!EMw)*sf&S9c?Yi*{SRHqG3pcAB>22kfRa@oeqzIR@o!8D*kYPRk z`NH8nzO7j*p6cxO?zAR!4T&y_V6{<`NYopK-Zo1*dTmB@OLuEmMBSK{?l%8P6g_Ml z#M|OgP@OPmgtM3Th2&vqh|kEx*uvv80^v_j#fy1so(!0TsUW0hMs#2ZO6ZBM z0moYk^xdWq7^229iMJbVuc0Gp|IiAJ8OR*wH3I*|BoG)9ocecJ=q2q{8#qzA)}*2h zLSoP~9lX(Q6K}86*)yb(w>DhmqwM4gaYm?C>xoe}CN-j{1@p&?*ZD>? zp61`tF*l;U(v?|nlIh}dM}=3W+@!Rt%iS(~Ir@<5EX(ma{-a<#mI!wXl;6$UT&e?B zwyx@2A$Thy@RF3<7>mII1N4oaT3O%!+!cG>u4DW+y-&598dqXMq634gJn!Jt3LCqt z#;9!6I92~()$+>3ihA6ray+VByZq(EWQ_N)R)jke?_$Egi0^^1migCmw}wnlm%A;T zUaHl4pk19kF=th_Q*W2*j_zJ));_LXM6vMng@-9mKi4kijY)*Z8`EFObVt$vC8In8 zm5lNvDH-J%q-46lGg!$e&k!Y}JjqH%d4?*PZtx6KGRiYt$tX{Xl2M*iB@+kF2qmLD zBbAKuq$wHY8Kq>p!ZTXQD9;!rqde(KMtL$^?)EpDd8`V!J0W_U*Vh@oOmBZebPNLH zUG5Gyq$j9=S9+q?r=+vIJ|#NI<&M4~dWQ;lMJIcGN_2|Xr$nc^+#PR-PE!G|=yb17 ziDr9!N_2+n1xs?#qkLG23wN92-6Aw8S4}l7F&AKwe0VUHAZ#^;~5b`fcDdwNIV z<~g-c{#d)S+0+d6)H0-55z#|$t%qH2pm`&#xR-r#^}veNa28G$M5@KTOtJVMdVn`3 z*6w09H^Zp5AssD>1SJ%OvVuWaBNn6-iOhteCMxujnU6mz6I(D2%Pfds8Jt?oJWJhj z6{ZvXLhgU?Z!gZuR?rIk!VrHC5x@7@uKre|wjFo9HP0{QA>3(b1F0Kw+D387^Xv6z zDkZh2A^U5EY*o3JZqj&3d&#SFUHM;wtg!76+zMDMu7==NJKqdjvhZu%DB#8~jd4b* zBW&R0)4+MFff?CM0_X8Z9-ZJI&Tb>YG5i(DG911iz?m)1rhRc*?2E7;bk+z38^Bef zn$TGbx@v7B@;C9fI^nO2`~jd|1ETtn3(O;GkWbVQX$_I55z2Bd0hft_3ju6y47rdf zqEP4v-9i+WLewOesOd$bW{_(U08oB-DN##5fcS_40JqgPqDYh%iF~bzsErTU0L~D# zZ3a+QTlk~kwu4-|Oi+S9)iMQ~BkNH3grXS8#}otD-laEK z2M&UZcwM7GI@ke_-VNn-L;h}%=?0lt0#P6fYz8MVZD5uY1qP_tDas7~|e<;y_-9$;v0LmW}gTF5dTZfbo4Mo~8 z36MSL}Lm7+;r$l-wZAjWh4XW z8;kI`6oB+h;W=8|) z%0>Be8i0#LcOze(6F)qU0%b(=p??AL=4S)wS_oYWvp^~SZYEs)uAhUhV{)lKwdBGFTbe+s&vhTPMzaU1e& zivgKL+x@^4{E69hM9;>8ECAUZ2=6!m&JjIVLiBt(C?nc=kjR}!RFqBhf(dpL?S||g zl(WZ8^dfZZbrBWA{^BJ>`(V#L$nQg)Ub;xM{}|EBQ;1&KMsyHz2TO@wL;lxM<{Qx% zj$rGd4McAy61^2e^mY!>;Ygx)VAnebh>oNH=y^fJ9KfDW>Zw}#h57N)We;#ocTtwfYZN5jo?_tkH==dR@=tt=N@i5U(c|@0X5d9oQ z^os;riGDpuREGH9a={6r-`9bQM1Ldz=)CL?(un><8Gj+qm1wXVzaQ-lAa|_{bJ8XJ z&b%00CWf0JjHThPLNx$+pp=-11%==$Cc~BB95F4Mn4Uz;h$3cUlC&yU4-kU1BB}b z0HoE2T%Zdet^v{-TqM@;60t_G-w8XMusL`OvBt2k@eY9a5ZDzO3ziTILs?DIh&4?h z*31O?05UBI93&PV19FMEPzTouVl823OOzRr4z>|%l}9Wx0IUNiiM57JZK46fm|Iv| z$VT~qGsN0KwmtN=j|HW~I&1)C#G(tp31S^{iFHCbo#1vx-WY%2#;P(0tGy&}0ISDh ztX5Zob6AlE0K|9S0xn_Ih`Qh-fW=1vl$Q_l+C+KQ74a@?_mjsz4$P97;ls7mT zoF_H}?vP?)$)Nys9O?u+hz&~wXNV0)9aEqu1$j~-H)0#Hk%x(;B@i2(O>7M87z4fO zvEUG~jNafRv9Sn`MR;r(v2nS?GW|h1fGy*lAQKb-=o?>3Yy#|>kVp7KUjXtGkvFRW z$N`&y3ST5PDF8tCB$Pd=5S$@)MH%=6 zoN3TEEe#;wbQ3_=^lY%3Sau4r8OSpu2Ef)C&^Mz5TqHIVI%lo}2;Z3w&JoLL1|XLM zU3VexT}YeN02Bhm%|@Qt@XszImb--59DibS{Q&aMMZUR*iQNtIV9&f}#O6c)0>tM- zM}9uBg$OU<s^%*ph9;mPUaC#FiZ+c26;}f;?jPCJA5*_JVzx#9nd|+kcMOf%C*(M&4JT7xNT*EsfagyNMkN zAok`qVs9-W_I3kehuy^9$tQMXGqHE`h?Ri%5dR+H-_HUki5)E^cFY7Q<9IUwyFN$; z7m0m{yeFm*`zV3f$9@3vpX?x3dW_ho1;joBpBH0k4jrc?vD2Bv&h#dB7VeiQ~Bc_J&D*KlGx=; zVt=B%zcvuNg7B4-#I8AsT{i)AdJYq(OT^hR;vyQrm1*EAacwhk!z6Bo61M_~+u6h& zF~ohMh*v|nx<7GW$od{4?w1G76R(j>yk-LNT2641cx~jZ1M0fKIpP6Zh}VNG#&sUJ zm3TwQH9Q2a5)aBGjU0@SM`%IpL^oz@ZW+#5i5Oe}yb*6qCOZsOh2h-0kf-Jv%gvhjJ~GVuhI z-NO$+Ur!0##CtU(-dk~wc%K9SJ$;jj_k)haB;x%c*B|=(Zv~JUu!Q(P=p49(cv3V# z+@NCOgAq3vBLpB5GNrv9!b;L1#@}ViA;xiJ7&pc23PNe0yh~EVp??QNX0`XjwJI76Y?l$6gLw?>$;`2=a z`xc-_?BYgkNFXQ9OXW-1VGPL*z@EW;!o!j-_{#!A-=tk_%q1=%sJxE77*V7+2@eQ z?N1!z8Giw3yPcqf_?~9OU(6)F7x{}L0rKqIK>Vd>u!H!1AL0j+iNBH#4iSG9?Qu|o z9B`HRYb(KJ;%~$fKZLY5vxvV1J#V9ow>J|%4EOLQ;zy9@2<&}#3xNE4h<`tq_|Z_X zjreht^?{o>#yEar3Gt7h>topVNg?r4==ltCpC^Ee#7`y?{{nKSz-h>whTb!<<1A#( zLiS4{{uN};Wr9P*zlJ?u7Zd*m;cre5|27GnBz``c_yyST9m@C~;fu)o!xRAjk7>kz z3Lt(-fja#h3y}WHG2$2xc^UNno=5x-xR=)v|MM#GD=EaUmJ+}2L)_y}f>x4XB_zaF z5?UfSKtcxw;>>&!b`%N6WfDH?NK}gjCrJ2~lJF}dQR6&`npa8GI!3}DZXF*Ib^SpM zfP7uZ1~dQ(U;{WuqMiiJKoZCWTfkuwfe1HG27LK@Z*yGwjqGbVz2;^&x_}1AZ+CVNUhXnRI1jb0wDHLoY z(HUjM#E|HMdc|HM(R~MrIMlf((tDjDfzJlfyO0FNJJIJHiN28_55SIo4FJkZME=Be z;3|p!D5L)|5(9dJ-6RJ30oXC{B8jBUBnC+U+XiQXlO%?K$+u(I-F|i7{xiF{R)tiSz~_1{9OXfPEQGu#UvobQ0r`ZyaPYH2v%5(&j*Zt`C6x++=`q z=57GRB<_{~W#63$vOytmgJa+li9CORI^>-vF%LTCMFQxU2OaY^1C&4S90|-XV!jI` zfgAw+^ACVCBo-iT0n!#A4f{D_0rD+Cz6HpakF3yyE#t zuz|!*k;Df9AOU0p)a3){`Ves+qK!XP{xT9L z;K%$YPV4|Dz*Q0-LH47QBtC8clEF%Fp2R0H0BN5fUuhE929A;V6godm2kQXzetMO} zXOSQiYyc%BK6e2(iIY>nMG{{`0m$RKL7aj-z8%CF=s5#@XB&WQfO>rC10efl8i1W& z?f@r9eB}fv{~XfJogwix^nQc<-yqMo(0e|I#0BWN0GaP&0m{A@2~Lvu5#b+^{^J1> zKM`;N=)Q#XOIt|%5>4XQ&EOn~vV$c4$RhEl6QqGWfI9w#vi?d0(0?tNgr^W(CQ0ew z1WAVfk0z`Dz|Z|bGD&HY)M7{)PLigZq#Z!g;Uei%NU~ZEI6$&GWU8ltl_Y&b0bD=m zssWiA$W!AO;nFf_2C_j3$y$CO4Iteget+cm-wMu?tnC9(W^LG2dkNSE4wI|{yXtNr z8DN6lBefr$WR1|9_GNHz!n(A^*pYynqEHgtk?fU+7w zZ^KfOjdDR5$)HS70CoWAbNU15bZ!RcNd_ZtF!BZ;BiUGjW&r7pQD)6!z9B9#DaWq09+*5Boa&kyTN6WO_AOddYU4=8S*zv0879j zP)4$O3_!R!^tCVn(p%&J$cIY+JHiVA(!-(86%FzL!Y%zk3P5_x5|R-<0P+z?kAVJG z(ANt3S}g%8jPfF3PvlB)f@EudkPMLC8u{BG+$Ifd0Vheeg}%1X*LEE^Lo&(*a=|um ziDWy3+hv1dlGw+S?PCDa+wTTtBs+wHDFERPmq|uP0i;JGe>BoN!j_IJ!7-AZd;s!y z$^!>Uc1E~!3fKxxkc{yM$zU@$PqIrC$OK650^7PeK^E8z%1CxYdNKpKF)?#Lg9a2#xlI|Pu9Jwq9v0}hZ(FhMd{0uGbxfpCxBpb(rS*%P+* zOav>z36j110c`KJ0if*O0U!xLU+>)jGQG=4_Cc9_5Z|W&>;SN%FXH+_t}n{zdy!;6 zKM)0=uU{V6LNYOwWd8;LHed}Y`=gxxu(Ln%50Ic4fZhSQ0P+J+rvc|k4%`hOlN1Ry zgM;7_$w3GYN(V~-WCoRz92@|W!Aby`A@C1@jYAPX6mdgOk{lKV^1(5Z!;wDx1j!U1 zkO1<)Zg7!gYA8qp>j3JNdX?k|lsO_3KxU*rfF69G%QWOmyG(LaBFWJkNREjHr6kig zlgxm82Fe->{bP$sjw>XY3A;0qJ|6nULuLZp2`Fd6Ws(!oK3F@-tP>UMpA9!V6C5Imb)cMifMgEJn6;Z^ZZgR^TS(pwd91tSe3UyMdKMtO z;26pLSg?)cLWCDdaERn$gqJ|)k|hALOHtm^b0n9ggA*k0*+R0Qj3m}cas|RGT_6`6 zCbz+IzU=w1uiwcAKO5CBle^$7s&@L(y) z4aFokMgyd83LyCq{QnncUjo=_xOCg^_b-0U zdpzg&d7kh6Jn!yIz}-Z+PY+l}ggu2sxF7A^i{A(45aGeSM0lv12>SpJGx&lCkD%N~ z&Jf|zE+XvjC&Gb2B0RQ=2#+5k!oib7cmnX`K_WaQ0FdXYQ$#qF20)rac=v-O0P_3* z&!3)3gu{4#KP)OM7bxo08rj*g#fhkwcSK`9q(WNj0is~2B4om zdxr>bpv*Up5aH*!MEHdnFhqnmk?s`kPklm!xAqa?m&pIimx=IpIsj$AjrVWAON4jO z$9K@yUxfkh6XDmm{tfE;%}FA>i?r{q2O!;VQPywKANa+D-?amF0&x8v(!RHm2=C+l z|7;<`@A3QlH;C{7+WH~V{{e0LhyY$8!pCQ_>2fcI{}{%VYmXYg$R*i0LnU# z-}88P{tF_Kmx)LRh{$OGI{`yPgn}mu1h5!znusF4!Y3XiqLdEU2>6EYdhc&5p8Awev|Nz!4&5qFtGb0qAEIuCq=NF&pV~J|rUK12GTx1xR0jvJ279 zqCz4D0L4xsmS~6=Y$jp|WtJWyVj1#{oI}L&EkvxqZ)GMCt4s?R82^u0!Oe11{65xFzPTE4m$=yVpq9o!}yqo$45vRRE#OcU4qnC&S%ZWI% zortqg#_V-OoP+zhcs@Uuh=coyxB%%EqV7e=yBKMf&LQHmLLx3FfRjYLs-K7}P~M8q zh`7=W*a#un+JC;A1hq|uI1>pX=jetW$ydLe?@G=o^>;kL%e5pUfLc%O(n@O;PJ0JQx!wBa_i z;WoUx4dvaAa&{gh;+-h#&RYSW5%DhMzv~ks-rWVj`&}9$-ctcU8}2zp#CyX4wC!G$ zy&G-Wy$*oq_tgXNY)?O6h=}*!O2obCM0{X35g&Y)hz|`CaUa^U?-&su?gHT1BU1sV ziTLO`BJMvz!~-bzu_OSlA4i(U@$TSaB0iA`I7GxJ2Z;ET9)L0qA^#8d5%KAMz!@SQ zLHcKq?ir+ewws90;rUUN|GWU$PsA6RiTEPY9P1_G4+-ET5r1?m5nplw))DdLQo#E} zJidyECvg4adLq7(OT?cb|4+k2Jh_{Quf0OV*Y^?eXK3de=+DpB6Y&=)^UX9Oo-z~h zE!6!>)b%#XeFt^CvmEdV5r2jIU*r1M9}@95?SNB6d>3W>7I{GT#rKX8@%_C-{Cx%B z3nG4ix;{kxAD$uNM=1LvwEd&SfV%-N13n|-$H@CJ(tkVv*aE=wk5SiYq=$Yg{&5cA zRshQW<7p!PNdqVb^aC~n4guaJ;-3j16M*M`-UvYYPf*rhkoPY~0m%C)%KEDSc!P+a z;rcVQ{clbp{vFT$zMF`jFDK#`Q;GOxGZFuh3qToPA^+DX_nSh%DI)&!3nG4td}nZf z2Jiocy#GS~&UOLz6Y(6{ac&jhBoT*_04R4j9k3X1nuzD|{(Lt8Y0nQ4i3|c>Arj36 z93>Lh4%i8JpGbT!U@wsbJpk#1mx&}M0R{j_D+vIkS0JzQAdytJ5-A}}B(;-B8a&rF z6G?}>y1R*_-%TVV$}%Cp32DuPfHOq06a!F~6=hm+556EJ6#|BcWJkLk^?-duN=A9f zCyC_5uk#p@TxP&3BBi7OkPh@;N=2SDl;QrGNL~%#Ln5W4PTy1_`PTzJBT_~$kur0M zl!bb728oo1bF2!SL@GQ=q@q$H1@K#f@}O%;rD*?1q^-~ssq!5nLI07$_^n+|r1~(C zK(nPrTsNI2QuDh+YWadlZS_Qg4k3Y7OJi;&(l|4bdeVs0hqM!4Ceq|CB2B@&X`6{O zV;_+Q05j2_*#ktHt0B@n)Hfe(9Yj3~01I~#X%X7DSP9rmq$T@_wDb^>mTe@`@=U-N zM7j!XUU4gtRwe+IYw&*U5RtAvMWk!j5otZjyS|@D8%`7HhP#P$;}#-q zLS37Y_NFetK_cB;3^+riTabPW(r&E);C>tG+g=Dj+FN%6@NCCsBHe~(kd>v|-XPNL zy#Tzs{R<-PM7!?@1C9~t&I-UjBHe|u??#(;IRR+HJ?n^cFP`1|8Ig7$CDMJ}0OZ|+ zw4i;`{kXp$@Ae}9-rYocU?-6t>;fRoL%_wpSBUiRCq#PW6pY0{EEjxETBdJ*}L-A$w)A>EG-0`Tr7 zJbwxGzl{6iN66t@C?|<$l(g*c`qeS`;^?tYx@ClJVI!L6Ca{F>pW_lfj*H()Q3zCd|j z^a4=kmrelEefb%Y{!tG={;$k{&43Sy^mQ6wDggIip9FkCB+y9d8|3*0?fWMI06Zh?LolTL;~HE&I}UiUug5c)&t%k(pmhTMfqpX5b0boU@-vwA40uDC~LSMaEeHg zcEAz9`$Re~0CE9Hd;Szr5HsLzqM*%yHvnG~1?L3x1NH)jh=Rv8k85EwQHZ^OokSsN z0LUXDkMspmD2f4ir&tF#1bBxiluiKdRo#FiM3F!Ma{xm`q5hC4G|K^Jh(e3}I$Z0H z5=A2NBu)jqLKOOT0Ln5b0b2m4iNe@V6ec|YZ84!7Gs?AO0#*UOCJJjk0Oi5=DMG0N43vh@t@X7N89U zLqt)y8SpXyX-1&T5lA!Q6{0Ar0HDuBcphj6pbY`!DeedCBZ?9;0PlkW0C_@b0QQSC zp|6Re6!+i*iqge^y8$l)J|T)SO1qR zXSZafF#LpPIPq@nJ zcNx6liKU^g@*KaA=cmNNK@W8eD#fz$9^YQ`AXzA&h`hjMV(+#JIr)Ke8YjV_QWHdMk zcm6C0z~4}}ktC7waH)k-g1R|))H!|hE3&M!SLxyZU!A18ZrF#;RL_qcKTcT%gI`&PTaL8 zl74r@wuf$xJZ!deX6~!3rc?|oc3!~9gSMG*4rMl}3YTjrFEGp~a7vTFPl3vgb1&s) zaUAWDuwS)`Hd`!&WM_KPEUA{1Br7tT+)AZ6Ctz?#X9A~4!9FHT0g5M89Gein_=Wp9 z`r5{q){b=7&aA(0Z{2mrRz+T=!Lh4GrSI7jd7Y9mt2_O7?~R-hcNI^)rKeFKkcr`+ycpZ0|%lipa|eNF$Oqc^mU zy5X6*;n_WHJ_F6vj-9o1{&A{%@Ik6OF@Jh@UxGHHFk{qhzub7^FL$&jrj76gDr6Wz1W_Rh3aoBPR7msC zS-uCe8{L*9u185ZuCa+GaD=FOh)UI}YEF*U^uNg1az#dvlglehpopF02p#;MT3ecc z@_3znec@#6vaTsBEiTH-@w!u-Hj7pR5x$8wsWAp3CQ+a$h*^^n%IE&eI0WPYOQf+0 zhcz1ta(7C4TdE~Hr+ZY^_D>$}`!C~Tz(|hyc#m6iU^Oa=^EvstiW7ItdLeRd&+uP3EL`!0S+6#4JhnXYI32hA z*v4k=jRzuUj?ET#&HiEJ%mW)w-P(Tcf%fePo2T-c&OzO3QV`C?J;zgS5~>u(NuVln z6Y%wJL8ua%@l;LJGKo=u=1~h;!9d|Q2-(A(T>kJcxu@yS)(Zp##o{koM>cL$BrEK{ zqz+-6NCiQzql#z6<8&WZyu|t$E8QC{d(`mZ6RceIo?)D=fifmzE!SZ!7m-l7*hobV z$4Ll9_%0FO2n!?5ixZ~A@rVf>!y^uXHTg1gGd+^hp5tRHHQgVdGASHeyBYcXWlPrp z!d?kpB-RanbK4V5{tJbOW1cCT5TsLS*@I&XjL`c1#OqeEj!HPZ^Ke&O)%F5pNE%j4h< zr^I;8B#~amY=9a)Yq{HNaD&)`f*Jy1_{7k;6DN4_1h-{)xwvciI_}yS&gp8Dhc5|- z_0h=`Wm$SoX<;P<=;{+dDNCDl{tND5Tw2JOwnL7t-e(kGI%-I@eT-&zv_F|;!clESed(rswl`KBZno10QYeDvi%EY%ue7e zR%3Zl?VLv63Hte}A8lxKE;U$;ncW*E@K0XEO99%JMl!7xW%K&ihO@&gn1@-<6b_pz=D0`$TnO0#|0Y3@?u23~QD@jZ2Z( z!&Y=0y$34C18-n?7$;t7&GE72f%>??p|_7e^bk_ZYeBjhS6<=|dx5zqcV~DW6d+Vo zHt|ue>9z(9SxmG5v9eXsXot}JV)RYQp`Hvz#8`L0b11(`V^t?uwe(LKmt*^592c?J z3Y-PD2oC6aY`ep$rJr+BQi&tEB#B>QOE^1Qa9IlNL+kVM_zjLC%ejxmT?w|KZLxVH z&qJI$9kv3u(I!PvY;)W7a+5%FZNMi+lC6&mO`*wJqfV#fD>?qLX|~kFp&xVHV*}Wx zsn8~zd(APz%71%yw%#O!?1knbp5c+hI{p&p7#<)dl5r{RyKK#7W@cVO`z~3taT0h5 zvlTy<>ENEo&y+DOM7pdX0V>dK6-*9YMoFaa8V*dOSRQtdKRQuz>!5>GydSK%( zcXV{@_~pipZ|xX0YR6kl=9zr{cC_zz#0|-|l+2SEDpxeZ?@JX$L{D&VT{N~GO2PU_ z#pu#SSP0cjD!V8_#Fs=eQed$xj3)cO6n$Y;R< zRADuWW(<8kX19(L!TzYcx?=qwJk~j2DR*_ew0NzIg=HtljxndD4IG@k_*_j}19yAH z&K`yj{!C59@RH@bFTu%(!p$j=C8pD~!!l+@1{WpU{yIJK>EoN;Zs9j%=P(Ri^IG%J z#zq-O9GQClAIe;ep_3HSKsX^86haNUz{L>bL62p&qQnH3dJ+_zBsDatK-+{K#sI)t zAX#{T!V3&2ni6tILle7Hj7y*jMdf$$T30I_7kC{wX~{)- zQYM(T5}xt+OD4E7XShpdwLhRk`?@0!Z2NS7fB*hZw>=Q)wuV<8m^1gls+yWr2j zuoCIU$m*i_%N`itSf#8)IpIu1 z^kV(<+!RdbxIiNF5JK!WLn4xC-Qd+0nXJZzd2fbH0xSFium zpT=I>lY8LcpSYyqPsCl-%lFM3cw|-GJ-M9=Yj3&-)ua9?k#{A3bRLoA&#Fa^Lc53x zs}4q+*y4(>t5}mDna8A3$M?KsG`W`XssE6@ukSg~7oT4yY*0fKSWwXAE*B2IkIR8-J7wt_iwVf+lTle27&dld_uP=x!Gux@rX#Q`MCq5p(!+0ctTLi*|x|p^lfeS{p zt=Oo3C=ZMklP0{n-uyZE>$Kr5hRGkS6P2;H&yr`J^#PTVlo@1PGJEU`zn z7&5YMf1~@lp4|QW-{Hm&KPK)9&AEMI`^LF##w6eHt63aLvTV(2n^V31dNyu2iQ)Vg zJfq>&Oed_SR7`=!4801%0R%G01_D|>53EsM3n1+=;@8MESC(gIdfiTk7a|!Zl05t4 z(_NCaLMEiMrH~>-Cl(HNEUtpcZ?*9|RhC3Ue#5keni+MT@@Z?YTRW{hy!PgBrp1qhI_DnV829IA1OQ@fduo=xdh>#56Sp?`26Rh1LfFBdf3hQJ(FTE;7sWR zPAD;(bQ*<3?9?to#qmXjCIi!vA;~bV3(b=Iuy4z>!12!8-`TkFot>S>1JkzNQ!#kw z1b+6=u66I++uM8ZJL_Ftu&e(&(nC&gV3^N`llm6Oxu;lDDt&dx?1FcK)BisNiI;3wUt zgw#zNnVN@c7@{EL+YGrCvc=>(H8DBnvWlsnnNX-V^#O-hq?rn>q)1fJ(P%&^Yf+af zQIa$Ynk9PecSUNRjNGACi7GL2d$euNAawP?(Y!2mUB;&Zn ztfVWztfwihiO)xT^sg^l?aIh{g*tL`g3Ww{`;dEHryV|Fv2z-oVYqA9X47$f7Sr&X zIvd&nBniJqJIurtc4%<$HIu-Zuq_LgPylm11~x)$O-EaD39`7iP7Htbm?K3^n~g5D z+G(Ussx0=%xN?57-8}rZw=yNA(#z!;oS1^BuLSiiLw!1C;X=1BOl7EZ9s0AltJ$4;ZtI?Qy;Cc!*n{5GfF?}E zcha&*8M!&EP6I{2al4WtE)*aZ1;UU3&4Gjcfm2KY`IgB;GuX5wksb=!iYdOykP7~7 zQYIW!$r<8y8kh@mvMCu+m|d1rmhNFD8uQq!3alQrNKTWy)455lT|~-qVXZ2bH!?RmfNH&8{Jhpux;G%ss$!*Anlhz zYEgZ5=18A`jRy`*fj)Z{_^QJW^PopYLrDQ=l@^k7Gw@r|8FbB9E#Qn^Nm^^yA+xs z^kj@3LrHJXnEtW-quLtkt1C-`ff4z6KCdg;Y)sUu&}mwym+fiHG%Uf$11qsi<6&RJ zSb-4y`w_E3J3=apIjUSzh)N1KWF}$7m~C?^^!DMKh5S)-Ya041GxR!xRN(HJF|YWl zmqN)s^H!EOEFGIyd;8^M`plA5x4DB)M4nsw#Ndd5(PcAQv+1$QsSVi*dOoePR}jN% zo?4vcnz(5~t}ET8QdVY``%O!hSM`?Ky^ZslE0*_{3q>og@n(DFF`qTDclPif5XjS< z-P4ucy0Ddg&IE^=MO`qJb7brJe+X*vI4sRxvLmcYc9?jaL>(7|k0@}eykNT*6rn*exC zY+1bbiZxW9W zKhV}&f8Eh#YhT~q+1AkS=T~;MM69*J*H6Ci6r)4k=l{XqB*3If=7$qqQm;!) zFBw(ZwscfR_NWE*HQgbf(W)tOcTbxan)1-9`s&p`ST_HmYQ9FTv8UKe2DbI~Z=V)O z^`{zYvPNbY8*ezVZpq8HfH+_X(AUVla$g(B(WoUAqM*PPQ&B3_sPQSNI;tSdX#3sA zQL8O8^X5UC!uOg%1SCPmAfAD6_y^%zCHR89FlQ!9OhnOd#c+1>3~J-5%Vh+(hb z-=TTr!&78CYiD6rTZ;aoo%L$vsEscyk0LhwUCcMND#PEgv5v<)ds|*-KC&dNF~MS( z?0}voGV027PZt;vGzjQf52gIx>#pD8s_?!A@n!$5RNp;52jn3Hq8x2Ya>+1S=LlG;7ig#ZN~ndN+iM zmN##`+fzH$x3+Ui-SsD~S$urk=;|`A=xp`%T`lx4SV}L>*g7#Av}7#nBW6Q7Y!&OC zv0@>`=}1PLWk3#;8HN(ZT>{4uV;AV|#kKUmN+~ZVyWdAiR;Dk{p9f1>l#r*>bT&(< z?Af`5kVolwl;_$&J{W=Kawp!qBy6+~;}huJ%bV+_H5M4y+UlRXI5hVM*EQFyIkfb; zoklL(TQ^k@E0-M@%yv%QHl-jn9jlAc+@_me-!Sj!rcoR2*jP2YEelHwYpei7b-(x| zagixuwLTH1bkG!m4RR3%`GRd-RzmRcP#_@O#4O$LpFvGz_duX92{@4{ZbSTKUs#9o z@!>3kCEaIb_V0ipBcE2%Ky*Z-jvpQ8VnUMP&Bd1Fy(1>B@2W2oxDi?TZ9x}Jk9@>W z(ux*y%k-X2lM2m!NkUSvw`S6HLwnKg5fB1C5?>-|WLh{u5B^T!&WShM6>p9_LF3Ja z*c3IMgp*mjneXaCyTLSKZ~MZDXm}b)GZ;)kA7-Qdik35<6$dA*gr+l<#qic*t7GrT zdoF*Y_#3YCXNM*R1u45zWI5>Ma*y*zci zFt9Q``it+H8B8?>x6i7Af#vd{vf5y_j4r(BXvrN8%-KC>)b_g7KL{?!y8afbh(u!D z4R+tPxK=~Y_KDe?bjOWBHeNibirmhh79>cwqwo#7yTf`VRVa%L9H*$s=0tcQ+78*# zsazPYVEj^WkZ%#i%!^Y%XTwdfHbGiLSFrjJkH$DzE8}DZz#>kVP!4`K+xO<^3%fcy zV2>ZyF{yJ>Yje2D>$cnUI(Re7Xc=>lQRpmgi#d^6qslZ?DiE8PX3f@PFa$d;lZ2x` zv^ZagrjeN{=If-0X1bW^OOy28Pi;y<}RNKr5md9njb7$^vJ@{ zdUs)3TX)&4t@MuUrpa>$i%Ofk%?nzamv&}HUJ8yWbuO7dxWrXDMvz?2TDMAH)783q ze7?b)Z%y~<1(mg^x3Ol;l(O8`X(erQQq6T`)`I+OefF0A*45+k&;8h!?@&vU!qE}* zl;_wTg|%EqO0X?&(!zz4^4fyX(1F3NSWCYJt+$Z;aE=+m5_8`(K?)>1CP#rJ$l4tq zTZqML@ybr8OT-<_5V_w9!`8z!duETlc3ke^x%0bjDuYOKuwiUy=C<*}Yq=YiUE5wW z4EsM>f{GW3hcU`F(j1l7nOh*{Q57)vG3qge=E93=sKpmw$Rx(hlohCdFd~>`WzQ5> z`(>*K%nmJ2ziaUpI2?H%v)Pm9a1?kg{5L~t{u^55$n%=bUile*K?*6pz({B-&OhXt zJ)bSXcr(x#Rt+DkhPED#mVy|B=Oa7mLiB~%p7&nrt%#V4p69aEARe;(&wL7238Fs% z>4X%*2qxai6q6Y=WyTdJtj!l+MhRdx$;Pa<_|x4{0?6bsCdorxiiY6CCOEoE7;YVRZW${TC^;_2GJ)Q8TG7Hl$T)CO=7|nf?OqYfcPp*4nz4sf4;ju`@*a| z8?kvU>2Bs1#uAP71iIqoE!WlVn}2bgqNxj8CVXd|Lf^obbVSTTH|dN{YMb05W`S## z=dDa4m|+>MVr{+RjV$SzEM`iQ?Pf50wThUiNxC5R#H@5!t|nPSib};+u5{7U*VNTr z^Yo&{huQDp#dq%9d1w2QHs2kB*t+@n%2h9KZfV*4@~V}`H@6P0dhN(FuNP0>KH6ozIs|-(kro9tB3JlE0~KjQv`cB<^)xlhlFUVC)PGLW zLLkoS@^W)a@=APgNoC0E;9}eaB>o&4;~8vH$v!D+woy5nE6O(Dk>c;Es%2en-w+I$ zD_wOvY8zS4J2#cq8{O`{q1Vglk(Nd6%R4h^sBKwiW^tsmk-w_pr48FtKt|_l@Kq3k=H1|5iVLyV0DUFS#Un?e@-q-!@l~u;s7Nr&2^*d zM^%gr)E3v~W_!{uNXA99NOxh1d`B{7rp~xcD!N7~n>%rp%6h@7A<{8hW|zaNu}#Q> zRim;moM*IX0V?JQE8J`*PS`%ZI64=3@iN;*<|%lVWFHXw=#05$Y%2o+w{yzOpp z?bOHtvE8?-b86iNrg?20T~!td3%`ijFkYOo4T=~3I5IwR0J>Kc7YCvN6PGEO$+FJL z$92wF43_JnJtwMhMrlvnZxt=)`xC*;MxxFwH^V20=Vhv^Tu?mCcMue}?=Wlf=F96)(LUlv@zW28`=uh^wV%C zrkY0i0rwj4lSH<*v2UzEZwFJeK}mrrE1BIva*E!?;!R9ge~2fEPM(W?VwN|`E!cax zn~ZG7G@%p-+prc3gYu-ggr7tc01=FzB#|U{y6*x%vBp^=j9VU=fI;e;<+2Lu!mTsY z%57RHNf-1KwwLFd_;0Mq_sqFUmw1C+;{q2PUXQ-j!PadC?Wth?uL|g!E{bmbJO39Z z@J0XE$kGg-CoS3TMPuOqLjCbI9~aW&?k`y$2T8c#{^H)#*c1Js_Ts$eKyqH|6oWMYhsvFlLsGsVwd&w&%4@nK7j`udx5d@dNjdCdq-GTRUGB_^ zp326RJw*+{dacgsaVFEC>!BU~oF`=8q>c}kBOTH%s)b9(tAF2AnCLp!8vfSrQ zOR+7a_^me0O(dO=ROEu2%*HL0tlY{uq} zY44x=3#3w5zEeuqQuPrJJq-7N6 z6*SK3=vXr@?;@_kzS71(_QD&Q;?ygIJer(?Eq3$cSqq>_mEAG{t1bjfR(^fK#=9AyQ~_>yGIok}I1%Hg*0 zM15fkB~fRGL7%9F!Ol%V0udkS@s~t{*g_^2HzJ4ZMQ!C#6CHhJ)pcw1)NbKLMiNys_7g&*8rrUbF0))>`hbLu%iGmcG!yw(;DJY`%g-@L!^B zSNJ=DTDdibf9vnG?XWsATQx?d(x|0^z)vzs3%krZ2}j1nJfC5NpvgG8-1BJ)Mki3z^T|t! zXt4X5$m5S&&B`+>!|&jY--n3P8IQy7d0wIW3|`Os5l-=Uoi?)3>4bu0h&YEox9R9s zmo4%ryq;{FEa02pq8%3E4BK_0Jc%x-sfgXk@pxpnryK-z!SNZ_#!je`og1HzOuomK zEYd`vOKYGC$z|Lc`IR||-p0RR(+yv5%dzFZ`z3B0D^UYfI@OxbLu&B{+nZqA&pYsPy>DpocEv;Iwp8H@6o6=-}ujcy2 z#~_5{kPw+29`Irg6;P!LT7;6trsDgeqGC`@6}+I}=gEVH?GV1u&KosCPna&x#|FB^evTT!u9UKe4)kotoSez{+ z9S$*0h$TfhYqlJZ!5UKlLqmp?$f7~wN1Sif%{73I!n^p4;~SADAgN<1W~Qr zXrjt1%Ep>fNpegBislwES*jA-R-%Qo5R6o=idM_Pvb=ZlT8&j&Z$R1W6;}1i4<12O zsJPiI;(ua7{Pi-ae+XT_U{gT)HxgVtNXrnfR!Xlv#c z!S0uV>jE(^JGY>-G}YyC^%i!Pv0rp_nt<=Li)&^3RdE~p1YKCmMw@~cA)tbpsvuml z2V>a-W?#XGwDmoEG0^m)63_M|iC5a-YK>`GHfv_8(U_WPwPmFl>D9(mY$eJ{F&f#H zqO4S-sKUk~+-2Hq*(_Z)+h}y@eH5Qdgg3dT#ClMUq%b2;6#jqwfEMB4af2MJ&9?C@ z;i`sDi1k;=<9m&;g?kWl$HMpy!>+3&TDj@vYebUkM0_0&0JwiPRsO=y9{m3EOUpZx8$H6j+_+cbA96PfyY!*)pm%5 z5g76K!Wu@RYBtnKxR4{VF^efT7BiTM-JKI#)z>)8GsJJcarFN)t$F1~Nagq{;_I?O-7dM_4TtE@^h z=P(-`ZsFx`K&9A2OcF{Edrae5pb8~IOp0!%Nv6qcvRt~ECJ^72#RBkx)Nx^#OmL>_ z`!>HkIBBr@8lWAJHlk0UM6h0HA??PH zTg$9)2A)mug|TTx@eC3pMGUG^B2MZQW)!x&T(?tBnV6K8Y4_I!%KJvT6zT*%vX!^_ z1655K8i!41PN^#Pi|?t7b_4&{?j(2F^rDrIuW0sbn_a1y-8W3in|sY&6Awnt9KXK9 zEvR&=)$NZ_{g2z!HnS$WuC|^3l5Pfl(GoY?b-`vj0v+X0w3tT&Qad3jPO}kdwAQGr z0@GjN&F4!Xd9c_WSyz(-7U>K@Qc0@-LXOFkmmFUN$$1_VHmtmoH@;_Laq+~S@p)Xu z*A!E|X;e*=cb;C};L)jVeX}b%H%%|iYZ%=e5RBM!nq5Dpsn9dBGq19z z!l$w8cADJqM8w+a$akAWyQ?_UmfyXqt$pFx%3#pF>yf;=^0LOhs+`6Vj+FEi+qu2* z^cVU@$^6KdbQ1XtYXtOPOKDx4u3#HUvfaahYK1Otj8(wp%zSoLd1^an0I-T5CoiC2!i434WJCqf+Q3wXblbyW#wKvKjSV&;O2i)o+o_ zsLMmTJ+N;AcXsaYq~Wj*O=vrmj%8>8Y2jEb1azj@a%61^Gx`JKgzcUepZ0|l@^jNY zh~pKMsW}AoT#Y%j67_i0Z(Yr5>Cr`N(V>=#e_MfUBKS@P%p|~gvrkZZarbmd4b{LV0-y(m*$h%(XMMRI%5J1@jk5uF5fFuMqo)L^Y*y%sU~ zm^}lHLbD`gIv6G;)A?sF_0( zQ?+Un|7_EJ_iQcoB)F7mhXWDX>ko4 zOd=ZLE8t)ftq{JtBsC@dkrT9@N|*Ha$~F#tr-@YhZWCF(D2rQ;vVi}7hJWlql*#a*gOHo0!+MV4xWr^jfi@)}!rf$roILQakv5fXk4~4U-J?_4Mskvk-r!Vc z*&^qXv^s0#oGl9{y|D3GhqB&8S!}!vtSoBbvA~#~8^RUhMIchF`p$b%&Z3N`jxFx$@O+K{V_>(h)#Yqxkk z;&0PDs20hei9AHZ;xJZiOm1PCF4$;Hyo8nInOklVhtE9now~rRu^JHA-|S6ebw#7L zL3%Rk+S5j8xV|=5sYX2RNjsb2@yc~wjcb|ynN=SQSF-s%DJ(lHnY3UqekHlZ&3zHSVVtFcX6MfzPL_sN#WmL z^dehUNlI#IW>QjSX=+MImW>;I;V#G&61GihLgYRAo|FjN80NcztsS!wR4I{yYlCQp z*gBH9Zx+ne>k~WM=GLU7)XZ(`Ow{Y=F5s^Eb!70_RChw*vX4&xdClriKK^L=hy-`a zvk_)#N7>aV`xwejM%gA6TT8_p))Lb$Qy`2%Hps~5f}x<1x);n<3X)cNu?8jVl}fn| zy7SpYn?Wm%SpLz+pR8W<=hGi8D}+raDe+mlGg{BHkq3S`MX59p?>Cpk>8K__Ilr#u~_vl2QYGjB0DIGT_}dRsga z-4^ejOZ|P_Q@i5bW2m49(197OcLiN$<3NwxJ72h%^)683mwPvUrqSG)&w4j7eR@&2 zYyN1A&{}>9_Z#se#OJkzP5IebK6jeatWQ)c6@rebGSM(EO`MDnkY#8r82Pv&&*%(o z=>yFmC}e~^Nj5YwAr1=RNzvNC!bS;^m-S_tzG{lsRAB=MRARbgsHWa`kjHXE;^d)XR_x2=FQhZ_>rSmyc! z2>)4LPC*zsR0xeQE~yZJN927Ztf|l{nXQQluS#XBvN(jz=+J&0-9` zr_GF3c!Be1+c65zDOb>&A}hbI5A-HHeXt|imCgqmax+n7Z^d^zG`ycZv@0TZ7<2!u zu+zd+wthG=^ZW*Wjrb`1Y7caj_<7eDIa`?H%1skh^ zg(=02o!yzWLE%g0bF^odruxeYa`Hn>{gtDy_4}qbT=YD8o%Xyce_m}MJ2%icDco_j z*FU#youpeU`{li4~a$4QB8#HRE?g^GstXU3)ln| z;d{jC6~HP%3L`sI0y`qvnH64m1zDJDj7|o`qWA8L{Pn&$k6cwK~(#~>raAp(csLU?3^MKL2P z>2_zvs8a@bO1x8pv z4b-6*lT(siqF&q;`Tf0VUT@mH)WhU^l*i!!5?MCJHSv(uY-*F$bQH!YFPv@BCU6)= zw&@Ko#zoC|s7RxMGtR29f=#KZ8oCzrOCX>Z`=zdhO`rl}ye6Djf)F!W6VCJ`Aqs-I zSD72qi{dVLp_%1EcFG}?gq?H~bI`HvF;}Dl!)Jm0V9K!_CJ5}Ws>FxOo2#00vwhxF zmrg?}Xa#exvPgHELb~MG5F1nZm^6+#5XH*H0E<|_6wjgwWvdUz-P?Kn#stmzTDT|-3kMzx( zU)V7q9tdzjS_RdL-SI_HC z8FgDn%lavyv+s_nr;nH2Ke=W`J%o3T%sG$!QDP_QAd|_Y@B|Z8apQQ7S7C<=0VTrb z6i&g8RUs-K&MGxdq+;GG5eg1Mn|@0{Ex{BzZqX z2kp=RZ9cZA>w>Vt=npTY#J%{jeI!PCi%}>D%N|a=iJtmUg-yUw=fAv3&m;$HKp+qv z7&Tota&rf>ht;hA(baXc@+O-(S8?iy-nxw5d*5Djs;= z@X5%p-@7_Au;t*ZgZ+o@+c34Ha{g@*F15P6$k3iq(028NKb-eM-<&I%|8+&8Kc@n04fzJ06Rif3mkWpivoXo5w7Cljiv7wn6s30B9M68-a+>dzAMreJvh7)kY7;wqXqKby^6@%Ji z(<2T!m81G$++tfGfqGaKlp{u&Vl4OG;ukQf)(4Jov)QnJ+$g?*Z zJb1&@;+eUlm)-JUZ|_4}myOAr@%Sejdmp@I+2~yQJE{rSw$!iLKQQya>bknp8c750 zk_W@vsMTX~^fqT?=8F#@KgxaR#hC*yva+Ie^zGZed~9Cc*yY>z_1*Z_r)K7lU9tTU z@Q(O+BqOr2jf^Loo(V&ih{rq^AO=@~iO=DzD!6Gy)fA#cc)p;NWsSJeF&2s>8?gRQ zIplCsb1*o*yQ3Z9D6Ls;TXt@)pPdT<{qaBISY*7c2$B7AP_ii+LBO{6%QAEho%w%7 z?Vonj)F&REH_u>KpT5JL_`1sO=v=mFf+?q|cmwyw{|T*!BYXIDSFf48(VmcEjy!Fr z`C8r5(e1v{bav3^|)tIV1s#-M9kf{FV$kopX<8*eN-AN0y%HczFL2Kj(2tMd& ziQLY0DYcfl5j*`eJi@FEeS8M@NBHVloI5{_9+HsIn9$tPTw4>aE-x!C@_4OYqcn91fjU%D+grXnZJu2E@}ZB3`PEq~#r@%n8y;{7Im!!9P9)CQUe%>fJrP(--rw+Vo zZP?M8ndXAmucazWD-ga~g9v)yQ^fYrC_PPw!p(#Y&{N<}b{0f=I}4hOqK$3;`gh3? zMtLzA_K|v1{P>UUBNd@2Fef6D0!&eTHR?@gy98J?A+W|rRrEw~eAwv_oR$FvNfx(F zI-Y*I`qk#3GD&ADY@Al_Yuq%yrflKf*$Fh+TC1D8t31c-&}Eg48sToFycq|{8QOwp*PwT)5h{3G&}oXJu$?z(9$w+uE2x0+IZ zsvR@3HpT9CDV(dX&n{i`;?1M^!)DiCG}R-j)M`Ugl44jAQaw(UqPnR~@f7g<#|MtvxHIb4 zfd)!o(?+2Aet5G=!zFOSa>bdzCfA5bihyZsKfLtlx~NPgRY}b@pWkcA^?8)aWUvNi zeS)D!o_Y$&AD2L7TbGxuVAv4?_(ddxyQB(kId5T_>&D>1hZc6MncR@n?8q~lvWn~S zs;7k0=uxcJb!A1)kuL6GwZ&;1s_;}7x_->uN%2#a*@DEB>F5u)gwMng7_WOqx?CeYT+rYgdUw{`*^!^n^4Z`79A-BW zy3t;CVr@&fQK#Vqy%xbNAQqEgRlvbhFgjoy#$m^!B!!!phJuqR2q`NK1(B4=H$i z_h_v(QR17vZIbd`UE^+Z+9l;1HJ@ljpMOuYl#|lc{cU%r%PqFN!yesSbJ%5>=-pa)7$$@mT+wV0`0-3v<8j_zvYy#wabR$92-svMHHzaAE$*{4z@OJTtR}IPKE8uG zhRJ6Bt?YvL)S{qKjG{}!g`_B4fO80V@L$ASp!`^@8rvYojU#eo zBqiw{vq`Tdg|tu(vWb}{70~?xkjSvDl(9*QWfu!ZMx$`R2+ws++_Sv4aLoLQ$c>p} z{PaVYXQ*Cppg${{T$`TRFgY0NZz@dCWceoPMz7r?9)QX=x$CBND=H$_sI{Kt!Aeu6 zf&P5t{J}-l)l;fc)5z}A%c!3e3{FC4wHfGa z*V_BV1I1G}kFB3Sy42u%a>I;0i^|IeZt6%> zbEvz3)P$=<*lzN2IbHl61Qzqe_)Ju=fz`v!%=AK8qGI?-ZN7g!H$j_h z7&aSVM(Xn9CY~GX@CkeD*`{OzOh1h7g81U>lLN3h2iVE5GQnjt6;cFD3bDPq@dHRT+_o zw1uhrxISp1)wP2i*%>W!Ynm6eXL9APVn=R%aPF=dllQG@tY7ok?5aic=Y}Fmla2qp zZb5riPW!y-`uVN?f{t0}1C88=)~*AtqP|%fw8rd(G$Uu4Wr8O z75iOj3^zsD@6zGOXvyd+y^+^pPvVE{4Zm@c`}R$er-+|AXI(_9_^~ zkF}OX1H>IFKpG+=al|U4_^gc#6L<3cL;DzTRh#IqV}8`T$cy|}!ZqM)(qVXL;O}&Y z0*ZhI=PUxeA;=IR_g(bUrPnR}GIDAP-5x1gdELs$SG0XfWE{Ws%P%*b+%z<_=_G5{ zQ}i1CH~ddvpAA7@ElRh_`YJmq3jTK{=d*2|ij3&OHT|3CywMfR_o|XSODcaS*dzn z{B*tEfim=>l&C(PU^iSFS=0(#&Lmx!lTTwlCo&26;&jKUBuua1CgI~e3TZURq+%RS z2UB43C+f7C3kyKSO!=2A02Zc?MQ~SS?ro9z^p41U{zpT#!qbt>nA>Ss{ z`#kC5UlMMGEMdVInqg6f%^`*t*@O~B3oH0}UNSl&P5A+wT1%gI7>CaC62L}RuhBcz zZyGhCUiFsRsb53aMiN-ruc7QWFDV-*L9lod=G2t2zZeXRqrP3p`L-o{CVFqu>*5KFZ?j`Z?{Z zZFR*tNYl=TnHHDNOzkbEYsjVpqJL(BEr67(XQl4tn*C8i$P^WsRm=LC(leTRmsd9I z7%nLp-qBFGytgSMy{T_mRm0Aql9HjF)BV{El_d^GNo7NJc4JX`dQqcrM|NXjdU|1F zc6LJ*{Z!Qu@znO_=JwWla98#AUNc%8`(8Xs-^YsX$}Dd~|AaD^y|A;WsI$->``1-Q ze=n!95P;Cog+D3snccMk=U+ic{P^VXof~R;kG;8L!~I19fAjvlj;dT;Qfkt^<}0T<%vxXlNbTU^v5>oNNUC<` zrt7s7L;rDJ!jJq~51i{Ak@>6QN{dPqI!aIBQlkpKDup*JMbS(u+Uv&e|2t z^852~SAS3W0*f61mgVQUz4Sr^KR`>1CNi-gB;nb6KKgWekngvpOLr&f6jHL9e-SB5 zyM=q9b65?LweA*=vnoUCKtc}ucu25yO^Oj5QH(rY*z4ivYa({nX zIYR$WHMF~tcl>uIpD52FUYGbfZYoPGSw{o;zr0)Vne%If`ssJX2hJ@~Ckah=+ ztP2e5NLeSl^BYtD%7XdBs2|f60y(N=Oo~vlm#sf$FV~tXuuefzGyrFYlQ6 z-c|fBQyu5sZM&9+3YP9@Zr|CTTRgCp_AGKMv3`noCb_tSYYR8q;cA0AqvmI{xTvvL zg^NITaUxT+yv&`2NUZv@j`EJYU{gb|gs)t((tW*M7&*ox2-$J+f-$qq`dR>^OQy$H6n3+qd@xiwCyU)@~Un4)$$t zZ(rSz?rvHc4zFx-r#Gxlsor$&#PPHK+^6>RA758fv+j8Ro~LsCXOBY8a8pVO%x+vYm9qR&O`|S zQ0PkqMM1@>VHlTfW)!9lTG62FHp$LZ)k`k#mUpS)EdMy_Q)`En5_Op7P9D`CV>b3V zPr&r3A0C9{3_T7$1Bx)2n-0QybwmM7xWt&HtU56&lH<1MVCIe#zEd``JKVBosHkXY zPfP2b;iBW|#mzonnC{E4&(~a>F5IAX+76xjK$C91UMi>It-ERX?$(wohKl9kO_V{? z#D*&x2X9zbRJ81d!QrFJizqX^d3kMGTJ7@Yre)O*NA)uP+T_%aj_6YOrGrOk;E}=M z8)@K;!_6yd($a8EG>y~1ap0@KT^o6t-wV5CEMFiRH;zPi5HHIdK(OhYd;t?_5|yQ} zjnB&$_?LLP!1w0r5s{~bjL^`?^0Kn!BSWF-pDF$)8cOes>Jn@{1Ca;C9IPjvFF@IK z@CTrtIR(-nkOHM7qwaky5)?Fw=TO3ECSO3J>y#ad0#-YlRga8wnFk=iX|7Tv=D2!B zH`MhXjVBCT6-yYXU4(>zdS7x{a%AV+IP~vQ!a)AgD|>o3^;Q%WyYGLhu&J!5ZfRY9 zo18G9NSUi4sfZrbUztS@Te(Br>oQHmksMATeD*4Vmx zxTt6tq$X1)NGwKbO~vW|JW^}=cv8g4EWXeo{ZRTk_?89;F8< zScTjoX;jDB8%?v1DzN3oKzSo%s8X>3EQG91|?lVvoQ>}r_0Zc)~neQS8(`QsQF&PkC+PBycV(idu8dGF7^dv9oH?|7>x zxpL3V&+fRNFXx?q9G)(VJmb&j#qXP~1>;AC`TT+(Cja^Txrypme)Q+x{&0Bss_`~Y za@C$&p51nTdwIkcPt6+@piqt-OvjsPAdGCGu^ z5|LC88t1fbbJ#P}?QVygTDYN5f;SH_N(;~1$>v3uq1e0#aM=c99wuL4Uc24ywrAx< zr$t^!d|t<#^>*>(&cwVf9-*CBGpx-jNwp34)>Zsm?||U~_(#Zc$#>}R4xLqJfjMHqcR1$lql^0umfId~G4o1< zsc>qgdYcLrMCQB+p0?S$;rVoDn%$sV@I5%+x$x>^?}1I5LTfQUoj~GNwDVt3Tu5#5 zOvd;tk^nByz=daV0*}iy%T7cmpU8#l@Xa6gLgk_oCn7HbTJf6qN(nXn^-4XpRLDZu zA86?g2po4u&laC?w(?A!Y$nvQM_eB@*@5#WaVAMZw>(`oP2^_l`5(-)T*YWIJ`3sx z-prBr0Hui_Zc_l}HsHqWnT$d342gC{>$&hA<{6i1BVnFC%!Ax)$Q#%g76iD(H^mIB zC^tztW31q<3HEj~UjY8nbTkVCd`Js;bigcUDmb~3j zfN!036&G*l^#6<**{ON`_1Op_O{I^E*+)7z*5^q+f4JH_kmqHdO{Q9S+z?|WDZo{E zaMh?^3SvB*ZzP#PwaE<@hJq!zB?LSbWdUA%&Q6}@M3qM{QUx(-9uqG#XD}En2^I(B zDWm5ZT_?kfgmreo2Fh{Zbw#M=0nAV;l-rQoFmL7&d9}u1wmhqk@jAA5nNKIo*~{i+ z+$ehH@Q~xo@rFeIKRF;{FlcLOY^bR!FD)zxcII}{E0SixLdL^{cl5D$z_UQNA=Z1b zu6US={`0BTxLFu%S&xz^oqY;_^1$*fpI95d;nt!^h3JV<*mXS$wgI1`Elkp#0`GP? zv(vLtdse4b@o7SuTAleZb9W+bKRS2(hvXZ~6T2(F5I|pxwuA6GXV{z}CP+kmsNPQ-QEB8I7J`wh%hHd{3%ME#n*O zy#f0HEJX|CRGo3gpD5z1bktlEnW(I^gMmusqgHSUfWT^(! zRzj)dMj1O|eK~3__d$e!pj0|N&X3Y2D1qNwSDT+F@J)@it#z#>#d$UPH9l`8uooozMfXz6_EOtg+Y)a0*u5Yw zX4bj1V=pg+4K2J{8$X*^Pq_*W{wiq~*boBzn4}Ut8w3JU&lDdK8VtxI2(GL znKszjxankiy1P2+YcIAN#v|mjIW}iMony!yS^&@LWB8TAtCM-Hq}GDX;j$A{Q)n2X z86kx+aZ9LpLtCPjCbT8F+Dy|YoCG;q*d9$4+a9$vi6T1Q$R%ktNs|k#DBg``{tQrN z^JMH@y12KeyOX$b?NHs&La;J2rU&|#VYPn_th#Xazgz%TWw9m3Xi*DV)Qlv}0TCL& z5QviFAR?PFTJ6rJl+z-v*gqBhl0YyA^mp*UCML8|%@R zDS#&yi%uQe)t{;oX7Ur&hDv8}SmstNNeokJ0AzOc8RbgdW z$;Ygp@#O^gx3l%14r?nBVNHh+%g!iA^%rz1p1%vq%c#daM~6W71hXy1l8Bt)f8aT` z2^Sp!l4fg*3m4u3(Up7#jK3u8p^NR|`?GKe_Pg1*Lm`f8ELg3s$3;Mkr%Pe>;$?T# zCw>&`cZQ2&FT^YGE}Z{l3~d*B9qoB6?50f*Ea~bXiD~|}NjhNq*9V}LD`eUMwRpIK z3ygLyti?C#Xe~m0LzNh+R^K+O+P)HD>auo8ay*i)<+>%%9gwg6G}DDikHCzK8r$MC zVmeHU8L3q|`5Ta8%C0EHi1Vanf;QqavNgVgIRo%V;oeVJV>_D>I)#pDn>Z9ag^5|H z8pY7Z=0#+M*<@5PeIvHc3)nXz(%5;=%qjhi&ACWEEx3s(>5Udj()rAU&aibxGfn(q zES$>o!GJ5nLP8jALdDYUfM2)5G4%uK7=sHw11=>DE}ayi$-VvxYWK=)ikNN=&XrD@ zY)#Zxm2AiCYLAukMIa~BW}~-yzC0dwuvz0dN;Hmo>L7l`o(bp1ZCVM>Ej$>Ql#%A( z`68rl!@BRzNOzQ`mGXApj)L+Y9keIxjn#ygacGcsRvP8MPh)4h<%kO(C1Sy)umxwU zkTp{{n21Wq12=PnUdA|<@Z-$(S}g)#?aj~5PfxRWte#{odb^uR9UyvMcuj5GtTkal zSQgfVOkk!hUt~=mJ5FAcm#xX0??poK#n;5}H~~)WY)$)K&SQ#I6kI@7B^6f01rR!j~}SXU=o*PHT!fMGFv3Ifh0^j?YD#$ueB zdgjHCQI<6?{~4^&8P1K{ZW7)_+Pi!e#9u%gg1{srKuuLyDfQV3_`UVn^@)3n>OV3b zFgj1zTNm5gDS2;RD21pU0mV}`_i-psMxaL4ZsL|mHvHJ3Y$tA6hXrnt*f(!Fc>_*5 zl8(0e+S1}+AaUU+yC2o_S$*IrFTI}ejJhagJ&bQVUooJ?BUC6kS=S9yDH$oE*o=I; zD8mv)qoyw>ML8@q2CRfwut>%5SUq72k-RIz;YsrlsiUqi+ET%21YEh;n%cMp*MtS( zl~@zCqE1-TOjTo0{6b@5YZ{5K$$>RFJPvne`oe3HbE6aC)XvtlhvZ^O#efydY(~j< zNyXzzK)eUi6VwX=YvD1mg~fqo0?W?{_?(Ve%bJ1Je#Y|?*VV<=b?@x+a}oY2fqF#n znwbT~Athf*-i3z6))WO6aa0SQ@Pbz<1(%7`sp%gkZ4c2-wdz8~RI z@Ni*q@|x8zA6rth{+1=vf6L6~Gkv}OvC{ApZ~7XweWTA0H*DnFVmLWd6BBk^2=JijVTpuzO|{6THC~Xb^}nHU@}ez-s-R z-;ZJvCNDKa<7WzvQz0FK8jF17DYywSGF0ZL+{mxrxOw@pf-{SoYa45F`x*URm_LY0HqHxa@UL`yjkjA~-KIdp{*)Zzp-3So|kLLDe=2^1kS6yhtK z;T&{o5&&=nfh{l?j3PF4EbO4pec2von!|3hq#E@)l+q0F0qT$|#S%VIO0%L8`xoU} zsX%0}K2}zfcSmcLOOx^Xn*DWX%Y1bD+M`O3;~t^@OG172OtsDP4T9~bNtPt7B`H>T zvu3S7&5S&yCsWg-x_{K78!4$cJyP7w#`P@~u01BPqKg zV(;zWqVwdrS0m3T>ajjQ_Xs=9SJ*+KF+x}?!n}k-L;`QLuxT#*nJn`SYZs}|KV)L8 z9d1WrZW`25NI1=6hz$Y`SVL*&7k>&W=ghG>dCu#mGeu6gDHYX~*}?jGWRuT5*eDz* zdR{eit_nlKaZZnmyQlkwg6Z!FXZU3^XPIz-(y50d+4n_k56_$)&J3Oc#B5P*78?hP zyBf?^D+xTRrmaZE|Dq<57|p9A4F$($Hk)l`EE;Q${+FVo(2&xESWxQC<~Ej!C>KR7BVlXmkg({4({Mr9M-~PL%Q79CJO;El1ADZra5~~J&*U>HiE1`6 zA&uQQ18e?~1X!29?Yszp6Db4u=767o$9{|)Djpk>v_udryeXQX!w-WUpiZaFXk~Tt z(TG$fu~2zcd08WBpz(L}htg4Wc+2_!c*B1BEz$R->)lDON4%$n;N;Qtq+#J3%(e^v zw)k`Dodln73g98~Jv=CqV|gSLM+rn`3MPxnjJ;c}g1Tx}n{k#(a<|HKa=#SDx&z!c zIUrAqum{e}%qpOj=ofTN0j*FwRy#^kQr~#MxB=jfhLm+vwOv;%rz&v>R>GJ7M&Ncf z+7ZC&NMQ+8h^Vtg9inr?Rgtv7xI3Vd;05*d?;kE&G!v|P{>y^!%$nI=&uxfQMZda5 zR-JzR=5j@eqsV+-#P;wX^XV$~;0tQIGaCfZ2Kix#UI6QYO)=3KjDkN78`#&WDYA zo>;r)$$c&N=l5@GK6XE?gXfyjZ}?}BzsI=`<(tM-1ewtQX{L{AOpo$vj@k{+`zx=A z-OokfJP5pC<)_fFU=!1wa3s(+W7%sRU~niRO2$}}*@8k(*VV^A*EQ!k6g`^#D!R;o z0!+eX2Hu%>;wtC)*c)-5<2D-}B)@1uK3cM+>XM;&j`QR4ZAMXh)TlZ@i7IlgJ{2mV z0M~dc9b{+5Qg|R!vF?}#!i*TcRPblx<*##&{%}#1+NRgJb1T|LE8Dj8I${g?0T^!Tid>tH*}!y>gMRXN7MNk+3{f^qy#aYSgG$b-MrO6*_DB)m9(nz($ZLFO zq)<9_I@{mpIGYM?fgvlI)s3+oM(jX@sQUr}5Yq@aBtxN{lG(&=zEZxF^}v}W(m+fG zAC5(I(?W>Pvgpwz;`}SzTthvbOl+`q3+dk}XxJS5xA2XYlje*-9IN`M$=% zg7zD$UDW4^_WuI*zxp5CKiy}P4NsXAEYFVVRk)K`?sWma{iASbUB9T-aq0G}{|H#n z2<_rMTW0}>@x#FjzgMmYd^Q0-Yf=e6kdMSvN;>~|XM$)Ou0;Kv&VKggvmi1h;F3kk zLnra~8j8|$GtFvEl2l%JxNYy@t5Yn`stw6%N7YDu*S2n7WjVY>>J+^pyS%TeXIEb! zw{L4}(_p19m0GM1uG~~Pd3s-K<5e&2&I_ca6``;C@*9SO;!k58zSJ7D_=-0FvSzll zwYiFx)_KsBxvc&`rK=eI`W%^#@-?@OF28+cDYD3oO~IN#YWoduU$gUzH!o5atS)J} zcB;B^*%b|hKamF*e69z4t{wSj!H1uHMH8XLZ+e6{6X^fRaI5*$WNN}CZj8$W!Qm5| z>;9R*?C4g96RvobM&(KKyR_G;`;NT6XC8#f-ZgyTk7(5M4*8f6B<+Dd%A|EM2^e}~ zIN1y}C*4U`2AL2^z|IDH7bzP+6d}CFdq=|ULmfL|nUw=cauyy&7G|id7|b*vG6{!W zIRS?qX8PhlSx#A2rrq!GTM^Z&R`NE%mc*>W$W=oB-3`dn%H%@a!EkaquYs*4S)?*o z^19&mLlqoRNh&^T7$42c3B$XsR?7`q8_2Dgd(nZo3me#ICO39TSeq%!74W%2Ss@cz zgF^U0jTtBO%kokS(=lhd%rU&N+RD9Dq)~1XPi8iu{5NM#oc7i8aGqaYNZ} zeCUK(vPbTOsrcXrKiGNhm~VgoWca}65A68-@xI3D$oVAn!u*fs$}hgL`uK2w^n<0y zLrs#7qFzJ`Mbee$G1pmPf!Ux(J5|0FBm+4>oFpxi1^=NNZ*fs=bx})k3wh^Q$q}kf z4~e#b3T*Q>YBB(NV3oF`i7Uiy#LIOiKh;950BjR`S6YBZ>iY&sqJ}7 z8hs@rds~+r9EO;Ro=}j3{sTU#I#MI5N!X6HZY_`CfdNrSXcswlB7VRL=JWp zrAC3E2eq2n_Ta0IB5>CnnWyIk-DN&GS6Y(S^^d$WTpe5JjGT3;6(`DB5Mo_aYqTj` z-`3DpT}g5lNXg2?S=1bzD`_F2FUsp!LLaKOvHV}TwPS)*i;^L3n7@SI#>K1VvUSg1 z)82IT3)_}Gurr+Mm|i9n4ese|S=nA_#2rz3&!9QrGRv~=XAhlB6>_~TQ!%Nke8MMm z9sBa3O|RY9SHJt|ExGBqK?+$L;kr&eq~4G$^(uz$KGLwhCkQ5lb1y{Q%Wq2G=gPTe z3$T&n()1b=lTE?VW0F%;6+=xm9(yrnLWm@-PF$S3JhyjSrw5nf z`)7ApoR606dilD%#Y;xZ8z0{|cKe$0x}A@&U308dqxSRtBZn)BuV}yhz8j_1WJ9Qb zThqXy^N&VzQ3uBF-`=QFsiq(68ErlE+V1^dyS=}sZMk3E8*TRcmDfKb??KawJ@i4V zR=+&BsMLi$l+IeUe511+&6fb<`+)2tOFprUyJvMK_PSR94zRm$l$+9 zn+x{#4is7D?QVA>AR_fjWqh--4UXKnqR2dMSJ*1Xn)=vwmEg^D_d5$TQvgrm{(0~$ zPRf)%%asW=vI#%Mn_>XBfxY3AMgfdyO4|1MNn0FBTh(ej zxfb0xZ+zsWu;y%J@C?-%sM`CQ^aWoAnsc6%PTXF4-bKe6U18OV2X-`oUl+qJ_66xx zSYq?Ruk+Hi+$?@g{R)`7PZ@i!ybj1skf)T?a`W5ts(X(WxHHl^TG`9Ry17j_qc6ST z$xmxnrKqR29F^BHw>Kx`bXw1ISP$fMeDtFK=-+^bWa*?%O#XDMhB^d^Y}`W_M|tlp z$m1+QX>+}T@;KQI!cvnV;VsacGJY4$-^VB_RKmEPS>xO`xl0xB2R^qt;7={^rzm+IU64vG5N)y} zjhmSgG;ugK3B}mS*6ew1mw$1F3ORUg%b7=oHRc(Uk`$Mg`s+fG!9>*3YFD5dB!A*0 z&~Cy*I%iCuk4x{tvLCmQd^3{0)JfT zB!#AepWIm$OV;u33ajNa~$@$1aFq*?O2{_W1sL5@-DK47c&Sx%ve}|aM z90-1O7IVcBUp~K?jRkY5gwbFWrtW#L>W;#+Viruz^Tzc=$5qSYATxmfC|?HMEd@Tc zxaRSn1o1_d|7YX;B^XkiDb0n@JX$a=%%qAw0f}6UYss98WFwisyoyNQ%c7eFaDp+k zxtp1L+zXP)f@jHKf0D@#@Gzdu`WW6H)wR$t(MsClMLE8^ZELT)+^G^Y28U@;^Tinb zx$o9*Tolr3r!*R53NH~q9g`u8BPSUjhBxYL=_kd9`HQ@KESR_O%jAy>>?C$y5wCm! zGG{&Zl02VRG7V|yKBrugZ_4k@M$T-J6I&+A(0C9Z;tL@jA(u1spQ z5*AfwI0@fW(QnZxBt&46T8oeb(u66cj2lwp+DEXxE?Fxosnj@hb?S3iz)VxokxaGy zxTi?s$iq{KIx8vZ7kyDUNbklfl$-{&$QF1oz9{IFtkrl0M?yzQagnLX=w@;U)sgua z-N*_joa}QWvG7uAW!Z)YH}u}#a`l;ttvQEpVRog9sFf9i_wHy;=06&fas}nxM=NF& zOX!v8Pt=B*Z?FZP^%}_Mv4BHpww41`WJVHU6~Ym>qtG-IWdxb4M_E>IxP9-TNFK9u z%`pxAG)G}Ej`P{#)byj_21BYL?!k$xM5_|D;1ztW!4x@ti1GOgzgK+@YwgEcTQ7ru zEwIcPcUP;*54jp>^uMD;%@$1;mWtqP97i2WqCtS zQO=FZ5ziY!4Ms#@bzMM$7uOOFXCemNf=JMW!Z94`9dI0MMe(c|god*aJD&IZvONwP zZ{@9Ml90;c;Zd9LPk6_F!5@>sA$Q%O77)zd4#$cbl`G;N7^RYta~QcUtaOyogc-<* zq5<8BI=A?(<7u%~%C zUvUFuwR*(s{fl&#_FPYXEI14x|1Q2jmBzj%bGVcolupb@7r=|!gZS8n5GMLlI_fE+ z1Eo@w{~8T3_JD6OCjsL3!HDFfst%=Eko#>$BaA6%DL%6C;v>PXP=t@_av)7!o_E%0 z#G^2$6XKSMTTvcDNs-&-C{HVo=TvD}P8DSH)sef!v)C)uDWkfp-QkM-6so%#;}w;1 zbPBW)L@qHQ1{ewh1+;(T$JznP*KPLI6y@2@<}bf>rMuOcENW8It$TKtUp+c>?LdxL zWbqcJIYM5u*&A}C6?!ex&sn_aX&&;R|9S|$&Ak=`HDA5^+GJc?+Uc}MrH9C@{CGve0N;jQKyicCjRBz7iURiiZFW@%T@ag-j%^2Vps?C zLB$TBIf98NQCygCfW>bL^ui1-!{`h6+^jp`CF2zM@TG5f@h_2$Nk)FeXo~Fin37%Q zNV37qKVs2E(y(KZjGD}e*hm{4)>g#xRDe<(Fn;J4cLr-lOr}M zKtBV9hFE?dsu3yYgl)>RxUmqNc{FgAvghUv4Cinn>Z?%A{DsEG0uL$BQx4_N;c|R# zUohKEq5LG#x#BTKi7Z~$0is6RTQ~bP`sOD#4;&oIPbf~BoaY}L*|>S}v1;)zzHMFO zvQbu!_3Wdnq??6PF$1jt7(ER??pvIh^K!ew$!P70V*e)CUt*cUv|C~iQ7`$7o3b7G zn4;J$!i{~=F^Gbb$H0niMGgxRuhGN_FGIHgqnhA(QQah!u>GBBN87{=A6IrtbQ%A)DV)RsGv8PrHDuaGzCH-FN%|qZW8Ev`g4RIVMR|9V?tulpX{ce z75#|_1Y`!t?(v0!KLay?9^)sdEd9mC#)CNKH<%!{A5P z)KF)sGt@n?dZIg&H?Y4yF=%8u7R#|;-Bi@d!~thPohP?4kdYN^Sk_dtc}Y=YWfL__ zwdIt%0%iUTcTU|%ebe^g3ROcwObDF~;*NZXJK77mt;s<$=DeNAR|ku@n;rCOLwW}p zb~2-mS2R_I03`d3@etYtQE_L)%Tg)8Sb!D+4TK-f-($(D+g8N8!p;XwO?hF#irXe9 zZW_y5K*qZ|#rmAVnO-yA*txYcyQv|`q!Aa*+x|?aSWo&qcqNam>pZlwx@yIh4S$FQ zFvWyGlexoMcf7H9u-+T$T~pP0Q;j+WHKPfy8SL%?>~1Lq?4--Um46gy@LK;fFzgcp z@}Go{pBTQEgT6Qe*q4M)L+@~MLt(7}P7t)+;fQyV7HMVrCg>b--*gX94gkWJo#@jC zW`et%1TYqS)E4_~ES!v?PR?2Gvr^;tc`6}!1rP)y8~%&O51~pm`i9uEOa(ZOV2`!m)Pn{5MT?3 zxElG-ER7Kg1#+$HB)7u z-5L2DQ+;LH=lhw=1wFhAI93HZ52S$3k?^#@%NVnZt|%HiIHQYWdE$+A_^L zTyxaznUhHLh$)qG)d9%CsBc~keDvZ>bYx?cW-grQ888=c;%50T?K_mP$TQP_O+1d2 zXsBuw#N<;+SX~ScTJX-gi@!6Dkn{0lHpM$In?tE4R?dq9^2@j=2)H(cQFgvbM`U&WaMox zL;^Amz*lt^ek$;zmp4u}U77}F0;?|*1eYKW~Avxq3q95bG8q`mV!bl zu+$*jsPRN26~!>Kf`cqOIzKiJ%7mQ!LYYa458&d84QDzv5rej5!r~F2#JY ztW(7C4q*h8<`Ol?Ad!evOtRUO#(jLV5^A$Z<=ixIa5xW^utmpf&hRrRlZYXntzBc4 zYi@&a1?HCn-Oa+U&nL}z>i{;;%672}cls$V8498LWuq>M;##nhLf(sui{e(q(f~DC zR|#*f%~0ojkfSi`*ZyYD&5t!}P!n4cyV5pqPBI9KBPU)kJ9TzE&*h3Y^FNXv=lt;a zAyy{fVm+=XXNNVHp{rz8CQk*a4;Etpn=WTN<{wWrDU-~;U?{zLD6@0#SblD1Ak$&c zq4CG)b)nAUv_JVPofTbqCck(>Ys@w}Q#I}F8P$c*LQ0GE$V1l#mu8lC=SN=eccu>s zdW$n9E1m6ksd%$cq`Z!^aoJcKB4U%VU$8c|gs7U&Hf}66Au7uf3lRNwW?xxuM`?Oi z&C=51#xzkhBo7|k=`BmM6lYX6S4-nr0dLEyaLww@pfAg(*9yOhe9o2m3x{dx_;@$) zvji~th4dI;qCD%dla3{yH^NJhx|66g#qL@(EqzO=P12a`UPp6NYi(w>!<1}LXXkFN zEE;O`xf>_yYe&3NP_0hZCy)0p9nq)ilM73{*{y3Dt5X$QY zW@fXV7pD$nW8kMyQd$uI4qAm~Ev?M$C`otKE-lTgvmg9FPnpe9oL<#jEuOHI`9t2; zRgE>PyMj&|pE7Nl$jJDm!!$5H*2UnA{R+w0uLssD#3Om_46o>%sgwjkHL4}XbDeAe zcPW%aKCgJ7&Yf(Gyrt}}%glE>l2X*!ma?iEXT^%PfTwABT}7Sx1HCgSJ(g8BT9sj5 z)QJ;ME_Ap}>g@Intz{E!!R2+8wp^D9aQBHP_`S-jknbFgn=#FbYhuC~JUJA-zbm9q z?OVUh<5uuidrr{}hw$j9)S^LO<{w+9Y0_(QtKG{YWI%@bAt3x%NCl3UAqII7Y_6Rx zjWwCf<_dd1`av3aRne1|o^CJc9_=pigjdwn4p*n=`pvd1Zy@BV?0GGxz9-vkuWAjq-cpz!DhP!_ z(&KtvkyWX&X9XJa?2_JSM)xFJS+TdN#AWjpJG~|Pr0fh^iP73#L?fo(v!=o#pOl%J zk(1B2g|hvjkl%}PWyDtp#1n!I_+tV5U_Ak?09EFh=m!pDb{6L~<=YPCpJ6_c^-fDACQ5UnOM4tbgc#O$58S1*Wu~NL zSado|MvA*wx;~P^|Nhe{8EE}u%}6n3T6NHKF8oUPF`F+1n5KT&WkKUNnokBjOVfqJ ze$L$AN)0p?crq1&&g6IArL$%lW3TZP;WeD6K9r_y(<)s#0ypP{ahQ}~4-|{V;tm0m z5~NX}l`?9z$3hS(Ee%-pZJRDdc`(Vn`w_j}s{8aVyB=@SKXA(75QkN+}50yrYWkkvJ zFO*e;mk#vVm10I~adD%;v8-fd`N2V7`GK6=v_dmZOXVH(oCSnarMk3Zs$-O&F5B9dqn^UaG8%c z&3c2R_Vicf0(TDNS-f@)VY&I|zBuF&sRl6l*ZS+OB@tZr053lo)k^ zqDo>k#Frv2%I9mDsHvHxe@75%}#^Utad_f;T=W~|#m6lJrG9^QD zvf1fN4+Z@Av)@tNRa7yWAr%|6I<3oYb(qZVvRr>-D9xK*tk&ubI-kv+W-@!K3bShR z(y~zmiRV06*Y(N@k011MWDr!hV!T>Q~qc}y!4 zy_yY~sNRV&~%6;z5z zrDdgb%3z3mXwSD;^6h*Q4Ahao+JfdmUZXcme`MwT`V74xLm&B36mE9x(Svm{p33@+ zqGSbQ88Tm$Ln#qUO+x8cp1xYIleP*fX;@?4^URA^>5bAhg?dsl>UJs~KBv|^uSrch zYWi#B_j=9CCc_Dho}G;fG-k&;tk^qzW=sal<13NrG#diEpf;sWOnqy+!6LE# ztPVruE2=uJHS$|DUZs-me2P*lTB6Ueeuo+c8Ioj0OXPJ!y7{_a7`<*)UF3bel25fF zW|$kqd%lf000Z8Gbz_})M^5GZR3=|xbSGc?yGNB;jrmr!#(1k) z!yDLI`=fKDVh&>re_WJ0*nkW|O3fC%{g@^BY7wZQR9vNVCm;UplPZVOc(0^UC^XVN zsmjP7XfD1`aSeX~woo0H7PjF#H-d-(u95HLxnwP;<8>nH0r0rZz;c;PZsPyjnxsn2 za%eLg4b{>+mSnBFcD&iD=V9BW{i%f?C_ms_SX-Kw_6H%ee8FxNg8mYXDU=5<(tiT? z!xE)ccvtyH+(7~GX^N#MKF#ignBcxZEPV*k@m5P9Gc`3cV6g@f()xI6W{wpR^hRT5 z4uV}XQW*jZFH0j|L6c@-5`Qa-#9zpnud z-cT9Y88f`#!Q)C3XMWM>dP*H{Qu|P9o z01BD|fiV3W4&+x=<%g=ONOt~;Vl@&7E7^O3ke$6*^e)6JTC-Hm@7B59QhIJ{iPMSd3&GZ6r?a><7+nDW+epNa z{0AE~2*O%^Bz;HBP}hFKwSWrcwfrcfxGCG$T#}Jd((KD_D$W=v3*}c-m(Ek(whn`h4~Ic6)xkFSoKXH&kBE-}7C)@+%-t{3mdyLDPFxY2X9YKUAlM z69c%#FrW7Aj(-xwf7d%LLnrk)ZvK~lH@M7GpEc%YsnY(U*ZtgLlm8d=WL3HZtqP$K zMDMKE>l{24w207f*z?^clRMw;K*WafK72Eq>03UZW=wa<{t zk_-MRaSpg^0131q7J?Mfk;`{d%VCujr4Yy#rO2J`e_PxwapyRUCzw%Zt+8qK4!BO0KqP!SNX8JlTGzfT7NmS3} zI*s{R1RXcKaFDPBTMxTS_)@9mNz~$tY}Prn8mlg{1r_=36goeXW)}bC>Cew!>^`rf zqI(3JA)Mh+e58KsNz^?JZAl85x{`*TXeR$LMN&NP|pN4y3L|b5grqb zYL%Ia2$j?S6IW9lJ@>An_}sf63Jue5OQ)WA;+*#MY2hfubQxzPsspB?J>is@BP`fK z7YJ<$SffzcuqQcuPzqC>H^s3S;_%SgImK=~@1@utsw|lb_Y-_th(o|Z#xRi9E~Ah; z%~(Y<^5}L7=*U$u*$q!^g6rvsabM#a#8oK#A~h@WMn=%$3ug%LoqN|};J+Wq)an(* z(=`R%zF=cI?{=jMKeiNPN49$cI!SR~mo+a%C>ENNG7W>LphK3pBllzn0hW#nw<>Fu zNw8mJBag2f$?MQ?r6uTfj$%woPBn=hWC+6%P`e)#zUi^XvGx-{#jn|I6#I|KKz0gwLM;*R?O+u!tAG zD=fO<#Wid2Sva51_aAu?$A$BPq$8aJynWQA2@8h70Upgs1!_@p9Eeq^%vIvv&vIpE zq&ux<9a>Ro)SQp^X;dbXhb&ZS$wsyZlwB%=rcElo3OoTjGX6ZvQ?&lk9q;UTY<;oE zb!hQ}AKd%SeZP3HUpf`Yh_p`Kv#~}JA3ncIs@ZtY6#r&MAi^E|=E*^{!saKGgD1av zP>|QS5o`Q~^e>2_1Dq|0D&vrqjel6wmrUOj@Wqd?=r8aUJXXuqdi~0KcteX*?n?J)i+R5_52%KVcy-GaVADJjHrJqyhEtY*vUhOQB5Wi;V!G zA;3HB5+i7iFwA0NKAo^YU7hB=gu<~MxaYXa^1R0UM(X=UA&y)wpG#*i!D<$mDFH=x zTEx>r%p|K>rogJKQdcrmv4ANNUU~dc;S6*&6eMRY8d+X2c-NMOwyRE0R!sIc*-gpW zn<@p3J+Inb8=ii>WLamiI!#~LG*D8Dc$wVx3AHuUUR2syU~N16`jyvw_10cTUae=7 zZ~AA&lR5eIIjNmC|M5Wo{=rCgb7^Mbs(aQ?9it#yfx9Jgr$UE*s%h{LKO5E?L6t#@ zA%!oWn($EFiEISJqVTjx{RibDgY3TGP;nc*%jmi*K>5|47jhOHTS|A!oUtgr0-N0S zdGjWYBtq$ z_4=yXNWS6%LNY8hQwLgiKkP|uow~YXlcP9H5H{ST2 zlPf(v{fh&g)D{eIQgDL@d4T*_ePm;8iZ zD8GN^m&9i%KY!+znP(FI7#~gv^emjk&AIb@K8ZvrqhBE7WYne4r`j4s$d|S7&Zvz1 zx3U+n*wXA*o3k^P-Lknqvv{Dn%p|!?_hbxjzP1%n)z3c7`~Gu(v)-PXwEioRAAY{? zx!1lh=}o)tufKk8Z3Hdm1VmZ?NsLIRQJJ`vn+zuv;dZWY3knvJLxe!a7+hco%)~Fm zSHb_I6al%(d8yw+tSo0!V<@-K>tUOb4JyoQAy-_Co7r*va%7rKWL9?IbtX*9sMvdz zXtU`WmM+U3@2(u%wQtv0W%Jd~Z{GRBRgJH_Qn0ikJ1}r~nP+6#vOsN7|N6?>O-qZs zom;!YTYB>(T&emLeMKORegj$S$g7G0GDi|f#*ZRGFcaGPiR-tHP416-<1UHo- z$>7ASU{U|fOo13wnX@Jtb-L{8f!eC2mCme&(W)n&xbE7l`r(S^(b|Aq8EkT0$-rIP z!yCp6n{rIWtL|F0<8+nSnWD9)+ik&$Om|h#cIC33Ky$G(TJ_7Hn%lplePn-DYH3|l zR{5%)P;&*~wKVcFvsaaKS>cR)7Vn+r5Rl3aFp+2$q;~biApti9ZzVH<+?|-1m{Jvx z!wv&csfUy{3UhIbK0&hOWf!bpJ>Hs=-L|%AVt1o8u>FDoop*Kr`I=k1X`|XsLUG5H{}EZW=HGP;n6++`K@=i zpfRnPnoVNusfg=M##v`_x#56S4atFm)sbI~Qnv~P&JmI@1*H{mo!L}ETvit17JK?Y zR0{W~Y}SYKOpzQ-erRsa%PU`cwXN;U*1-eAd6B2Z_vCZ6QeaG1Yt*r;n?zrP&)$~c# z!*|{GuvXZleMowG^0mls&%6}*-Df8zKFb?lI>V>FHu=%_AQW06zmEJ}@#uxf-+0Xh z;w2R0^DF5|HSpmTn zze;y)RETx^KYPu(yH^(#Hq?geik8&5)2qko+IBAqiHc+IKROy*w6k;Q#GXOhYv=z| zz3tI;Sx2|@EfSx#X8RZCeLC{n&#w#bd2HpIEp>o)THTuNH=DLD$`9Z6{^`8Me%{x+ zXK}@f)Ld7|u2Gw?D#cR7WrTSwKDnY`LPb|l*z!s?W{O`qq)fBW zMhFCyWkRu!CG6TM0vlfF*APWUl3E^nOrZdZ(z9UG_;GCP)dFvT?h$()FBXXLTSOqm zhY4fEf8$1DB02u$wMl8&CEiXgYzldc+pALfo2-r1^#!4vzP1|6D{8GEC87=gD^b}|mHf>yXtl;e8=9= z6}WxtfmNfzV=YXe~L(gHfq9b-iOpC1-QJ&n;+E0td$x6Ya~5B*sA;I!9P;06&Q5aI z7WUn~t;vp<-H}mubzexInQ}Pb5uT71W%+~cQz3V9edbK*jVOH>>{{PYy}Bz;XkGv06^*S&zIY8Kl(f`Fs)dQp zmanm7l3@QX1enM=?P>A%u#4n!u*5+^ie6tp*60dL2xEf*w+n;pIROOo$d|^9ub3K} z;2Tfkp^QZ2suTD24K-hLX2;gE2irSuefOx~QyZ-M$Vb+^mQd;HTgQVB+;#5>ab49L zhj+elQ%~EG&+Xg$`6C^J8dHika#!=dm92)7sau!5^u{~HqeyB*d^JeIu)R6c znEb+X+heT1jPESS_j*KH;cS6yL6jz{6Z;aYvX)NWJlZ^1Vj>jwB?E;gpSrfI@v1Ys zH=k}4n^=+6vSs@_R$Vh#g}{%hCST`uB)b4-J(>FS&fT9mvgXAjeQk|6SFAbh!r#Rs z;;*55y(ep~Rtn-~rw-`OTn12I$ULynueovMW}#o{mg#wcxa>l|%FmLLv(T^dvlQXC z(699DfOg2(5$$X<`?@u{(_EQi$nA=}m2mGyzAV0I^LDsA)35aQ zSIXD#x&~no@H&i`{`bK*J;XOD;!x(8>{f?D1DJX^PcRr&z7nJpKkOL9v!WPjmu?+&hfbnp7FuXm?6?%uhl@viUQ)KtFu zwlU!-XkrO^!t4O9`Qdp--|{R3JyMTxxiM>52SV%7L7FUBpjZ)?cV|gaP5?$iubHe@ zvPF=jO~{!u#x)AoLs3wb9=80bbxUdC6(y_goO=Aum5=TYFS+M?N1nR=KThg1Zzyp9zmEnWOaOK(|U#|ukO-`9KOr49SPe#c^-D#G)NZ~okl@kfrV zb$40{Ri$r5c)o7ysfqsUC(DPX2oFWj&NI?Z@J!kEseLssH_MeQ=e5dEi`xHaiO6Gx zbeCw*EI;zylZzLh{O*ybVjm)VOIM$mnmVz%RQzo06TI$Q_@0}-c;((N-qPTRL($1dfr32VG* zsLcsFfw6}=&XPYfW>q7GG)mBipbxyy$ImDcH}f-oAf_da%3=WPOhFd2s9*?AJ7)ys z1dT5{==1x@z2Jj6nmNZ31u{608+h4?&x8BUNRt8n8ZF(%yR8!Vzvg;*CYSf&KJAkvh31=6gc%l3x+#DQom|;sL)hF0N_d4Sxkb;=q z3tJ3vA+OOHQj(RO%)G>vXDEcuI-f_$eL_#!7%UDizGXw5&X}s?vrGq*Eqe9x`@gZ{ zOyu{GU+pK-DV;h#f|fuZsEViV+t$8)a=0)`HFy8}p|Cpg3g49y`H|qzTkJ`ZP~X0h za*YJZlIKQ|>+vY)xt*&CSLQM~h?2*#<}H*;ncqQiznrYal_+4fuC6R9@MmW@^~o^F zxAX02T#`pN$;1W$Y&Q+CS5hY-nc(AQ&D2WT6)Urfy1Ks$wdPyTT0^a&?8Pl1XCRb{ za2uQEKwW>$`r8I7#=5G^=Bm!ovVq&y*DR_#sIeIon$%Fh8ERQ_AlSX3k=I53)VQHL z=pMXlXWfB4E3>SbCe0NWxa0f2aARj$QFBgCb5UC7jbGSzoae64m@=(dEB73z+j-ZZ z8%HswxJIazzQ-xKa=CU#GT52S`-`bL6a@?+0*&y02)}TA7uuxYo03zyMRMSna673) zeynx7)2!VF5C51qBk~K35V8iY27}XUp7R|G173`X@A6Be571@B8a5>Zqg$|4ZY_R8-xb*c zA*fL25jpn$0O{>~g|mHgWs0Cq%Q2~~wlwL3J0ic{lbw{Fl-=Idm%G72G0B+sLJ_|N zTmFaV<+~P`SMDD}KDiXc%Rz=i?kk!^!0CdQGIyCJZg#T@F=gI+zixgF_zin{!BRlG( zQ|G563V+LFb=`_4H{Oc9z6!!2Ie3<@7Yl*HAp3fyxUbhbz4~o&GUl?2J*#{VK0kPR zVZjioNCk7%%}fBlA51&Z+K;6QnnU=?z49bHS&eW{>LaJ6KVuCx#5pvE>!^sUgx)5S zWTB2|(J8I+XC9sro_Fw_c00$}U3U1V@SF|I$ZOORoZyloNuIL7=%3OCF^#XZDUtoA zLM=1xuRQ6y&t2^7>5)n4l*<`0^a)=Ue?HeYy+gRemm5)J z`Gl=y^#(&lu24^V&xH@b37<-syFRS1MwJqDOje*SA@agy=`jR%iURe%VMqox@UWR8 znVgy|;v!|X(sUA6nc$j1o~TbS-UYu&ILYVDfu+=!ua;2d9R|giu$Bo@k~<@9cA zU$SdaacYWLQ@G^&H*J6MnifU%mM02q&4X(yC!V;feeE#%`-Cb&{>}|eRfubSB(r9) zqIhX-78?8LQSU@AE%8NwV1=7 zp)x$%m5MQae#RYdD^$jSX?kkrv$Wji|7gAVQSOSeP+!J*m(33nm-1GW7xbY{7SXnZ zK0mN`2Ey61>t#^wCJUS!g1}gfFUOaqlwjPrBqEmb`|b`ky7;|@yo}S4en+Ff90j^x zc|IeU8o42@uI$;j-V%N3LH|y^@{Q2#OUticVw02KZMNNCoqRw!cUkgfK54QM!kxh}Gyu870GVOOwJP&KxL%fUe zBU&T45Bed)!@ombCAcNnk^=sHAaI;HVbL-_!Z}g~?M25BJ4M+C>Z*oKxL~&nTfJV6 z^A>s`sE|5>edM@h2A0U@=k6$x@BbNG|8wB_*MaNjEU-^;0N22kz4A41YWm*zHL&pB z=iUwMzEUp&94PksxGa6Zl7zlQf}rArN!kz2jIyhUCld^MULZrJ2Y83bZBAk%r3FWZ zv3m_wiBN+%AaP5go>p_`gIsO2*=$~$$3vOM#+)oI5q=_oaO|vqpaXxEN#84l6RyJ? z#FLTjNgaUSrGBqhlGQ3_dXL_WCHaBIdpS~+34d{KhklaGt4Z@Wik7*UBRp% z(#kR|nK{{N3D$!JqKsHuB-Ha~PEmJ(DE(}q_@e3ht!JFP#^EiDG$GH_wzlJ<%ZAU=z~TW8m5Y&t%eb!26E zZbg2JIWqXXbSlk!Ugzo0%j@@u>sL;uny)G^KevhG@IJizThb4sdNt(mOGFb9zfKG% zk}flxX!Ei69~&Ec?EPb}9mj|9$KSu{wdp77wmmR8`M|b11y{HIfr*I+w%19;;)(~~ zz2eGmJv1Rc_nbKK(6_F<;@t;Vh)+-3M(^L#im)!Bb@%-vBd7j9;=TjEt?J%i_i9_# zo|dd_4O_M(FUj)Wd&DD-on*YB*$ewt2(c{?qzMS>qTngmiUGu)h0OyKjr^B2)1H2j{?C`*f>}n) zFd>yN#o|1S@d*zrcCiO9a5ZS_ck`&1b z6|8@0-7mg<`sv!K66# z%j@OFC-X;iA~%1IG$4=o^yk7C>An}~xvYIk2t#lSj^+~5Z&*X(<&fz^h|Ufx?j>CT zL3NQRO+=`!;b~Z^tJPAWd6Mo^Y0thPnfysxK*L+%vDm>yehbt!;tcU-YzM2EFZNrs za8@quw^-?UNpd=q8OF~S+?FJLB{)BR;)2_PnjNrfM2IE3(8H8E0+R4~a>36r8`Qgl zjSj1mhr9uH6p3n6rK>DjHJVK+{Vu7{5r7{;d?DhWDPXO!-Y_&0 z8HIG1h!4W~MM~TXDJ@E~Mn!nq?-UbJpS(`(1^0~Fn7qn!mtNv@&kPU-?pgnYJK_+p ztFi;t?*uvUZRz?%r$07o6c>x6PaxtEXwo*BjX{8gjUWaRmtYmc{UA=e*`(K^V{j^5 zj}R4-vaSbkY+@rtorTaq1ZsycoFi>nqsyt_*}oQ~G-rjJ(Kv za`Ghe$+?lWi@Q-9f;Rw6N0C^c7JdZD0>}CgqKYVs6<8k%mynj%Lf{QT5m_J0VOSpw z4$>RjO7ar2{7B_?S}i7nS}7JL)<+@xj>YZS`*0H7JEa|)7{Q_O^+yEvs#4qf&YwO$ zc6!0$Z&LJa$KLO+6lqnOf}U-27d^bIJC%NIJSgqj{qVxdC9_&QYRWI~Uc7eX9HlsU zl2W`lvY@9wMUG_>wR?Eu^E+#mj$9YHH3UDQzuxz;MuM(jglRPGQ7NyrN{TQffh`%3pEwQVK$(3&L zW>|vhLA6@v&rnH;U*IeUza#}3&^{9XjVhXPn~S~s16H<)ipUl{@P`98fBewAc@KSj z^MOA+ut>)I5GL5UrT1^BtlV(_(q-INzUjtK9vx&uq+!sU8yR@`*03Hot_xO+1!G&Y2o<^f~myqBm_0UUX*QQBW=l*J@5h|Sz(FtcpkUQ zfu}9mJ{(U(QK5Zh57TJeKjpRD^t(>0RHk#)Vk8n-W@ZuYIZ)i zk^0Tp2kw>)-BddBU&NrMmr*IEOdC@V2U*tVQPmD@ZJc{#q~wbw0=jgd+D(mT)XW2q zlUVp;n6s127(au@A(9}!xz4SuNTI<5tP_S+I(cYe1_#&4N@|2%Pl}Xeca{(y-CXmS z5~?tP`V0;x@E+zrUS!~F-Odyw%>CmDz-N59VC;6HJ1i3u!tI!sk?0N;uu~yO35%T; z@>UQwjDt}SIK)QOLNOUx%_M|(iYjpg`GwrT^vcO?iE#UiRR@1}7hWqcG9_#N^Ra_K z=&9EhZpzgM#)t9B+nF4ji=RDoViad00-B8C-NdIrX4*pR8R95vYDa^3p@px0sq_>B}6UmQRtu zzq#p)1epX`H~nUc8$h!$k7dGBm}x$5MhV;VOAIGfWl@ju6BIE4yNMj$gI-;;0kXQDnME+YA2_7Jj{L6fnT zQ4hHcLN(h&a3~m>KC$@5!LY#8x?o+^qPy3W*6lbmy7=_2mg1d1I!rB3;hXHt{v*c@ zA8uIN5%9K*3f_}8ZhdG)xGidJ*!A@2nx}Wx*WNbq++9@a%bVo(x%Mpj{N@)Pe&{4&))2kk`nR2 zzteUzGm=&0Qj`p$pYmWy!?wqlt$Fl{(wv!FJHowH9$)9ynN)W{?`TPMVN15FaaC)@ z^0t8R*!pxcKx9ouX*5&9tXQs=Eq9{dHMmMeSGg*IMG^zOji`D`80>)E&pJLVs&jNm$il_t1NK#dY2PU2e%nZoKCNEGBvX1N@C zyB;+vbQ*_Ps6(n(+_C{=$F9~%@~XLO^>~ACf(}J86|dV~vSfb;v-zQ4 z4X-!kb(g;NQg%zkrVF>nUgCf1t?J8jHdYrZb(i9B!~b;e*kSxp;_n52 zgHPDN-547Yh=gOm0DsEDw~3)FLbD5m~G@` zY>q3r>=_itK_E5{x-npX#0HRX{Um-KK- zMkr>d{((x(H!|myMX|=n#3%d!?xZWwTLw9&BBXT+gl4kIlNc`Ye?($*Vw zJry>B!zC;*g5iGc=ZRpe)RdJJMS|IZOjI37H|Sgva*()~arTxw(ViWbjZyaQo5OKI z!s&>vuPt_J-P{8Mx!Uadf}zpM6^Gh$7Y)vI=A{}mnWeKTqO(dJS8ZRnF4|Y_utd9} zrQNX%xm=yXKNzV-eb0Pbb!mahx?^7bnvN`uuQ;q_F`31_=d@50Qwc!I97fNNx-eYHT&4xg%^mH&~cM zcfqdY0^fb`i~uRMQYyQyFK78)nM*fvTELfTrF5VkzqnTB)KLgCn4!%v>KqEXWMD)2 zjZdqrV>0@2ZP18TopkAZ?pGZD9*oa1o#4F^)T0wiHj3xvN|cBs#ri>Bbrx{H@b@A*}vqtI;3 z?RVB6SxH7LHcM``F9Vgo;<8`x5B_J!UPImJG!+na2szM%g!jSt zOXd<|RP84K96`F`*Hat^vzJjM8=eh!#GHYK(YML;Qnita$TPHu?iP!fyCi0{PHmAe z$Ayx+4{34#P)dErn46X#q*W%>n1sIDQg0i-RjJV^0hu(Uj}P!aQya%WitDF0u|G1x z$FT8pVkN}=CjOfjws|c#?K79$*$WGqx}(INK_7R488V%VCtsHEG%pG& zw>3-#l@k-S(gEo(E$%$&5ms7TE*p9d7=cPGjV+{9PHS9mosbFni>(M8BqMA-Rh z5_V3)&sQI~O*Vd1cKgBWPAKTbiW351^WJkCHhyPsQ`6q>Y}{~eZ}Zr?hwr-UVZQi* z6DJ->;sY_kWO2lhr~wl@nFo?B5RL=5-Dgk#%7ncGKaBqi>^qBr6J(M_t+3Pa+b`~p znxwcAHnQ-aXSSSXwr~d1O3XtK3ta#us{KugPk zSFXB0@eQpG&D%Gd>fbjnG`1%+ckgU!_TG88Xk|u3?bklHZryX&whNiZsTsn=Pa^7; zv7z1r!!hBwKq@FkzwqAu3yV?Qa6(u-OzLov*!fd}o4}(i#!Y~2PFo9m;fy38bZ}=J zBSuC-5`gPG2x)hQHGXd+mM(u)!rCSL!H&%*@-%5|a+-RH!+P1VYSpj7Aloz%MLpPQt|yD#pU*{Eert z{{4ds&y=jaf8}ZFQJ1Fh>h)9y^Pf#UPKBBJVO&=U-@(`{X3k>V$wU#dm_LV^$LT?6 zLMD7W`R5C`92_k`4_TZJqT?7(L-a~~yf|hKp`U=vSt^6hB*q|V+(cMOV)$o4kuPpZ zdPUs9fS!S(70kkWE{B(cHeZI9Cu@u(iy)o)kku98`TJ)xTbSpm595lWbE*k2f)A5a zKIiWWNsfyGE4TAXDpB+U;sC(v0Mh+oy<$FS+>p4$)oKa6t+gW%O^1F%C_Ifn1jwDj zg51fI1ErGYM@4_R?9ePPH$B1L(_^o{73nB28>X8m#4!7Gni6AmGh&>{952S+F+X@5 zeZKfn1lG&a|oEyp+O6S_6HW!`qHnI`~K`;vRp6e>Cr3 z^p7s_JgaeK?hLig4f~wszYC5L0Qw|{XbN!eYpA$q`MT4aD(W_#8d&vmbqEfSH`Y^C zv9vubVjR?OCE>P_>Z10DN2yRr_&Y1=+OPZ0nyoKhQ{U2Ag3>zH?4B(%wl=Px5iq73 zWjHFJ0c;BXKF}aUXb{4cf)#$^1sYsBCla71clQ9j7r&3NepycBC7!pFoJg79%Tj@* z0f*$%HW0Q^XMQO)x9kc9dz;}C`0msV8u#5@|KEbQzVS{@xZ zwXwEh(-UkMe!WbF^R2Ih1yxemvj?Ya2 z3O$bF8`5F;xEvO5x);-jHSW(ygvd<=5`6?*NkE8fvCGPTNb9b+bK&xbHda+{esJlc zyVuuBK0U)@*AD(^k2bd`0`mm~2 zoM{Va7pU~(;*G=Xi9Jt1Ha2cx(wuX;0oAiOGXZ)fQ z?6>ON&{oRpE^S+0W6PX3w5W!QSg^AA57#pbAdpCaXiai; zi^FapoPFufMKih2!O3bZf~e!#WJ*gd00jt6C1KTEH9xF5^QqI+AafVGYCZYHzAZNt z_7vN;jF8S+PYK@m%U||0KdS5cr&!y0*PL``bqiUJwKbUk-moT4F zvIjrpJkrh*p^ABLAHz&KrOWqG*0G-_DC;< zun2a$=!}f5|28=`lJ(Fag^X;V4p}@#>0GsX!;(cCRO)$t!S`h7h-Fnbc6T?btyOvK zSSy8}(Pu;qu*)wQD`}R;_w75*%}~^>@mGbN`r#EThV{;Hl^-PnXx`k3kNKN~kFdBo z?mzUzg)l1-c0kt~DCFl;H2OCR*w6zOZ7U;^lx;m$FKjF;$-Xl zxDgo2kFt)1kjv{LOZD;NLD>naQrjHefz}=K3SzSs&#n^kM=b@$v-j>7swKvXnyP%e zCBHGp7Le$4{1L5_6bf^p=oI`~z)WmOVEo zkYDc4C=Z#XO4a$^#GhGm5Z3L=A?tpId4Q@Bj>8%e^Q@I@Mk{PZ-1>00O=y`!PKkij zCM69W@$WO&;eW#Mu|F{Hj{P2cA>b{V_(WtzJs1nG5R~fV$tzPj>S9sMQ6ylCl?lMI zq_nR9*CT=`%KXC5MkUK2Q62&zhD`wW?j(4AQNiFfC!bxk=(&@71_}xW_MCif(V}Nh zUNcy*D7$mrbtn7!P90p=m9y}nKke>2dEL6sY+7&|W$(XwW>!}3HFLJDE9(sFv^g!& ztLgt-^xP@@8HPLc+@j&<$PnDn{r4PN-<^}wz5dWW{d+!mY*DcL%0u_P!F-3mHPE`W ztaw>RaE&=s>GhNa2u6!sKYpFCPvgjz43JVbN;FE!KcW^S34A8n zPl(+n%lsM@J^4QtNrhs?11T!i@>SAjQtcYM{AtOmWoo62`EiO`sm95NU>FHEkBXgLZ zA(78irz#QmnP$}+y%l+x^@X;8yGSerBouaA?FOBL0Rjt8~IcX{sdt?-)cuh!O=NK zvzNwVi?Z>v&9&QI-WdvYmt|y>b%#QoLT|_RaCO$?a)Djd+Ks|pVm$ZmZC%Z?mU~c}d!0xHUFshSH*NYpsWFz%8^w zQP|mEy85o+ZdBKFAzqWLA(Od_|Ag>S;D@3!Mpm}+fyI)(t+?gW`bb0`ux=FG216=n zCF*d|1AX$wjrWa|g9{-q4%=@++%7*j1S=HBdEt-ne)1%>y~}W9H(ywe)LB zsi*1w@19#=HJXd()t=nRy*C#EKqTl#sI2IWh13ewI@yrGNhpN?+0a_-|54+U{Qo9O z$=tBdnwj#R#wZaR)W4JEIkqr2Q3~e!RE+ul-OS5WG4nDlqubp&X1BK}Jw4{3w&>mC zr-z3YzW3h3A;_E(^x|rQyp|$|uaVbBWX{Z%npm1rOhe{C1he=#V)GLrCkQ|14ARL> z-W~swbIw_a4yURm4=CLM)3O(XfTQ7@y_4jCRG?i}*(TMyPjFQ`5$oq0r2YO--A6LkEWYdKWF~?HgujdiVHN;W4@H z{P)dyM*cs)SfbJjBBrozj1TPPm4=P8^73YFY^dKvzHX{puxizUp_MC{W8ff~w|wI7 zf`fu(z(~KOPU!RkfP#ZPH=J9!^4tyG-Q3rn(D{YG?_QdlyOhNKp)MiaDwvO+4)GeH6j5=IQ(_T< zuBaCdK0?!fH3ihAg8Ao9@^g)$vX^+vb`|wPq^Hei8cy_sS3vDl%Rb0?fXmJ(6c1&6Wjox2Hf*ip-lII0Iiyi@DQp<$M zF800_cQ)9ad_Fdca`O9MPt$$l$oPY57hgf&c;^w3kkM1`P};dVBl9rTW6`zqdzkN< z%N*luJaGl+vmf#*h<(dZbM*z>PCijf@%sP>d{T4U$O(9E|4<@F>*TL-XE5cZ`SU}I zPAn^I-0{ewlI8O|?74~@V|Z%|DkTKGO)DF6mlrKxM(+~vtbXP}S!&6$8)hzjU}Kfh zmv5=p$d#_V>=|q8ONZ(_YPFq4m@&@45NyxC3+rK5_BSUlV-cVb$>A_`vKU_mSZ?=yORIZ$n6Pz(pR=upr7w#Cw8Ofa};(rtLQh{C~ zmY?*x$#5;~L>a~ZrfU4xDIxRKv==E$eMY;Wzt@{_{wV{hkQQc`&18*y-U_VoU12+L zu6$kt>XelgWIB{2N14>EBP-*|PjI`C;8tJaIwmfQwbOp4y$eoWQMGf+lBKbwhx_{v zFDqWQc=OK6D^4w}7;f<9v@D1e4z=WX>xawBXU8nI(!S!@tWujL)~Adh7kuY8GQ4-J zY~C>tjSlQ+UU|DO;~P8suU{D1>#3O=tsN@2TFZxOqjPIK^lpE3Z!o8`%?49A6vP6 zMU0uLOXuHRHdyWU*9}IuUYp%CA9IUBu2TQ9T&3Dj{%!d2-L0*=A4hG<-EB{Vy4F@# zujvj3yVq1#uk8xa!9#BxYG}ZJ4*i^b{rRDbZ?(tattg zRluh|GKLfp>d1AJb)3JOzQY`~-lrC7+bR2)cQ@$E-Uji1`R~ct%>PRn+Xor)z5fjv z>;L~JV^bkxRbN-emi}upb}{Jl#J?$HkNzLY*m;mYAN@~c>~sHjGIjxE?E7CXW8eQe zGM4C(pZ~ARSj+!c89N9W`||%p#_s>Wld;R;H$Ds7dz$S!rQ{nF8g)?tYr(T~j{acf z%2$rgo_+L{l`DU6bj~v+i}tj%Tr*r!GJH)-%brCg^nX6j{PoGcz9%W|^UqVdvweMM znZG=L&)a)TO7^~e&pp2-Uw;c32`rm#72d|y9EbZ&>?C5tMq$YXDVRym-FSxoJDDXt zO3m{&LQEcBRHHFOBuKVj0o{!FH>Fteqx$T3Y;=y|VPRd(7x2Sw>scp*q zVZ(y1L%>nLmJPf2O|9*dfp+czGK(DN2uppjaFBiBOCwuZ}GWuYP!4Nyl~1udGf&1Lq=W!3BNn78(stLxLUBDPjDqVZtgx7Dm@&C=+c z^c^f8VPfcaLh_#Cy_Vo^B&El*mZCtc6pueD4|;ddv*i}`xK3>r9-HCHR-W%Rdjxl+ zWoa$yO~kH({qSe(J+T!fXM_KWUB%%?^f7~19o^s7dE=_8`fZOcU2;DR@IbkbIVBI< z@1gqxt;;H^SF~rLvTar4Xse$tu@;!KgOO#&7S6wCbA9dR2bYwOjx38Z60MQ{x0;o$ znSs{j6}2PH-cb8ua&Bl|*@S@}peER}@2VtO-6XMo0G2L~-yKK5_`DVrx6dHp>GWb8 z(>+>xAke%hhN50sSxpN8Z#4(5Huy-t2oG?&e5S31mSUJz}+ioKxL+IgL{56dvU{Y&xw<&ht}#A=|EmbGMYNN5i?x1?UY% zDv<(vAz_#}z!ZYaXO=n%-<>js^)JDvqhzVS$*U{P4iza<%;pB=erm!NX$$%5%8PCH ziX;YITR@(k`c~fZNPaY&rBMh{moLZq>#<+8m~V_%S6N+%J5v;KF>gI%F zJ!Ju9)Zmi{Rn{DrJ>*cSeN~}Z4aMPbEH%Yot`TQf^-vSm{96Bx9Bq4fv?pdw%WVvq zq*8T?-KN*s{d!vMJVa^u8B8r744Gc)_^PW%?|B(w-ycpLjBpi#9(s@Ea@N+pt@f)eM0qdtDz2Ny## z@bjsEtW>0SuV7x)>i8+ttSu{O{wIIUtdc1oe_WLsqh9}wHpj#uiI4DS5B4F3xn=Qc zE35oM#KQV0z7QKB;3LTlRVw(XQX#^VBBT$IqTr+s3t~b9-MDWdnPvjIMTc8xzsn_- zpe`@L1jLiIxCqEKB|4dK5?puM>Gr>D$qvT)N^F^p!^L$gJYKmj)$9s7EMbqKs@fc} zbd*!esB;$gi4;c+Fw8)mr@$T2s5B~-tH51SEt43i5stoHSVJe)kdE7;S!a+<&fb5U$9$Fhv%k zq?&aBU3#70*HV(wZ#VtB_IK84??CQ*`X8D5&#k{fn9kc}A)SL9Y?`Wzu=NUh}A zDLdOT_Ddm!3*{Ac21G_C06O^OR68jcQc+z{;416M%kL?56&6%idTQpy%F9Uu7}Dyc zyet+`q-R+ynHELi`!)b}6|)V7ZZxzju-OV4vSQr^Lw{wsqsX?fI^UUNO-;4tIPKV|?n%0Z~$0;Q1J`O-^E&@f};j|PAIOJ2g0CtuA;ufR6aC_kC2PJYU01?Ao#~6`^hStJ;8bW z*2W_@oJh-su4bd;NMY=9E=OG;aRtb`DwumI6Fnb#9rxd2f?eRo#{jAkd@2$JDhSQ= zNM2ATlNGg8R<;!3n_%9qB|qrX8O84Pf8MeE{dF#hUf)MTEihgbOK=GD>9>+_o#}?dZBq@0nbQpiij*3q8!&%A=sN{B|0+YE^D7Mj`rS!G z;6CwX3;}je>OjL9%prz3aQ)p_?Dt<$=H36QGN<4Dca%BJ`geo$o0s$>F4DvQeF;5G z$u6OYi5~upj$zy^&>)lay8mC+r1Yt;(xfC;@iTe`=0NnQ78siHxI;mD+788<(9e10h@yjiHcz{C7fW%K9t&+6=GZLY5^EiQ^& zJUfbagr3X)gnkc0C-pu&!k;^K5B=V?&`G;^Z=s!7A9S$jjFiL*NNKT@@=2+vl;V#e zAZWn=b31d}05!~fV}R<1qwo*r0p^ZDY5{ZGAT><&4>I>5>=*wd_qQL4(hw8lKvXWy zu+yXAD1*#t(9bJF0VMw<42|Ek+RL3-GhRbv2l z3F+MMK`XOn_){Yti#F|TF6}Q)pZDNLhbgTml9AC+6*Jysnz?#kYt_<5pQFk}KUunA zNxNpn>75P5^io*7%U^lo@JLCZaVWCziK9F66lTThBeT7(ivFUErd>ltg`2*6y-lK& z@bl)M{Pni1C0FjQs{!PJ!Zy5G@od4j&^uam#)RU?0WHNQk&|piRA7eBg{GG<9F)`w zy0}ayRWt8~e0ifKLc#3UR7tz>}FMF>@ZmkfUfrtT8%P@#8rQ+f7m&t1=yD^~4A1(gkeW3yG z(Pf#Kx7io%9Dlh&=hskHlUFGgpOT1GUK3^KUWIp^p0EisMX5;ci1!gjsWy?;qUgWT#bhYvcVx~dB_gHQ$WFRKlsf)$xlW3guxtI|FG5|(Xud9BV&2tAb!=aU zGpM19aU*l7@8GV@YNr~7RMiIgMXOzdLJe**gBMSxt5U-(bawLQV+Y z@o@YdtZkwt?JV77@39;(C^m;Qc@w$C2l-hDtuZr8T`?1e;vZc*wlu5BCNiY=33Yu| z17Bcoioc-SAFgIrm|bwA@QyI>jt-%NT?filX9qk&5*vgRF?Q>tgm7e8Kv0AoV?QS^ zp^my@Y5t!0avJUAB@~61z_hkEv+rJpRfcP*!{jYw9TQjw_l~qwydz%?+ZhulnYUO7 z=iWLa2%kDgNM&n^FQ5mca#2SKsrWv2eJiSS@n-(5>&BL4HQV778PnlD;vM9?5MCxW zOcv>%9X~G^JDH8Aa`^NUq;;wUnkigeI+g3sf9S}Vez3H5c@ndazc}R_Slo%@hB-a~ z-ps}s$iy5CQ+YF)|EHXc1h0OW;8l%H!JUY=akeVx^5nB(@=fPo4OX-vaYn$qWpvq; zBXoX`-4|zSiuZ}$Zl-dv}$Z)I8dbL=ZBAmL?yNni%JKqs*R0oE|ezTtNVw_jV9xf998S5tg zM!M#bd-!Ejnofwz&1ec$?zqH+$l;)Q^RVAP7JUmoLKyQ2Im{`9r`VYIc#Re|2+&vQZ;WXb?ZWKAq1+J(up*&6FiGeVo_nHzlR4 z?}Gc6uQ9JFr{GI_hQB?nbGrCvle6+WHP#GGprb6q>2osC>+hS-{w}=HbbzvprAQu*yd{8{MSFD8}!I63Wrm0 zAkefR>Wuk~q@YA}0eY#Z6YZ{P-b^%~%$3-9Qbe>%&MLY7(n)>exwjJNjD06Rmw8;7 zt{?t|%I*AR-==2A`hlfO2i7~9H%V-XuJYr5^fwGdtGl|YqXP|o>^)h}YogoY>oH$$ zJ$!NsiR|THVm1=`D&sUt&Efo$(X75?C3uF>>_(BWXRj1AwlCp$Crg!t9^6 zo)?@h_0I2kE6I5cfNDMsc)iHvewW<9^adI&E&Oqbao*hmPO2J&^0@V~_Rn2(@v z=JZ0{^cH49-Pny9_Pk%bd1*#VQzYD|>xB9-88Z?`9&5*5V(n?jgJsXWE_q&)JNTuu zO5RZBkF1JnEL2QYP{QQhrG96$)J8%ja-yvC#`O4X5_|qF(5MhJ3OkbL5)XW5dHAvt z;1V=)eu)UUm@BAPCQqA>J8d)A(*{)vTJ?ZdMtnZ;w- z-t5!c7|?vJJ0y(5>UoX+oB*0M5pepVQo%;9TVi1Wn$oZ!E->NAz&>sth0|*X z-$O~}H+L!3%8^B4$#px5%P;Cveo_74wM%3*VZGICGxi!{)~)xY_rH17^rqz$@7{^O ziH>7kAs(rPjKc3oE@N-=P|%KG8>DA$B25Wp88b6n)^xpADiO0qCsETN(SSoAkF88B z3w|(Z9nHeZY<4(JztewUDF0lzEn-z@6eGhDalyhvvpWvIz8j5WI?m+}9XwvT;>c|N zk{{{Zq4dd_w;))Y8h>f)>nHm9PQ1RAzhvzA>?1449SEt9@oT{$#94EU|fsxM&iu$zpEo#TxE|=%Q`sDk>YX*l^xlv3SQOvo*PF#*v$EKGM3T#d8a~ zx6hQ-gisPY-Qe}>3e(peGsUiHn^HkzBgw!lSa4`In}bR5t|oOhvG#1>c|XW52$m4FE1y;RBtAORW}vb;O>5rLqbJeSyUu1{VzFFV7D1TMD( zcetp+OU^P1w|1Poos*(1fV4U`>Z0e5=U*Ajb0TR_aArmY>KBtWr0I%LynVL>X zMQ&FrUm_)oCN(p2xSUQlgEs|eova_{zoLOBm9iC7D;rWNiG=GW!%`sktDeVkE@%IU zB}Wq)2UZ##_E0b<+vl+d909apL&+t?IY>~vJijoXTtg*OAf7OycJm3ng3!Zk5-yM! zI`qkz>#ra2N>#OYkM!TLC{nie)Z%%&3O-4nwIiB)Mctue`LV6{OQd%*PP$y zxvFb^-S)F0}*E)K9A;-+kfqBg_|Ta2D3`mI$5|JT~=SXKI7EAU!=l zYHjZ=udG?~$}PQ#uXmO$yS}sY(DJgf<%c>uuU}S1Uzhwbd93q#d^-8m^`s}uR^BSX zlY;wz2O5E7hIl22!0E>I`v`9X?`qy5-U;3}cxQMokQ?FWpL+bkd+s=T(}6uZHm_f` zbiv%-8O^ojMS0m?hgqkP&?*>Zq%{^%@h~oo|Kj(_e~Z|H$#E|Cy)fw+Pty1Q>hF{1 zNzZo~O>Vcz=z1F8xLo+=HvGr!#t(}VzsX8`GrquOA`h8dClY_QB=NK-@e!YV#*Q?$ zKk*@7mH2LaR^l&ddEzXNP5fu#&p$o!u}~)b1}p^8nScP8OCp(wfpDt=z-<9nupB+8_H*`u#yR*8l(9pQ;kws)q%;BkXN<>@z zTXVX4>*eNDH+4$J=Cl~P?E}!M2z1K5m`-d8Ec#wuhEi(52fZhLzGL9Q8#m-s z$Q4p$W~_N=V@u!l!%<(`n&z5yi$JjbAef+Zbo5G&U=usPx4Xt&))ktik)>ybGt+bW zcg>`Jlb9o;;BQVM8v_uK?C0YXpYq>ChylUS+ywu@Js|N4l6MpOkS#8oyq75F_0Y-e z3YT7}mB}*PU0s7iy*rB@*{Vd%!a!SVdv?Q>Q2UV+_bHSeI$28RJZjhcWj#&fVg9EU z-Q1iKr@U~^)&^!DHwXUIIe7jT=TLLvUb$k1E=AfokG|p(Qy4$O(qZYuKlsmp4kVu| z^Ah`oyi~&2mnOwCWovF9Y`ALqEJu+{F45+IWRP9N9^IP3JW1fO9w}gE9M^> z%1z5Daknc|ut!&}qH4&T06uR?Cd(`AoZ8Su{u$J1uwhP05%xw%4iiz&Bv(GlW@9T* zDhY?KoTm1RrF6P&UVh)Aj?%m{N?n%Akeg++>Eu6?2&;|Oj_Tq?D6%#tli7VCvo|0n z7zD*D;$KJKEn3g+zmm(zPb9Q{S;8be>+7XK3aY*$zmd#g3I8yiFIoYAdop$uI+m^a zMdvf$Mz-k3`$a28f3})=6SuQ8<}Bn_W6o*Z-DJ8>K(GKrQy4*+5C#5C4u!y$O=fcP zt?l*ST$AQgFDopX%+1_46uF+{W|lY{B_uafFfnvT-VfxO^@_`-U1HAJpqm+Uh+xin z1bgOQ%bEymt~-mEvZsi+1ms>#s1;0$ zsmNLurp~5n$9*ghnlaY%7>nS;KohV|HZvNxX%!U8HSk#o0icT#e2HvZ*&p{Q%napk+=myA@K(AW9WZNKuglH9tPX zyKcd|ba)pkW8hr~WhY9-PHrT~8`-qp>-I7K*sRfuuT4Q|d1cBzp;5hA@DTGS%0!)0 zEBi+|6@~UO<{-vYU`#O^AI}D?fxD2YjTB9KP$FUuQX9u#ms9JRqoNfB zGDFJvr=t;_hE|MX2p%h$x%n+3r6IlbdIsJ;8XX?$0SO4nFQh#$$Z&!XUHXHT-C0BgP{g?RE9EP953phWx1jhq1b3nlcdVh z+Ios(`4}~?iZX{hR*6C?Pcc^C(q1_Ox2kW z71hGN_h!6zP5iwg_O1%i>LgzM=Et@_#<-d7R10%<{Uzo|_6OiNoIAA}qdu_xfyg@M zNvbtzjwBXB!mcIm2$Fcj<9HJPymc=oikWh2e*$awTsY?#m&}w2y@fYZyfw@LIy&(e zWG=_^Wrc{DCfu0R3NKPfJ$|jVq_3oTjiW~@7f4kGmo-?ZTORJO&1~&ND;=Z7SQBI4 z_Zr5#B|e^BfprKubbhkkz6{Jdg>}#7!`irf5w#8~N4kdJSwr1A$ zhq+wiSD0eDZ{ks$7lNaw8`$%5v7gD>@vOD;iX+nK&ul7kIEtDw{f!aF!bmtL8qEnu zm`}3m@+_9Tx~$CFu*DLt%?uP31%lBi=s?Y2qSR{>A6%f5FfI@EM7~kHLgsP$wTY)# z9%A#Bj0iF>#2yvWCpIyCo12+0Zoi#;>xAvG$x%?8RLk`cxI-zS4`rQ$*iE*U`qtLB&;) zN>|2qI>S*Z*{T?9$Zav1T3cE=ooKn7mu0Z|(0iuE+1WytL*{-;u!&wMim`D$EH6_i zxPnqED6%5BTeOdW#Uq!ZYluCCSeSv(Jzan5*Num7_1sxQn-$4B$Qh&tB$~YFM z5p$rlfh?c!a+E`?y@U|WI=9m8rIw?`ug_KITGX?^V{!YaC2655zq8u0xJNK1mE~oJ zJ7RW|>bB6Ws&ICwqsVSh-WKHc(ZQGm1rx)peWf6Fxi$#kqJn}=!G;QhjY}2yA49#( zSkat>aWcondgRS-8y?=N3@f%RSisVJ_xK;_A5T1dVZTs1g4OFp_RzxkpX?c0%?|d^ zLu9?@(RVmQRLaUqR`!xT#-eUH-u(94&BD1yn%{Y+8P9zxxQTjQRKU(r%Ic?tQLJZC ztbFSAysl!Wv$!iSSW*%c++>Tkg+gsn+x*gKw3Mt9LH2?*xN|c=RuKJuIo*1Z-lOU1 zi2T~#EghcqX$2jT!j6Kpb)Jqbf_E=~^mdKLo=I7=+ea#MnhKHY)Ra>>(w@!H`rUDc zPMP>t(t5GlsF4~yLDtLs_SU9%-fjYqDaOYkcaxvv=yE?x7v?t{UC{Gje4KBXcpl@) zu%;9V(i*_)WJs}x{R=vBOEZQX|1a(je|Lfq6sLr|2JdMVJVFOV?VN2*;=|+h`3l)< zYzTU)mC!S{o6xp9S12n1Ip=f4ji4AD*~4YbYU(GD=>$VDk-gCpcaGT5#O;p4g+V8I zgyKMyfoX`{ODYi|JQ?@?2pIRFw#b-3EY&MIot+AcGCjT3*_y6_mnXyTx*VMflLG&A zI=Ykwshn9oUzILT)ks3IkR*lXt8$96RVGEcdSJk5OjS!lMPdA!mPkWIL8(?@aUz@% zQu`j}Ci>HfpFm3lQ2i<8>4Ko&r4yiDgE5YZ5HB+(fl_o& z&}wVKo>E-aWR-ftHCk;hn)j^}vUbC&Ew4^tosOe|pcQo{MZD3)Xt37n1$U)07IR2&}v{hOnqR~a?)6XvIk z`qj|rFaI#cJZs3R$lTC7G}OBxvmy)OA&67$5!@mP2w!4*pW%BHCS8oG=0n(FsffxU z#wzw*@GFTyh^!#|meqNrwDmIaBcF8(2ludiu}NZJCNA+gGeJIIFStP>6aJR<#Z;`F zNN|!Ms;Y@#c}B1wD6ED%X^HGNe_V3*{=4pZWaz|=H^#qzc<97UHws@qe9D$xkZqee zXYw14Cwl~sV*bBLq6Go)e31;NLtqpK2`$F{@XOKAkEo9jSreo_dNs5fv=GiR1S&E& z&Rnoy=Eh7&vsN_c)Pf|(- zenCI=b5W4Rpe1Mh8R;T&Hi=75*bA00cBim_xbyf4;1bJ#Y9CSlEDS=ORH2i!t173W z*<7)ty~*q{8x%6NP~S1?hx&Nk7BU6PJu16kFhyyz+sn(-^86M$ZDy)6RW9)~qSl*_ z`CX$4l`my#lRVu>=G22ZeJaXo&1*2Q25K9+(Y>pd9W!AQLbgr!b8G%km4n z6bkedT2oZa2g1q%v&X6jGUU|eWgS<~gAAv8Fm_sV^6^ZW%V>Zg-WDp+U`9G}P8L(Lc0jn(_ zQZX~A$8WV}Wm)Z6S!93Nb$u=6Y4Zqq^*Sm_(i_#YXc;w=T8{vq@^AMBZ|u zhP#WIq(1l~f%zc7?~D-fXDYqT5Q~=NneBR&Oeu1D218jbQKz-2JCfgK7rrPKr^r*< zYwKI(O1Ug6+hH%ARg^cg0t}zn_s>9cJ$9bh$=Zu~kr-;Q3|anTjSd)~)M>0sYN-!5 z&r8p5%=Q-O*Z$mi#;udZsz;6}`Hly^Yj7<*gA6 zQWNYuMQ3oWNA{Rp(s68#q<#*3T(izxo<+#E*5fgU^@!iQ;qx@BIauLk-k}`6Y?F@p zCP>GPM}Gv`5!+c3ACK4<2^$j&(1VMxJTSD2BM=Ub3=At)NAQ zVxLVX;VZ@FRClI=j4lVv6;#Yp3cPOS1G0uH?EjUbN0A2;k0FLUC?nFKj02$9)Uhcp z5pKOvz)sO*LZI-54SG$AA_XCeskGiyD(J5*`7AXxDBq|((DfIC9$|nYafwck_mqQ< zGVpIQW;O+O;=9Y|rwhBp7)vIZNo!=Y&nyvn4S%qqJYCfO2Pj%LH@^zw$T1G7pUTG8 zYEjY>G>3TzxGauPCg8HS4zHBUg!6=wCaHSq;bSXPmBRUG>C-7x$`%Woe=U*RqEW8Z z{PIJ&^tePRx=Jc1`^x8)2&DAyMLv9IgmzAO+6(26n}6_2loBWIJ~*%u6;P+4FAvP2 zw#{Y!p+V4u!B0#tzX3rL8tMly!Y+hSWZE^td*?8_=5`wWHnrO3H^zf0D9^NCTxLGF z%*K3tl#w6DU=p|N)U=;J$9(3jn?4;TI(<33X#lhwz%{Ph$xLM&1^y5yi9}aNs-8H z)~Bgt$Q04o%x0%SDIwvvz)IyBc(3HVY!h4sT#bR9rvmGVOW(0R1r@|aD#a?bHnQ~S0_yj>U)WOO ztXWih``xu@K8aeDk?sv`8Moib{0GJB+SuVedKdG#P&z!voU2OFs^tPxusgqX%dAkr z;B~VK7xYx?ZTIe(b7VyceUOoR>jq+@JNIW)&WUWhlIR=M{zupm(!?LyCW>QyRq&C9#1tFJz{oe{i2 zNv@}gW?$8w;qAPtmw#R3mQ!;Ud}B*J|A~Fnzy1C%v-_tvwOyvGE#c!q z)C(;Z{RA@M!IsAzkO`Uyl2HJl0KDY^e?ja~y@mWzGVPcB+~X*g4DrE3+cmVCHu9nM_xLu@}FgOX{MVxLOh`Xvh@&kw`E2yh4of1qCy=%^iK_n&!4WXO~qj>22|< zRVsOF-}xs_Bs%NPy}j06w`xXlZ_p%=tF=;HwxO+2@ZVhf+_sy3x_i%0Z)|0|=T7ag z>jB1d@f9S)7o~C_uo*=UwiogR$7yJOFbr)J4xP zewG=#WBgASoo>3|4odLsVnpRVx1M>3nz{bD-Hjw7@3ZHZTJDzvxnka5d5r8nr91|0Kf%$Xyl`U?5n0oEl7fVW4-?^~o`Xw=D zBsNgvrN*39NNscZs616a3pCCew zk5;phm<2+Z-HHB;KH-Ues7y?e+Sdez!|PDxFLf1tpYzic}y{G}#MHbasW0 zB5iVHlOZ_$HHXr+SyWl$p8Mwhy-W7~=M$-=lTZi&Wm$n9+IoUF?RNfuyDm2Gd-o3PJ z_53E2w!Ez`r*+@bvRMs;Kd6Z-nZtrC@L)ROK@Idd3A$z1JTJk1U_{t3M1wR78naLr z6}^KHsL1yH0zi_8LM7N3G&w;yp60I`@1Wbp&v-jFbUF$`*~T=n8`a+R?G3_XcQCR$ z#&7T1yC5Qz%B92UQUNEKD8vANB-#KS(89Zi6Y2)!IEwO6ZG?nbBIA;FKuigt2k?R9 z5+B5M0esPf@aGN{IpwV4V^tu#6jlkK2WMOfh~iTJ%bq9F--PlnT8|$b%}IY4kyEyr z_|j##W|*2+YcP5X681iz!bue%j6~&`X{Pf2P2HQmyT7^Zx^wG`hk9GRZ)=UzGm-Vz z9PPi28GC-&l5bP0`nQ!4x(bI0MI?ArUr&F!gr zyN)U~s8)^t%2({uj+{fv?md*^+;XowMK2>NfhByhQlKZ^1%>8-59B}yGAf-4nTV9g zp>R5QJTL$ReJ|t#WTR2zagw4`QtY$=Hxclfq?D62;Mn$cJ~}vl<~f5-M*V{NkvjdG z2apqtpfYotfp)Zep_$5VfWNBjHFdfX~Lgg9>VNh6emqf_|U zOHCcKOo0+t&EmQY;j#0#_I6bn9Xd%)=jvK=Hh52iCXL9Q4)Zo~3NeKg(XzlKp}~Xr zfiLEMi0eyI-ia+##ns{wLwnY--7VR0ST8Zk&^8hlN4%VsSj#)a0D$Bg>#tetv*?b$38w! zC{w1;1#+!iG>+!zgeLb-d@Ozj--dbfpVp+HU>VE?u4lJFOgj3MHHgsnkw?#B+q;5a zP`xVt0pTC+Q$8B%p|BVF`&Akd0+Qu%+pH#o3Q3e8UziFLec{2n*|O+>rU+Q^Iuw6kg9if46Lp^@N~dFZ}h72)eo+Xy_D6yvZiL;%-6*L z&LZxS4SXkNsUdzK$XXx~*;YKwq=BIpQT@;vb1r-i-h0{~aHcs(ngT+6Z1hF7-Y?ud zCnV>vT%%A(_+_Z+K4i2j$6lgoSL50l#j}D*B9t$dr=0(RIoA*`<{nK8>(2kVYwu7* zqn;F~e3DZkB>sUG5o(!i{z1HNrI>BdimfADN26vFSQ47vVb|+C8TL#^ra4V#)7$(R zl1T$DsY(EBHj)H~mX&-h3}5uDKmR4;!y?XWOEmfEow9z1QO6vxc%6;x zP2I%FCb^qrlTF*3?A>IO%{sAn9h1;~=R4zY6J1?wQ@xnU~p8V00=BL*7?eF(}@HS;SY&`JnM*MARI`AwCP(JDJsK~Aeto)CQ zPe%WAV=JU}@{>>U$!~32(%m*vI&pGvdZ6#p_fMVr{saB}576IBeKaRzk3WI^>B4`N zM@mwe{*F`?xF}JHT@|OeOZsDBfhP~Goi;e~HMFcmw)hb9TQ2qD$>)Vny}3Xk=ifT} zjnj>7XTNsh*S}tJ$7sQGFaBCcpZPzFDdP=$Kec|{rw=qgQqaGn>F!6wHGTD_SNV_N z=h(mtLS;SlpEM5$$ekD*;+)jTuz_s~NlCgF=bw79A|rai;Pqen*3#pn1Ha(ey|d$5M9jZ|^ySQgX~0d=C40_wX# zPvqh4-2#cg4inQem~4QMs|uHwx?M%6J%kt!+CdE85bHURb3)>bGTQ0R`+;;77q-GKyOx8Fes~TF@v<3~SrUaF_ zqbIWMLeI+M%c_flbz@C?4hKWQ6y1uE^>sTQoftbjR$Ee3zoZ^zR$NZM6IB7BuwyS} zVlUaaK*XDb9fVSpAi%|8IrRzv1{vv~C81U>Z(|7}naw+!dy6!CMhWG=-aJub1MHQM z#h{tXlZqwL;v35MEcs3O8O5n4msUnzu6&TFe2?}6&t*sVDepud(vfW~8J0ZVDkN{y zDPyH<5aE8oL5DKJB(5Dh1-d#jV1OJhk84S`h#udYjx}_nESiR8F@vgVfqEK0uTVcXBQEG)(9asK zIub5Tgazd@QD)IL@yIE$DcGgX^5BtBMLLH+t-|e^>QlpOd6cSBT(nHc-@10O4Zd}5lZX?CMge0Bhb9hKn9~T=XA_J8 zw>f}AgODis(6I95I43b3Kq^v2*+>hKk5tiBw4`kGjzMqawnwgiZT-l(H5G5#EBZ=X zE}YymQkvwbDKZs6Z8jt;GE}Dx#>(xFZ+sy7r{DbbsgCfTmk%p`FkLXTx6@g*?XUj! zx2MCa+I%QYNC+dI;zM2qZMqW&@^0fUjWJmI@<&iv_lTec24@UnF}yXik09$0S+`UBPs zt<#iRU@h&;6>4U_BGf2WW|(Ha@2bnrsdMs|x347)e`QvJN|jhy#?}>VHRXQnTMJhf zDMrX1;2xYFDyFF!hOtDNs8mu6XB|(VbiBb}hOK8xAmf&bO5k|Yzr=+AF&F<`q135%zLX~8f* z$s)-HrXU`oe1sCRt}2Z>Q*_nIFWep)f9RXLyUrcj=b(XEQct@jM=e(gjX%H)*|>y%o3TA?qqeC+nds>u%jP^u%9KS>}9 zPqpcklk%9d2~)vM21`LfI08&p6%w`ra+Ak23qy)yO80tvZd_*A=$PSbBAdnIiELPN zpabmnI$l{lGtQq&O?qnM#c^-Z^1DVNoBJzM4QV>HA+g)L@!+|x-QRq8EVS>nlhM_t zL^8XNqRT`6j>)RV+sDc?eT8Xytx`8!hC+aCCtlk8EM2UWCYIa-nqd^_#JWm#e3{8s zfXrH$9-xU*dRaNGESitZZw~XwSmAR6fd%SEyapQPo>BZMKKKIA|=EM{&_IhY=N5`_0!@i>Nvuiw@iciIic2id z_Pttd)9p{L-g*6a+urqkI!%hcFh3`}{Pu?CO&uO1a@d*_UeijNJKz|q-$91fbKQ}S zT%K1~@)|`FkD9@4_!Ku5w<<9~5Kt0bL(r01En^cJjf_oTXVi1`ZeIa*hQa925!_HA zVGERub1uFB%Yq4wxmbkQUirX3!|naXGtY$f#qfl`0iG~?|B)?)1V3cdj~!gf;D-xe z7U73~2K?~D<7UI!=zC|rG8aO~C~6MO#~XB(9Mev-VGTPAh(FV!tQ4|}Jb&GQ+giTI z!T!cs(5fboNe3Gsc9VCISX7Rxai0(*BNm7UmE%^8)oK<%E6-DAq!{z5hjES;SLO3Ky2KzD!1wx$XgHLE*@(#OkgHJ6g=)%={|uS6ZASP z?A9PWol37WHAalw<3o93tS|`tw#-tDlPg^8Fu-NB>U!eop%1gqIH7_1Wp2y`TB&|31}yaJb0TFdjk|v16%^ z6jPYZ6-M%nI_zHvICOrLa1I=1Bxz-reUp-;bT*gmb(r1E?{(|=xz1Y!@!_{}ZX;yVgVQ;p8z{1wb!pE1?%c~Y>rS*a9b6tNU2&|p=g#G2 z%C~yj>xj3?&NcV5ty&G#QD|cur2CKU`m)Y!ayG_z1OnSjAjDg9d z>lX(`zI*qWrhlLqa`*0EQZ!g#Ql;yXi(G*^uW@>XPOB(jih?8OgQ*vKkFP9GOY5^F z>+NN20WT>H%G>FF6*v`i(w|_g>97@{btfX#J%ZB(CEU&vq=MG9>kxS^dp2zu9G9Du z;kLO&^&cnQU`T=z1GWyGV3><883P1UrGm_O^p`fk^*4og-hAn${s+XA2`>r1ql^kO z`m!|_6nbj9G!MO(JbZ%OLsqAllrXCz1{I((#1O31k+ zT{d$%K|>($1brBXoHPXd6=nXqK%E=Ka~;kEs3M?dw2X7%5h!9P?uc1MOn&S} zQuT;7mQ`&kSW-eZ*2KGaAN}Fu%QwIB=kt5s8dLC@rt>ooRqxv|>GuqbudCkt+L^xA z{ZE-Dcf$tjH5w{lgZ*gN-ZiiAnoob8Pyh0|q4l@f>>ntyP+3cOt)Mw*?Y{Kmi>JSJ zjxH1dIbu2Gud!$BK#h=jBaNL7fL&B}95==)44+MWT|1eL%)^GH1C$31wT!W063AkN zlts?#SoK@YqUgfO8!x@Ye?rC=Jhnyf1z}|7d0}KqcqP2)((;~Do4eD}-7{aCgD_B^ z{jf1MpwCt=mkUM8(oF_vM0{HU?RPEqI}ECo;(o^p)~g_Fv+QVWO-nNvTt-JCDe7YM zp98i8g8vYD!;B27bO<_@10W->dzlQ1`}kkpt94|&@bWLC-;TcbX7s)2w}dBjw$$y> z*LS4al$-dH3{!NPR~qcm?@UEQGyg6a_-{@{i?ZuoU-^ow9#afX?bFfADpUwzoZ6@H zmJ_Th+GCyklJ{?Nm5~baAJ<`%OS`I#p>yJ84_A`FH`G;><@+6g9aE66kGBc71Z_5P zap_)s6!_3(#JyH?MYTZd$fUh=4H2%)1VNVyqAdV32kHM| zS}fig!cA@rz0%_WRFGG|V0UATg%VqHY=`;qK^+fRmy8X7WUt<056p)aZpfgM>hi+f zF!R{tE`744Pu%W);c5(jdNul->Kx|7M|BzOs0g16uPyK=80TtKg;!zRm;$w$8xshB zhmxexG--f7c->A1d1Cd+NxDQWCwXJZl}#|2h@U~1U`_@cTgk70UC*jHD$j`Sf;3ZM z(b$a}ot{D?|4*iZ+)vH?%;Yv_7MS@re&n?8VSa+D3^RENW-b`5g574Cc_=+6F~Mb@ z`MomQZOg@lL%Kvo^f`8K895Zv!~82zU0ta}*RklRXhEnt&o?o1&&U};do(dcg4v&9 zm*(9pF8iM8$vIa^w3U7>c7Y(rJM@L$Kp+2q&69aD)!^`AHQ4=PkliFIElJ(ZT_ z=KIK%kjQew1i2R?2`*>4R+*rcc?2GaBr4XzDJHOV4eg063k(zuWW-5GP(ih4gd?c- zbZ|dTYh;4K+5M2OWg0zwH{>9tjTw&^5pv+p3FZb3c|I47NeAOlA?J*d@grhVBg6=% zAmVyq6(T_cxvQb+X&$)x``4?JVE2x^MEimb`l9=I;I|WHmzpK zVxs@6YrNsu8^?CPajv(!Ww}SWKlu0E<|C;6Q`i+&w>cyN?t?E;=QWL+Z7 z$dQxbwRzDsE6q~^U?}VyEdBf`nm0dFiu{?gk*78z!$qie_mvHkcb6q-J^bM4$#C($ zj*AbwnpUfBoQS%*$G~Jew(G{!U{A{mk77S&#?ln}=Id)OE+?Y9aP$9QZhX?*T#gu^ zvZMb>p3M=oc-f_cwhg!~luD+jVtQzz)CvKRJ5!HnDh5*6K@jn(-g*i!v&|xWEGGyBX|eIx7l}qv5@Nv$UQE&S=JjNc`O+d zyAIj;z}(FOPS{u(|J}zrnORO+=0|euW`Bzw`q&)1IggRvndESLeID0`udJwZhJ!EfDIN3K z>(_Vq1`3SobX`)h!x^+EDUL^UNg3H073(gJt+;1R8LFxo8vWJYw6@c49@+in^L?o) zgY~zKlo^b@*5s7*f(9S$Z{*Q>NAZ1Wf8Q2KqKx-hcC|uuXST`WZsK(L%vpW|wr=TOQP!z${H4KtxPMjii8pbaFAg?T@h^SQJkZJi zD?83p>^Nh*!JB_l{6uvH*lZiOI-;v|0l_WBo|LT}98yrXIXGz~$PYNU1kI43qeFbF z&mrERl{GgO71(VqCvgcG#2fRHNclR*n+8WMbCWP2m>AW}lovf|FDufm$@N3a{lNxr zT6p}n1GkNbn+|<;>+Y8hHoW=@0(tVhOO7vhjxJyBttsl?5U$xeRO0H`-r2adC;xPM zsyeCCbv2RhmHQuBz467vEuD9~xbFFXYsjo>>MupMk33bPK0)y}gGVQO9p=W> z$A?=FPlOAW?k9a`3Y?~V><2Hm@f8o`7rO??g(6BX2qUr1mvjb@N=^jAum{){Q7CYY zQX|Y7?GtwO%^qmcCiik)uiNN#F%TIBt}MAkg_XHW=;|ZSi4>$Vb*=HSjZ5wrF4(kb zE9X*XR z6h=n(9CSIIQiE6$7q>K$0MY=wp$ze}VSq-`Nx4x7crF4XOAwk!C|mJl1Za`uGwP5( zfw5`D*IHaw7rxJ&=TKw4VX=cW7ZbyPz1XcyFioK_Md{s|uJ7wTwK`n4>B8gB4e`F^ z4^(Ztao@0`egx`rkNe=j>Y^2QjZIv+cyL{RR`gfOw+Fgrj^^(?|MZ%g<#jo1eV|YM z9`<@6cT_x|iFruJN={J5@yP>;SbPDAOP3BFA`*{c6)go5uxvw%BV=?Ju+KE0tzpMY zEuo1o(hyr4D2l=Doy+rq3XaXpm_44Df-aq7z*J1Msm*+((3F|NNAx+iC!^;xbJDVs z`3sL*9ZAt^DOuTN*L*|AMv8kO&Me7E`JSbt!b+WiA2k@Gdz{9k98)wY#l$~uPLA4@ zHA8o;t`KpTO;m?ZfAc-mW_T8C(Y+CUS*edQQSe*>d_~gLOl!|}BgPGnk<8@5%~Fi% zS?p7$rr6>hW2y-~3;mxC`S`0rSH9cBXfk0i>d0|Jj`3_E2a&cKfN{jyQnSOYpjcK7 z%OcEsHTQloQ)hFRy4n+Mg)V<@b12R6WzU!R8cRb}T}jy09;q~6M-rMO?Z2rqt&i|$ z-LEUXEj`)(3|+H6Jx!PDZ7yBbzO`-oYE5~E$C?u8s^NbX@EX0QnG1TW;?ecQ14C>c zHq-M;73W4aq4g0RJpYPBNb_nV%Fkb=vqh19fsj zOzEs+UwB}Te@i?Hsdkvw`2kL$QKy0)tAINQZ>i?ICFv<1GV<7Zi*OS&*&*^Y8n%@% zRibzhzxX3sW8x%X66CNdz{?5Iy7jlq?FrEGd5ePH3SWi8?J@copfxLAm~j9bNS^B1 zl}(WCK3Qs2B*< z4pjM!c7uOws5QTLYeU0|=3=iaKkUsecU!EP7E5Ee!QZv9t{y6*Cofo=pHr1@vpemX zbeu4rg6JjTbyYof(yv5)S5KfdK2RZ|LQDH7{*43$u?|T8EChp6*ulY|goxe-4>qqD zh6rI7qzL)9C&2h*MC~pOSy82Us$$MloEE0DHevCnVXwv>j+8C>92ND0P6q&yDDoH% z_U`Oc*kby!61Uq0+X}!7`Ih8m5ShVZelKQmi9RQpk1Dw>fu4sdgxvH{ZUyS99!fPo z?N^!&%lN$LPwR`b{8^@ietW~Z4qtbHUQ|^h;e@1QXVaPnVVlv^Zsw~}kh$yl%oCCN zl(dw8sozZsYKJu`WrS2tOmY6rKMG&KISz8al;++5KXn3vWb$Fgv$;2b=`s6;H1`1x zwgs=%VB%tg1`>O!VN3*8fMB=;T=f(%AkKRUriwx=;FuGioYeqt^&sq-`Om1(7P0@V z;wd51xOL)w3iF-8bAE50GbcOCo?*2BNK`AiARkO*G#gY&!Hr3wsI=`ZPe>Q^|&K7ygT}n`VzZ8+pN{=$_r1V-gQiz>Yv}f zOK<3a?msg2NqNEz!}(HdmI=DiQ#i*i?vyysx(sN=dKFX$QY`RFDZj!DlR}tAGb~BUk2gEj^ zJaY^wj!lS$zmbq>KlO#^%15j=HJ_r@tC9`>pf89l4Hvd~^yIhkIaM^Y<&h zXw}c0KxN`!P~hB+#r7076WOp3vB&D5_;e#LqLo9PNd=)pmJFlq;9uN&nTRMb0?Hz7o{(#W#5FOxR`T6HnEAQz@5#FFeJ}d=?+Jk!RdUjMe-Qfk z%nLonyyWP=9*KV8d{?q7m2g9zYl%LnxD&shPZ+cfHxk^HP)yE_3GL|;uYE8e{j9XIAwdE3|3w(sio+j4D4LEqYX;L6IOvumqW z{P|QbX~sO~j6R^qMBhW)|C#F!$3!HXAfH1B1{VXj#aw(2;lGTA=1wmZ9|&eX@Yusw?zv<4z9%#IBIJd6Tk)LLuaBwuOH|eugo#>whJ`=TI4(RVftk|JD$BTvrD|H&JI?<71aa4Bt#?~e4v-zDo)++(QYov$v0$cbtj#3_^ z_mS%;?Ig%bxffDp(O9kyhB1DeSg!b%Vl0=(4bkdzBbNZs{InEAK680|-fS!vXp5qM zFBZxLRa7rfz6FZo;{Uw-(cO`>4B=@-(UN@~&1>35uI4rR+P%+i3)olRv$6;g*l7`8jn~+I?wcpKyn3eh^UH}}1A8A@w&}6$4Vuk@H8fOd z-@SF)?ySn8mJ5$2&3snvZ{NW07XmHgYc~~#`gGc0n>nqqvS2JHaA8H)!QsLzdy^v} zwQ->9;7Fmtm7kN7qE5;v8)@EOJlg2-G>#SvJF-LF!HFF^CW76e>=|=cy}iV3`PXcZ zRi{yFEOlPQYWy*JNl_rndy#Y$<1|2O#yEwdFqDu75E=|79}1PnBq1+jNI3BDaK~^a zf$UL6c@+M`oDzL?`xBeWB8NY}Z~xP^enXbgUo}+MwtFDo*|xpsUiM7!OG_ptwn-XQ{V>IK_%JW;5!KnI+S*A0*lqecR>+VC^VyqfPnFzl!+e-0o<$- z=6lQMU>+_09Q19(SwJC25cMs76VJ~65VmZ3b5nU)XM0nBbAL@$Sz~!4qUC%}9TX5* z4VEEE_!q5`khO?z8EiT|IJ|5Zds*~PA+BGxHOc_|u#j6l?~$+yk5K$MBW?zvLq+-Y6d2 zT3x?)StxS*vzs?RdwWA@d{2G#=D}iH_MMhgt=^d5xw@hRsfZ1rHs)^6v^`QhxTU&m zMXN8rYi(ua+U|ViTfMi9x8^vyH=J3{_()qGT(Rub+RohE&XtFU!W%=*^z0sg<=Z0)LC8rESY2~&=FA6`y zIn9O_`9dTW@dlhT6B=bk8X`Yr)dV0Hd`$3!!XM90jO4!}o>litW=w!x`T$2Cj#20| zq_wk?%(z$|@&!0uaB^~-CoiWUw}4o7KDQXhGxs2o@TPMV3d8szxHNWf_!dPzPRf9E zQtlZ~FlhDJ86kgR5x+U^U;z5RBbY~Lq02*OVWq*DX3?g4mbPqrOtt*|s4uTd-u{FO zO{s2!PErngpagjtBVFnK`Xl9R|d zOp*1^wqyEv%m=ujEusfQ6&zPvUC|V3LJ!JIihTY&@LP-V_oa-8 z&yg{NEu)IcRzk?dNvk07vLe#HCrGmf@!~JEW-z>5F+g+ISyovKp`v)#y`ys(f#)-? zlRR-&bz%C=o5~PtQCdmN-POVX@SHZ**$rDh3C9IjzU*JC$D3=aC$0dkqm)gfQ z0wh*k6e=&OEv_Y|u@~wcI9@a@%x;c{DcK^%NB{fn3^?nWxY*xWr6KVMX{<{kB8IFnvjORe1bNU9NxpqlD} ze2+x|Kd9_+bK-t$Xiv}~0|vrUaWFgDp$QU-pyE+Gj>uo+Mqkh<5z~tLG}M$wQ=ac6 z4y3Cx?Dz4M(5AJrwYbn1@`v)Awsf<}0HB%k@?I1e$agIC!Nr_1(jL^%*_y1jdwr~ci%tP|2(6MzuM?NBc0@V z^<#h)0PsHQ83nrQ8nxoGvjzDgXa#uuy!4KQ#8J2e zAa`IH3PcnD3s!O(CAURB)E%?@Q08zeUC^A@C=sbhuuS|@q{$G#hKB%Rc6YY5MCx6I zZbtzNh{dKQuM`E>KsAm+eMj`w%j>2Re z5kb2PYL>P}ysrAnicn=vKx;9i`Jhdg_myV^yH>4T)fFsWao5PY$E$rw87ZD{PkFGT zEHl`(a_!2lARlVnITF(7b4~Ulmr>-1nhQHhgVkPJW?ohcc*H=Q3u~Q$us18$U%$Mu zdh1|uL%7jm$wXDjiX3mbC(GfhB@7pnQG@mP4fGc`x8ZtP9PW|}cvDSS6=W-H3DT+S zXOS1Sy}dEyWs#;b_JWp#y_nr@hda*VK*964`BcV2mK=)CWZld^E!;|OGF>ocK4=aDB z)G+z|CozdYYAUeef_x6bCI`SB^C{si-qgeWl21kQ=4Tp!jx?$MIm-GMU2B z7U_3?@b>U9wn>N4P(HG|{$StJO_v#^TT-xMzqOAOL^<=OFZ?r@(+>&$=)YSEEY<=G4>GcF^M2SRt5pAmb6o=cG!Z9VoduYb zbOT!OY`g&%1Iq)&h*KRbIzl!wuz|?wPvs27R%(2wnuEqAQ8389j<~QD2-l}fO0i}N zG{feQzX|GlVjf8JUZ0a8ukjZa7%U6d-N=|443rJ=n_OdMP22nOi-!+%bQ~Bi8eQti zPfE5xB=i=K92@fS{q5~TgKh1DiXYo-fu606t-JdRg2PApKZtDEG)pK}erIT8Wa$zZ zH28;y&crFh;Khcxx=6JFlE4k$qR@sV7RZbdK0?FWYp|n(xg^YHNCqfou$Y3q- zvgpvb;3Han6+^W7JmsOQI`Ot=n(8dQ= zj^5WaW%8M#$8^cg%x!f>pMn2&@)X8baPtoeKlJG^w<(fX0)vBKWLkOBp@~7R-hp@s z2n=L{!giJ&0w5|;QZt4jJLa?kKc6`&nKw#mgLU;5x;zD<-+aB(!ebNv!~na-M8+&o@YK3tufQxa*8l;j+g^yy`aUmg$C zbcRcs*Y)+CT3uoBhaHUu2-U1mPhnwGiN_m^jMf#&YBa{bDtZX{#cm+~$FlC1>=<(n z1b%`@)kW+Kom7;@#PTvcsf7;m;w{u_mLsh}O{#$r(FWo_spQ`TWFd!ve2x ztm2nn2yD&82&=?hub?SD6)-6TYp*s}Nu;q)x0 z34AT|X&w5MM`t3LNBAydfTq9dh21PfgdkSHKZxfCYcBFsevpz!Uix@?OkF-M=NH>R2#4J+$v$7}4)x}_z% z^j4%BMZ!{*-FP9o_Q}@`y3DrW@{;l@{s&sUy4K`X3u=YeFW@Du(-$-k42dC9`o!ZBjrahGlO&SE}HIGHVPES0CYsY0IPwes~7z_vihes z3qSkxdr$S3O`IGECa0!OZpvSIY4cO}t$AWkr0=Q!8r%BNs)GFXiPGjyec$=N*}d%X zQ|lca<|0kmjiWs$)P{!7tvw{`hD~>KzOeCw!rq0u!ej#x(Rl9oIUDG+UW%uIB@vWYI0`m@+ zzVdVETPCnS?e%PXBIRbkW&h9*>`bQMSgc4ZO+XvL23G^oqNRjrs-))q0#j{fMlrM`-6guLHO=7*k ziW6e8yb8gP6Li^FxX%V+G4pud4JG11glA7c9j+VayWs zNbcy8W5fA+sg7B!UyrkSDnY*-A7h?KO_)=YYmtdcoKvOis6Dbt?m*n?QNL7I78LJN zvbB3l9mXB##ees5$&tj`(tMvYU9VIEYhYjuc(IabZpi<~6sL9dX??C^`mg8iQcS(_RdZfu zYHDVl+3d9&40f-1-fMpA&-D7Yt>*W?af`9bX9&g4Ud1TY*CIxoA;*WD6*@2R+XIIT zgC!#mn`i!^Q@75Rt5n6+u`I;4iPo~6Q?l&NftG5OP#h@iuE^rQF?$Seb+Y32(vs0L z6UC-w=}K#8ys^1?J$nvr-FMaH*@GMXFD#Kb7WGdtmMS)u`s%E?vV^X>`RhP5Se)Cr z=NdwWhQrP?J2dm>|Jf&Vg3j0>?<=#4hdf%Vyfb#brOmWp1nku7^>a@>oiMpYDGq7?Z10Jn~0#j4@%#t;Su zS@GZAaI?b0_z_~};|=(iF%fcdzI2JcI$r{P?72{fMbQ$ybDqqZFN0{!c`kr^`Z8>) zddQf9#cJM)Nw#Poi&?N`3ZCprh`Yd*TjNAY+01(l#f)Z`l2}o6qILfX*^#hJ`0M0Z z@e^MyceTWGB-))!%M%%p@%OphZ%qpNy$to0Q0jl(=Em{#3B26KT$M|B*erdCQQGdLqfwM;A%FgD5;5A z)Iz^&%hH;By-QYA*KF(!Ha+l%7uT7(IXPa)f4iu^wLbgsXSS8t zf^~{_)6!R?9E+Js1JnUBR`%~d;P5+4`l^9}%5_sC!r2{0S849|l{uv?0bjM-fc=8H zr4+{nY?5L)pA})mBqOg9vh1*}R7ByVmx%2WUjmb)n3oJ#u3}mgBKk8oC+d4L50i)_ zfw3v_l?B4u7c`1E=6y~%lPKy-a)Ocv3SLheNUvhxm(|SNPU(EQ7PGm~?Zhy}c@W|z z#LXb~OAh5+d#)lW!Lv15OWuyXVl1coNdIaXHf)a!xTkgSXYjvms*s>UDaKWrpR181 z@cWUBz>Itaw4n%|&5*{=_6D1lxbRIjSBp0QBTquzC_*YSJ9Ze0u^>=tgt?mc`6BV1 z;|l^j^BiJ;XPkeSNoR@+o(+0sLH*O;JndKw$aQ+Sk9y_L3M6{4B${za;L1WPp$; zz>>--$xoRX!E4p*YZ>AGkf;gDbt5L+BY@KR5iPNAG6}Q(uxJUGq2xYhM_Alv1{tyj z(L#c(3Cd&Gp2*o@q0|zkhiQ+DOg7K;79TDl#trY8AD?u~hzW`!o*SbyH(&zuiyG-T ztJ^WQ0Jk-gDAvK44bI7_$@n0sW-1l^`hO-XTudMmpq0JUdFbK}y=yfmw>wCSrm5PsU)aPaD$EuU(5 zMWimsA*bcu&3=V1e*TM`M#D0$fKn<%M=e`j8$Aa*B9xoLeO+WD!};yr=U

      _5^5%7=ibfV^8(M#9;^Yx75^KI3 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 z zJhXr}9grRx?Z76;FC61L{=xnklE@)LLjjL<=wBih4->jS#G(?@)6?_Q^N7jiwMBx> z90QeI_FUWT|1+))ak!4Pt?%ZwS@D^I&rW9>v2Tx?`$m?RdI{x#6!m1#53`u)rtIJf zY#4>6HHcxpQ+dbXp~H~$A$ox=eYgj&CEDA@whr{SO|?%E%Y`VykM7d!6`r`?$@}sK z6L&(YB`lDp;0rJvnv0M}UjNC#J$*b<$I1ALdBylBhjFw@O>1w{=CrwO({@Coj41Hj z>51pr|9m{Br`y|z!{@e-k3xiN?HUo(z;pc;#?y)$6})hUdEt`m3$R)2^@Mp#_C{>s zMZjc34cjaX9ZKX9Svr)ie^7*tk=9^dAZ}|0-5HsXO2=F1H4o#RV7+xp+4i*{!}%_~ zQ7frJhRQ&HOLGGhj6zs8k=`RhE!&N!D^8<{ZAXZ7LOeP93te_Dw%WZ`b3%@Nf9%%f(Jf=kOEX?jq(u zhI!G47#KToII@VsWUEm?xT!i#C5llE8P$3li}f5q0pDI5Pr%OH1~Bm}XY< z0+(e9F|h#axkjKJV!-@wz}^+ZH+`dskIq1ola(OK9*07Db9D4>L~A=0`3-&q?g;OL zmZqPntD_$oiaDQ%QAi7tq(<};rzS0!q&R^#kC9N))QbU=jCHYrsCcaO!wb!Z(TC8Q!8AqNWwg2`Y@AYFno ztV48)5bZNO(qf*ayKcYY_S1_;4%|Jn9f#?sCF#U9)``0RFSfpI$486gH-5h5-n|bz zvG$Cj{DJLU6``jMbv%TKLF_M%H8vfAag@$x5J-}$(a!?$kA=vL3kJ)1QxPQyk2FX8 zI!^a1Ya-|ISEP7!!ax5Rt!uK69vtphl>C2dBL7VMG%q-32jG3jj z_e>7=Tjez zDRUftPw}fq3@e7Yd~_;k&Op`Z$@Dk(d*OA4X~2FA{4<4k15g@WtcU`;wVeVjqn8zG z$buUpd6wVXLsP*5wxxGVM_Z=5x!X2j0Y#yjdz*06LH#bzh>q~)-iFX~P)02il&Ip~ zgL&trS^16Bni*~$w#^xH%xRaWg7*8Q7l08gZ(>gKL7RvA5=y=g4Ro~GW(d;^`u;xV zwZDj3r2@sM?Wxa^2R0eWj8dfDvk>jjo9O%SjX8LTBV#cK&c`y-5WT?kxnL!e$r6`` za?Ux?cWtX{by0(U*%!UmhPc^ZVr`IU?zM?v>Kta2pe5XgLqr= zX@3UL@iy0BU#zEuWY|W7XwnHw9?l=~i(x>5V;x*?ZZZ-8ob8oQN^keOBf=6?s2` zDc-C_jM>QW--^o-?$-;g&Xq%f!~(|`uzm?4N_Or2jS8{L7S!Aa=R z(!JB7xE|@&Pwmow{V26`Fhrgk_g|#E@mBZ2|n$vnP+@9U@vlc~# zqDONfhCXNSl_u={PHi#&Ou1WUmlFBr!ukD|;Jsw)veu=3nR)vP?XYb&Fm=dwex)!@ zS2(m9xxhI-a(K^f_gRjLdK!GLLWQomzao7eGELJaPFU_bD~-r+q>l4jb*H6zvm^mf(y-+I|}aU1tIW#8SNE zpMBr1zKSSl=aUE*9{`Q&aR1*cd{g*mN~&VsTauoKEJO@7Dyk!-A8r6PAmV*VNq#=` zLE+3enbHmLj6sX;D6Seg#Eno`x2l7_b1(EAtjh*>Kf{Gnnj}uGfJJW&JcT{(OnV}eqUQaVU)MVCmt z3WxmnW_zE@BE#&dmm>aueQF~((9LBTVeS?j^#X9vOOt4kmLAai;+0b`%|>uNr7A{^ zpR8V*REb3N7N;OEif)oair(r?G`v8bqv)TRGZM%d9zu@uLJ0+Xzs$6ZYtY#*lhzN% zR3h!@l_~$7)hn|n+v7ix?d|k#k_mc&YR(Rsc&D#_6FoB5&?B=9TIID`0d~e;9t+^| z#Il9uB29}pje;47LZz_aB(_O+*FLxHVAt! zOVcx-dojqgE^dPvmK*(V9m!t%T=pUAeyMa~Jw;J!fVuW1IY42KOKaa=+af=g4cApF z|Ek>dR3Z9beoDTEbvtoJ_>9_kd7tzg&JR_Vhfjvu_~f#wELSGcF2Wom>Q+8|RkLV^|)zA-joSjcZ$r z3-y>wj+r_oU|Q0^jJuT4rnS^96F#v1Gqno!lt_R50N|zY&LnxZQ(nPO^V)Vi%h`F4 zp25(QQ4=JvN?95ch}#1{QEeZnJ2lk`dLQ@ocA^JaV?*_5&1hL^VFBI>RZ3MXRHy6X zVlJU8+vi&5xsXjkRG~;RF#)w0G$v4F^uVmPfCd>TXu~k|-j{ZmyBQ|l5oGbBh_bMV zC=;M@Qcci=duvN3U0+w-Uej((5pm)jyex-CEAk$(1Hc5Pgg7YuL+c(6kAJcbJiDxv(>tYAhkc4{Bk(vgU}Ib0FTKN`LFx=0K#wGShT`Pfp<2OGxnn70A*tYX+S}bqHFL}Z;oA2~ zH~kPDLT3*i|7OQckLVCF3)0w4?p5Tj&W^TP+tCQQ`1WH?_!4>LS9GsD&9hyb_VUV$ zsqBYbk+)569qH-Hq@8Ec;xUpXs4?V_C75qPK5Lr~oq*7})9@;rQy0erkfA zz;4E7sbcV8s3m7k(9kyLedh%!g|bOm!GVzf1e}3^o8e6c4zO$J2t;kft=3u$HR}Q+ z50mC}*~-EkMW?uT#EEMzeddvWE}|r8KbStk6CG4<-iSUVxeWTCv|Uq8lf`6?IrX0C zwsViD5}J!-OCW4Um542{3&-XRO(HBu?kSx6o-2b9T|#rrXj5i%34}17P39G1pNZya zZ(}jsS<`7Pgv2oIbM~8F@(cE#U8taSR`?fN%*)EnO!K(C`~k$M2Ldwzs4q?CNO7(C z14rDSQ1($hVb$N;iPn;g*-*`pg_*e67&lMZivHBJe%wJ#jgG7cF_U$QjT@Q>(AvDg zSw@_O<7{!H#tJaFTth6Kd8W)r4OBqY17O6Is1srej%L0!rctk#>X&x3XSO$QcOSAs zyPW@e&fG8X`fl6t35uX>rcf?2ZBel@6+U!T-NyNxPE7%%7e2TUMa<}*c#$52pF_Bp zIQ{l(Q?MP`Qec2lw?lWqdj|hZNtE$SnoAN?ht(o1Q?{-d&;$!HW|mML5?R|w41+L6TVNWg;nV>&sMx5l=0n287U5kl{zq2%tzWBy_dx?7#*Mb`B;J zo#QB{z&Y>UFc%mme5V#nGt<@yv!kP9uw$S}2PtYB3Yctzv*Ed@+yguTvmdv$fD1bi zjD9yG6$ZIzPPoXT*I~kgialbO!XImcxr<>!uQu?+!KBTB|I7)FoUsg#`+^zp#M|5k zZ=doi{H;T4HQ;y6lzm3=JuYq7r;ETu_#71oP4gaONr5vA;?hwv(*)K?oc zd?8El4f|gPylSaVtB!-eboQVman2HKO|>>sf}hRO>+lg-Hg{A_t;D0^=(ntgL5S^7!k|4=>?FIaoNtWt@^6KgAL$z)tP zTvoF7&3JMHJSZ7lQOcDC#sfk7|B-lrzDy6XSNLa&YyjZ?Ge*@HwOda7}{ zAfHOk8v=$I;FzMYIRlR1Asd`s(yu{vyrpzFLagLM0tXQ+Jysp(%Kt-g7V*y%@h6={ z>AQf17f1n)93Jbiu87L52sx(;L571kS&s6G^~w6qR56wC0B+v!78oA*+kz)b9LYWh zyz=t$`trIa1}AEe2zY!3ZTKxpKLUQx(rY2|1x#fQsKRxMDwH~gsw(ZrDEP5)2pJ?d zcEQV@)(pNZl~7eS=7Wt5E2NJM&tYdO;nV$vf-`M->dLpCU;E|LRdrE$p}000ttpo0 z!wr=mRmRr-R2lOft1MmntMo)&-9%dHN?$K@@f;~2Etyn9O?CNDatKrCzEa*-QH$1suarnX22U3XRX0%%4(V?~ zttc@Y=crIZNh$vU0Sisgg~i|eRIip^LLMJ^k2hassObq-L`_d0?gT2pY|)3K^=QTv zX?`kFKR8J)!M|jr)uSK9>8RG~#Q=##LK|N5t`UeH zN|v`aH`JGRCOe5TT!I;Ab`8E|@Vy(CJJ;w)zu%1uRq(5aJKUH)9OQbc0mmWU@d>IY znGv{(!IV3Tuud9{p6dLAfqB|K4)?1*Ob@mbqp+nFU0uoYu7NIkR9nl4U>R7$S3TEo zcCGKXYz^Jr$@1>O?m;T1+t^UvmF%K3&1=X)^Ys7FR{vD+#9ho2@6loda#-+0#NdfO z;d|5;v~ra@9`d3ae@N>GiwiE5A3p^SO}F0U#aZR{+;K1x2*lkZ*D%m zo}G8iyPfyL#xlgXWrYl(+)7i1a6X1jhU{ip1Rswfi|Edxnh!ANLXbNyu4Fk%lj7A< zo=MUL7NQM+3I%%no!4D&L@&`@PreZ{$g>t|zw5u5bJvF&U3dLtUA^tDM`vTnf1A*! z@XwUg!1~mJ^erHQbwDX&OApm|M5*Wfx?>50_CpDQr>dw(mWwKjD#}U_ZdX{AC<_U_ zO2B13$Od;w!hVy@o2-Kl9~eW|joub?Sxz-J)Nv?Z4s4d+HrV^5A7EclEzIy8cq1&! z4Rz(EIMYO4A6)8mb|o|oFrzNxqrFH4jPA6IFRGLI-*NrtQIw$hjX z+Bf*p{}v7TI$!>8>f;NI^)J2c-8+kF3jBAz8+dusW6_{T61TXOr)E&wgC6yDwbeQF zfX;K9(0MF+KM^A$deP}WBq*{qn)F$jn-5q zOH1HpX;<3GLIhd}+*zlz;l2a7|Dgx&gHi-(E@}iGWP$W?3u#1Ig!e}w&?g|)8UL7p z|CY^tMkb(1{@7YW%lH_rV&{(e*=cQTWqieJExIj;*Ag6Y?t{GNa!GFTSj%jYTo5a` zS&D^XD7K_;30(UsT>IwgqEWpPgtbnT`=HH<>x&aBZmsTUm!-bm_N^UT zDf+6SyaaCvsZDN+s3jeZD77NTeH5)j;W#4*VWo-%Fi!M9Qgaw-B7=grBSVx+S*Q3C zRW+f~)?Is7N5`())iv|T|NZf6PRtyh?nxF`g&X!gf9L-DFYnF{^eoR#)!p;)oBFD{ zCK8paOg^xu=Re<$ zJI+7r*4Ft~ig9Mjw30D75?YkQmJIVl*{7^sjZ)qs(eNqeMx^|^cp?(XIW{htApH5$ z4mc{(`!5=hHhT#$JR}Xe(b7@bzjtMM0e&5?LlUP$B4nn2Dd3VbO6ld2^nzBjXGRG{ zOrdY2T#U!%Xe0`cNhkv8iAcTNh2j}z9%dJ@H0|O(_gJ3RvU4X3()~O4?O0lzpYXgC zNRTpLufGL%+LdCB_yz7XWPQLscZAot^4q$`UHTe#?cc;2S=N0iaHH$&R)F`nYZW`? zg6MT}yx{T~C1&lXiUUAN=sTr&L8Ks#;sLQps33L{8%z6YF)*6F#iIqrMFP1UvF~q@ z5S4}I9YPh*ciCY^Vxd#745+r}6~ZgzyNOUW?k3zQZNx;^oV;@N@S&CE{6rS_iJ@Nv zzTl#970$|!w89f|yeQ|Wz-Xll0ZOagTf%9zMM$f~V-Z;|YB+9DwW!EWRkW|93n-ye zRoijNkP^Iff@dyW>l2#DjW=9>EpmAG?^)To#5&34D%ldPz5Q<(bhYA{sQN+|(#6wiXV)jK-CqXP4c_CC2-+pgw-zJLQnU%p(xrT9bC&|d zLsimx_UsY+yXW#fhY#%ASl=wx_m=ej!0)@(TX$HJ>s;%lJ9Aq?j)lXq6H);dT#&n9 zoBnT8rCkda*Ct383qxytC6I`87Z1dPbceN`%XHe|R9t@9pSbvwuAg}vB_Li< zxLPL1isX2hXMM#?n&fY-&1|G45SSPkaKydqxx6r+3jpd>3#(UGpS)`I=>EO= zHoS)kd)Mr?e0C{%WEpEyKkM9oUeo5@)p~<9`&!&qwcK~L$47bXYWX&YBd`4H|6_f~ z_xJwiU>lv07Ny-dfsGAS2;whAHA`s@o)Sdphj;DN##+^22qh3vcnBaE82czM zKP<_(LIz2vYKe=|v9u>X2KB zU&3%)njDGC?`UrCIQH0$e>`y9ZhV=!q5Zyis&eYj7I&LwnzUAXZ9G#xDL=(VnXRks z&zB9z<9`2*!xP!j;Jph|gQ=^w_Z?XtFP4*IhGnL)?k~zJvtK#+uC=qe{U#cHUs;vB zg>5xTD46|5EUHu|+e$vH%Gs|slz**iiKqy>&0GEJu-jvl3 zO=G}3DT)*gD6qbn=OPwC`4@;p7I9Q3klXn!g{l0DD2r!2Vgh*g2cYfcf{-JTJP^py ze2J4&-nwNj z+<=f)YwRSv^z=Wid}exKetKnQWqhwnog)mc$kP`+547&vgt z!dH6^-g;m*?!N}b&mz((P*O@B$ZN4ez< zU>mXS4Y+J&X<*Zajk`c>X(><;`WD#rnCyzB*P8R*DwseOL79=7Gwiv6@ z)hJ{r8hVHQ+uSADth@Pjg*vc$4lQ(hx_&@%fCi?~Uv1jpCM zw6H~ah+qf>YZ1hK z1z!OWrX9-KIydn`NaUwl2hr@xktqTGT-uALcJ|AlKRWtJdVNOZd2+IBIIMlbY11w|EE;=>56(GFduw@UkoR zUa@P(?DnaNEyDwS-AJpdt>(t$_gIC=!c*mDUst?|9 z*Vyc>d%I>HcKUJ8-*WaHjl&<$e)^t|pXxigXX{lW|K} z)gF1{<(;)nwc*f2>sWKiEw@h|+ESUGyJ2Dc_AAEx{dc}5-JWJY?=?pbUAy)VYI@5; z`@xl_rJI-JpS3NYnVUYn(nV+GZR@}AN7d&z*W_*BgcM%eBz2ah|B9bJq=jp$OA$S2 z_OwGRDBcK^OEU#uH-(cSu4sY6Qx)So(+aW zZdtW!s!>$Y1=zJ3`{+%r>qW11A-adw^>ogZj*vNdYsqNA#IVngrZs8+fxwmhk_MQMaY_mntnRP-G2$-FIt%~T!x+w4=%n4 z_~(o&|1IDa+S6c=D{q4{sh}IZY3C50>u8Tc@3Q>E7u~~&r72bonJ&0!^UVTI(3{LG zk@)J*`vKK@FpAANKBD(oaaZSHf9IC2EsdGZbfPI0fdxaQ!Y(jF1gOqgLJtrrMNL7o zkqN~YQY#Z*DiBQ6;V0D1ZB{;+?5;TZz(6?EeA~IH_g#PZp_4;b9;unUdZBekXFO05 zE$B&Y8@T%5?+o|dG563r-{@D>9kW+7tIw^ycgLaa_x;Ij@BaDhnaNuZ3?xbxk_CmA zulUZbEN07RhQIdbpZz0n7|z|k^ zFrvzHryxOe#Ty?4ku(?#LK`QY0IDmgDB8t+g6kB4*WKOSBi+Nzt?PAfdi1tT$Y9@cs3>08G_-5Wj$3!NwC}oU`}Dq% zOmTUvzj5D{H;k-4b$0vI-G6-BjZaParlYaSy2_!G4<5SWp(_XKo9h$PZKEy4bFY8? z)wewR76gFdASvtr2z%{!V6Pp3hvRKpd1)ewI$^`8pxRu67mL3e5za>NQ#VOcgbbru zh(Z}7RN(Rkqon!-(+qYU{J@f#gF|!Y1kH0QZv>KAJPqybe|S0MZ=DoYGetbZ-=F?`XC&+aImg;F0hgd1%e_# z*%n0lYVIfs{+zTF;zbVrtgN6aEnOYZgPJRw%gc(3LIF9cB)QTF_T>QLXx#Xr7mD;@ zaNGl47`A|-@cww>X4ff619gsc<7Xd@Fx3q)<$LG=`iAG=3Jvrl!1Z-rxSEQk6A^kd z*vV-smd;^rd`)^HW54C1=!v>LgyTE4gtgb>)YOetoQ(KOc+lb#El3{seK+* zQ!^sytLM zeZAh_;h>tI!To^_BFLA{^98629~{jpAHo^sw~+BMblDQtWkTALc8xBwc{ zDa1ZQq6*}b~$cbD^ka1X7~93YR5I2}+`>1-W7W*3V!a_L&(v05&0KfS_>` z27$}@m-)wPXj3WPw@@(X1F8m8&JdZ2>cRD>X;XnlmG!mBOhu-wG*K8-rEwdo$-7=(vgGt-NW=IML zQ7RkeSltYZlg36^deKb4EQXBngXDb2n(WH=C49%~ZGB6#B2P_DjP>=jw>5XSbfc7s zFotH7jD81-HLxwzwuU8M!|$Fa?2WFXJto#cNW@?W-K!XT_f@;#db_BZSf3pf_Z%*{U@UJQIMOi|W6vJ$nD-wL98ysLg$2AB=6^ zw)4I{Y3`e04#zRcIqfLi7Yx=QD8<-27lp_Yev#iXy&47giQ3}1dl-Xb)Wo0t!#4aE z8UOD%@E>sRDH+W|kWZmdneFg6u@@@GMSqF~R8tU;U?NO`xj+Ug;72DGox_Z?YE4Ir zKCCs;iQBtJl-ne??Kqk1d?k=NE^1ODP)p|!jTXsT82>6!Feok zOES_^whgo`igrPBK)`eDqCl`D;XPTL-##-wHqhs>C+t)**Y|*PPoxFr#eX+>ksO)h z1{Q^K5N>Q-q6TXmhdVcPFvb!+&Rjx~{mwOsf>@Uh1BZZTFMBRlP8XcDMC z5X==i*!c~vyi5L?_dBC$eD5u43;DDSt=L{!~2baWWL{NM=%@>azlYj!cd%q7Gjml5AEN(YbQDq z=21=^=K%b|@%%QrRx!W)jTSi|7Zlo$!JKhQ`H1c1q0%A{7=+ zApV~&7Ro+wQd0X(0OG^ZBTl}NOf{BNds1L2gbrFzQ`_@d~FNxtsZN(eO;{D^B(oAKlxqb)~m$sXh^SouLS?1;fEqRdaphHR0WFdiGVM z{<<{drjh1y-&D!maKm6zNg_T{?0>DPAER(w?fQ^E3ZFucG$M^l)6yrjszg*l%<&My zMaE!6PFJE31S~14&q!_>6s`h4Jb->Q4k4#PK|~3~!gvFRl;fl>dwCcx{xkM7)J;rm z+0xfLF+DN8Wqix{;6U$4-$)apzMC^GaVrqq?t0*u51+&Dpof4H;So8G-AImPCERj?$16mah)t>=_Kj;s`zN%kco|YmG2xsrfMSZtudo zN0H8ss=vQ>@R+G@8(5o)vzMAYhtx8PL#H6s8IH^(o8ZO4SaiXFtTqT}z9SvFdoX;& z3m2iNT#U-@6L%T%&~TSY$KxI+lkcJP9kFT}kMgpGKW@ z0k{l)0~h1uuIr|2UK3Ak?daH=iod32`ubOJRmzc$#S2Wz+r~-q<{INguLxNw;lMr?BC{o~7O;4>@PrTG%emvG+Ee zeTLWZ35SdrBU2B$n0vlggQ%fRkv@4ZqD%hTeiL2DT5H-VTsA*tlGpQL$9gQuD+JDQ z+K%ACc(}l~;Yu#yJ6=N@s{ir*gVyddqcizze|oI~v@cUW92_Q_0{)qjTG?N*EL|tR zTDnb(CW=rmQbB<@x_|n?Wld(cKm38>I1zOPhs=Hi+-`jD8Pw-j7UF zW4t~H5o@wcoeH2S)g{WBGD*=rU6y*Xk1HQm|4{0eejsdzg+PO<&j!?1=qTjabo?f4 z`ZdXg&1ycdLYGO@cavo_Vnz5V3K6lh-Lkep;im=lQ-O0RJ>;m|=u^W?#G3>;luIzQ6R9kx%YK&>=O6vahln%T%CP2e3>mGL1i{hkQNReb1aJuX=Ly_K)A%yiyyK z3(6bIo_SI^`S|1K9#;nC&X=Fm*R@NA-eL$G-#QaaI zpElMb;{t^5ZC3s_UQa_Uau~#VFs@(JQKfZ@aZ0iL?>w%p-W&(|yy%99+VTQkN24{4 z=;NN(pih5>$C>o`G~VoibMajIAUQ5c&x$<6dF+Ai#@ed+?K)K^<&;U4*MIP%krPFs z46@?s3wB{}k`<@-&YV_y>N8 zaZ|v*#lqjc$2LwDtnIn!>Ibmt*>T?YzRSVWqpH%|-o0a}R{m-ZAH3^b=N{Af;JCT! zz0BX2SNM~|ho^Vt;|#$U!6w`OL^jPqW;1p$rWfaIAe2nkcXo5TGUaahA9KZ ziV~dZz?+}Uo)jf98o{4n@|2K@6hwFDpn^nWQGgn@B#xSeET_6>r5@ygXh2X-G@IYxQyO{uDiL?IFxMwL-|fr19!YukafJ+Box z*G2vpTGyBqErfp}8eWaN*F~wj_J!$w3j4w)jrCj*3au;$0Nf16S7~i$PTzR_)hAbP zKYqLS`pCR$u8)1tw!K@%`aY3weZw*LvT*US@epxmeE$+=x>Mc0w5`U{HUi-JEqr{u zUpHNSmG^2y0S$9KPZG~s>yZy!{Cf6_(q)&v9v#3&>p6k^t4*zk-vicqqJr5L#T$_nSOi5F+M&v0iOk-z?Vm z`F#903JVoX`_ic#HiG{v0!`3k&kjLp+uD|}wvXjo+aT0TvcMh9LCb4Zl>5M|8ZlOr|8wVh^e^>uwFy2vko`U1 zU#onsC{9)`;k)2~^nPq(>YA(GJQNEzXFqiCbtAoZEIjzm^vrSJuU_7E z$gO{@}`z{FmCu^XFFId>FT@ z3-1q!wA-R~Iq2{2tMCPa2(VH(&J({lEUH{0BoSV&^D2nWB;L zV40+lGB%?xQJq?Z=ZnGgK*LQ-pMatAeSnG(J;<&Y9_$|P83$cETieo^Oe9qC+fPWs&|vd-lubt0eK(-{ zuq`Nw85128P#gg64md2(!Ii>Z!-&n0k+LMCiy%dR(i~g7zCw8|<0I^b@z0#^soco8 z`F$XOy`!n|0;aMAn}g8_7&CwomJ~dN!#?~Uayd2y3Y4-|gIJLZ0%5iS^I=K*!Q@no z#|DCnja1BT-?_B?vf0a~5gU<7G!bt#6~*yvZsYUWEW&;B9oaFwJWXF%p15HD53|1r z&)@a_Yd3L}Z$jcmmDe91+W2I@!}0k3uJfGZ-t(4`^Bc%Wz9Vfi za#kNZZOJ_oF5fw}u}k_`hn!x28cE&X6Fsf5Eh*$Xk$%6lj$*gcHcd-G#+3Ovxf>P_ z^gX0@&^P06TwIEcK@0OC44|HEXbpsht(8c(mCMs*>Edum^iD#)ufLvZL*zk-$2H5CGV8Hf*N>(C1 zGl+VZWiR;aNL}=OFYpV}B>~T%&#v`j_zAs&bm)ln*W0Aw*LLi~Cid|2_Sk2L&TM<%JWCH76G54tOTZu;HV?tSh4&U4q_xbnc(cJI#E$Rz#P?B0>9 zA3U&jkMjE4Ub}O8t=!cooA>)gul+`b$>SjXR&ChWZ)!6a5UI@|lg_CYGgVb0Twdo> z!A$b{FR|CO7q!xfPgRD{8J9wyNxU~GcweIRkmNfGY9Xp$r(qH?_^Mh?#!veY^RF1J zqW?P&IjqGJB{&u6rCtY&%&o88F|*d`e?91OOZE}pDfJxjDNH>n+|4-0QjeSkRqj5Y zq83|N40#jL=Mm=_SCP**J5OCkSyd*HjPu80n$=0$u&KPm4r?`)mFT#I_`b@{%Fedt zhPpE9vEY~e#nDhbjwtCfKuA6f+)aGs(Ft-N(ogh zg+7r^l(42|WPYGK{o*r!TbAyrs_IIWmZrL@s(R98(6OSvU&)hIUFp)&H2)6&g;|?v z@)*zSpo!A7PPOEY3t}`F$jl;*+nW&P5Hwu(9KuHJHfkkoEIo*&udlCvJ^M|iMC=J> zH1=d+{U~ff=fwPI^{2P-wh%!@7BXPdjySuciWG|6Pq07vKG9mu3CxD7#!U9lBnnPM z(;8W(wwuUAY^<%R9H<&FmlWgORHSROZ&iMXHC0L7(udC%Q=dDXuUa8xB*+g2t<=Dsl!V;8rn+L3(;U(hbo<5zV8l!S)e{wW@$B%jkkw#v$?{wLVbK z$1oyz@jJkyRP<@F;jzScaAzEHk^7G7&J%1IZ2c%32cUG8RdJTFo*x5FP}uowaCR^p z^h}lfkS>VsSw%-bAGIyF7D4!-d}3iVg2whpBL&!yeog>0V#n=YiAF*P37yBSCTz9q z|A=vl$}#KK-0Hva+{=QgDnLd^7n;3{XE(%4wN_5OBY~VxStYcLKX{y8l>`^$#~9?+ zdxUKm|4d1|cS`a4HJJSlEdtV@rMizZzF4r*2B9hirSPAWE@V3 zy-1_8FIDqYR0S<*jpoB{&Ib3Jqi|KyK~Vk2UAzsyo=jcYNXDvhwE%UT2zTOb=uidN zr(Xc~C~WCL89t~IKJLQN^ucqwL+QEfl<7E7YD+c`VVD>Tj7JNf`ETwycBZx}4QAi^WoiD))65b}>BXLgH_bo=!xmRYGKG0H_ z7yalF%3MM>vi$;*7V;bxfWrO*NBJ*Rehb)OPcrNgZIGBBMRxo_xKEu>iwX&DSxI3< zQAISY#shICW0*NhS^rG-5&34w_7bT@I(QyxqfD~B7dk^Vge$8CHDDw~!P$Wil(PLR ziK8p92lziKZ)P7vjk*gZi45uhSu&gnsAYCLfr3c7;USM(zG3dBoejg)K_y&NS+YFy z-LiDIb?0}}o&VCa6W1?yMIy(Ml`1dp@oOFmfU^FB>?2A5>#0T*;;rWk>G7H@H4eF}Xn5P6YQRj@SSM7xNT|}}Let))FE~9U zyA+$xJoB!1xfcCS`Lui4aE37tD~`3x+541r_tm4U{}J}`B-W0-l%wWeQom1gFZ*~e zJI%f9#$JkkmU)K^^AM_%ns<<6xi(ZIpTjQy~M`FqJvb zH9?M_NEzesYbrZ+#66zmMR`NLEO)fkcQ$l#h)4$gbtCAk&T{WVnCQRTY!!qN*(weJ z@|?D<9qIOjn1YV&flvTZttvu6b>yH1JCGx51@cR~8tZfBp}PU|jN9xLVy1=ldjW2{ zHZ7J9r%M2~5Ii%@S#pDc% zMg-a@ICrkQ zw7O8%;`LSU&Az3&zPPqPZhV2QflH``m5dg^8aSX7CFJ*%6=ZAF=U)DUXhJ@iD9PTI zDv8yXW*>G~{`fo*PwBb?=^lz)iJe6^d*?0$pzO+>crI~YdZ;A^*@Jq2(yO3S+~+84qBaDgTgL3kDHirh2LJo)4^5Butrr`8bIbd~Z4_YqxR1D)(j zz{DH>HRcMSk&%54vskFn1Pav%Tq2e>-?jX*fvo|=^g^q|IsR2n z)N|7>L2Xu#(hEWm*9o_#x~kHI%^Evke>3}{QXp_NU?ZEgf^lrp8et&;6%Sje<~+Rs zPIKlWoA_M;UrOQa#KA07rd zB=!SuP3mupR@*?A4=dvP@J}dlyfgIwqA<(ryHjSwbPWuphrWYdqJ4V!Vc$EHp0#h? z_sD%&zx*=(0|3~shhe9>9&-}UJ#0|}ma3QV(;c{3M5O_$qL+f0kPo8&A}t0QzhAeC z*mkm7Ylg;8YgJX2hWQ4fDkL2OdP1lbYDHOb3^iErgb=zfzX#NRM$lqAy&)vLAxLP{ zbALrt?nIqWWZ&o}y14l-7(L&1V{^D*%UiFw=Cw8Dvj?v1U->TwyU$&BqI36n`rL_Q zGiQ2yzsg)Ud+63HM^*+a22MP51sON*x~G2p$TXVR>oMW#%T@(bvjY3s&lAwu&)O~vjc|8vgW2#jLYHa@(cKVHV40D#_zNXzXlke zxwtYtYQ1s85{w}m;Z-Wjn(Hk_gsPT9wJ&s;P^wBE-7G6yFwOzdrExL}(%h3v!7 zIU*lUI8(S61MlHnwy%kcFV;|1;tR<`s0>awqxEBy??&29#D76NA4DTuz82x7-w(He zu>a{rszrANagov>`a%@wLsCw@46Q7vL7p^x*oC`hWRJA9+fP zcD0wrgUD219hE5D0HKIZ*AY2#IurzDm4nc>6=>P?zN2>6c=*s`qXWi8`#8Sr;Na4~ zVa4411gFp(je7-=&@@aKpWr~(A;T6~)Zg3Lkw}*$T8XA4IniT8_nFwKC{MAD0u9Ba zbJ_<&qX1Heto(?@iH(4%dv_hD{RT;X;_Z+gPU&tQz7~b-!WB@ibL-aHvIuAN8^{5X7@Mh)$ zMo{9kdBeHFCN89jsIoDJ{)&MvC(L23jGPCRsmjK>8o5HQNS8H1ceVQrAGgUHfs^o# z-l4@(^{_)SW)!AQo7^a&=8=k=cdFlt=q3v@!$C=y;R;08c4LeaGh-Yc^um`}U73Ry z-bLTT`L<*ZB{D+W(U@M@6wybYmc{k?=dzQ+l>8F)x3L*4TibS7~`a*!3)@9!m7TuGF6pw zU?uK6;AFp3#2$;tpR1j;thH|V9I8@%Xz-<>0puf*mJkYnfd~8j2oLfh=k6(d$WH)N z4jvX?>3eGPA`>27l(2i659h}NzRg@b;M;r`fUY{}QAHJl$;0VJhlo*U{Lu>+dS`s*LEE{5i8qMCjutB7B;oQ`RjMdQ=T0Bv#K<|0&mAg4 zH@VK8xL5rTf;OGfXT-f4Erf?wPT@gE*Q)uGs3S(=AO#DG58*dHAA}Dg3-*hrCKBV# zceCz^Y6jwLaAE5uF4R1uwJtbN{ft@OAy zeZTw$`^rh&$7kMuBYDry=iZaTOAaxA^Wx>?Id|QQ%-fHs--jL0C9k9&S=OAso7tDLW+IqF@v;RvqL znJh0;`W(G1w^-XEQX>g#YtF1M?rD=;DGcMG{=ULE)eFZk$b}@bK5x8YYF;=l{5uYjT zy-?f4IL0j9)s<%4x`w-k`g_xz>5kTBJ9b<*Pg2C*;Y^oEjbsVo?V)hFK{hn-_VmjO zWu>xIU0I4y2}CoO$R&ZG(Sd<#K#J&q5-wp*b$`)cLD_Qpnb&OF_L^r-pE*bWJ$L5! z9(m;VcHXih^Qd24ded`voqhIAi;Hi1_Uv8Hy=m#?vtRw>`L7M0ca~LB zsK{gPStQBJgyjen&oM|Rw#K07C7l8C4BF}EJeOQI%i2q&SVGL3^oSNo!yefOWzZ0O zJurZ(0lLTNW<6m9`RG#3>qPWAzCf`aJ@Uu<6H)A!5S|#@GK_r9j2&qz_N&X1Cjuib z+LbcSZ~4^LcE!(8N#t+tKqEvLpka@KLhk3diwy+Jrbi3uGC0W6WnyrApuevt?KFMBzD=3;m{c!Semg~4~`A@@jNXK<(A}_8&)`+@HHeRS;Twl@(2T?<91(maA z+EFLpD55ro41+*8f{MSPfIl2M2}%>8Z-5pMj&SKQDvwW$ED~K}c1bRJAzm^F>_RmH zd~FB>LVnowHi-dkA_Dtq50`f?&QELTWs|dyoG@eDU!uN-jW$(Go2Sn&p&7g3HytL1 z5AH3LA>0Bne*n=aDmtx8D#{b+t=WxyBpC8+H|(W+$c)$~uDQLJ?b$uM4cX0G(9Vf2 zyqTsM`{^-zhV3KSBYbYgTF8z|vIlC+9Lu2JJwF8pk+G&8@)lu-ae%l_1MR0MVj3}* zU>7>5?R?=cTw8b#WfAMMU$_}i+r zIQ`@Ug<-`;5WOCtir_O`11ifVJOBd0qY&O~gkPBVQKfV)1U*B@cAG;XXi*-XBGKKS z;HViN;P&k4mL*h{8Xp?y9_txvZ>=cD9(KuH6sxKlEhn3Y28T!N1(eWrDQ+}j^4YZp z9~2Dbt0=lsQ+IUW(AC?9uYU5(I4KXLOpM<2`&SmHYZHC#$-2^lx0?FI8?P?qO{3Dq<8K z-9#+w)Sm%7Ad?d`b#N#z7L=vO7FP;RZf5&X5m80Osz-~XbIwn1Ns zdPIK&J))^|72%`nz~r7(gQTrl%|(a|Ubp@x$1;A^L@}!E?|wTNwf*_r2maPcEA?}X z+kX{2Fj6R^k1nj2YUE}F>_GD3^dE=&SB0E19}^-459zpee&~jpa7mvtZw%QcHp575 z7!ZM6(+WQ6n4A=1dvbnqZrk+emcfDk-mZ?8=JZ6F^xn#JMubB#i*0d%OZ1WQlT$AcV5F|Kp{Lq1AlsL>!1ha>| z;03O6Xz(jSM83#0xKGfa9j{0g7HTzsR18s{{}`WFFGk($V8R!L#rVzE+tc0E){^dQ z>a_2Z>pkh#71S@da8&(35AC)#h2y3M3mnCZiEzw)Rl0Cgxi*81j<04MUwgh86r`(^ z>gS+p1zn{l4N0Rv=;$^bv~E*=(6t%2=>^9ki-J%6FhZ$Y{~z|=15UE5xEsBpZ|5*Q z-90_AXS#cOdUDS3&g|}l&1rUKzo@q&CH5tV_W?AX{Wo-sZ*y;Rh>F@>Qq^& z$j)`T-Y>xKJj3sA*+qngWF7tM5@|c7w^}`HXxan%7JP0L;l`a2`@lGWY?eVpf@=zZ zkmi>f!-8(#=rNe+j)05xdLwDRwIh@@@5h3>HA)o@N@nN81QB3jc4BsVa-@I^es;Vq zNr&72E7C!oUY8De=Tzk!qr=;Y1=x{~__d9UDTi`~s-rMBV;P2R=WT_v>o-OcYA*dl z16`fzvF0%=*LvA<89JKBLtEtPPKM_%Fyli**21@RW!cN0F~Dke_AU6~wuPgfe<;Pc zYB%qK-B|0f4%4Zb@o_$dadljsnkY7rfSvF1>3!iRV;&O|d>$k{>NH;3cBRLg$E^#J zH;0l*48Ml$wZ3@R3u5$8hV%lRZ;CR^;X5kgHhrKKfnkhFd7Tm;Lnq#;>sM+~66uVYs zJ|wCSq`BXVZR{NzZEfAz%Xo?n`sVqGk=x8-BWGx{ajf{9Ub!rG8)(PyN_Tg0Rv+l= z8txu0v^wN8|?Fp2>0z zBJKFQucD0_jYjO^ksc&!m8DQ1K?7v8!PXqDjtg3mAfQu)fCRTvMS)yetP|xJ=B1Uw zBE9KM@amx562&=%W`FVQDiu^hx`X3y9}vTq*U-6Vl%1Iidroe7kV+^$x^H?cr#fEI zDuDjR>Gz;$l6JocTG(O@hOwHGK&1$ONA=g&p-7wqB}Eu*n3od^2(OcH7T!)Q8f|8r zQtVcbITPk#s>$-4L8*@QyHK`M-UU__-tM|^k7D8e#b%l{&z>8Z{$6^vmTu`GcV0dy8Le%FDLNA6thUD6xrhjFB{2fvtAbhDS7xHS((OSX$8dQi7)3^ zl`+cfx?XeUNTcR(cbkCOA`x^gqy(|R+9Gk_SflDDgqvnFja^M$LPAI&WDzyRl73`% zMg_3~Zl@T=SQ_z*>vBCyq;=H7`FkDP?2P}J`yYPze))Ivc%SJ3)HH@3=oBWzPxFna zqOUiAWaV&wC@B#NiqcPzsc-+@&0c{UO}%J}uPFHhkr27&JRbd~n-?4*O)?D@cex}y zsF$QUR>zrN*3#8A_0TT6%XJ{*tqV3<$qop6nq$N0ciupsA~y$Z7v&{JW1TJc<=WIo z1s4KQ^-Fe3Uo1MMji8uNTXR}ckkqLJ1pa0u+T8{7aiV(y zm-lg8-Y2yfIArN-$y(yxNLM;t#V+q{np3(oHarG(Nmu#02AvvrSaM6S%F4fNVW}W# zPg9@X_JsvoxSLT~S=XzUJ*Eb7`7>&~t25hzea59Ysv{M$q*R8HOq1?4=oC?poo~I} zrdS(eBcba}wpEqgYbpexqpdlGH)1s%%}H0mKI3%7U0F_4F+PouxNh9%YJ1K|*1F+b zd-9swZyg?|J!kCvz+igrrBmk|gebNLDp+?+RgDVapa1>#!YdP9} zr;!|8e;R`Tsk}HiYOQH4y)hKD)($CT;8H)s;R0c6c!bs(sx4NFw-&YOTBKR>znk(=6Io+B}*2p6O;ippJ0n zX>F!#v!$49bG99NY@M|^n}lV~dKVmJwMe|YX+o;?p|rM`F~afaReF7G!F(Uc-7Ebb zbSlNSJOEIbG3~SB@@2~XfLHbuVYlvzCI~~@8bYgS@nlralY`-bdX~wsC9$_uTlg9} zC@!vOz#gX=En^*)v8A~-TbH#@3lk8KUs3uy%&STGlr{(4E(!?N(YVqNuGBthT-ksc zyKojMPI$4c)4}FHZA>9)X_UV-T0=O+7#BLu=C{R8pzpT~CguQQ$cxY-{!ivFHD_Eb zIJ;kA5qjo)ip;_alUBXVe0VIDJ|D>A_83J4@LB!-2IUcNy5_wvn=d@vz^A}4~iP%;%)4Kl)E^q@!TXC9it_Zn)JZm^(u&?9LBJ?OEhJ}4IT zC?5X9;>w{Q^ilqvT~Fj(HVX+9gT8n-bm*6qUu1g&{-(Wwc0*|nyWyW~kQ1}mi~0GJ z-87N;Y2Wb~#~3?)2Q_D>NlSAKO|LJEeP8dQ_M5GBwxnAFU~<-{1}!KtrJ!@6oB zA0!`-#b{W@o5y&E)C2Q~BGJc`*$ZUFO@op#B9QwDV(qvAqJoGG69LTyg;96!+PR%d zf^BHb1&q0@?nh#9Hwt9&iOTZ`Vo{v#5)MEdH~N!VOpJ- z#JCN7y^A9RhnP0?25E786z`;)>T1$SmXrck3LQQud^CXq;@ktqii>O2Lk7E@dR}ws zYyO&0%gD~buEl}6uI(pIpV;2jf9gHQZ}{cOc6U{{vUP0#)Zp&Hny&3@r`NW3^&Wfp z(3y{o%e$+p>QLrms4+X((vWPOT$!4`Yo&kN@K%-@w61$H)jpDKXlk22Iy-*jzTTM; zE042S3Ue)l-B|yf>XNw@c_g(sd z-Fv4F)9du22&qW}uz8(uH75vkt&OW%^_;cv2F zpw5-(?Ge!qZYLwRB81lp1uiFj8e}2G_U_)bgX$vobYX`}r8B7tpF55;WkHdAOeGW# zou#Z=s+j9Z`s)8kY{`^YMXg2j*ZcF|mbl$zRMTvME<3%mi2a2Z%+e=aES4F6rbHY= zaBAHx+$O$NxL);EAPEA}aUp(?S7o6`OO*U+4K4t7&cv=vmJ?lrATsf;q)+HUIt5Wb9|Lz9*8ltyg`&?lTUz*9J3o5pmepHWk)FJPWMbGerRb< z27>66#WlSj+1Gq5mYfea^b$(vqNNKH}b%>5tIOPJ%N z@DDsjGYrSPqo>2~L)7rN$difYeP?D9?F0tM)`c)l$%T+-ryx0n8<65bax7!xRJF9C ztFU0q8TS|K1NuPuh}OQ)FK)dj&R|6b(mNr#0e)~Kkh64w#MFqwC~gRwQ;i9n!)huk z5VtcaPV!h!GcRekI248iO^G8B%JzYTz{zkFX{M%;xfJy>MSHzWal4VDwEfss_f%B< zLYo{5AEC^f(|z@AiI_X+8_eD?Zmp1MR{N@W;3ny8B)Sk2$3l_Z$M3)Nq&gj{42737 zU9M?MT}-}@cU*o|`ZCwkSS#?KCJSH0&mXXJAXO;p6Hq48Em5gI&V)ElFby)pl4cg= zCuB*?>!Y)j+1bWaY7KuokrWNpii<1@u5`Y2xsMb@ndG$1-r6K8>t^Ch z7s0@iB0Y;zl$}|Krr$2Wa|iJJkQ&nU5W>A(*gLsa!LkyvD0Ys5&;`nf!hq+=J;M(& zEYnh#t%semh3yeaEs6bos8m&eHd8Fp<@a44k}m@1Ze%HbRK=x-gxthh*0l>h6k^mhJB z)w%DQvfll`wyWP#`3kGaDn9+RI4{+j0{$$@u>N*SZuQqSG4JSGJDPhbRx7uYtwMVY zWZZGJDdS=b$++?ZiCi-7=Lg#GB!bnVqITEtb1U&GZzpWk+O=i$c5Rnm#SIQS$J3rA zwqVafMiA*BgV$=b13ct3Vdqi{ym<}YptYUjyF7oU*-rUBYv+A&VTv%+>o*Wgh5Pc% zw!(G|X4Zg7IC_iepO=_v*9} z(x5eH0~#$#yOCqp`{M3d>zsHW!v-*LrMB+pOfHy5 z(IPk~y!Fw4_kx>5|EQpf&mmtbfe(GTFagRN%ro-|jCR~%o+mm?&iCwcR}IM73qWZ`G$|FXy?!cj;z9baOy zw0rAN#E?zrS1d4DJ7KHVZmX)d1CO}ww#a5XmrV!qqhjs180|n)*Sjoy&*9B$@b=i+ zU2Ty~j^FoLJMW99RtZDPTwHfqWRt_(uECr$U=ogRvB)OJaZ$r@c~PGW;dny)4H`I~>n|zao1Ooa z&$oz1*x>BIKzzRi-Oily3*}Wm=kM?XX8|C#lx?@Im;5UV&`Uee#1CCWX@! z?I_!YC-CX27m#%VCli=E?R$RRRfil5{-0>R&lyz z7}Zd=miD$xx-n7HUE58`76>!rZb9I<{bd1tcCsqCA2)HM0yoI|f%A*Yxdy{ud&y-% z&!7}1W*X#jyA*i!v`)pEs@YPl^r=vhBbo}kw;LJi>!Fly`aHCIJMa$8<8Qzd`Rlxk z(fDq29<*48$RXRQ>q^XzBy z>513&PXdqMQbRRh(Jbyrm;mW7tnpS6o_{yF8^9)~*qs>+{+XgA=4{ew>w@&@bYoVs z51b9w5sEdp%~fZdfxhm}7OFR+2>@ptV{Hm$bAj=Vo|lSElDtWbd-O;b%7%mV=ca%f z5l{663D+5A3l zpI^HlqarJ>;#O{^SZ_D32I%5V$HQQM78Xfv;qG;MQQc{DSD8JfGRusORi=2 zIz93*$3!h1034$rqvT0_fV}3IXq_nT*|lv8l{;#0ZP0Q|5vTHL(!R~-`PT*W{4iy+ z6$;l9F`an*>h#{cF?PjTmhF*;Gh0iegTb`r)^cu^)^c|H-1dCNHP;gNB1QBvy;%9- zW#J|}zcv=^DD29VKhR^*IcdFx4S9Pjw&Ud^#1t3NJoiUM@mUl;3Jd#L6CVovYxUwv z7JAcdNUk9<3w|gu7aktFTyt>Xa1EC++T&OJq_~dil3;Wsi>R%1JKMaN7DfrG{Ax71 zHYO^wIThXekgJUL9Oz;uE5&n_=^EC+57!K4t}`KL5>v&*{VKZlWGi(wv0BZJi&J65XK*?HWC0z%$msA^I~^#J1XK55yPypO zB7D3!50!40k1lQv%Iq#8Wa8b*O|YH1g~wGN>W0Zu3sT7I+jfGIaH|VcO+&v=ger9E z_jq7^+Bguc#hjXS-$zZ^#nn8X;aFN?OT=dwIPl&UYYgwL4izN!Q{5t@UTtpTIpb12 zxVT`6u29v4yfMQgC8`<8Upmv`MYgyb4qQCcfudo%-!)#Wno;JarNbj<-g8KL_|iS+ z-?n{D`iIx^iy47Ubv>=cPg!ltIktZH+t-f;O65mB=~~N>GSUJ?W2E$!g=<*mL;@V| zXXiC;$KMaMweuQYu92+e+wtHXOIVXWrVYEih$g*F0baO|Bh2`#H8a1Z)sDwgEBV{p z|AIeL!W2%DlCXHIAl!(G95_e9KqNV)5;$Oeq&-<zCJhebxWq8XmFgr}*OSsb= zlyXOJY;A!zXt8KV8@%I4rdl13cE`HIo$!&BSt){HgjZ5 za1<%SPO01F#nueqD69kn`3S49ue}O5S>aAD0JuDrMLfa7&4uXlK`cdT!$ zJ=r;#bQ3j8!rjK;4yywOT6Co9y}i9-y`#+<*k&xY0hiqeSn!?K;f`X1;jpE7 ztOlYRkO@*4EYx8`k5_YP`$o&wTxsad)$EkvC8u7>7VD5Zew^gXc2xh9`3$M##zcNfu0a zQnPp;*3$yd3Wc44S1|&tu|jx^KmO7VPuMBG9q_KQ(1lzgP2}A`xSPc#VjYJzXNrR` z93j-y-T*XeZn4t{a!I=84=JTa-S4Wf3m8^ec2WKM{hj(G07$Vb1;y5 zsJLLLJK~XJ$K`PGj*=14JrHznHK3%(cs3*W8^& z;(21ZXXNj5J%|?_L4}B(g;v?}oMGU!7!7dC_siE@G+@D0N#rMlE#e*O#7K^c&O!V< zn*;V7jV_dF7j#xo(a_Xpg6So3OfWiH+{C&&=y3eEybRT6e z-}VB)A`Aj%37rBfHG0rvLBuc%SV2@#G>K%j5)QxEn!zZVonYY4?uE^9ghht`SsI6X z(Jkf=O~YdTnB&l}NPliKf2gsw1OkZ4w*j&E-c@Ni3>cF@5P*N zQ$ulZKnCUkLrV8dLSk{h>_oIUg`}MVe=vh+#>ONp$DXAb+>1rq!GcM*RHuOv--HaD zw%XSLw+vKQutiO41fn=oIDn2@ry33$gf`%?z0sT-V(bV`tC}(3@XCC4^o=Dm;IKW+ z0%s?q(GhdKXbUsr^qkJ3M5zbbPDREZr^V@6(FZMP`+8%v(3zamLgDqnG?`)hg=G#) zj264iIgnXeP1?zUx6%1x0}jWR_!atwahN_7@TSdz@K!S19xAT8cCqnL<58nMAIXgk z*5RnPiD)tzkHf@5_Fr9xc@$lTAwEoA;<^@pri57*RJUyhay(I$RmvbCvmyovl0K(HV2KQ*Q#f44gBG~E0k;Fs{y$*_mAI?6DT<4iErRG77UtxdBP@o@C3h>LlRtU>k4OoyiN+Re`4i`rW zPb7_riooe{`B}nAxSiP<&sP)I&DYVtNcW_jo|>?jde~Hn6BJ#Du@h9WrUj=cpukR1 zZFp{t%_%vQq&Ms${%d*jKt6^cIesba_e-sp{V%ik=~SWqc`n_O?Y9-Sr$Uz{+ZVtu-83IGMQ_)&W)W-Kk?n8o z$6ixY6%C{0oX{e+P&BHTYJtB-rYN7mX=#Mjd10jO5r=sZsVp2gLo5fW_;h8&>5FFC zy6Wea6N`5p?rcwF6E&eg#96g^U)N$^?RQ&7>V}s(A}#UU8QG!zG18hKQ+M0xZx9|n2dEOb6r4nH zCrY?V5{uBBb}g2hrSfB%<&n49X8Bj%aHf(bxu8w57n2O?ll;uyx`qQ%AXZ<|RLADH zUw%aDb>4?FM>D+u5?~_K*GY;4G2lo7giT14_mPHYseQP4$M{PX7i+4Kwxt>R5!Sy8 zq4x;tV5_5vfs4*U;eiO!5yZ3>6xe7^rU=-#^edQ!C3M|G|s5rUz?deGMaX zW6F`HYVTc#-!^h*Df`_0D0H)|sMj~s#ef(_XZnfRvi6xIaM?=3*G3a24* zH%$4#5r`P9+RHtj^X17ixnrk9(oHw`MIMTa3lS$5;n3`BgD{XGKKj=TQ zXa7pDGU)H=Pd9HpGc$H-0h>ucutiJe7};1xL9#1a-yN(?`k3kjvQWM^a3wPe(*vH(ROz~9|a@m-atAlQUN|z zPgMYMP%O3xD`W+nIl%)IsbARKWE#XIH>X7*+mh~R?m#*5ih$39C+8v_HR^Q~obVZf z{k0%@=q}D1ad7_tl5&V0eFr9!{&4OK&h3+l&SZ_R!rdGj938J4KE5rRnmsl-Jn8;c zu&zycs%dg{v?02C5n}7_sYyoM&GXl79XzqE?bzfT;QSx8IMUe%>vIf`cuGukp+VJ?&%3qq!qQPg%%He<4*WPYZ)MqU{#5 zY6Ydw=?X)Yk7w}?T^GMBy)2Pr7f_-M!k{e6&g6j%g2A+d%OcCn>!IHw&t3k{iY@V`j_kT;weN%Y@oDFQ*r26h}JWdVF%?&{%zYOElh;&UQ79?D+N8sU6MH>d~$0)_3=Gc6E1k zbtz8=1HDyFPjypvx}#bNhNA)a=LY-Iv;B?nOkZ8PKj>?2i1&x9=6k8dr9ZE#ge%LJ zsBCEM6t{IXw{&&2q`TkbfucP5-;D=E;i&upsS$f{Oz2iSkc?l9qL`{QkIJGjGX#lB zg)vP!C6gkG36%0I>?G?4+nZ(pX*EufhUw_V#A09jY-jv!9UV=hHGut3xxa2mHw-Oy zMDS>fiz}(KQnJ7Nc?zDym;xaw0nIbn%t^PH>!4LcB2f7y$ zg(W=h5QJzYENNMg!-_k~N;i)%(KKuo(RcCvfq0^#q9GOt#2PA+eaeHm3h~uXRy0%v z0#ywa;Y3vcuU@6guSEFR75_g8Kx>Nw=t>r(DC{__hFJE*7{FFEXPoXBNXL~2d$Tz_6gCltO0W8x%Ir*cDxpaJ zNK5_u0#%8MFfi{)CVPRmkeceM^=|Vz8(Ss8m_e!+_=~~;(7PY_*9q{fQnDYBwiP^2 z-bdmNGir_QlKFBaxnSE6W)Mxt-4(SYAHx3}lIHqXF1P5us6l|C>-?s|^Hz#{t5F7F`l| zXjPpWV~yo-8P<`hD#S*eB6Oz3Y-Stq0Up2$_-xDMb}b(`aOlv10}xH%bU^xhsTcMI z+4f87Jp3;LY@{y(JyO%2xb7Gy|#1bD{; z)VKD*BPj`FYfAHUTce{)jxOzQW}iVVCexXurWW-~R&jcKjYL+^iwCx2n|9P}=}A?4 z9H=`JZ0`;egM}(*ddDhGhLx_i+{=vjaV8Rf9XvH8jH*LJunlYN`6=)X5esBv2R*#B zU4gNvN{e0TOc%z=JHF}0iRFPfR=3-sC#DcTr1(6ZSY0~a+@1l2GIc|{28K>HCX|rh zAFIpMBPSrfZmH?p-aEY7p!B(2-hj8Ux~e7;O%ArV%yiYJ>-*f^Kq!!jSL5YdYP6?m zyrZ_c0s1I~xjg6`781fus@Efma=rFmnqrt5*n>k-=FAZ}wLpg!p2dyMbt+1n;|ZhX zci8k)?SmQ-x6sSU7)e$-n;SYL$v~_9F8{A)~ z#AhFQq$XMwMPa6vx&`@>om<63ATStwr0VITxqqmxt?*CBkrYAL2|2HT4>T^InmaJS z`50Rx;|OsX`y|=8oIS9FSPJ|%E>IRoTv^dZX$0V;Epa*jS7%4lNX^AvH7-}v&Y||X z&bab;?uG9Dx@z&RORvS-ldTPdiyh*2jPC)fRAKzEfNOA6A*9PtAaIV!kFXf-Xp%`b za2$y62nY7uL{59IOSrCfdKJa*x>kw?&b)G)@_0?|+qHew)%~?%&=i_($9b$taaYqQxCf>%iU_s}J|e#q#u+dxcZ)E1kzJuf zthp{2m3M>`uj`PzcA&w1Q1Ln{_5h93pEwD~QaO8Wre+hb? zkAyzp31aN(%S{qqQ(|n~v{>)Tp%o6$La^X?LE6D?%z?p384SMk%ss(?fx$DMzB?E; zFz5gRzv8L%G6X`N=fjon_rQXn`NyHZ+A#kr!MsnTA6R8}*h-zaPXr^dNsgfWJQm8r z4`Rd}sa(72%jZI2$4!bG8Dy0k<*5HEIS>u~k@#03Z|=2VT`-uy`!^rVDvZ|wUHCG_ z3kul7p{6xKCEJFSJoYxYry~wbR*bsjfmo6bK#}xNQhYh`om}pm*Z1x3i|rhG;SDSmcyVb8u0tP9=DJY zGaeLVjF3$eO-STwnwE#cgAhrwEveEv3Rs1|(Uj`F_Q_jbzU8TF`%;bf@BP_tefZ^{ z`R32=Q6A4Wc?h2&kueS@H^UMC#nP8ZudccxH(AmCkOiGjdXRnW;n5hYVo|>pXG!9gHVfOoc_Z&oR3Enkf%l zm*}#Mw~C;P>x`E?`Z9t84Jxcygu4b*Nb{D`*>X*hZi2znTCo`Fz6Gs^IYk3DrdUl= z+_P(8e(J#V0b^P|ObdMe!J>1zlkxcz#pXnqw)^>HkSv#G6Yxr;Dz#5}Laq+7#u}n} zM@9v`pM@m4gdbL$4jv@D4<0#qWM#Pk`=F+8bBH&DzRh2g3qJw)FE11Rq-Kt+?%ln( zFm-VHph0~D|KhTC7vrf*rmO{QvNj|Hz*B)@vKIC;HiHpVOxS4ghI!`#p&>~v*IS(} z(J`oZ46X>lVBdlU#AHURytS^b5LvFj_NtRBH?7`OLgp$BnfoQSzO2TMMdof{^!ah` z-EfL1f2&x=x=efbtvQOSefBv#v>@F`)Kh#tiUeJ zg~jSJ~k(t?IWbQ?E^Zpxrs+ionqQRboJ7&*+3}&>+^Vvm_mNGXDp!X zg>Oah`Fed6BSF^FfUT#mh;3A~E753BH^4QeE^=Gtk;3btJT zacfs#HS25lOTuo$ENt4;n}$XLy`Y=e9Jev04!ii zoda}$OiJ6yF1hEz9p`U3SN1#*HEff2FnP7vo>+5s9x&GYHdEJ{=K@;u0qtC%?RSB~ z<3Z6~i#9x}G(<-Vebd@#U$Xv&^y9;3I}&Sl%N)v0_C+OElZuLFt9 z51eNbv`}lukE|{qEPXEcV9~W<=Ne;eP;yH5$Jp0K+r`dMG&5``?O;<;O033!XR?b+hAzK(cv*gsH0S{iP^Shb&C#2+fo^fO~GTNS6ld*?3y!ItsOgB;$%k0 zW$a~dFG_!QE_;*yS4@9?rZi27A}33Y{>AqrcCIw&|JUYzWS%ccH_dD3%hLN%wD6c& zazk3MK`Xk0Y!ntNaXV`q-wb4Wi3M*M5RqK&<7JSb zbF1D;mODAVxEd)ymu(!$+1aj6Nt|7nUD!G|I^3ytsjV%E`l_hkD|Sd7wi?}!aUZ@( zFBEqtdJU?9t%x+#Xhwm|ykIBJCoaz!ylm9ess(BIv>4^QHp(Hv(8juO`q93>;VyiA zh>D$j6p7wCua6lrM=_*q&Fyr}n+&6CBT;qv;O?D^^Tnx(_b8kPnQy>C)ANj`U*t90 z?S#dvQxMu~5E`#Th|>LRB9!;1Zz1TDC{aECU?F%wBRJ_OlT|m{lhd7uxY?e3Ogf7W zm&Ddi)k2JW(R)hp_#~f4TMcc_qR(ecxjYaY#;yGk#R`(4yLUzKdRY;5tH9);Knr_V z%^p5XYkPR@@Y=B>rB*m(tubCGH@CmJ#!MsS5f~1WpSU$XacpC2%+I+NIlhCf@yFG` z2{8~fM3zhJv=9nNfzTPh=*F4D?Om%Bp|d?fToK`RM%z>^(i_&Kx56g9Zv={|LEi`z zQ>o7I8A)fabV@MD8BNxMV3+Sa!Y~2tnPXepxtp)M=G4g*cm?R?A&Tu!*gs6rx zE{+?~awEu*-#X)11-=_U+g{yE3;@NZkNagQe+vC!_D%vrMS!|{o z-lWuy)m6SUt0z|B8ZW&-75059pZ_nsxjtm=7u~Dg(E1!c%-4skh!e*S?%%m%c6DyG zP=M^~Q?SR}#n$JS*&Y+h+hY(2fITLdzsH2I$3(yh zF%_H2CsnXXY`3&Jj)dBkDrZ{XNbzKS>9c=eg1w;sE7z0D>HX*2ekH_x7% zJA1M_Xv^MwEAhVYjen=JI-PkoaIhy%RokrI0y`V!c?{@0VWGnO)bZcA)X+*CI%%k%&T886A` z%}3HsuzW<-KEuGYbT8Y7$!eRnA0FDjZ}09MOWU^29-TW{NNu~m<+T+|dLu6j@!bDY zKyM0YTF)=TEx`3!np9n{C1W)tbk_#9lb{HnHPES*k}Ma_+Gpi4mUF{0=N)X$KPZ?p z@;e7am*jDwQdu5%;g*JRm(Rvs8|+|GV1pePA-eLhvC|_DBa*ue=ZO9LcI{Z0pFK2p zsE{r}jV`$hj>mX?Zj&y`Mez>!zWNL3Lb=R6I2Ty#QJd{d1r^zOq1Qv#lVq8$(*;2V zwl3U>#YXW^@)O-1S#B8e>QWALV1_<+;*{=(V$pgRL@>HMN6Yo3@^qjp^L*{xzObzr zryC&(y$v(d)~zYjBH%FjxN>oy=Y@i+!<~GB&M|M?E6=W?|&7 z0C^s#YhYW}(o+&Xs{;U+U6?LEtE(s|6Kp$xV#Pz~YM!sUj_N z`qZ%_hYptF0n;~Dln1!~6R}YwU(!9B@Plp<0?17f;2vl08Vr|khgN7BDnuG;LGb&T z&!so0OXL-T0-xAG(GqXvSOvMe`O49vg~mM(&9DqC`x2F#Ci!Bw8Swl<&>uW%an0H( zR|YJ*${@GhPQ$gTBUuQvw5QgFDp^t6%YkE#+i*$8Z5}YvOVCVR+;e;5^|-7(S>AtJ z3C+)PS{*FPquhV{CXeQe&YL`HVfh~qkCyg7+j-RP8^B)5{m(j&9xLjH-lO@Ug>Xe> zMc8x|#LBy)qnh@NaP3)9QMn>iR`yov+VjT%7Mj!smUi5|Hf$?RSMwV{mo)S~-Sf=J z@Z$kYqOiOdS=5G#k z8yP&v{pT7Fir*;eN1uY}Lw`PgiII5ZtMexGR^B=WNtqd@oFSOJ1>8nm0 zJG@%nn@qk6wrARW$>0U<>(}*B>n42ungw+RxpEEHe`N{RzisEwv&P8szfxGmEIY$` zdZUQZdN1jwSZQGPg(^2wx_Cgql4dLNJ?VGu*h zTzB>9lWXhUPSE9CNq*vY6L0cUkrT{+AAZvBQB0e@+--`Lp9<_HewU*2(=|o!RQ76j zD#h(3x`e1IdbLt|FXs-R9|zoG7Slc(z6FNOl_5-<+;f^2o+7!DG%U>JY zofzbX`{iYY-;Moif!vTuO#b;w(Hj)~@FY{nm2V{kXOiuT%y#2j#D{z(a3D(sp8Q#k zkLT)E@9yvo;{If+<_!z%~&@40^O^`*Sa+8)1r`MdHmkMBlao0NDBbg3lXdt4CyS`Dhm z$ufZaF)hfou4hFZWeo(lzZKbmtooFVTvj9*w_6lY%bYpLlEYq24pKH|R%58&NheSW zSusqUN}cL*c;a2#;oTc9yHK>B*LKOR_bc_PLOaA2u_eKZ`9k z=dZj4^Z$WbxfO*||75)Cw2(mTVz9DezP#6F-{YtK2wrqJ0 ztF@49O8~X8PC;Vd((80P*6E#Bv`*W~^3sNA%Vqt)=R)aTX!}ALdWQLWEPCb~^vq=@ zHD0^a@bKpu%7){{(~uJUPVqCkSD}D|_%e{9c|%|rSF0S6(n3-e6UNJG)!eM^5i_Xc zXKZZpaXx+S1RoD@4;bm2JR+6TH;j)xh59DINan+%dpv0H;|+)xC7{`ph7ttiE}{|( zunB04j!X;Mb}&s-b3p8E1;eVmUQiR{AF_Le44Q`4q3H$CbnuF3iVSDP_nA$Qfpg_g zCQ->rVh=RUBdQ_CEGE&EljbpdrlCpdm-+jk_52v$WBe6D1eLEu6;;wDvA!|GKyO$Q@ExQlwI6iXq zdk!%hh0~nb*app!*HA!?K;eSwOQX&aBR#zsq5Y~AX@ne378#}`UomNtw*YOtDNZ3y zXZf}$16tMGuCGGYK{r~0GlNGr-hN?$H6?QF|I6Z7&%J-DCrLza#>C1Y6h(~cV@=tL)=(b3WA(dmgXg9v_?UN5%z z`rIx&`Cpd~Qxm1=!2R78KD|SDC+P62s&7j42W)&gfmk4i-;%a4#B#2%1R{RFmN=xu zlGGu#j`en!Nme$|9pQt?rro<1w$09nbSEY zd-pSjcH8DesluSo&QK{a?KEF<29zZXZ5?OVZ+uvdB%Ats+uNFklfxWG?>ac%DLe+c z|01_kNDg&G3*?ZjiC!N=*aP#9We%k$%lt!0^t*W%=CMFXpK+aDq5}$x%XQ6L9*F*$gV$wAP@Gn4RH zIS@~1WZ>kCOvw)_aK_c1X_g>s9RfsI_X0uKSpUOndSX1;v~&B`E#rG9_7;T zXvyp_jh3I>fHg++RgtVnKoUZWQHH{T>lkIWd`CPLA>{!C9E~{KJlixNG7k~At^wi+ z2{(lpGx{lF7&jK0(N`MUMvO2n0>6R=|g!|GRfpl%}PefCBd4YuyUiu@&X><=H)5eWrHc0 zCiIm8CC!M$fMm`?GcruyFjRHNMga1Jg$U9te_o(tdM4R)9C_yt>@RKjN0?D<=v15C zkF{cUzqVGrdDcIz)i}54DLWwTPuS?o9s=^V7uujEY!C#*9&ZW+t-~Y-VeU|yf`L6& zJCzt49N(hWgTnVH7%p?_)WqmWp@nbSEj)hLvhTCAibmI~HgIAgT5EgEnV{w1g5;#@ z99)WQR(RFK_n0>Xi4IYC+GN|UHV2R#VtDLT1Ohu^vAM11r@%8`I%F*&$=1wtv7;6{ z*_PyQcGh}x9eyn9K!-$glg~dY+SZ|9Phe+7Z5`g7cVZ;o-=&=xi|+|^@QbW-a4fPZ z?6v_dP~TSom9)_w{d8JlSJ*UIY>3)R|uAa>wAPeQ&Ux zKZTTX%LUx-uoKuH+D~8uxcn2`9y;Eab%-xO%-L;Zua~^lM7%-Xm953b`y$N_8xiI= z(muJpN7oyf9nq?q;9%k8Xw9cN5COqVRK(>9ppbK7q6if2&DaKf6=QmD!)IYZ zhJz`2)@QEO`K_}vlM}^U7^L_>+lMdzs}#dMQW|xkQ2PNlNjKsq37Ii3Q^CmRD z%rnZ@jM_SU#J61Di=QXdQ8(^UP)XZ~O5n1mIN(TRdUCM8y|pQ!L-#W1BA<`^J=EFT z$zu;H02Eh98p2CJc*m#dhROc@JWa&@6`CGC{Cp-|!3*=D0^kJ7Kx_3rAAWXjX@7Ow zaO2eRnI`#rmzs9&8I3eVy{+4?oyLHouoZJ01s*lRT^x@(ms6rbt|)a!bOK7U%<4Wa zIdqgtHkn5gwdAh=0Hd1f%b~`243rLs-6$bR#eGpy9HpvFyr;zU&@<1z@`?rdtEEBl z3%Qy5pRml}7w=~_;zh
      |W`j!5PY17-wAdd=<*M(j_BV%SnVofeX&)b3)ux9xK$T zDc%OkP@8yRBi!J@sls?g^ZSEah(8$)0I6}Oa-Q+Z=b1M}L!^%WMFLmtKC6|DLd9nL zP-Rw96bDM0(T4)WxJ#x-P+Wpb(Xi9{VWTM74XF~WJrE#>fy|vHe;BM#MMpW2bo(a5YiK04S>H%`gM`r4{kq%+zH<_oxz zP*l*3od4O`)58Df816R^yD2*EDFOB6We19e$TBN!T7=J#&6hP2P#2_RD{x6Pl1Vqz zN7|xoz{REEa`^|0PZ%y1I^N0n{!?QUsKG(_5?q+xVi zi}UAQY>l5J{`Bc;Pb1*R|UG{UWN~%d5PV7jMYJ@JxzO1u%{O(vAkZy`xh)vSCJlQi%wX# zllkpYc_A9vw`XA+og+)EiDpy%O1@2{+`_o3Lv1Z%P8G42gfS*h%;q06_rO~>42@{W ztS`{;a|{-8Xb9iJwXHG|?nARYGeHMsd5SX_sr80FFiC5@OQ8C7PBSe0S2aTH!J=<+KJ2Fqb(&PUk6 zU<~2_rl682439P1(Jhl$<;H6?(wuH=sHu*$Mu|vnCR4(Fh-nJL<{+E+J_hwxvWbzU z=%?}NJ~h}bDo!$gA}D;V*EsAT>p^iLFdXs#x?u-EPOKGlK&X!_Q}K4OpCX;Q$<*xR ztzm9#p!s3dhds3=9cj(DT`hcX;y8Y`0LOC-$9FOuUHLe6Vq+B)C$?Bc(V~pXA=$;7 zljhn$`@?EwYj$j;uQxl@I>nIn@HG-1xcsX8H`*EF0Y=X|_!)ymC>`Nvj0Vyq%pmSt zaLR~Z!zqI*GJ|6MM6o)-ffjhcalG(XgatJ>iz33J+OrukEvDPrTC}y~W8cf@WEopn zVq+iUS|dT+p`hrjqO>iziws_mpU?)UlC{F0F*=ol<0lerbdR=gYjgiv{`lfs*!Wx3 zSzO9NGb%3Un&9y933>}KpxN!&wQbA9SYMBAmVWy=vhD8^}(UHEMj<#ZSFT{sOrTsCt+&NNpgq+K;+}qiB zv=*r8>6V;MzA!LJ3X$ZtdmlwFx}6%PT2BPfl<7$EZk9gGlcG2| zH#s*mWt*{Yy*0RP#`}FomBX%u)c+20+iv+L^_$2ZigL`a2y`&?rI*- zj2G7*g?Qb`@cJOP{5f(KIU-Z2!^?(s!8Ai`r5i_JCo~*=DCBPBFy*b;#>EZBSSsi%@dgkjo>!Ci}3SZ4DVke ze)jA9Jc5ibVDEf>_Jf~8ur^uB8axLp!qB6 zwXp`=4z=?1-E1z%w5J^qDfWh9L)s96YwW>=n^2vaH8-oWEpfUoyJMBX?VkSt+}g4h zCeU#!!UOj*+}_XW)@SIVkfFusjNwC(Z+clAEVAr9Mf#vMx`{sT$-*8e%}r~4>g4L7 z-8;9=UCCPC!f=KqOxt2f^Qx%z#C#xJjthC{)=j}RC`?wF1@1cw_Kn*Z+&lS6BWDh^+0Y*J^IXiVME+`^d(o~dup3Wk3GVJN1 zKQC!NBT%rvw>29MSEr*ccXfvtO-S)DJ)uZQr*0{o za>hhQ|Ec$#eENM?J$YW;_n|*|=o1hA&kyVwIR4pPv}aA z>$;puyh99ge6uaX6JkQvr_?D9h1nFtY`*fLz3;wmG7zqGicOJ={#ej`>?410%d@#x zbANxYFB3_4b(${^9+qJNJUPRFV6dR1=I< z`*K~oF02fBlsNenS1-S+JjvhgtkQY@9)234n-}42&v%HxSbMya#j#VsT+Ui-Q}P~m zE=W{^jKAgSr`v&y-coR(t&Eak#o8TK8x|KOadGz|a$=8<_Vr{liTY5$?GhKH1d#z|irFPo;V%tWh^iKGuc1IizbvSB^Y-%Djdei0 zx+ESux_n^Iu3{J)^vuWiJiEyf`4Pc_bRC<4m(M`EEf}<+Ld3?tZA~Ss&4j9HnKR*_ zslt@(^W;rOgJH>kS`-B2zgTY;XhQpl=Jqbu7blYR$&-?J@|u&^oW80!fheIhn5ra= zZvSsYqpMGEh(_GMXyN-i7~lVn>b)9uoveJXA}gbeqE0&R7>VkUc@6GEdvPai1*xEu zW0iCiliFDh!sMMz!#J#VEJ330yyM(W*I#?$*y_rmgZuXE*uHqx(pCA=V&o6y^3CoN zEb~0a=J_Ee9UkjEyOA0M3dNWwMKNgcPui^V1iXiLFlV(+58PDK9FDB+-?w;T=|n!> zMh@}fc;CtJ{w%l3NX|9n^W~h3-64IgkjdUiEr=3&W>ukLl2(U8#hPy8{aD%q)~%d; zs@b(Qn%COZYp8o(YIc;~#*okaHM#JUJGYZ3X>O!^u0D;5L;Dxkme%rD&N{aOxw?zZ z?GKn-g{=HGi^N?r3fbs1&yxvCHCAb6T`MkFa~y`rf}00&SnWA|ispFxZD(&hb>Z}d z^3tW{q2WBreDxODx`oYkm%5$iDbDLNTW42aZ>u)-dj5E~!WSk8S32IV9r+8%O#^d0 zc7I@*-)(GuA2Dnfx<=^JXNj^_P=~M(thGtBWutl|7Jb;G_c4~s>|Cq|Vu_iA9Y4H^ zsIk2}cPyS-I+c$+Pas7yhI-6TA|?ZGbu74Fl=g#GpEGc$xV|nO51ti?-Rr{UvgkRM z*l87tfLC>(fT3=CCl9;lEz=8SAasjKF9yJJBpuUcY8j11c)$$eSu)ir-Rn z)w+O1!4MIVp@YDff~#lM-7q>-GPDE;mJ9b-IY>lk#O_KWPcT`=Vkk*(Zg=YR{_?u^ zCoRD?gA)oW8dMZ9L#c{^W`?rBwN)V)-Dv<(y%{IJ?amh^46+;ro0 z*Os%V!=^n=x}-qXxIO*m+8gZopK$Fo;R^vdwm(BU?_8*9nVLdII|v7d=(Eh*`{ z^-RQfDZGKnKN^+aG$~2VRxiuf0 zwtH>@Ds6UiWx=rHD4VMNIBJfF>(;g{(#I~(d!Jfp<*v2}2(tg$^;i0_V*0Xl;J&BIov4SJFMFkhxlqmgnA>;xb zzgf_v?GEN2?n~@Sn}d!0nPF^EqQ$o*0?QMJA1g}~E^|ZNiSW<^7vFl%-5YZyP>B^& zN7~Nz0`i2@SzBLI;aj$I>!_h8Sjy}(l+aGQ$k+BwiwB#%dR-NKzFwdH&S}iv-*xh%lY=!|LXK8bjR4}Ve`d+ zKbS8@=MQn&#vkTB5)6dkV&k6b;;tEst9k+ES7;T_*Ly=cr>rUcsbh>+e z5k~pLxPz<^8iXE%bmH-_%4rDKr^2nt3U;HK3@5eA z)HMDS@o8FOSE!EVOKCCw;QzRHV$1!Xy^w2@pTOs;19$C6r+3_WKoN4iW7odt;OURu zGO0ZN`lXzsWy{*wp!aFL#?RVzLXNEsh;)4v@7bQH15RRxT!!;7!IOD3y z>$@32FEDSAU>$GLD5g<#o^(h-SrB6M@<36ll*P#jN!-12aehvn*gv_yzqg~U74cY& z4Y5ej@AG%34eU~z>cNanc_o+ z*pQ@i+b@5|QRif1w$pqcV)NZ4dLJf|Kipzn>->@i&dgSj2!ekwa6Yu*-3G1qCi z(FU!}sfNMCV7NV;_7FGduw4@cuouK@@N1vit-(g5tO6E8sPWBtaMQ_#mP8A|bXj3K zKUx5DH^aA8&1f(w>_R~BuMJ?hnm{=fdMu{n=lpg7tX&LNr`l%D9Vj9?&pz$e*49pf z=T@{BYocY3O_uON5^p0H#WrvQXc@$g#}ZsQT{jC((Mb}8Km>VB0U=`x6mU@`Eh4>D zTT?5-c}9pJb7q?`f)~aJxR(_9xC?iKENlZ|(CE*YrC(TV zYK%oQ&5dnMZM8MgL@d$T>~_TvmmxVF=~QzIR7d4-^FY6&s#1g^8A&GOND6Tp$!=Ns z`ZX`*e)Pl>xz}I1=9-s8#}iM8%1hT=n!4$^2lu#N_q+Ez^xWC&KmEWyzx*%0eGhy} z`h%x(-~Hl^H-1qJJoS_qc=_zvmvi5})VcM6m+rdjr3bb;uA9C0*;{UT_TE{{6*|y$ z`MZv`9eiX89E|PixZ+4 zl+&q}DMax@QRBB*)QQi?D>^~ZG2*V8{_ghh{H4!7Uz_lWr!sMGeOT;rCu^R(^iti- z;=$hGaq+&k(R9Uik?2R>`Oc3-BiB`=M<4Um_cXs>{$Wk@(wz%S&5O;_yTbK9N=@wQ z!b6aImCseS&h{o_XU?8I6HE5awjx!BLGvd-^Jd}WcAD4f;Ypm>P9pY-jo77Hm{cy+ zf)-3I^`l1Dh$!H#N7AIHYh8LqlCk7QsCQWEzVv^WrP)M%d;-EMEwOaVy`GvNy+=X5lV`I%Eq>; zST<2vnaIYf+8Qgxrz;b!Rq@tDIGkvWSG6W8%M)7p=c+8V%~r+R2ufQ#?=$#RTL)Jy z)}b9M@j3fCB)qug(H~WmT#0h6%(W=jimgVu2HJWwc62166FLSv270@b?a8*5W^-M9 z>#qxf;5x(+24`p$>H7YuwO7U%y3 zsj>GRgWY#Kw_EUMN_?MYw|oOXBSNkc(Wnw#JWB$$|FclIP{|V80h#?L2vx!&Ho#0g z774Qrkng9?J%CBEkldCeD<~}l9DmB8i$BEYMRgmj9Yh98ZWl~nKkOaBvF7wi3@~0k zA>4(T6%`etsIz=iW1^v=zM?J?7DHmFH5E{r_#QrX`Blfau!qCmWN+O*tj*(j;B!X3 zDgm>lTSVshd2HV@s<|LB6J~^6N3*(|WOd0#(~AEoB-bf2mF~5A0-^HBUE9wQ|dTgyMdG*r(32MNia&* zm{A9;U_wFHR>_MknfkhpwoG?Rce1grxxP7)?o4{QO%3RPC%*^x&{3gL=p;J=;fr`m z4?7HyxwXi)eU|x}*#gtzVk}1Z#u{UZ>Z)jElgl0Li0CH>SAu6INaD?Z|1dj6WCyhK zM2GmOc>cu0hgvJUc8#CEIC1T}_T=vQ}r2< zac(FSz5Dd`o3=NLujD>;d|&fKXZ5W$T{A89Lv1x60O&*bCt$k}U*K<0=qXT061KGn z!jRgJH+z_cgzImI1Ei-z2J#+A2*=b;8CVRQGw`GXCR4c5#g?An)?B{q4B_}(F6OI7G|a_I0eai7lq-=-;p~I%R3{yOAX>QDFk3h*V3T^;hZ_tDH!+!( zGM%D+H8x9iOW6??3(T3U1?kmwc1y$Rgjtl`HTLoI$KJix7wMcIyy~2K_Px9Nu0FY( z?DtnywoR_gjI2yHz4hYx^CPR%O?4ytMGUi1+3UcF({_7phHvZElpd&iVof|;IHpWC42q8YG<%>N9*F%)AjEuxm4Qa_2IQHAc(;ON-v7)u)*QeLyNGChe z)79DDoN8={$I^bKk#y9fmoLlTfj%_#>@RSQDEtOA;;cGd=fVLITM?bG=oAlisKgd% zBZ3-~u>s@s+1@6K>h$PvZ+F|)_N`*8n2jUTMWq)*FkQ~ZuM)%PjMHE{qd~vgqtih1LD*-Hm&zR=vQAi+b?xrWUpu@zrnNiqf(DYaUoCBw{IzQS z^3|!;+*rc`tl3uq>y!R=W zGxwysHXIGtxpN;;+)uqX(i{*c#m~q4Y6iNcit38j-O^Ka^NC9z4pml$q#F|p^_SM< zAB5wVUgbE-Uj^^^gsj?(gRv+$#N$pyl4TXHEa=}^G0K6pICVdj+u8n6+-g2}M_ z)#q}x&pjvpt^B>$ed3?xTIBEL&WewLU-rTNxxn=k{!EF#27*Y!5{%#7FH{gA==lci z7u5>hYVZs~+_?rDh*{coY893ozmjv14nO)2hgC1L!sB5VC{4TxTQr8TOdas+Y#o=x z8GyQHKRR9mK$)Kgxzv0r^h7G<0VdyMnU*X)l2$13|+0i7Ad7_kH1k}y$*m4 z>gwZ#+XUCumE3B}rklgjG$esMu9$laa!?6d7&a^ZOo^YSxl7aVL)`p4KPd3}DvhL@ z9V_hAKvpq%_P99n69df0ycXI6CT9P$jRWV3!)m-Wn`poz=HAv`?o5rOyZO;V5_Vnw zwzz=(A|NCg#{-pR2bc@@5R$~)K=U#{J?Qqd1BMNuPFNkZ(4{=xFd=4js&W=bo%pU$SO{$^?YM*OQ#CNL0 zA=zD<@kJYhzKHz7!bd;y=xEB@;BGp0{VjvBq?_#pU|PozU|~J+XIeOZ`DMpI8r zRo}Mb(+Nm*2*)&`tr{ei=COoZ>+-%4x8hY1HH=_Ze3jJ&#ld&GIyH{Du0h!{^r?K?;jh66vU-PPcXsa=rY#xDPmy4xqnf;W*CV-^FZk_tM4B&G=rr-)uve zQyXe4PNA*)`RWM#$!HDTo%^_0ty}_SBP{2gxD1swCoYC7BzLSMG7wHb`p6^7r62qP z>7U%kAsnC; z)Fm3@Cviy|49>s%l>XOVk>2|N{U$srzf1X?!;e1B=b%ZkmT2)PwQ%?!!0$rt>vHt+ zQT98)bap7QnNZMAekC6YL`Yb;{HpUH z?&>|v2fHc+RPXYREn_tyq#*0;&>ZU6{>6Ud1i}WYij#qd0|^}@wPVW2aK6{mMYX+* z-yMJ9sjI&4M}Oz7k31wk<#Ug8-G6l71IPM?*51B%@4X$}j)2cslNsyi-8bHpn%vtx zvXJ!4KO8#sjspkYacW5a_tAT99Qyybdk+9Psw-`~sycU1_e_WBnmnC*f+mNaJUx<- zG$RRR2@#bLL0}=l+9pY0v)JHBlnwT-*Vy0ZfD%GrOb}s_P!^ypVGOomae~Fd0i*8k zJ#Y5}1!Qno@BceIQ>w1Ib?-U%+<5N2v$_I-u30Tht}|Vq<9YuUXP)6YTUVkZvGBHO z({EdtXsPP6*gW~3P~SyeT^IF*3QO(Be>L^6WIV7eh7Z!lN~d=8&mOEmhUK4dy&ws@GRjSXkpzpYi2= z@V>TLyvR#vGLSla@{?>n=p;tVNN5WOnQG z_^l_|8S!G2L1qfg8fLaMlZGih6`LSsM;OlH21jtjP{t_}Iy*bZc8-ZxVBgxP)ta4; zJAL@$8GdiFYbbn^hEO##!si^?>B8^o?Cb3u+ch@(fiT-0nea-Wj--V(abqmB5D{EXJgEU+JXU(Gfik{(A0*GhW6IxYV1l_R_gcJaa691 zMLSUYBeW0u)_8U3Tk!nFx2*UUb~HM}w;J&+>;&A=*m1^hm7JU|Sk!D-)W2u4yQ2X| zl~3-~3^r}hm|VQ2+HJk6!A=vC>~_L~$&;QLvYrO)@oTjiFb-x_ZPo>{dOfpL>;#cH zMu;qHLJ4foXRz5Z25OM^FCTm#TP=!z-kDw(J8C=K>#zx|!1{~tOX@JnJtE%n;$M#V zU;j~>RjH;#mMalEbFR-(d^X4RV7Jj`Td9GrxLuxk6n_y3JgVl~r zm}Ge#md&0dH0KDJOV*h@ar`(rQX47|8cwbN9jKPWnEqPK@fTHu-f!gLo#&Cx?PDVNJBf0@b)`ypZe3N8uR-UoMq{^*a(4$;Zd*4D}jO>OOM#i5jS zH5DzDE#;+oE;X*j&m7mW9}-uSI8LE5!A5-&SCi??as7yoXX2V*T)R42dlS89iYwPc z49ivXDBp)%zn{!)MRhtB-dz;%;Isq|0Yxci#hO#uxm#*8j48pCQS)N#p*OP;q9}O+ zO2(0*PMq#V1-5jiH!~>_nNP(g7Gtn0&WS0Jf)kNNUd-eX`bQ3@1!F#vM}Bf*9>E3> z7zo46sB^f&v0BX-Nim!0#;4#|IY|IECC>CzC9h;UuOI(iB%v53NcNMg>@2A4Mtobg zjy&mul5VVb&8Sd}5$9I*bhNilO-wye04@qZ(w|yoJZk)k)PKY2*CI^+^(Ur3CjEv_ zU>Za@#U@79gT=`Ye-P6Z!xbh@&Jzud8{5@!V&rUD`~58TKyjJ=ljQ__3Sq$&SquKM zQmovYbYM~R#vhn^XuMEcf92gmz5{P#l;ti*!L|x)T;(g#`dBd{5q7)G?39;=jlQi7Q|l)A_V34e%v4i zg(D>pgd-=(oF*9~B9X252UBs<`_in{WtYz}eVrYR^~2)Lk=ChTShTeZnn=kR!uit(c38;tk;d9l^`IheIPW439N&0obcgJUJ9 zj6)5-W&SGO`bgobQ_cD69?RAd-^S3HI`yWTEL&5PFx)lO_%(HpdD0obn|;GP32)%L ze<4gw*<{Yw=JT5tjOm$;@aMspf`o$qZ@T$rHF)#Q@_F@P2@ua4zoyM+94ty{vIwJf zG7L8~XeR@4Zg-y1iX!gBKqN*Cax)j;0u%_u~JYqt6b-sb4+kx=EoG{@Q`&=7C!OiqNF%Lf$}i zfnF8xcmh>=L3O}u{9<+gf<&;rLKk<5#De~6bwxo{xz}4>RZvhZf2EP6DYGyiw%ziM zNEzua^tp_Z?vp-f$VAC6&P5U-&3^Ldt~=-2fxtBvU3%$7*8~QxwOoJFr&7x+#$S{e zJ$?G<#6{z!qE}X!3$$-rB9KpZ%wCn%5Mk~ihk?B?lB#}n(q(-mD_o)W>gx88Yeh-l zr8u*ufBtZ)=Jz8J2+MfC_HEPm5LP4^L{8DvrJP@pX~?rQ2zgk*CT5h6@Fmmtss~1X zX+XsF|J``2Ri7)mvZS@J zsK8=!m>Rk*zM7t?$+Pbnt=n9t9FwgiR#&9oQrsmkunmFKKPRv>MqC+X)=xVu~PFPUzM=`@pAf~O^?sCP5lG(UI4x4=ZW6o zwqB*i%M5S>@#U(u*jrLEg8GN<2D9B{(TfVLIgY}~GdtRwp!LQ+wWuyuV#~2R?fU3@ z&Q4C1cq@*QYV@R@LUGsG~nT8w6_z?{k9Wq6F!;shaSAM_s>eRz3+fqY%aVQdocz+n@O3TLp ze^l;*ibz0WW*nBKH?=h7%V}BRmhgQD1^+wpT_{K#fe_AmNx;+*b-*MD|Qpc+6K3Cd# zPUpa~z)YLdXv_15N^4tum)Fl7TRCZ3z@+NM`WSdeOWgM0d-w2r@UO~o(D@`Y#3pi= zoFOMD3}_Q@Xhukyc_tsKaalVs?`Gr91go?`kwm_h*zp`RNYhYn(eN7@!Q{S3;x9Y6M z;^M}$sw&6U7Z=x$t*mZqtFBEX@IkbnQweoX`d83ZO~yCIA-83Mo3Rpq(ZO5<>8bs5 zAI?lfo22!Nrh9&-9j>&b)@ggvkDyE_Op4z(@{NYYXM?lc8H0wIwIK7gX!l>6I_J89 z)cfE3rs(8vd-p|tH=<15h^11Pf19{YmOlB=)R!zIIXB}|Fj`g+77gEq5@rnjYEUM^ zPr@7ahVvs43mio=>qKI4mntnus2u0QB^p~3$o7!BzZG}1J;e=UD;p*i6ijTW9NSR5 zG7=3$w3QL;p}+E?mMKkz(Qr6g*fgajKfk6yt&NxFS2d{(HJI6Fn!lTsS0Xcw=7Gc@ z>IHz9d}h;Ox7>s=4Bwmk$Y4nz#Ul#XV9Ryt_pUvD@xb@KmwFpPBhL+%Cs^%uS-1JQ@gdD>5WQ} zg2M?55J8VyT&cO4Z4u<`HkvTzgdD4=;?|GiTh=^D`6EBz`5E#Ttq+z#5VBiUu!O+n zu;cibBDF|*A|@;xv&1luU5exOFfALi#KpE{DVe5EnCH6DnhZr&YLP(FdV_1;_=brE z1(PODoEDsj+3+fVS-eJ7CkCfY6me6w514+hEwnrWPc`!fjC`REk0*3q(;zDrAw zs(z+4R9fCXrEb(HxoDeGS5sx`(d%2g!|~DeMN8FKSZ`?U4poe+^jl4_ z8t`571|8m|A1iG0H}rT_Q#cNH=A~*$SdUjXg(`Zh{a31`qKB!bhqZl{>y!|}4ze9q z3rjRxq@yEQ1L~B*FCpD4>BK^@1HN!>IHq1+1h@ClS)q$(E{GO~s!8*&w`InGo^BBA$@cifA4Ft#LGdAaSgp(q8@{ar`I9C6FpGHm4WC zU#vZ8$553r*6o5UGDrRX#ri_m=_OT*E=RA5A`AXyxhkrGE*JijQeRD#swJsZFm<0L zKi_9rv1rlFx%I9U3l>l(>Mh6L)OM#Iggtg<90OeJ>Yn=sUVU}I zd~j9&t3U0R=ZrUK5p&mvJZC!p-hrR~bl_uz_a20?*Rme6ML$#gQ#hPK`^4VxsA|-` zjng}V!H(&TwVj={=G?Nx9_XrM)bwhy6IIp`3VEgAl*7#m+3 zOwk!){J%kFs`A?Llx9yqIU>KK7ES2t()-0OQa@SM|I=4t7pm*{akS${K8L4ZKi{MM zq+ZF`g{J7oj~o2yClHPRz;qdAT3e8p|##KfFO_mJoDn~_lrTHhLz9YJCn?n zTD4_6?Iq75_L6AJ{IqD>_lZF{$Gcy{@pA$2=a4=J6?BxdIYV|zx*;#u*(ScGP z9!QU8TN=K2U=)5%XA8mC<0J#OKa)+N?$wECMa)7+Q8Y^1WH&%gLUATfUy{Pl}%> zx&lcl`x}&o!UC)=srJgKm3j ztbVlDJElI`g>tK^D_TFs>m6Mm>#Ek(3uB>RJRS_i{u~d=MKHcA*il^=4+P?c)yS`% z)rA$oU`1hdXL)%%ULJ_W0@=TiGji!3(@yOQ%OBv2Zr)&FU4fQRuG(Zk#Cp}Rde&TD zj%Dnht~uB1#2?Eaboa*82HpJ#-!)Ff3e)TGZgS!}*~v_&J{O>EXwViS@3YU>En60# zgCcznG=G+kxIgz1Z_pcH3-U}~HD8zcs%PWh9_N{0U*sWMe0pDYp>yVRI%*J3K5>J#FjJ^&7MDh_NOX)tNiqdFng@kmL%u(W|}=1pjfOZmY+y%Z65R` zpJ}|uT5WnR^NjJH%roZsvZlc0v|z?%Y^HBFGJ=}wu&Ex+V;J<$`3T>+3eGe zRPHaf`-UCXFSD%v@b_m~*TS%X!$v#k|2I{?geR6}z&SF^hqr)iR?DYBX6L ziKRch`jU;``_^|>&%ghUJ6?H{*ALFW|IRxsqx-L(T2(fxWmMVhbMJZ}dqEqy#`smM z!}JrSM7d?+y8Nlz=gE(7e=rz&xwKKzRSw5P z{EQ`DM)Au&FXNFT&%qevF&SRVK7oD~Jbq=@qQNKOR)9mY^;csn58WdLe(RsG-hdF z^exTV71ni`mB0D!xQybsaE6gz{dS()WDoV#^bQpDUUGJSQK-o8a=10@>&#}fP6xH>`Q$L$fppVxa?gD2CN>s$jI9J_o zu4SCgNzN+9#&U6Zd0}eJY`~5MSetG{M+JKqVJ`-8Aheh@3s#|-6~#P59PKbx1t%V} zG7-mEDQI-oMeE8+3jAJouFGmx!fMzq#o6CKjmCK+(^xnwCpX7wjUtW7ciNv9c6!4*crsuGWdDk=6pAZ8)zF_fEZynTdgX zpPFcz-WdpVPH$?O*@;%>%%&wRt!*uq9|XH+x3=#iMJY?Qx&wfz+$<>H?oSKGor{2TOuQ*!o2cBJKzm<-zaGF@%d9g<$#U z8)4*X92PK2j}udK7>bu3C%YetHW8NvNN|>$F#oDlhMv)7Chv7Yz}Ssg$w%kS}AhpF>PlP5Icn z#E+sDwJSfM6&M+1iSs{2 zRVgIoS2;8!6pes zg&Ov^M0*=5k}?ESP}rP7GhzD;X*kc2Ei%yT!ML&!4iJ773$FbkJ>>J|Ns|X&Ue;5Z zJRdvS#(8IocBY*9AC?v7zD=*FY3j$k0i}bKJ5Bl7;Re)PoY%Fumt9@dQzb>s@@TZE zKHv0;_SHWXloi$X#!^331MzCzmwF5(2lCl6<2*G@+2j0LEE`dMunkS@LYy8lvw#>F zk^QAGISTg&T<0q?iSN!7IDh%;#(DU9Vd>DE|H>RVWFbl`Gmlzt3&05Rc^?7bB?{dC{z=xiJdoH zWH-ICQvOs`MSD{!Ouj1~=!}0wZHNqbd{2O25RCdj2QK=1R!#CiJz$|L|me=oV>W zQ2|$u!PJo1-w`kKSq-_CqMUH0OC;}f*H_fK&T$!I;nc4r4Ob$iH=&=DFRcqWk!y;y zmpL$prZT)qxp|8bo+s#QXESOr91UhO>Y$MS!ly-?&b$VEdQNWk)AH^AAEl)ab;~EM z)k+Y0$q_q2->_SHzug#d#a63y(iyCf>B55jEs~>buKog(uk%x%%JBu42L> z#-SVL%nb~+$Ya5*BM(~7CJdEeSs7N2%)lR$at@kACS?+~Sjjwtn^<^;>Ko6RWmtue zV*F+B$+^jVRVjh%u*Z!(2y-y77F2`T%Hgk0vvF=V&7byuar&?Q`6JW(KP1~8*s}xe z&phZbmt~#wRK@+Fmka+5;hqaiOw*k2d2Mks}Jk}8`R?(jnt_A8J3fLU;zfsm!Qj#ctgCUEp z{ypN?hcr5oM)4JJaa})lTtt4voG@~!MbEagbGgUSk-M&RI!qUsto=6krFVV(%A8!& zh1j-lnkm<@*u3Sa)q0O7ce&@_Z=Kfrt-0nESkAz5u@5qELI%YOe7n3(Z1FWH2DGyw zjiH8iWhfq`L)Bjy2h+faIN0t(9B#A?#^E2HPJ_~Ex>fsyX_NEKN`cl395Uv z9}=o1deRK#$upMUKTln8e(LugOso1UWZD$_*j8aj+pRKzIyfyU6RMWbd8yBwKW%W6 z+k#4QmakN!C*43SI*m5%7v^|2KDEheWIUNxkV$zo`7*s|_0)L=UsiWN>hoGRcd^u(qa?d2;>pNQ2KSqtmVs!1-JSzpwCejiLn%HiSg zMq^q7b3Pbd)KSM~b~)E%ED?)`4TkJ2Ue>z-ucEEbAF+wzBff|)<4pRu#pN~l%hHznpn30^?i&dTZ7(LL& zVXqIH`LeCJ{Z_O7V0=_?C92Jcn3G-SH$8Kepv!5 zdgC{-&sd}E5`(Q4HQD*^G(lo5xGbI?4ic(sR2mr=I>GQSljSFB8RjlB<9rz(Xun=& z7~D=4JIi7gUJbSwy$)aMqR&3|$=126wk;dD{kluylk9G@15KyIluP?&-+Eqs#W`QT z5(+oQo#cX+f|M!Y>zPzZlYuN*f7vA2IV~Z`hJEyod zIJ9YOTsDnOjhXY=M8h=`zWlZD=y}l_rpz1jnP*pA^~{&2jZaREesJd=OkWk`I{p0~ zY!bVy=c%dv>MuvPYu1mH!G2UCs_b|Nb95}e z+?to08*ZK4Hn4nhylT=X#`Mi>i+FTLVK~-5{%c3vM zJ^w57o3PcfCpm4>xLcpSVcDiHoISP|X>3FqFJT%xl8NCoen{e)$D{0I;u^7eO(x2g zj~L}E{ytGw)by8AtF*1A|D)6>`!iYJjy{$Wz9@{naeF80PS+(%j=ye}FG%o4?xjoA z=Wd2v`yto2A=gfIVW#+Tl)(3=0n6i1&Sy)Rp|1$F({ENHsupE=} zispe$M=TbZ9+D!%CXHWpjui^P(v|ENYESzt_B$VXR89#W`Ie}uI@{KQlj3Q=gm(7G zS1RyIBX&Z;{>~O`K)_}iv}Qg{98Y+2_$A3x(zrYQTX2;a`W!de$!kwwV|FMw9*jov zM9GzzgI`8!^Hi+|Pguo+`GVFKZD#7%YSr``XO2|*$tqXZmh@aapzFThkHsSrpn2Km!&M}K`IeW&6+12Hda(7=vXUyCE>Ge#1`YUJ+rjhtv|pBfBsP=?h?wa73WqYTv+Y-yYAR&r3a7DaMq$4Kljo>}PE zqW-p|nJmw5yk^&Ccu#UlFJi-{hk>zjL6|?<8HM!`{d9@Am@0@q{-B(<>w!ISUWe|0jc?~<(v@o&+Lr*U zyYO-B01DYbUfSETfoJNMI3f|7d14dKFMe^!b;k76Tj#ZEhg#>~iv2iKCb;S$pG$h0 z5T>l7%B)Sma$Ly^Si$Mmno>_4Kdz2WHJh(kx_QaArP?8Rr_JyM?Md@BsQR%c$SM6o zakqke;Ro!_%(rH;88{xA?UwVV-a0?gvhYiD&b_&|!iIB` zf|ZTI*4aJ5aPJ($`+2U#!gca;$U3&BFqwmnJa$n7_7zEsBGtNK(^7n(m*oQVh30lK+`(`Z=r3A zvn2mhzw_$>{e$ZYb=!7(kzReLvI~2U9N9q}g`QUdv_>Qcd zh93gHBg$-gM-8QB-DWgjJ>ogTN<0_Ba}KM>jwid}bQ7L0(4{5}X3RCjF$FNV7rj^A zhZ);k+kUIhbLq9(;k=+Xl>3UNU3;m=YddJ%9Ef`(ZuKj9=Hqd7w=3XIT~c1Ie$8F( zN;SYF^HNt0#!qzS!*`kIyy7?zYst7`#8uAvHLZ1f9P0Ik>&CnD9jRLl*G@2BVRfa- zB0+V-@wnZkz7i}=^&=@6yI6+sq@1yC%+Ez#hcu(jDOD4#^zbz`ZX2~+ekXyu}=I#~@i zBJfuyUOqN3eR7d!;|<}wRknOz`^?D``UhqkSEt_44wbi^T|2O}Ah$U6Uh$hw$Hn7Y zTRTM_1;}*g;9C~R!@xY8S-jn%opa>&BjzivK7OCJ`09*qFEHG${TR>69G#u{Qkv2@ z9zvSe;=h7RzxstKb8f3Td)c^gSDjsT+Z>~D{tVf+X7nef)znP;#Avymo>_aPlo{?a ziv6RjumP(`nJ0BGClC_M2vE()e;UHbpi*)g!e!UQtkbtXK%m7AV(#5)u$r?*G7}>p8Q$!Kw~(i zWB3xo@hahDfIHUmE_Rs$6VbqSnGM*{$?sCdQ^u?#%vpz2bV0_9GkLr;My(DO-V?OWC}b z%*!8is>u(TUudnb>`w#&iT=v^R#SLX+e}&FT{X6`cs5SA{-=Gn$8fjiHD3)2!C9Ry z)a_-NHqu}N#fYB7l~BZ>2NV)c2dHwTJRHOE7nrTWQs7fsB=Aou({%Tr&!1m0?xI9d zTcRmHV$IDd42>!u-Jf4Oq1kZvJ7u4r)pcHX!0HPY*5<$Z!N&FsRobU!6XnEP~G_hJvzvfq*#tX>&}{L2FTGlXR26$A zn$4rl6A)*Q;t8Y4jsHlm1?@7aGCVPZ>XrvA+&wjOtH%3Lumy zWPsFL8!<3FxKZO!V)26wyD1NeMYdhFS~;pUZg@m`^w5a(M|rXT8b|~)sD1T&>x~sFdr*ll#m}qcREF6giWt2J!j~#K$ zY;D4c$C(up!`)`HzeOfQB^YUD;L(GXXr^*bjH2oZ{POW3%=d= z)QM-Ct+?lwo=YZHB7-2`PsVueP7}{Kn=JVU+bXFBrC<41{JejoJ|f>Y4M{4S+mW}1 z&iEM=Q`t#5KQnszv0sG&6n_*$8~Hggnz_kfJf^9cBXU}rsw!i(@!Hbje7HQ?t!h+@ ziq#D5$y=03x9mx4OlH$9ZLsJ?)!0n^I z!*hVDGWLnpDns^p+7D!o{t1_s_|Y~Se^z&AQ$uAuP+k%$4HXvT7yFA*CipZTQ>Uhn z8OIw&nXX04{E|$Y2yHyL)h)!TD(F@<%!9V_xoxoQXX}$L_R^DoOBQ3u4m$;9e#7Xb zEZ;Vqg8)>+B*(AXj9}5WqX{!nC$?3vsJGQc*ito#jXCTfEPOg78w8I zTxW4baYqyXlvWiX7_1mIr3|C6ZHbQdu*)ocqL9lNZfWeniZws?;?rW)lO|3%{}W?7 z7o9V0=6NkQUAxjBZ7|>C55+_NEA>!CNWcBY%8rPPVIe%@%}D>}5gyJ2!;By*c=bFJ zRK~St`3iR8^Lp}J*x=r*=&EkUp}HUOi>888zxa2LKiaeZ1)rXF_Ji}d|A%aprs`PQ zn=M?pVV?S3tIKSRMB*)zn+ki{8xr;Am0GOAYV*ZH?E{sg`x4dR7RW=bH7>ykI8PwF zvo>P#dZ;GzKvs&n5VtZTktJevaMV}Sr6ccQgBrHmZHiy@8!4>VM~V&{)6`gHCO#7@ z`y@V?8%BKo-sv;_4DxDb{_#2_|6ss?Ga;GfDeR8oQoSS^)hteHdwrszy{DjQa*M|t zx5g_qtvOtsm^iv}d}~=OM;wksW{V-SM-gVH$c!yVsr}uk2Ni9hJcDH#Dn*tjjqIf( zZq423k3-SM0QvABIRAVPR)^{lwdb|vss-ZlVwsoCc6h;mz}ad_WN^_fk~4lT{h{mg$pja@Vs;9%$_m5 zfBe|dVQ(ZHuZUDcJ#uob)Mx*K*5da}Vk0Bq)ojR>bWVIGfp+zyUKG>8p_m! zBr9aYDJf>O-xlFeUBuaBH)DnmO4i3au=+txQO22QgAXYa-v~bm+0Pi)7zeU~VI^R;OH9=Pv-DQR zCi`0CJ7~XI?Kn%ruG&9=-84|!IHc{{jgt|P1gx;lOp+9Lb#}Cksw%E5uFQ8A1S^8k z9GnnBdCX3~YkAuAjL2iQd@aVW^%*}cUsJ{#pT%EyX7XaP2X3xQzORU~SO=!1wL*pishI&%G3Cu2fA6Qf;+V2=|#&Ek#yCqKZ z8s;=KnFzs5I8I5O1&@T}sjnwTf6Ozf~m|kmXZmO*r zRUIfRh!x`8PfwoJtm>N16C@}*=*QNBe#ptX>NEX5BRz8;qF-=PsP3zL~Rar6Y`p$U4%r={x7XgYI%L00LQu<7h*PXygr zjXUIs8_c1k?=nAOI;`}mwV5^9ew?qR8j>+Md|Op*T%C#`9IJK~PJYA>wo`wAeq|{) z4(UNTr<^C#qu3oDLz*fbJ0@hVxhG|Eyu+?ptvy!Jt~4cTvo9g3aG2te3)yYiCm_*i zKg>d6PI#*kZ?z1+Wu27?@uR#9_Y(1FhKHuC`INZgvmX|~U__uuK&cXC*(5=#eB;zTIQ>-vqE~D$25jnSv=K3&ViY_Gwj{!Dx(ACVYCox==`jg$> zT)DKnG{3X-?5X1iuFLcPpGrf%`&>1eIua>Yf3!iJ;|l~9rM?uKSwCattWg^-TQc>w zcC8@wbv1WZtj<(XR(NI6^%rSZczxsZ)%IL(>Vcb&f2*O>q0P}=OL^73#d^x(_9ia= z^6cZ+YyW!n%1M34(KE*yXQe9rZ5)b)Jq(mF%1q^AWw~;_;!e6gb@dgCFPbxTLQ@1A zA)#VK+pJVPS5YNm@qDdOrbD|`%uji-vP?#W@Q=(46&{mz9Og$w3K*QjCUTi2pTW$Z zFnc+&3|Lwvcton%%ofqH7VX|U-}v{L{vv;2V)k|4y7=O6T|YZfh=0!f_c!l6AHAHy z(!%kddHm{Ye*D?-xJ)kl#_!`%)fcI}G+a~|);hz5Md3>;BdRYNPpxg6P?e`%lUId5 z#bIA%hv}6WUq5imx7yF2JHLC>;>8zCsIH!H!Q#cEy64Y5zx`Xc9QgW-_bXb?UokN0 zx&>2$-&*>E<(-|&f3Wmh!6^%_n>4WE{1)xznowa$ZCODiQXu~?t1T%E)ujBs(onA7 zpBpOmsa5&m;@mdz=^6fy4!mA zdNWv*{!g$Z{Ufk6{R^->{Serl-UIevWK2_%>0RK1e0MduhFnXoBi9S9_shGsU*dUG zUburDNFD=^(wNkJQOv`WT)Gk>T_oa2-J|GD2&@Sb9Gg=XC|ItJ6Qjol$(U zCjDnz*OB$S(~$l-?lh83e5;vk<(&jWXybKz`W-ykk$wa0M1C+rgZsel^h;n*`V}zA z`}5OpKcnqp~Oc9{3_w zBp8*Kurl4Kyv*3{AfmET9z0&Q+E>74fKYbW< zK?2xPGyOVP0{xm`LB9jbu)C`XcJvY$Oqv6B68 zP0*SwPkM>hFEbT;`OH3YKY4&WNFL&ohsh)4QSzAl3avqguqJ2$x_c8fp%L0admi}# z$3Kw{(o6bCos8gJGjt@3A^v7qkX%%cVTd?><33Nj^nxBDXW-9pp}O7x|)$1R$SRgD>-2dwG8! zxt}~h9wZMj4u{Dj|lQAA1>MWkd=L`oKvGrtB! zN)}4VLMd4&B@3lwp_D9?k_988T`)?<$T(S%{v+;J!&PL%dm%GnAze}L=W^iRPgv|vR!@Jn!JdOJ8L{W7=^ zdDW_1nLY?EP45Jkp=`9GJeSZOq#Rb0Ysj_aI&wYvJkz_G+(N!UZY8&o+Zo#(d{I)TB%2?@_PFBxG&nYqLe@?*n+Y` zv+rY;Tk2dJ>s*^6buPBpAf?W=A?FLF&b6`5wV|c-2V6^?Yl9wzQs>%O=h|QkaxHbP zjdiXKdi*o4rOvfMkMge6xi;3hHrR-SAa$+{HX`?>&b7fts%Y_TpRTG z67EZ#Yh#^jQ>4zdvCg%@Y9!85=h|R3LaB3Yuo|J%xi&@WT$>_wu1%3T*QQ9FYg44o zwZXC^K2qn}U|B+`b8U*$xi;3hHrBZ|*10y;xi(mtJR^0k4OS+UI@bm(6H1+HgLZ^c z=h~nhq13rH=mnC2M)oRpv}s=g4e2j}#`J8^j55j&9SI$zD?JX^US9i1oh(FoYlps; zgCQ~uz1yL$?}Je?mj1uEj`O;L->OdkJMN6)lhVGmLtnyr-f2KP*$#aPoA_2U*~&W! zhStXG_Vjo0Ob5yVJN0FUzBb~z8y07WzJ3ArqDNqd)?Neq((A#Q>51Sh=-RH#Cg-F_ z<9a^q(XK2&&2EQPO2~_muk6sWr07A)XEnKoTuZJa*OQM^CQp!0l24JF$mc1a&EyvH z1#&C7joi+Z?jU!PyU5+x8OM&Ca0Gl2eN8)Zf)2h+Iqc;#`^f#|0rDVuh%z}$9wCpC z$I`1XzEvuzLr!=NUU3HGMhEi1J75v4)q(Q%O|TTDr2{4Ht6-4#L!{WI1G<*CqGXJW zlNHc{1Gf1~P};)|*rtS2M~ZDaV4L!-MzV=-HIuEpli+n5uiGI*2XrlObu#2G*q{Tt zeg*77dF6nviXxJD=P^ z?j(1SyP2*%!^mYhaX&@qV1w6}+y-yE)K;JXu55k@aK)*+@3=t!A>7cM=Stjo0nG z?%;JNtRn{&_ghffy*bdr+hA|{Phb-DS`O>G99WQi_j$g%ncPCYKyD?sk=yy*9pp}O z7rC1u>>)+AIjE;3%$Lc%d}bfHpFBVwBo8r$hsh)4QSunt3^|Z3!huxZf(NZg)k zDOD$>>ZDYisCVR7k*X8*j$DgWos_DRQgtG4|2OW4RGrA%LXoNy<(RxBQgx!ZDYil&X_bbyBL>>y+`7R)mvMbyBKM)Grc(NY#n@MJQ5rqJ9yI zRGp|_gd$ZZ>KCC%)rnF?C{lG&s!mGPi5x4>h*X`ZUxXr6C+ZiWNY#n@MJQ5rqJ9yI zRGpNnlTvk|RQV0O6^$5GaG@>t6EKL@jtg=YN`2vioaNUj8G}W;AZNK#f%3-%Iqw6d zzHmX#Z-aHD)E6$u`7N-KY~owZWGn9^7+M>z+fmoMAZK~2lXtpM@4F!9cfcN4w+nLq z6`16mKE`$?pPa)lE+nN!aG^Yrbgd@WkZZ|x!GqyX(o#ZZZ zH@~$9mgRzWj)O1p&dZF?UOuyr+)o}L50ZzNuEXRJ@+f&sz6k9g{?N`l=)s#&gXE&F z7dl8U=_7Sg%KTjDOBlg8TP`#ujHRCiV0t@9ZP@lLyFyG53>Cp*u^{D=?S>*!PsLSWP27kI^7J8NjHJ>)3PVW0+cX$80(W~ z7NgaXrz}am1};xGfY+uw!RyEyk(ctI3*qC8{}besgBc$oX!T*lyN?ZkE_?me_8V*lw2CZkE_?me_8V*lw2CZkE_?me_8V z*lw2CZkE_?me_8V*lw2CZkE_?me_8V*lw2CZkE_?me_8V*lw2CZkE_?me_8T2}lb| zY!9XCp;SGr2R)Rkhf?)Wsvb(!L#cWwRS%`=p;SGTs)thbP^unE6@G=NJ3N%Chf?)W zsvb(!L#cXL4|*t752fm%R6Ufchf?)Wsvb(!L#cWwRS%`=p;SGTs)thbP^unE)kCRz zC{+)o>Y-FUl&XhP^-!uFO4UQDdMH&7rRt$nJ(Q}4QuR=(9!k|isd^|?52fm%RK2JN z4`cU9BkaY?F%2);*iYlS1Z6UIzC^v_#hAucupA|i7h@W)f-9Ka!kXEF^v~-XCc}rUW{oR0+(Xm#EUVF1E7p)cu{YP z99ENS$hG7;ay=-kzOXSN;*Ique zkK9ilAP!W6U)U1!1^-;4vSlPP>O*HGHW_{GGkDB#Svp#Cp2P^vxo)OLZ zs97JZOx_aB`e0>pUo`8ZW_{GGkDB#Svp#CpN6q@ESsyj)qh@{7tdE-YQL{d3)<@0y zs97I1>!W6U)T~bt&H5D4tWOcm`V`Tu4|e(nD4O+Avp#CpN6q@ESsyj)gPltJMYBHG zsZccQgPjURvp(3VP&Dgg`!y>HS42heblUv zn)Rb*--^*qL;4$_F?~MhB1>Q$e(3Z~upD)PAKLsW7$U>S6@F-QI~XNnXc76LO}SGI zTku1V@=Og`N7j=KNRc0U6gKhsX0nxc5)7w}*X{gz2jA*K57!S(^?`HJ32;8j0YCKh zf562Ub@8(=>{qU5%pc%e4>Db=$u;C!aviyze4Z)VOl~1xAh(j+$nA{b4ss{Ci`>nx z>>*{;!Vi5(s$XXO_wt#29jtb)~D0@bXuQI>(gm{I;~Hq^}&}B9jtb)~D0@;Nga{RHyanv_75Ir_=g$TAxnq(`kJ=txt#b zNvfA(j!B30{Q;D6Rj2jov_75Ir_=g$TAxnq(`kJ=txu=*>9jtb)~D0@bXuQI>(gm{ zI;~Hq_35-eoz|z*`gB^KPV3WYeLAgAr}gQyKAqO5)B1E;pHA!3X?;4aPp9?iv_75I zhZAd2Y89YGEp(7x(nsoK5o(+Qw5b0GmSB9W02==#SPsiAfR_Io43S}!0|n6XCNN6I z&_*qQmgSE0=nJ6bKY^q8WDUcwBkOsmf!ElH1J5+^t!9SM$~y^OV=of?Dz#?;v@Boj zL@%-cT0Q{E{8Ry2GH-%1KUDxbJqSL)Cm-j#PmoWNPm!C*r7e?s|p*6W97F`HC6_%riQV89>3x>!rYTiQV zPJWG&F)~idsB$56_Zm2gPu9RL3Sptbdft(_-9lKXu!(OqlQOqk2n&^vWp1|+y88v# z!M8dwCR_;J{Tl2>OQsOIlT`F#jJ*&V+yTlcK_N@mLg-QA`5;rYnp{J!CD)Pb$>*7_ z&EyvH1#&C7joi*y?I3rOyU5*4*BMpO#7~M48QJHYQa6|Qx{>@ zpbdOU34ky2nZ0SWQ&D1zF7~HO!2`TLm@dQhARxk+bz}cOocx4nrzXHW8qZk^OI}IqA zi=lC06W?kkTX`qJ>o#7uGn@`ycfuBmq4C$iZdg+>H2yx=i+a2m8kakL7}+R>#$N*G zpd2oSX8#Km-;84DPSUlSTtluU*OBYV=lR9W{jHEcaRPN{m*QU;&QoZm|rb zt0k~y3Hb)JKTBZCzX4Z}(poM-eh?Y1CfAT_$#vv<@^Q-T3GzwuDRL9}JUr-1V9O%U zE#wR2*7OS8*~aVb>1DXyLHX+=A30x4eWoMh$geDRRpXKx6t-pc#3o6uCv{AYGX2EJbdS zJ3dk;3(+DiMQ-^D7$U>yTa_ZW$ekz|OW%X*IIm^yz7)CTtKcX;S%a2CDQsU@&pQq9 z(J5jOFyX0nxc5)7@4*X<~)OHtZC4N9$Dik$N>*o{0~ik$O0*bCb!Mb44yKD1#< zk#p_@XQ8YvMb7yxIEUfPPd|q11$=U0`rEi(40|s{4*3~)19C+vN(o8bgOt^3at*nb zTt}`aAE$htAfF_kA~%uGGew)pE#wR2R&pD;o!mk0BzKX!l}^NA587R&$Q5Wsv4k&0 zt`LdsZJJNl|lQ$F!Wdk?XLr)WDGJdgZAZ41=;|tTKE9J z_&8(!1o_dvR@s9Lk|1 zp@Vd#FU7T&*FI7w3*q}w4r>j8AyUfra_B1xM#)$@j_WwDE8r)Lb0^XEC}-JT&a%B6 zW&0f5X(XHYWHZ^yI|+u+#_RTUHJ0)pJa&kG!_A9}Q;oVXWEw2QnY%gcoUe2<;9G1HdcW$8E zZcIOi>lMg><;Vk)YH6pHvz=CszO!6QJFOgjXQ8yy$}t1-F!%)dB>5D%iF_U{!*b*k zk>?ij1+(wEQRsh-&iWgP@;~v7@SiKd1cI3P8odTu3 z7=Vr>{^ErdfR2RXg%v<6S}0yv0q985a+o|q9wnun7N9K$prhxMpkhK@5QL_F30g=i z@7PE?>EQhwUOUNLGLLkV9@5JveWagvbY2(mx)5>;Vw4OXlNdQU0+yg95JVsRJ75`V z!yx+LwP1kHS6~bw2<`k1>_!_k2)(=yCZV+;W*FZE$MDG+NL>(fi>tvaG4mcozxa7@ z8T1&$4C8+ATE^r$@*%#pfqaM+(bUj6g@*eOFl=w z&UfDuqKAvrLGoCOiSiRWmq7kM1I@?@A;@27!)qt$f;2)(F0b=QH|Zh0 zeBMX;c}M4U0j~?mqBO>*sD%);a5=6^)3=nZ-8Ua_Y5gBFj5hM7S@7SLL(t)0V@%qg)QK6}LW*cAq==?M7!?#IYAQ@kg%!~hJmW~wR9F#Bg%#0M7(LUcLD5uL5lw{^(NtIw zO@&cE%JZTrj8gNCXez9Trou`gzgvW{g)lW0hNiB1!qA=YLB?%0xrSUzt|QlzqPwsnx(h3!yRag<3oD|#up+t(E26uwBDxDJ zqPs9kRFQz_E)2g`q3A9QzgD5>E==8psk< zXyqLnX(t`LpTlb>nM>x8Zqh?~`J|8Z^N!Bz0$vwlObnw$=_;@oef$XY^(C+r77>A_ zrhyU2IfB|vD06KQ)NXR!L^hK$YZifCegn=&-ys6M{3o~=`i($4KLM9QM-gaeC%7CM zk0=i@4jaga$&KVA#t!ls0xqbO`jC_0M5yIZbBM^V_+A3)Jjlsbx1M^Wks?H$HPbQGnIqSR58I*L+9 zQM4%JSJ6?FI*L+9QR*m49Yv|5D0LL2j-u32lsbySA|xiFqbMvwC_0M5B7~x&C@exK zI*P&~B>tkKC@exKI*P&~grcJ;EJ7$ciozm8C-82MxJamMNi@=5Y3aufM9J z5b}Iq!5J^eKXKM6an>nu)+uq;DRI^*an>nus z;;d8RtW)BwQ{t>s;>iCJg48K-
      m{&ChRame#>TubdAXYG%^7wWz^YyUWF|2S*^ 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 c* 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

      jfP5&Rf(BZ&Vg^F!U_lr$XmqDpGmNj--u3p5 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

      0naV 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�LFjJKX%~!LJu(Ii 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

      d2(=yl#K?F<;csHpRJIFIYTk5{`dVHI}>{%0H> z9w>#p(Y$G60=}R34WF>vjUWfcvZ}N}qUj^-(n#*_*ji@QKLP*6diHn692j*cm3&#U z>tdSpV(zW~;1fVIlj7IgI~EA_VG0TTt5VAZfTrEiX0t>S~y5#63{3APqTpEq$8h zc!EHLHlwFh=MLo#Zj$pm%Mg+Yeht5OML#OosrdbG-rR8`dH1DQn~CfnF|)dHlbL)v z4)7X?Opnijs5evfhDH!VfCQE8u$RZy?_YCq<6=VBoK!S!v1hPss}z^_%pBp@#7B_H z(HSxlO4t+(XHfZCVKdbY2xNPpN}wH;%E}b)SoF$E-9=X+MsxB@FTCGZY5opx6+ux&o1^Ys1ZoEm) z@g8vdW)eh7AXuQywf1^8OBxaKxx+GRm?of)19|yN*@-4w3h*z6gnR7yrCsn;E)lBOQF4|y!t*b``)Eu`UU?G8_ z)_bG^fr3Qz{QAgH(xsV$2JHv4IR1ESK@d`)ZR;IdMvH!{YJXCnxXNP4J=DC)Q_`V(aE!lo0U zd4hTHSQ~F2lZYDVUvGW!dEWvz8RUPDHH@HlZgi_u5eT zAg(>9wTcgpxmo)(^wJcv8_GiyD5g?Yw-kOhFz}(VH#KW}wzTMY9>nGtNW9)b(n0-n zC9UB%$p{+_$fbx0=LJ1)+~9YiB3<0))x~g;;m_ZPtp6_3+I8V%yZChbsfR1%hD=eD z-o}X{+rn#qxWJ~lNapz#Q!q4w88aoTR$yKZ**bfMb4HE@S=v$bo_B?(2G+!Hb`6dbv3cJ>&y!e0~6CQBW0^%ZCqSz{D5hqibob2O%kec_ZxQiyVrJh8T8`6%V6yz z9*2p>L~N}(5{Xn|Y>S45q;dOAuvR^kSSll{UVMG;c{kUQ^^7zcsrn~^&^!tSz+H7= z#n9nq`d5`rC`w{M>;>s#w>)-(nO3MA_NVc z-14BWE7U#F4xldCUuARY&L{?#ay1sRi7KB;90YsBNes({g8c7LOpslMp4RuNB??nc z1Q-)0#|z1UH1UmLC%n=5$=DIYRJ3tNSLV*TXvLRfOm&wz_VDW=JF7?#jJ|v$@Cxxy z#+fn8zven@MMWk|?8QkZSZyhGOqv7Sh{1j$GBC@V!0S==yrbwZtP{I_kuVV|E?(V_ zJ4@d@?E_0t3bz^Gaw15IY#br_6UMYh(9lYJd z6!hBAiA1FW7Cm>)H8!qNMKnnMR76t+tE-eEDTU?PERV^c$Kr@uO7Q2$E7^Nd6_I@9 z)b0VM^Kb$iK$&@?I#Yy)-WYk(-5K=e!#u0e6c;@1Q}B~&)kKKM#C5%65##FAvFHar zeoDr8)SL+X*V3k_4(BN3!{kNEYEgW6%Gx8a%O2d3Xh|{zL$S1(|12j1$X*Y9AmN z1raIkW3h>XcuK%50P_Pxkh0dVH&Ui?k;piB4`VH4U58+Z${WQHHNHzpm)pdVuk>J~ zo*UA>;TmE$R1HqF^ZK2CLI!YP?pqgImDoenRO34?Hw zNu5-pQSGHtM(wb=oh0(rpDt?P6rR`O2jG^20$^980?^K-2ZVRLPT~2y>^paR8I=vd zx9bELc5G-Hcnx_C_$-Nkvy7Sll;_NHu*@9yXqn&tv2A&`s_*(@-t!fwZB0~)p);RW zmci=Sb|z1y6ftUBnakzr!X&3Q&+TMdB9+x5vl^n(vd~p=AL_HQe=9w-3aau_m%ZFgO$;Kf!kS1; z%i{IYqEt*Tqh8^v>{!S0h_n_rul)+Z>|z1JakhIFBZrn3n7hg%Z!`K`q#;5^Q7DcRcLHP2Dgz^`5P=32IW-6i;sPb9c8ggt zQ<5G-rBvHV!2j`SEr8Ed6WDq~XsbPrrcu*q+to@+k<*WdRGQlzYf#q3VYYn(a?Jr@| zdT!ca`pDX!Sp7>ChKKNNT7$- zs|KYuU`2Q21OBH(7w&xtG=O$XbcuZR0NNk|#WJXpl_WP#QFeGk(y2Pphblg7MU0c< zq)vlYP0YJ$7B}i@ZrH-ZQvTs^9l4dP#Wg$ht2qojr{2mIdJYwPIzMT;Gm6<>#iByd)(`!o_M;-#cJO~7xiISxwZZl*ph16vkDSoOP zwiGs9D9gzLW#>IWpW&__IzL)Ok|=Lc@UV)ljkD7cH!lwi2>HCy#cHL^(*4-8)=jdb zB!5D|`be>zJ$=aSMLU%}mGoR8w^O%f|7Oyi@Gqr;tt7hwC3KygJ5M;iWw_+reV`Ng zJ$^fL5*^pl=5ig;;@EbZV`=b`ISAdBs#=;9n!+HNR12x&KCxB=7sf)FOq_%*!;)c1 zGq0c4(Qj;io#dzHQL!&|HjKPezMCbMj8P!2;U9F`fGZGu<0qV!1D|N0F`OB??Ur&n z8_M{#`bSH&6dKpcPg(6*MVm^YW$}3y#9g~oKU;6W*BGI9$NeGnaBT!c>e2y#Z*$69 z^ka|hzLU`sa1B*$gO-SQcEs_6& zoh{O@h4pqHwdgL2Fkzc^5*scy(}O-pEv1Puf@O@4 z!kMBVtKmHk7>%@aTtsz&tUR=gRQi?~LCcJ$Vmnb|L4>TXHoN*qOe8L-QmO^LZnO1D zaIs3J1HbR%35W5#o9K_rlK@ta68Sc>*=TN<)XyG4$>6CVC9+H@bC+_vfi0R9XkF8}P553*6s1qVx-TdF}#a!r~oz#Fk* zBze8e$#b+03!gk%oK4<|GQod0C}^8Zm7)ai;|S9*hv-Y#ht$?>%ym*!J=saM8SGq0 z);Pn7iZ>E_h4XJw?iG>%L@wNk;`(y2Tm*fPZPx=DwZ3#mEgXG;yko^A8Y_eiHoFJ@ z7aEPn3J5|*mt7zeEwzF^a0KMri17%$lY&(yI@k>4D7mPqs_Xw45Dq8eYo zH;ACXKv)z#%rv5OT=6zoroQtuT<7-ue$mDuBY}eRk2Z7;55iA$TF+%r#MCzXASQYm zMFW}R5+ZaqQmkC$c;$Jfu5Ei74mr671;A-q?p;Yb_GNACo0tAPH*I?*$IBcb|M#hT-L{1YO^}2cLX|{)R<$Y| zpex#yEi&<2PK_U zPrzF*!kbkI0)^(kUA?BNtNqVgw_~FL|A49*ifk6)sw1*9%UO$HGaU=I`|p;Je}Gur z_;_4petyHkm+iWzKpgwe2y<7!IrR5Hc)mSCf6H5ementd-RSq{m8Ht9rq54>NRb>j zx9j=*`#$#)YmF9*#gOyq4o6t5>e{N`K)5Ul*b^ldJnUdBE@6 z_#M9~@(}cJ@s+F3Y5=>T1LwEqXay!o9G;wLG_%=etQQP=9c@6nkb#{hud4IgFp>nT zUCa^UGjkJWlgzdY>s`}#jEuE}QWhqYv4nR~RlE+joHz^Hy`D zxOVaExuN`7v@Q#WNgUpeCsUtK)ZQ2L`sOSw1AQ>w@rY9tl=6XA1W&(5vxU1BmrWO$ zLVvIpW=*KHf*H?vTvy39D9^N?Us@QQe!8~*MaS5sv!7u-f^(01xz3aOcz`S4 zad+s5YHnQsFYGejCA%*!t3FA+aL>xq%ye_7q{Zn4vGGo3(+G{QG1mhsCX3O7V!i_u zk~6Y3v^Qu7m8RIQZK2Pfxd7TTmF%VyHWpd90KA!+MqRnRY1$alqe@el`J8{}h`F2T z60+jivua~`VKS<)#xigbQ~i^4?=6ga7sa(oI2p#&DRkCVC*N;36bRyvU6(|@WLTO& zW7Kf+o}oha05|6B6n1K1t(%N^?vkH2ix*zFr=pj8)`=qAE5d~G_UZ~S({L76BTGEl z;Sl6FUwFXGg0G5pqvgbdrc{l1UN{@8f>DjjP0-aKQ!k_>rRMfyUD@%^nZA{ao?6+1#9;P0S^fq6*kBp z@5w(*1!q{1d?|k85eX|Sz3>7KCC>+c)YjXw{aIABq(+q{+yi%GO!N5K>iCUUk{n?u zlp;4&R9>|0r}k7HN{Iv7ov4)iX=CPCoCZ6diS#EJo@@ivV0DK`U{^_PZ+XE3zzZ&T zf((uwhNctYAZwD)OU{*bT`kfmw64adRyG*ldJh16*WO*cIk7IRM$ocZ>`UAB{**UN z|Kq**a9W8fvCwp3u~Ig1qa+RWE9# zZsy5Y`2^?L2kjx+%T8o!gPy|w7udT3Ft3z~%h(``Bx#c-kD<$?>$+M`0>Fu7m1$ zr>_7yRD*W|L0k}*(Cr{Nkp43`?l1~bxu~h(bvEZINGHy%C*eBxfK#07x`s zMG%5Gk8gTSqYK-&d3kekY)P^L_%b-Mg@PRmQivqRE%=;PwVA_7`~5P{XX zpx`eatd*xK?GxD7bha-O-|GZXRUm1iwYr*GszvKM+s? zUD7;F92PRnGFT*7U>=cR;yez%YFp_9c>q}&QP`*WfD1>t5dhZ?Na+n}g{zJlaj-SKVuh=uM{IhqKx0pSsA47MTw;DR1>2Wr}BqN3YnR^BHg7@vGL$6c$rxq1>}rdz*W@iJ$MewD(laM$3z4-VFuh8!pG( z3n-SPG}D@7qAAU~7k@I0w}Mh+6~C3z43vC0p-!%-C`k|v!vitZ*uOf!$~0!GBgy0? zm;YZPbAeex7N?R+jY4N06i1R3ir=I9Mdv&G7`h(z}_I1vJcJW_j!lVH#B>hJk+Mbm3d)eL$$=nxy= zERCRk_j$QSsfu?8pV9_Fo6f=S1Ho6ZSs}L@F_f2Ms$p^J!uk?9z-HSqe2h_zQ z*vy~vEYY={WBoT)r*pQfDU}obrB(&7d9+?qX}@797d^F+Q>ERY^8H(`ZDyzJT&0z+ z;xaSSpsvjPJu4?x4xR7z)FvBH@0e>u31>V2+3# zFiid8^@EUXRg>lq)KFt&l@Evk+Epx^cvuJi9G|5$A5N3Q@+UnYjW}XC_q=P;il@mp z!{~6{ujleJmbAD5D5L+_wgy%YZgBF|fh&j8HVpPjG;xSf7$-Zfl*N0F?KXeES_}U= zbbLXKV8zm|-f<$0fUAvcJjopfMgFy%>-$eBXCy#x2%~kdZFDpKEHT2l#qDSM`WDZB z1eVZ$`PZw(aUTyE;w-D$FK)ugO~Qm3God?6>vug2J>c~H!U)Uvp~>0n2yu5N*&CyW z8zcaX&MV9T8|(m-&>APc%Hb!qVzpeV74xY5T_)E9pJ(4wqLa{b+jSQdfq${Wf$w19 z^>Cw~;jv5irH!eDsfVe9X`o0;+iUFQg7>DxV9jc|U<53Puu5lsy?0I~8_EZPlcX3L z)2I+EDy3Y?eI04Cn45g@a0LQLFF_SJ}`FxIHRdO-`ZL^rI-Xj1^e<6Yom0rm|NkTXyb_zGw^x++Gj zp(3W{xzJkl{6cE``%y1+zc6*vA@&4A5^EA|5^kOxB^bA8Dl#7PB{m+lG+GFNX@Zp~ zgS=Dfa$isbcSmC6Y4QFtk%DOkaJvR3Z>b z0WBEgeT;d+G%2{SMuL-Yt*Wg3ZXo5Iqg&{ zlWyreqQ2M*Gie4FUymH00kdqScE(BgRg`Mn3FpnRfK4`X1=$(IXMDGyNPeTSq9Iyg z%c4j|^Mh-oNJ?W^CVXj6LHTOGODaYgv$>J+;!`CU$*@pjZKk47b!o~HHKrPK2SQ|= zYA&t13+p*_Dg(X0msA=CZQz&R+#^PZkgU@9A@+%5MNkiN=jdL@*~AJWEXP`w@w^Ch zi5N&8h^Da6Zdgb3ZeS*9-Qi90JA><`_D0(!yJPF+_|voqCsIdFN3<~rtqHX9Ru;6g zuWbsgk$X1dPVV6w3NHb`;Q#P4B4ik z_ampG98IbJ(!5E$THq~ZW`Mi3vUPyjX9gFmwS&$Z{h)w)UHFjj70^a%Z_! z=P!xPPG_~y1L!q+m_ao3GJ234ABiy5&$ey{5k!7*<*dx>c+;H~fb&;9(f{=h#$>Jm z>o@!ppU!z4)Y0D!1_PfVox)*cQs$~5=?|<*%3h8djP)wqC1|YQ7dQ2Ux90-hQh5d8 z5x^+_3c-yXCc$-L?I(hbpEKHagU@A1_3_$Pu!YDtQ*_q@S-T_lD>;g%6%sq1fPUqY z*zd~NS7U18X%v42Vd;I;mmRRkfGPMp64D^Hq$BH>0KfO$Iv3(k;uG05EFjM$Mq7+X zsSTuhoiMl=4J!B`2}~}APIw={(#&TTSd1pzj7+vkUCAKHCg>z+{f}A@8;}ZA+J?Su z-3|6I9Ty7k-Poh$!&+XE?-LJv0lG_D-rgyHf==G|z@iOmS&wbjEHioiV5Qy@Tbs~} zZ@$KLQo6Qux~lZkQw`kUTV5!ZUz{R3*Y+vR1i^-(;o!bGP~)!jJF@dpX26F|q+;i3 zg(O%yye_-de!`i7pN-7B!-DG8aBuCX%Jjfsk~v7 zqq?~z9iY+q8uqJ*WubbSmFBieY-GbAvR~wZ?Rk+0;IG96@6z;weQ1KlL^VcZq8z0* zQjAs`EyQgw4jiOnM@q3ou{(77HrTq^_kgJW#ds5-eREOmOVO>^6GO59`u%{iQltko z;cTD-F>@TFgJ{W@LJ$-;J3QVqCc+RdkR6Oa+v_eZKe%CJhgTZP9Jh&%C{SKpJw+8qMxgp;- zucubT;qg-Vo%nycN8lr4SfL zo(mQIc61CEte6iHgBwW$WworvP)c?*NoHEF3L9kG#F%daL^v+3!Szu4k+NxpN# zxS?Iquc*{_C>yl>XoEb1<5UFu$cof0)z$#OpiwCm3k8kN-QhxUoyUnHaGgDASNk8s z+!y%H0o@3Eq69(^oDuUTPf)8W;B$@nES`YuAsR;5_#tLaK*W%aBTjm39#t|`a@EM+ zXo?e>w^SMLJqSpTRkrWo4To5P=^uFU5tl}3G{649W~9O}RZ`G%DKYUtsw&FJYev%2 zubrg4O3-VSnlH6g7Kh6dB0n_PuZ)6#uJ}BGvYnR=+2`B+>ObxthuF90+p5RXO*#;V zLRpWYjfA|!4_nczJv0yDvsRNkEhBrlY!3JvTwPx8U}0i^2gW^%YI|SS?!x3(o&$DQ zS2$SNvtq832G04Lp94_fGsZ9=#f+m=$u%g|tmD)xI56eRV^-7;A01$BpzFPSgZ|$n zu>=h9fI@g7R^H(s;Vc~^u3&JfW%$YelGLLZi>@aQgkQol1Hf<;F%d(d3dfhkWh6k7 zWb>Y^CC2aEqZG@=55`T(QQo0pMa*+KH)S7Dcg(ekIj`znm>77)*$AOZJ&fdvqrv4a zbZ?kf)}9G!6X66cYRYVGUK=IwUOFlIZuIVirXJX_Ts}q9$hFfNj%NigEEYF6?`FsF z+_q!%UvNXI!=WgW+oQ?`Wj5%PmmYVYJ`DQDw5a}-Evjx$&A9ahbNHYDNo#iEoF(^x z@v{X$E~}e|Rr36Nd?T#W8b0RS-9QLB9vKxtjt5tO4bI%eVM4M-KXxE7guD5R z;B5?CRey*9@LiI*c|aLinI*@_*2?t~^z-jSq<#{llE`S0CMN6i#N2vO(p>B7%Rd|r zvBxOGxorv*aGhTWsi~>6slBPuGhDnhoX_g7>~-h(x_)pt)z;ZTeWDP9nCsDUvupKL-8NFgH!RdK|%z z7s;(nA9KOsUFbVG2`{6azs$R9kS7O#4M6FtTyb{c*B@$kJyBQhVD3yCty8rJ%g>aC zR6N|YSsAFjg#`L?Se~hV3%FZO^Tn3mZ1Vcn9kkDf1N!j-dQzyl>PVOP0KD~py!HH7 zqrUMFy#02tOGr+~m>J5Hqq9W~rNyj@@20VnudmxX;ym5mmwB7U3*AbP%G1V#iP zrzd(U6L(D8Zcu6TKwe}$bJSS&UFc1y z{`pO*jbY;{?P~s@8Vn72N+ggUp829VikTLnNzaNABPcef`)(O`V#?Y2O4V6EOy^YM z_}C*>g{y{N39JvY4tBv<5^gKvR@9?})$PuPf}X?8BAaZ>@p?RAP;5-p@qii7F12KO z%@aZJd+2m|eLH@dUdmUPJJJtee7ZgvT;S}=wcu;m_0^7>&7bM}#9ZO8%lG&J^NZ(j zokE$ba7h^r;Qhqa^8EySef+GMOh)RTj;VyG0~G;o!g}3Rd!X-HW^pWpMV*{>Z0hL>#RQzx4LQ^&ZgO%?7>tdZrA% zPgfj8`I`Qdl=w+WYQZsjqKsvl9Z^zZoIqU)%u->>bjzIPnx){SQ`g8pJ5qmUbiDv0 z7tb{~7$T&UQWoY*3NDgtU%EYjeZQCEG}S_al!|Hm7pZWBKkqI+P1t){Zq5IhEW3># zJ)_aSAJAWx*vj}o^#kl2kSMcvB{-hAwQc{yBFr}P`z_B$;^J|k`?3mpRse&NFQ2Km z;cf3-f`Rm#Fkph3UoV+VsTHlNX@zBaUhoSnERI#9%(vW*Q-!tZa0yN6XuEaeS0G(e zZ9Q9Uk)aI_bk4v)SYtE@EzScMn9TOOmkT=u6-vz1K=FSIUj}xCOsvf9=El}~HsvfG zjjcvY>2^HsH(DDW`}0T=crM#e6nV~@SQdFMyI>f4&KqbNdM-O~96Qcicpf`0dmspW z59=rje2?2O4PHAqyHDvIeMfqQ0a(=(1g+K$K3({P;WR7Maq0~$m~!YWQYz}B<{G&) zll)@V8O6DjS{H|;FH)am&Os>BG#bG$G|dtazTGTlT@}a+(kp0K&A1w&#(5>JzBk6M z>z`HUHhU1kJ<(fByT&mxsp}Wf5qVbUiV`xnhGl7K`-LSjcY>2Y&vm~aJcFZ{V}kuq zz_Av?vYaTBZp_a2)#@dyM0qaiX$toy<3FRii|1p`E7QLXr|C>N&a)xIWtu$}RCCv% z_jJIVR_I_*nS%wc(N96ezEA44QVfF-48!>PiX^xcycD}^B$Q5v&O*Reh%~~rof8Ts zO@iKNLKba^F;R(*kMSnQnvCa*CXt!O!ljq&UfVFtgz94SNh?`ffc>^AQ;2{mKm1JPf@reT+$rJ;|ARf!P@5t(74@ z04gRmZR+dE@eGkz;;T;JUYxl}Noo;GU1ruP%uv&%d%=#=$U{o6y{#$sm#sEK!B9A=p=I28c@RC zTkUfx1(x6BYi4L4!}rk|0+C4@iw!oBiSltBwl_>lbqNfaa#T&0s*8Y5Y^;3~hyR2S z+Ot;GPkcG`rz8DAt`f)F3Yd#9%!jsPdU#SkVJIoQxH1GqmPq0@k<@`=sjH8A^u!CsOKY zGU_R5X`kn-ES={;+3&=xI>jl4Obv+JnC~EBRT``mN5w>j2&Gk*`OGjTIgv%~pa-NF zi72JXUWlp(2!+(*UpErg>v7&f@e)8M;`}k8FuuuRi3mwQ!Mw^2-HKOd2%E8*k1`BC zX*p5+Bq&qWDno7rj^%XPGW82HLTtoVeNAk# zUwe*bc-Re<(-YMUc8;XUS*ccGGxU(jKe4PB&DY7XkhW=;83x^De24quVJIn|10DgW z`r%M->a`XEE94{cJGwkXeBq(w$BMy=8-UaXpE5zM;rCVd3`=KcgF{D5{h0q%;gqNS zo#sS$(-dagWf~{W0CLlj?(!tuV{Qc0S={?QlSOK@cj5l-tX)^*>D7DO7E)L z8?fVts76aLvhL;8=}ZlJe8!7q4EQc@r*Ku|dM?CJL<0q&AplVmfRKO`BJ|iBm=Yec z3J$2Nkc+Uih9YnmKqLYph>wYf$h?9wcpaEn1|Srug@@d@gfjFH9A5xR#F2*x)qMta z%s928b*WyjKtCDgGA|rM(BeQ zH|3gL?UK`MQb_A(_OZpRq{`PHE6o1p&wTLZ!b4ipsQ_(z0zu9~F%|?me<2i30unzk z1XHI1DYAH%V1JTH(ikT5%h+N^@v6zs|h!vspZpf0PZDe5s^AhAh3{V zgJ@(3)`UrA@xth{_Qa2>Zr?x|&Uovv(~Fs?s+fF+f?#`Ge;lLj6Jv0Jj3w=$n&n{( z!ll*PbEie-anDF-?@j0BP*QxOe+CR2G+ZrzlVBg|g-l2JbXCP`V+GDYG4<$ z51a_X$EUA~>s~@62|9-7@g=0mHu+0@FLCI?KM1>jhCBF|| zOb)Pm_r0@(t49Lxf?l zEgAX;8eWX=*4D=Caz-U$>dYD9rsMtqvj`h zWsp2>NAuR)tdX#Nxz@a>6cbmESmv3@^HJip5{<$Ioh$Q!V&`94;sOI5<&{lXBDjn= z%w2*N6DN^`%|VsCtGnjQzc!`Ua zsCTh}+rda(4GWmUvyz(eq6)3bW23p0b6xhJPSZEv$$#^BLqeN4CTnr3xDCQmHtI|B zL6i=K*a;iDC{z76PU-w8&qMv|$cB+5GBKL(>~i(Esi=QdL>vn#uW?Af&# zIJJ)ut3ML{eN^LBP<*y0=7keMk29wWbJQ5ZgYZ6`cf;^+5VLF;0JB1BmESMQ?Fl}F zaLH{kH^}oP>5p~}vR%bE)G3J6(F*)vdwl;13D|(Yon!a-KHG`=1mOeR4|{=Q`>|A| zkUURwPfX~32|<03MVv@lmM7UA?U2(Q>mwMW03fMVq|10A;F;=_uQ)AFnxFSA@f0}> z)Q?d@I9Ic)hSChjC4*6u9U)Rb|B8gbA}ifYMa{`EyzX1hW;$Dfsx%5=!<(2l{?#K& zrEXQ=`W90K?sF`D+m-waALp`sc6u8K=;<&(d<=xVWM(0m#-FK#x75@>GVwH+HLeX> zd@!~GaM(CC?nqn-ii*(d%*D023a?k@-f>vjZ4a<-sZB{*PT3FSAo!?##Y$%O^8WI$ z!YrGVWHn$9BsvOIXgR%Xh#DRd$8<60bTAQCsAMjtt73b7fG#Pb4RfOBSX`4OePcW{Vn7GBbj23yY`^H6t7EuKpURv(U5Yb38N zG$hO8DpfyS-khG8uIr<&NpP4iMt}C7H0#~`;Z0tBpR%-J%3oRUav3Z_@gCx}5hcg6+8cQL(erFYrUW#1;rs z&AGwHn}nN0ha4n5ULCqzW|vl1F1PVPr@Tepf$cyfBh(;-t3w~9;Pg#X)xVQqrGN*@z&nUgl~9; z`y8Yu3ND~e>VOH*{dcqrAd;TP?dHAn0^Gc$q?$F zZ-ki~A?)SjNT&$w7oWn=#oEN{KVPDQAEcaomeOd@7?N0k!_g+Ft zJ*aY6m42g|3I=rMh#{5@g~pmfODqwtZ^SIF%}OJwpC)O zc^*+UbmprSb&oZVZmk{@k1fc!Rf+NCOiLu!P#@IJ`@i9r`)sM1+W2rz=?Pen;96Yx z;zNX-f<1_(b>bxna)efY_{B^3OD$*7qUXkQ>deN85-4C2ObeuieCVy5jw5GN?@E!( z-LIEVmv>x$%%DF!mcwP?M)#Qc6EEPT%zxR5FtYm>v_#S4u_M|bu|u)>()M@1J&qQc z$gJ-84OW8|LLF;~8RqsVKy6`Lkeh=t6Omm05{U(pLQs)Uh}Y9lL@pA3V7hk1tPh63 z&De*h+DS!JeZ@Ne6MN};KqtCN*3$98Kf<*n^ zQB}j6)sY#{?Y{gT7S~t7B_!x(G0zt$y4TZX@Ta=vd3hpc&cIOHoLF+&=a5w_N_w=8h&Gj*TBvdp*!4wpZsOhoB6bVil8!6e&p-}~1{ ziM*L*0pXlJ-{KiAH~CEyf$`Mi<%?A%C4=4a@CS(NW=o<4!{NB{FTp<{csUOPJLfX_ zEM;fu*$J)dV~}oGXcN&~gcZM-CNCPZ%{nKF7&dTrb1A{cD=sdWogoCR*$AF8qA2l} zuuqrhx^N;mWV%^jG-QX7?y5G_WFz3@zWFBP?>^}a)E9WfOuduuKYs{}wt3-xivNjE zM8y@oIvhue7{r<4cj(8|R}bYC*ssp)j9#+aK@rd^v#GBijJTnYI$2=?k0t`>!WPOl zJ_0y==0SKVhI~F?N>k6MAJ}8FgYP?Nu z(YCkLO34V6iwM14zj^+C*0(@y|6c$>K)%0=t{roy6;Uj?I*EI_(33yeCCBooPJ{I3 zZg%aCVGmg^TlskUb~7!%ioqNP&xOJfx7P)V30Df7WH+R^c;WAApn_nTJmbm4F6wk3 zVMWZebP!HLG{uadXJKNu@s0-Pnt4`^*#p&@Zh+JOb>ABCsUSNP(Waq2Cm#aZa9FgZ z$OSOs{kJ+kLC{hKwcQ98+VwKeP|2Zc?i7yMD^nrWyA%hte2N^zI4$)s*Ddn}-{~OM z^g9*#@IMg;_ACEMvxuH`d;PyDE8E)(DLQ!EtYpg(ibnRU(U)0=8q7i{d-FtHMmDt- z$k6Y|>EHueb%}G;sVc`-8Zt7L$dXzib-T4waf#XhpX{87Uj0@yVI6TDIb2!AD*4JL zy!B@EQ4)q8&h_v~+7@@x;MCM-iGZ{!1j#I>q6+Pa4@JXf;KCrj3)Q(!>Qq4MyfD|T zUyhp!rAxZsUIVkY%U)7DJ@?37Npx6^gF+3RoUx6bH%_ayd+;VbJl1^c*krL55Z14cCq->wpguf1YxllgE^yWD+7k0Eo4oIDvW{%FI zUPWhl+Wc9;+X25t4kLfXm)}0z7XMIUtxyqrK8#pWsne`mTH913tiyRirahcS`>@49 z*TG_|vbA5LcOlA9QjV1=%D&@LO>l&+cTcwBu8@C-NHpGdUr}Jcd7gv!{WV?XVGAbZ zi6wQU>jt~;WJgA5Or$3;L=SS3Oc3eXg%;^kZdh1&@HmvlvSe~53#a^z$`O|{O%#I~E5>5V}L6psj{c2AZ<-Ig4htCKmd6;$+ zZdgtLn&bY!ic-36NQ9J6`Zc_WgDS&m1qjm<*gO+6tS#2D4x+YjXli2Krako-0^C_T8i7SSS*}`p;Z?aDiBl!b z5Od=<`Y~6iAaa<0i03!i|LlsjT6Q*^ z7SXjuGNU}b(6KC}+nfmv_T;6XkvB{{+2bwn^wulLhnW0m-mv2&Q=oaCj>JV8A9N!2s)k*>fsj z#dL|M0?Vs(ec*tA@Lp;yiEoSy)T$=q60!v-60q8Y0wim0))4(EL!UH#eRH^pU~ zU~wYG3qYZkEhNa=8VltqJAjQb6xe7kcU$}=QJaR9K4U9c&Ke0fU53$?G`)xBlBiBE zpLj(aJ{7KmeE1Dub$C3*&jW(=oYk7QV|jWX1t=r$P#h^|MSjSZSoTcojVh$E0ZR+% z%Wa~F^At)uys&#s#<;IwGi8dZs2TQWpOnSpo0LZ^>xh;2<+70>N5nD*uSH%j@RFF) z_cz#Quur5ciC2HBb-`khcf5;&@!(wzgLmC1>QP%7`qcg|X5mTHRIsl{v`y_Gbm)eF!NEIL%G*YNs+K0Z? z2@}B=o}RdW=tga6SI9?|o)k!D*{Eos7#NB)l!Ku%Ky*G65Dxgc97dUq-)$iIM`?bL z5F-*54vnYcEJk?CMA z{0&xj49mSXBjwYec7=V$HRl#7j&o%)5?$U5+Zvr)NX+JaqiRP{BbN881HmMnPFr%T zyQWEKuEtoipzomGvE3BH2yR7DM^+g23DE%yOU}TY6RPLfRRgq{qNVKKbl_doyw;Wl zXY4Oroxz63B#Nf;+g8A*#jGZF7V-piTO0UtmYb-?91+FI{5V;ayQX51tNV7Z_i)9b z>%k-DS^Zc~axKODKI8qshAq$zYzByqM(lpZzQ?>93ALMZs3l+CAq|quocH+mto_Od zLOV7n*nE+f^A54I=wc|S9-RFM@jt^E-jQ;gkEp($Ze#atxT83Hzi;n zA6ng3a`^7J7GM%`%?fI$1v^NTFc%StzLOQ>V)M*|5EKD>p?Bi z1(d^w<7Y)13F9g=U5lYk+cu{2RhhPy5i6Ux3)kkptt=-d>~{w}R>pYnL4~K!`lptv zdw46*a^f@3&0w;Jym-d4t8frVG#P9lC4S=`{oRJ7kfi7d>)IC3s>&0cvXNKUNRaKq z-8ip;fE+VhMmcRQ`(qng#4_1m<;cD5xo~2@KXGhsJX`T{+8az-65z8m<{>9qzmlzh z^{XMW%-Tn*m-m;-wBx+0Ez`Vox|D|9TQlc54tyIIbNynH{9jQ-S!>&yHMwym3<_MI zQxIF?^NY%uOCo)N7>Ig`=#8+4P%d>5@h)al9(XCB1ZJL~Sc{2UT2P9`uUv>PpoSi& z+IdaOLb|=^%!aQq52DHqQRaD^2yEkJN~EMy2$m28;$nR%TD z#x(c-EEF$dqGu47?XD-$+WA0Pi(@*}t>PZFrk>BLSGY?t=O;sA^OUco_P=3`pFW5d z1qRY!?!^X>RYTo2+lLZrJ-7c0jBQ%$I{p8{PAg?cdT#HO{3yn%ghBFK9HA%wW3sE; zJtMcOvAN#gHFvKI^|a+#H|yltD!Cx7CpxjE)6m$_wqI!-Lm~GKmcOHKAQzez2ACi3 zL++vG8ymA?GRsqSefH|{r0WGmq`?de{Q5vaVdnszU}~)}#~zFS2UIPTpIUOW*v$eauh{n8xjE26 znaJ=Bo(MEG(%DO*I#TgQij(Tk$K(D&56?_1CePCuhD*H5eEX@^D>5#XU zR)W5Kq@)z9gemmQ6?Imw@%ErGc@}&mPPLld=VuFBjOB=?)R4P1%2p7%`p}KRePzEe zPRIZsa@X8b%q(C~tR;Ef9WE4>7rg$$gTZP0Wk!UM0e;xFm&fOm|AZM|=Gx;N;h77mD{Uy91E4ch{}J-`cr>Zx z6kmvIL&2E3doWtjHxvf5!?P079o;E$BYDwt0JQVR$?Dqq{$1DbOX1Qz;^DVq??R8( zS0MY)Tf(z(CHdI&@%-HUbo|huv1-`+)yCDE9h^8?TnFdPvMAAvPxnP3%d^*Q6bls; zE0EDQr0Z`-OG4lk@CnV!$M0!gPJLa4E&*eS1=->0!@~`wMPt}_EiQ&Yx&qVV_2RP> z>!+9!_DThmC+4U1e96}VG^G1J;+GO z+o-Rom@?DFMLniEc`WM8)I?!w5_9^*y$$we?C#ZlB&-#$*o;3FF6NS0n8B{W_jdLn zdu!OLnRE%Gn4>>-@#FnFi=Xe)ECnX-Z%9d9s!vH&mt;3c!`a- z2}`9Bwd-xo#j|ESN#?qoFh6@_?$N3O7+a$NPF;m-+Fb)Xb@ib+|6{v6OG+`R^Z${L z-Eug!yW(fZ;uq8as+5il5W#k~OQ5${bs{$`-xQ{5dvkl7a;|ck<1Epk%G_1f4X1}*d^v5sZQ>x_8Cp( zxCS&q&O?Xq;QW5)yDuRMi3+S<6*qUkyYp^7g;nthP~bxSSYEurh2+e#mM)JeJKy)9 zYrtH7K~8$aFaeu2ug3=$`->Xx?Ok2%WjF(V3tzxCEArae%f>y!MFzD%`@icp)MDno z+{-V&Hd70|;ozjrexyhSK)r6Lml$rKwB`x*Ibf;W9!{_Src}b>U^M){&nfb#)Ofq2j z?C;K<(1i5}>DH^-;micR6xFxP&^YlTU$YT|qu9^PE4oY9QPS(Ua{drCm|NQtQ z_UCkVk`(WRTn-B5H^vtW-%f&J-^gOYujAuGcyjss@H;Gy3BMuAQzKV}rn@1)F=2i6 z+Lfirp)0$SBGYiLX}UOpIW+zrK0cV`fxrk7@|isg&X$GL`#hY?9?yv1QWQ_m0-8;# zG;DMHBYb?Iz_{>u4F4DpQaXE+Nj89ch>H!BT995)4-|JOAuu7=gp{?BWfGD2ulUsP z1PD*y1>c{*(aV$q3tUxcNMh>l#n2OEtFw*6exxr;ukk;4Jp+Pg%@8v{)RP(fR0bo{ zSK(6ANN{3CX55)coXy_rEdQTJH^uk!#P)A?bubygw+&ptl@SX7O0JNCu(cs4)3h%_<{8apqwdJ5k@;`4D@8gdU!x3|yb%=Lo zKhal6%~Uk0Hw)N)#`7M4J=0$CCKxJ!Q{@o@!Eo}|1)OF2&!k*RiE|PiO}rG=OQCbe z^WM#97@|I+mAsIAgOr~=d_nyLJ1;~tggKq;)bQ{t!YjrD_x*!W-30+V(q0X0uu>p14|YrLyt{a0 zIU%kuR9GKgBW#qDT2&aNh^aF0e*B2{9fed#DRoI=prOyg`YDWt@!}6tdYUc}NBKID zsf^n0;CF7}-XnTTRq|r-&CEV?aUho-QgnWDz{H{1d7yKxD615)9_OBc@diGXN&3b; zM`pmBr}%?E=F3J|9f?0+T6M=}3{>=p@ zt!jHx&6_C~E{Y3LiGX?mG|aUjakmy<@pg0;yQE^Sgt(j&s^E#|tO-fv-~gCC%tIEx zTZPMcF*S}|($-O_-~_Z`n}p3u^HW6*9fUo{z-Sn{G`X~bSUEr#fGH|nw8=ZRd4yb` zygWa`a(dDpWn2%)3=bKy7of&WapEf}ZCFmX)E=&-nM{^vLCjP*(&AxI77M-u?;MQ2 zF<68CGU&{R?-1p#n!y5N9Ox`KXV$~vmPf-pm2j@g9FBCr(}ed3VrIGCx=oOruok@tI%!osKdhtF1tB^IQH!XeuFC{sfW@$Xy-HY?uxy!Ul>^l+H zFJZ7dStTHE^4X$+$Ys!-#x*qG+ z=JoAj+aCz4cI8=H6JhG^=>dZ(?={kXlvxUbRg;L#Gz=Th-_EW)z7H7y<`QvMSYeyX zrD4d;YNhu>xOvSDOn~aT4vBT=6fQsXisj4{ulNO)Zzx$*Ru>kPRhlSY((v}VsA+m_ zy1KZyre489&%LES%iL9JugQZT||u2zo4AIGP9 z&g|)bf(<66wjEExmQhqkQ21%QV=xDT1L44kpE9UnV56|DP%bHgMw!E&UZYMTIC)&Y z?;y>cm(L_OppStWaQR|henE4hn`qL1UF%Hi<84$I`4;*NvMM~A z*wS1~s7`cK^!x6pe$jt6&S(4Emc7OpN$|s|1_E}}w9U{7#w>I{tY{`wr?~I!;mYBI zySty5LK}401IXH;rslTU-QlF`vk%&uhnpeQ0Kv<(K`2v=#U{6?M!j4GT=?f48mF+| zzB+~NpmqxR<1r6`y25q<=G#+TnqP;HXYkE7?NS~PA`_nz zqxXlRq>&0v1t*i)0l++Z6YWx{I`PxR; zpj@1NSj+MWKo6-xs^~=A#bek+Lu&Iqa#cMsi5xi>Q5fjgK}^OMNf5E#cl)9W>i1x( z?R!+vcQXX{2^A@=jN0B?W<}l5p>?of$oI!o!NZLk@(W~*gd5+UUWjKv1ylCE4Wf7%3r8#V>oyQ zlSMD=D%6^S+uq*3vHWm$e9>Nf3^s=A?%TMz-DSzAm$1my@Z80b*?(BJEs4fJ5G^d7 zv4ES%K~0uS-nL=DtvOw}!$ZN?)1-LnI>_b1QScP6kw7I-x8TV*vL6FKm1~=nzJ$D^ zru<8Qe-r8~X+BS<7I8xnV(NUta%4c~o{MB~CT3s5*g69_`XxaKhoKk1V@sb?G=vM> z=;4Xu1DSQ$$RO8XjCI~3hBuH8bMuh*Zx~w9|K9|&Kk+aSs)#YMvn>RTmLS|3XWR34 zKPTH(2YM3mZ>!q6B#idl>l?El5w#FMK+KlWi13%tIfCRF>*6Qoo=QEab02Mxw9$zg zyyuPKm(iYww)Rh6uWLCTeDc~MRNW41I+|!3%mB3T_4s_;b!$0_HfhK<@U;`jandph z)Y3#D24^c<$YTn_XUx^>8_hc%dJm40bE9lX3USFp>Dacqt@v&RG&eUig@Jq3>xzIs%k|{7~F#k5kJRpz-jsPRX z+N=_K+wRrmkXA}^dyj^c^{5<9W>3l|ukV z2lK(*G5(vLM#^uiDUIy;D7abc0_F;eMO4$W5g2EJ8`YH%`Ps$%M&OzTd~icCrq;;! z2|@wSNL>_6BncTHc$So1JgaEpkVHX&bW4*+aRYbXEaUL2*_GM+8Ri!L_R98Ed5P6K zs|>Y@N-W_{^BsE_X=a}=8X>q@;03@MIB{Mlald(7=8rq-h@ zEG$QQZl9WUZ90%oYV7ayJZzBdV&eahgVi|vLgrMuz%M>V&+~HSF3`PH2nYjfTh5lV z%|>dvI1ntdXJEXMS7n8vhO9@;tf?0$6f_o_Jqj(A&(JQgTFI)_+5g<)#y+%XaJ+%f zc#@&D>V_jv=)p&n$0W6IJL-i?3;V51ZON4;i&pQavKfsmjiT94gEBfxL|L}~ZDn>S zPbmy;w1+j0l)+{C7G6D&-@kq25QP4LO8I%#N`yA7-FPQ5f~sFqyHYgv#H?9<&U%Qp zd`&HfWV~RBq}*9b2vE8|CbNXek1$ekb#RK^RAH+SnqYTwHNsh{j}R8|>m`G6^hZ^* zr%R1g*AEnW^%MFFuiwD`V0#dj{o7X3JquerBiJM_Zmc%;PLwd{P52=%Lk>#^ z+3jyv1N#ilb(kcggAWwA^!xFqV}$oRvE6f#w(2~x#v=S`ss~V1_wT&efv2XgHR2^9 zDelt#uEkV>OOrN%2o-ti0E&u~(=q_RWwCCv`6Q z7AZFkdh#6h6gwwG)mXb)7*M0;ZQfNkXHM(4;#1toghTzro`7A^lYHebdpn`3qNs5b|z2S`L0 zmwmF8$8EE48`=z9Ub{if&3Q*cd|FCsPF!-6Gr^#U=2@D3Pl5AUBVVd~16#Fca+8A5 zK8d@QtYEO~nb_@WwCt{st)?TbXP3kexv3oYP|Q--k;%UraCRjDk%Lw8Z<&}OvJ zdyFdwtP|J+^?YVMC}i^M;uE>z9XOL6ITDk&Vmqg^hux--Oopu2X55p*^JzK{K@DaQ z9UioZlQ01uMraOn#5WNC0EJTN$L~-B;t=8EzckI~P}DA3-1>0kkd@vr?S-LS57v^- zx63Qbf9~SysgDlR5oLU==B_!65A0*?2F1od5X*}ujPwb?MjWmns2dE}eK_F!>YuCr zHvX;mD(~zps*oNW%p)w=-$Y0maE{3E=y57InoJc{GDR^uCm6fOVqB6BaJVo9wM$>4 zPj@#mYBfrKYBzGJNAO_=S;dThYjfg44kg?kaMd&Y)vUU&XkkI2IZ4g-h@}o)2(!xo4;j%J%7>TjY5^(?64?sV_*3srd_Ruw8x|Tscc!t zcISkR+(?m3MQWpEFqiQEWALxHRD`bd2^n~;d#El<+f#tHi!^1-sA01uqP6_BMsi*GvCZv7a776H?SMLz!ab}5Er;MiWO z-APX7@Sq{TM9Wl^`7Hq2PSZcR_G{2sOmuiav7` zN zlWg*(uVMGYkfns`P)p5nY-c&KeD-#8JGP-FhTXzC$)99q@-m7(`8CkNj0Tmm4aC{Z z&ZqKEm$s`q?^a32i}lufwNp>L(klVZWei9yorD>_3-f(iC@uIVCTYy**AIu>6rVcv z5HRHh`1}8F@%TamL7B_`Sc1iWRwBbskm4tZwBVlQ?A!a0QD7`Mr9ZB)_%%^HfAH3j zbfY-V%H(AjbNVRIL59XC=IDuWkl!nOrP>xh`lljctZ)GEFjBsph2Ei-d=eS2jebid z{#-@LRxCoEUpwJJ8Mp*gw%5+5uBg`FSz}_fH};>nWcG7sphWd2Taj&pY+rvvP>E|^ zGpv^?9fMFF+>#H`_9FiHX7z6I{*%`QYN>*e(iF)OVlZ#9Z;;uMJ;21w2GM!ni-Y4G z^@Fx1)NM#OvHh$UZ9@udAtv1cl#X99D085GuOR>KMo*NtdZ%aNwCPzVHwHhYh3@*7 zvX8MleA60O;8wb1{&eu@&&yLP47jADsICHB)>hl5RnKOC3MuEr{Rs2oOKATHRb`_1 zpvtPz%6jX9r$=9iE1168a9&KDcPP@{oMULTB9!dIvt5ouhjH_8u;}lA26i!e8j4U_?+gp(-YN zhEQ#2er1`*bs9Be+0PPu@niR+e3#?NcNXCrT)F^TInoR@p0LQ(Y3VIKEO{Rc9zB_2MFyGlTk)Z0z*3`u5+G=Ar)rB6OP%A9| zMgurByM zJ+9%eCg=h?935v#d$a6Y2PZygO2Kc9(PP(-cG0={5c(IcLcK0PR!?4!zL4%djlyl> zECMCYhF?_v-y2>G=;vGwNIx1O;}q+=p1vab>S9~+0dxbHjU8?(ZXK^q&Lw5EbvAW2 zR%OM-94qVhE!Ef*-YBBdwECUVea`aGSUBPy-pFR-qx)r;Dw)~yROei&OzD{GF??$^ zKCq5zW6<;J(Is3(op~r39l6sgH;x=GyH=H)&c669rzIo|up*HS^FbdJ8%6UYk-_$? z5kwCB0={@6XfO>5tXC3Ia%x#c8TIVCuq;@0B?ioFq=CQ6xXR+N4JR;rR`Ds}@1Tum z;8(VBES_!Uw(Ebbng-G z1TS#R>Ydw&72&CpXgL*@$<19aiy~4UcGvRWkk%Dfs zb(tK1psqg5LBkv?b=;dqwzJSftvG)jvA?2f6Btrua?6@^?lLpM9$?0Jt4u@A-|_phJp;HV4}^{qG!d(Y{29H%g#rj$Ux@ z_!g_5o%I%(Q+;#!OvpZ?n0pQbZ505P9ZBsR9i8&%86Xbq@sZN|2c~Ox2HMFic5imm zk0?*tsJ+kp`cvYfp1dKIyAKJn_UQt0wqgQ#beK)*XkgT4Xlk$F$id^*I2%nwFn_kr zkq^=DAR;ebKt$e^=+I$bN~WVN+E6_}H9Qb8&0Bz8>;zgAhsLZlmP^YQD$u0z-SX1P zT@t#2u%Iq}thWE5y2jkCm7T0)vlcklKOx>FBwXOqurdjMmJ^5(gX#pY3U^Cci2Jc%qS>p zn|a{W+{cwUa=UM%#4$3brdd%9^#D#fb}dKFkM|-uN5-UJK8=i3NwgAIBYp#b6`c-^ z%s=R;GjZymr3-mwIPuckfrZgO{m^z`#ymSJ*w6x#cxrmnW}Cy+D{A--PCuJ>{y&O< zSEM^r8usx#DEFEZXK?o=Y^ZePKBIkW5gU#=VlCszZz-4# zZ&8c9POrqK3RO==sO_`g6goKZP3GPYsIoFY6&%f?@||NI2OIJa1%M#fCVeDL zh)MY>UuN2B7p^DvZYI~IGE(UcXI9*Yd0PWc<)K{U;Rt3sBt6*wj#sd??k5@wZK<0% zIE>GJ(G0H1hHUH(X>F9Ybp6O_egLxAqa3NQA+HG? zVtG7_@sJ}jS%IPKI2J7{~2hMdr`Ic?b1|tV(vtr-qwJ98%KKkd`t7Dp@pdM#&DERN$xEd z-q{v;tx>5h6{_ZpQ1>^#j2w+oj0e##KA5bk-k-16`+$<`Bj`f|%v4CJHW1oA&~^TO z`PZl47r^?hmmwh@^)jlk`{{g!$*F^C(ibDd5$BJ8jee#l(!ao?UprlSFMo>v&$i7c zknfLQ)dDCZVyh=RGZB4`(p-7&h-1u^!<|(ziWn}k*Dbs+3orJJ7%rvP->;(=C$`7! zSncrU_I#gbrI9#Z8sBK-vqql3c}O`7cQTQLX0zd~<<-@`CN@)fN=dG-dzeOyW#Hn2 zjjpc!y{1XGEi^9l743A}lk{Q!4vA3J7iwsn{cPucw3}xP%zMJTL_s0g`;W5g=I%&j za1ou%B7?5tMD7)EbN*^J-&P4X*YP`%JM!}^;fs9#>DM< z9cK{81{v;S6C5_8$31$qD3pFJOb^biC!e8YXxycqXUJV$*>{f%3XaiOm#t!4>_{)a z5jK^J)!^hjrY8#L{pwl`4#j2Ya7zAw;}{l$RoM*%=^Y36-}}M)%lj9?lBeY;ylp)K zUxr%UhCcss|NZff9fj!)@rCzp&GO89f|m0{*C5#?k2kNeW`9E3dItvQNbrBPcW(nu zHZ4WrWj!S*vMHJ7-u6=jmeY+{>qt!RlkEWH9hus5Sj$Vd%vQZ!POuW+l%fJ{B{JNv zPWsRPx)FEN%PnAsYnW=eE${wWGA>pnTzN9w1t%0qq7VJ$*|x)LSj)>M{<3OgB`#Jw zSyEt;n8~8=YXMz=rq9`DZPPuy8I(zik?0aF9LBF8UhT=5>sOW-x^sXe8qSovN{Y%H z!?%lNRaYnFl5$(hiA;iB!PIw(pW-^yG}s|R>G&+E4GR~YcjU|rDoYGKI6x8|XUbh6 zfg-c}!!ia7U&ro5gz^5;nb%R73f3y3zIHPoux)LRUf>)MJB3Ptx zC1bQjC@~amQQ4R#PlB9{C7jgCmkj4iX4(~&C1&M>UqSTJ%g=LKvGo=AaXkH zW1E_ZC`ZhV2`fxRGpKkL8-|IjvTcHpx9m!uB!p+^6 zaK&%N;(9;-ot_cH=VXPunZh%FB({3EGafVID9@GV_Blpuob0TMnX{MZzi}qs;TBzE z8Im-IVg6<&8#Wo=T9(yOW+939grFSWB+qyFG#W|c#qpI!o+r2GZyuV|) zO9+Fq=lAadaL6NIu3>DnvulZl0=v6J(-kXs21kh<=UEe9N4MsEeDm}Kqz;}8&)n`*|{dr{d7*jRN|mGbnxix`Gz=viQ9et}1yZ>d&mNAU5FAy3F+j@ao;2)f6iE zNfY%5LAUPrKy245uK$Cu=r-%TfP8g^KvZKKm@q&p$uKIxtB+9eX@~6>{^mp1Oour= zP>IKq1^E!#$JetMwA>5&cVjMY!z?%nC`Isg^JAZ1ophEi-z zM|Q5ph=p&q!&wKD`f*nR*CZF37d+2Df?3l~0E}I|7#Jy7gRS`y$~<(og`u+#Gfi5| zZG&10UL9dnzex~GFJl+kt}4aNjW^xe>!Y82jGeEb&Y5B^awpF8)(;TM1k~R5RK5|Y zaAJyGjGHj*E^8Gw>klHJC*Z={Y(MK#JinzW_RxvWT5Dskj~C*ft>Jot`egI6kb@A8 zcORbvGp9_do%vTV8EONnODdw>B7J-%Jow41y zLiO3!PX(-qUrAD*LGmK>&r4jan( zjmXuz#niXZb^aEgRT&=65^sZ@gDh)~s9}1K_xHd-^5A|bESKeQ7;}yu_y*%gGK@vR zhZ-$&Ei@3Uuj_3n?f1);Yb`bWPHB>fQjG-Ceqk?;3!JIvKXy*%=q$q5hb(aUa3pnp zdg;5Kw5+KW&6;889ItL>X%}*#^Eq*#CjP!^W%RZ?u>DW}5RZuYi*Mj4 zd;AT}DEW)}OV4Y_T3h^#?KQ-|cAcRr=%hz)@Ad>7U&Rhm+u(fsYzCaONIS=`P=n{S zRD^-cM~a9&eMhMD>~+EG$E9?9i)F@>ZVmmCcSeseO#6fTi1K9;KY9kACya(JL!)HZ zfcnlcy!t6c**$vCx`0j6FR~imDyB2#qt`rdW80-Ih4PE!S9KVbbOtw&@EuY9`;@P` zGP|yz7TeH*0f?lA_mAl>Ufo?mzIw8Vf|Q%i#nv^Y6t$jZLwi|kRilySmKrFj_~Rba zyO-o;e$0uD?WJwijR7-4{R~}wx@P>yh}I4+oSip6Dw941hlFPT@WiKf z6Em4)CYsv%%DLHoFtqMnvdF90SYCBe{Sx$ToAO`5g1S)4SkSV%y}^o>Wb9OLwcg`= z>iFH7W`_s?#g;(QLFPQixGm@T`~(-kMv(PS2P14szKxAEkFhO)Jzee80T5vuG70kL zd5Sw=9>munxCwTH(6DfBB!S!QMa7B@?amQl;IwP8rdscx{#(M^&{&W*k^622=*%IP z+Q$>opmZwIWG^Ohs3LBGnBPN4%T7%j$g#^5%Vg+l0i7F|zTr^x`2F5$bo`M>*%lGa zaE3m}%u0&UArf{WH?`@r>GWIz@!$A!`Nu#m5X5J$u~w>~ChC48OZX%H0KsXnA$0%s z>)s-&!WdYFnUR(TzYK1eOo&y`nNkUi@QGJ)HUU`St2?)5HhSyreB5HRl2ec>pzLs$ zm4k!pAqCj)URx@`-cYzI5r<^k&}}zb+49HJ2d!fsftZL^0` zw~rRT-bXbxLcO3Nzto~2t2rvWsY=yT5$5{xCshNGM{Nl5bhT4-h`4D8NrNtV)`cGT zl`l!~9M}Q!k#qN5E96h=N`BB9Dl0d>C(8yj5zG-scC44M2eA_96%P3hp5-G9u`)RFA;dJM5j$mVrY z*9k)9Sp3yr)h8aM0%wwh_bEKsqN0;V@s{f28c&dgt+yR(7{Z7a|4rHafi?+C&Nkcr z1EA`<7uU)T0tgr|XZgs%9<5s2A5SEDuN&9${_+rB$;dD+l8lWJ#~f|J?x2B8J*Kov zrg1-f`qU~`38}%A4(5p^%k*~z+!cKYej)c5It-f)xl>v?HdY=TcQk9{R@1GCn;E&u zE7fDo%T2Mf0Axe&!7D1wSH`R{TyW^1pVzB)24-R&QF_kd289U#y#3{`+UlF3T)fPj z;|zt_&;o9J&DNloNoBkyLkDDL0q)Kq-=97&7R+u-MGK{+u&FSSl2{=iRMAFhD`+f$ z7Bm%{ol#Q-v_b(9$Ig#3OJx=_zgiG&+-IAOf|zIyg--!-v71ceYjFlHK#GseGE1n& z8``R&IN1ZsC}gg%J+KN}arLbExW#QJA zB>D*N8hH!(LAeXLeB0bG;cKbn6P84N(Ogy4or<09t7=xgFTR}NNgSmz13E@Qdiyu3 zRHLq>vNYjRLp0xT@qHzv5xNQK1g5VX0&mpgnJ|njEmqOt<%IstLFNzXAG$wSi}djU zkl>mMTxP=n-omqVJp)%)1qlR3RP`+Y0H-BUNq99_hqWpVJ)+6z94N{s4P;p2j|>(R zk_Pcrt&cxp6OBSwK~5UGgX31~^{;_~I_YheA)9Br^mP7o3gg%O=${;nwyYMX5(g^8 zTh?uc{N1L#D-)<7+mhyzRG}id@NhMQQzzVrK;$!r$V|&b3zVPB$ywLH=GO@f62E~z zYpvt^VIHKt_tB=tQDMd3S}BRMx8}k-awFNL9NUDuo_8y3GZ2~=o{ps(YF>wO#&2Kg zT0VJ?SLuxm$k=~O#lq{Rx}#fCjq82}X98#dsUyia}I8#t}zzsi?x6+hDT0ywKmMeJZEyeloTtTi_l~e@$ zS}X=Ui&|KSWChK5uXt}&v8$Y?Y77c90oU9q&?D->MeLYaaHK8UFYc=X4kI<+<7S(T z;n?lpFMmpJcAxHB60M1+`=qTO(l2#ie3#wqJbP%}XxVW7sC)gV-1FcUy8T(}_`+Q@ zN0@j*@E&U+E_18LJp|pyXj`uFL3SDfM6?fmG=ET_1!gOO0tP|GbvuOZ|?K zJ_n9w=u@={+j?h+Mab?xUg;Dp{yp4DoBPR8T{*GX$r=4{>*=JbfH|rAArM>+BQ=$e zO809j_dot$y>ONv{}s3Z!VRb9zi6Xxf^zZFGmc4{aH`#2LSMqo2Y2Um06{>$zq5HA zxKdm7lalHZ12x7LUDWV;#!kkIF@v*oeEVz7DOYNXQn4P|--O?fEnGpUuv~rr_`YKg zZzQ(>1anCKV;iIVlD>CWYM|QFDYw9$cCE_O4yU~C9!#U`Eiw3mn-ejMB&jxqTOJyi zQ0qVwD$at1X!Z3Z8n)^XQ8GZZ&|R7X_?ibZL`4)&r zJ)MhBN=+$7Xi1i3MsICZL3buqrtlpql7#Y*lDxb*(Nek6#ra9swf;5J8&D_|WH%0l zLYYLrmTtbd(c$9jlA$%+!t#*BB>0LOeGTTLXm`~rU^K2V4QJuueIt^iBz&<&+vbl@ z;$K*5TtdkIJ-1jFnyUTH26>Zg6Zi=6O*gnmQ)ceh9}$3+#ln1@hmis`Ug8A?j%VRQ zfs|beT(WBzfVsBD6&AF`!CiqlMO__;fCGwVY0W%!#0rOLR@$zRBMR~`5%&(5ilrynNEp^r{>=kyo+_JKkVT6=P7iaga1*k^-sbRi*p>88B3Fb~|YlW7fEyOkcH z`1K)hx4WskX&K-JwIn;vu0eJX>@^=+_&^!X=q@1dGqk%7sY1xqi~!KsTb0Bn_ahY+ z3(RAjm@+Y+2}qGGTg$*>1TBm&`O*i4D5Aib(yfEo_rO!^WUw^@E*}>fmWTZ#gAEIF z7vy#2Eq;b0gua$O_}J2F=h@@Pr)IO&cy~PMrX>8lP1!LF5s~;KilbAgz3J#n_7cFU z&g_OxT+a$E=2JR=oc+GGe8?q7D~ROOc)b2)4KfYPr{tt04h)>$6cp8UL`iy*(I>yx7i`ltf$WY7MjTt|J^Q7Mt zds4=Dz+vN|TRZwLfa{MmOX++HAAiFu_uc&~pm^}+?+UC5m<}LDXdvqDX*21xH)EJ;Mz*+${+BBwOD{)ZeZXu$ zg3`cmX@{poD^i^tzZ1atdQKnvShHs!z7-!7PpXcjB(uBcaqfZK!G6LeP8?XS;Jv^X zWTtCg&94cU2Sea!!J^BL1G@L8+y?bfq5u%ov}qqr{r}+hLgNp2_n9no-b`?; zp?5_^I@_~195|o9Wf%#w12O%O*?}wGmNmli)G_yQIuFGQJQG`5Z}8TgxU&AL}VJfkpCGy>Oa?SB_pH~VR~6DgM`t83p+C{9b? z-mIt0X|r34ad#G zQ(2qYn*gl*`O3`j%B|jr_@(C7?>~f{I@n@VAvQL$UVCAgfTqx|{d{7v_Y+&?j~&w% z$xU*j%gBOFQqzgr-e4aohtj0cahhd>4FFdB@_O&W(*byFRnXzd4`T53mrG>5;%3yDOGhb z04aH;BRv#Zrs_O>mvUp^d~bf{@;mw3(v|P+md@?9SEbW)x`RSI{l3B0R)6K}ud^p4 z9hRGvDf*L|()y`Z{O1F|pPHRJPuc4zq`KN(?%DBeV(QMni4M=ysSshIkS5!y;cd_O zz^k72KKr6bAKg@>J#Q*JtZ^t@Kw;Y2$dYtQXjCUGVcFrGPx8Vmsv_g>r^^$Uo@@)y2E*541Yare zo_*B0Nhaap+f{`z+6fKGv-CioX+YYL*mMPVD38_srP(UNT{8(dS7k=jz;T{sZ| z3xT!M$l54jEy-9Aq%bf5nD#B4`$$qL40)a#7sU)#unUpUzyhUkT~1YTYQhylMd@T; z{(k;OFRo9=Hs@7ZOGi1Dz=EplObq-7nsb{Y*KXnm@e_@Jlik5=3;3CpI??qjW6lQO zI?E)sgs^~(uH*Sp5&(9{wMsV}TaYynOSrG#s#}kj1I5K&8bl1gI*uS^s#vONrI0Ia zqf)J8scqeNKiw62d?rhm}h7#dD|_+6C~Ic>V$^j;4ss5#~#ZD;H)5=BgHpODY!T z5qHu$xE#fhWoJqt7`lTioenNEvQ-hdmzOn`5Qww8;S5)BAG2`wY=yzHgv`YB{>hh*Ck(ptI`6*Hp|^CbvK z>Iqj3tn61-;lyA2^yEidysNy&Lgea;GAW917QT+sV2))qv~X;tDxu3TaBVfjqW zMGaTzme(+ws85h%+NsBEaA#gr}tV#$(aoVhL~wfMQ1AezSQA0<|EZ>A~PdEcE4<8J2M#D3|_ zTPumhz05z#&(@RsEVeZNYzA@8vp>KGWA52)Xb~`LlxTrB7nt+j={Bqwn1u#cdi%-} zznwd(oERCbC;l3GxE}WFg8@4mF&h9p;nUJw@`Fv;NiI#YA@bS&=3=Gr`~@xB=T}@5 zww(R=aMSGh7M0VRS%z-c4#?c6oO_*Ssmi}1MNRA9`0gJ{?u-xyj3;6cmVvSIGhe)| zUkfbrP@ag*9#H*Roh9Wy`ReDQ^qr$$BWcYT_KZ`S${TR?_9*|k zym_e;WvT}q{ph1-=NvHTATXQJ+uTysloRH4a*G%^C%khVT7H01fZ3AG%6j?m;nwmE zbf#YZ|2KQlL1?vn{;wf<2av%l5C30nU;qCYt?g!OzqbEx9btxf2|&s)!)eixroQwO zGYI+KHrBSbzLvz{T3dTrNws#Gn@3250~WUbgr%}jgB2XkFngin2B6k`kadE2M_gS2~{SpFMo%=eoW0O zJs04{oh0+x!&N)K(()&wvL1K$oaz?qYD=aNSNBTS-rei!dbhR4Kx+oX+Bu!K-x}~8 z6ibGLB$rU!)}6qBfU`;_Y~_^vyG&f(spJmAAG2Tn-OcIt`gL?^_EONzRY$e(S$6JN`S}R&`(5#|YD; znC0PO_Yy+6uRD$;^#{iQp$B0^i;C_6gdHQ zv(Br=+#Ck7^-660J*UhP(YL+Kw}JETegP2=Bk+N750}Pl-2{>%DbOH9Q4Vg#`)7LY z-n$p!_tr_KeR}olQ}bfStgvk|I9puOVpXhucF*+o+Cvi)P}BlP-jQbvXOly4Xq)!b zFx_og8Kgbgm0dTPSHRe?eat(NWcw4P@BSwKcIy6j?Wfzs+n+Wmn$^r2Pr+gVpsY;K zY@M~Xdeh%YRvdp!cth;04F0so1LA{h#TCClzdo&BM4rSp#BJj3M_h@4N56@`5sXnZ z?6-Iw5Dzj*kh`9FL_FHu_AJwcDn5_6<(}_r^!pj{>~iy=58y|;phgHH5U{m7Uyb0z zj}V_l9A(5mBIek|r#?KCl`j}xRZ*%AiPQhK*HnIt@D4#pKi(}ZZDeC*IBc)24+1U= zh=2_eTO3~R%=LkCe4V4Fn)$3&h)QpVn-2;uF4|j9Xq8wd^g(z}94ROJ<04d`W^5S4 zeoEP)fM6q(4NAF{iv~mBq!=KD-~tM==5RVPhcg=>fairc9aE<%0m0nel13-||Ea`O zZfA((5lh9j zZ}{H^l(NxX@dxbvK}e0>0-`Nav1YKS1FyI1ml-AQ2yjr8+3^0&@nB0^#-643OJ_Xf zzNM}5Doe`t{8Z0?4*@|3?U|`;D{`@}86Ii?^B1O>sQLwH(0`0F+C~g{cexHW3g+R2ssStYN4PKu@!&Juu#)oY$ zl?{vor&(Q;1852?8qP6UXS_2Zr=-wwrZi!EDrF#VztyZYQFgAsE~hJv=7c2ztG7>i z<}4zxp^WD9pu`=8QfemaC#hHNCTze6+o$a+EnOHiB!lD6jel)*CmA(YRY;yg-ja&+1JqI z`FslpHgis=3kaw9=v<(@&uU8HA{jcKkh#wU)QO6P(oDv_pmRI0ATa7_3AOH7oZs6> zveF)KS(NDqFfRe+ofAxj?&U^=HbWhRCf9Hy`IwgGCP-O3r^UV`$Nbh4zS8*VKA%o> zJ0s5Am(19ZbO$d#MidA(k^o(Qx-HWw_ztK2?jE0RGzh?2)=R-;iFzY&vjA(rQ)8>v zW)0Z9rp{rWVngHm>dCE;rrE=PE_r4hynR}B(+tbwPy5{TQ?T(8(SG||Z_I|d!oW6A zD#+ANW9@C&ytL+uggVO&&(6X;xsDKsfK1eR6|iF5ZJv4MB8*Rm>9x42lGDqO@sqK z`fx^IxX0E0I4!EliEe5cL+qGvtdoTynJ`7^)?ji=MscQJv5*RSz-tl%yP9bMz^bMB zGF(`gkP!e=&G%zF?D07R8xX-N3q@SfgX;_C&sajAyjJRG^#=o%_fa!9N5+6A zPSCkR~vIM}iFSl^jz9-$JxdlRsrG`Y1~L0E*HyX!@#Et&N`bC0Toyz1&Ah z(rXpUu?0tgDeV)n=9Fr)o(fUHy_a(!nrMlsio5KjlwSn}TF?8F=0&JkU56 z2!^^^GF41qhil#D_`kat8H97*{r9=K;Me~D%Q{mdR4Eg?|KA3e$H!M+3RS=Xn$CWDMil*-8!}yX|{8-Pg}tzMX7 zNjq|jPeihsty(I6e<9IP@t5>cnxjV7)N2*CiDslR{(O*!Tm5ogc3$@u9z;#7lIJP#z!FD%}j>=wS9xwi* z41es8_O*5&Fi25LY$v5xwE?)kmPCPho_Wg8Zsds4jcvsPVgU&Xk%_x&PM z-e3A*9{cIWlpYq+N+sJ+18{se@)&r?o(>jMtq&SSkydQUSvEzI#URbw4)l-d@O*aS zf?)+5p#4WkEz5Ih)rW9N=fy}(wx&~A?Nw3?jfIP zkK8K-#rTnDti^*FjJ%T~XW}mL?V(zXjwNPgUDO^P?a4Ay*0fToN zDsRZ8$yLazk)Nmifjowh0FJCIL8g0V6Po z_S41)w&FIT@$9jHm2h7?14S7V0MDkwVTr0fti7yZQO9Z@A<4}>$qD!A`Z9Q|=)+ZJ7 z)~pn=c82(6J*^a&T#>`E3(MPCf(`QEXMp8`t-(*ShcQ68z~FkiZ)bXkqYBHZwsr)0 zjv79`F@L9MUot_4aBqivp|o~Rg#C@7O8e!ZVgJp;6IRXlApu^-|G;Z?Zi}bUMP>wr z?mX!R8=;AVQiF25rN2#0wY_(ep$vyK0%NVJ=B?UL-!Y4|T_1JrP09BYdzO6=j!!Ei ziK)-qjf7kLLP7B|!gPi&bcBdj|L|suvl?&~pD&G|7*O>^hqSNeVlwGU?rpPVpLO1O zY+i8<@E&h6;44Y3>Mz)RxAORU82PeuTD3jX&E`FfYrAW=G`T)c!KOodNQNKYgFymz zN8^?kdS5g-)-H)Jh=xYfmRSNgk$GCEbGKeL_Lv{reNo)Gc zv5$bI5DwL4p$%7XqlOFu?=gRVpKi_A9%L|m9Wg2`nFXf2sMOolItv-$I)~Wv7P*>{ z5l3e^B>3PGX1EJa=VB*8;h)msNS3YBM%5d$K#CibTIq;2)rHd4X%Y4;wIIbW$oHMC zshu|K*<3=I1*KMW;zeg0u%Rdu5vcD`WeMWz)ZTAF)j7YnV4}go-pz1wP))R$dCe$c zo{;CKS6x`^lBdflPF^Zn7+^>1;El~M3eE7S>0>)e=J-bVA(lDO_9g1HwS&}oG~+!Z zw-Z#Z6DC13T)V8JJQn0a`#E`C?xU=wk~c`b99nTvMreENS!$s)ym)T{XV{`*RA3gE z@(N1rc@EVIx7;8yUZ)3|FHbA7lwl4=D_11b&VKRUi(~kic-wAIq!|Oh&DFgASHKs-6?iS_%9-&9DN_ zr~Mpwf*;kj^L1cSX~`6&Gef2Zof~9YiRQIl;Y%OkF`1}6MEIbT_R>T3G34PI>@UC& zmYlyY6L6>Rk1gPyqq*H~&Fm_rV{+hqg!K^&2MsDZ?AG2ht(3Qwy=auPO1pEgN}Hc8 zMrPL`ab%B?{`*H3j!pckEP7X)ydr8qKULj$bV!eY&<*jnPU3X71IrSo{ z*f{2>bLtPx7?h_O(<-b{(ThsNo?TxODAx5D2-yHuZ(Qs=gwv!n-R8{m%-pkw!^on1FI3 zGcsBfrU#|b(u89|qFp3S5Fda7B{h3PDsk~(k){*#NmBZxV99Glu*SxEGdQerF(S#Q5;3gB zAx;>-e~YVwhA})aYUZ9%E5=+Sp*&9t@(8usOE9nG2`??oGp=NTPz1LYq+IotM+-Ji9=iU1ctd8WWeG*bWL9; zjafoB1~**$Kl(+R5dM`c;yb*Skx4z55ykdu@UfY&V@tvjXt{7vv&91rLGM|4x1x>0 zg9~2=a(`;k)tAvtr7)f1KO_93Xvs&@tr?EY4; z!#K->-FjT+cJa|D7tkWWS8vrDn=_1pW4&?h&J-$WvZ}6mumEatFGM$;M1Dq|e%``X zOMPX)`}WL@_ouTe*lbi*bXp8w=Q$nAo9O;L^~OLwG4l)z?YrWxMYjm1IGmR~OXg4e z!n|>C(-hNwDnF1OqkLAmXcJ54d{*E4Xl1ig?@4E{OwLpf$RAz#S<(V`^x0{M# z*!BFmX@>O}RQC&`;lqK^zdx!jb^M|$B6lhohTUFC;4BGMuWg!wzdt&eFlT+kQ1XS_ zFgev#r071La=mX7gHzL|lR!(Ud6SSVD$WK?2iyeb^Bz8RlF*5y#)SG-N~|X9WoDrF zYfc@H+3H-+1KEE+M4k7H7Ao6|VD1p(T7{W+Gl_4zq&8jkr?zZO)h%11*3DiLxKk)k zZu86&&ds2*NcmynL#5xUD*|$009tb71RoLx;GFaWWLvZo0TpW_qPy`+%zSBwxKD2) zWX}&S{R$72-{U!Z_G@ub)W?UNR1v(!?L|$^bpXYLHX<(O4*(b;8&uW*i@Gjh*FUd| zUh>wv=!gFGNmYOQN+V@}Kof2dWLR!s#R@>aKoh<~eQs{ulW&p?Zu;Tf3ft&!#u^;* z7&RSGS8*CrR-8zGqnM#%ULXoSu5ZICs|F-}o1ze*pOUUKVX+_7WlT^N{ z$S~jQ-CES z5Jqs2Rd6K>wxq8wn5IhxNLQJ2*s!fhRr`8FR=N!F-r^q>_ufAM7|Kvpif#T`KZ1mC zPU4hs9Uy{&5zR=C5rB5&2BfZF-C|ag` zXx83@AwECO6Pxq2q~=qa>R=>@yocRfZ3N*;-vCfcIDG=K`I&QLLEi;anTA@TRuEqG zBeoGnVcUqwDQ-4ENprCcNURiV3)kN-e!kj<9g&x9xAmLAyf1-6o|~O5^b&ck6>+}~ zuq2(ln{nWLgMM3}auab5C`4U0h&^dDnup!oA9Fksx~b6i5iT&;pcx3`26eNcy0$aD zIO}BFp|c~?T#)$~bVh!nYFI=rg+U(o3Yn@ko|pa6zc9SekETTcC)Tit{u@@1J2h4~ zr-yp;fR=&SNAJ6WIx6Z=f3UHg>$XI!H%0jAu?8}*o}GVuJPsH!`IDvAoD;Yp!vdBk4CqPlTDv0BNYih=E)98rH*bam-9mCo$VrgF^>Y<&jYs zwNm)lOhqZ9K(!pf?WE|NVBXC^_b8Hb);4kAw?j$nKpv*0U_??)UssigTpjSZsqKtg zX|SMC53)%n^rPqjhkq`Q>2B~cRI19Xca*9pMN=nj$pV!kuSq54D6puglGbw=+)0?h=8qY#VNjHto$Hf;fV}{v!-TWA zNyjdGi`zW_pQbInCC7`>HW#5zN<^f$WKP2BdsdSQmEY5%{sf@-7OmP!m7PbXmXbSb9Kn6sqb`Jvd z6;@xOzGVMLlwJ-DFkTQ|M@mRoPu3C%P6PPp3bAt&fD5!yqqvL3hD$=4>D7q$1@s-vrWEx76Go#tloKMVMKwYW%+6?&MuvCH+bYCS)-cHWAetC! zBJRo-WZVV+;KB&S-7^{pb{Ap$3LzpBs)NrM=)0zi~;83Ks)&)SG1sxoIhe!P3+7xb`UOSHJWsVH6Hn!-M0b5L0S3q;IN;re$@#@*cSLNkXz~dbW2m zNnwi$5`WL&DoE^ASCC9W*1~{N;G9sv4S(s>+OSxNPoTm<3&d9NEtuRKUY@40N}PIS z)%12DyynP)L<$cOAzNXxy~GW1kbL*hVG2Zn)}}Qi%jvUegpI05yRd|xgPE`|2V)ok zTJ@b$*JflBZ)j($)Iu;E&LlYc>Wr607Z(%SFb(&rV*7%6x$wu(uOvRl%WK4DkQnWpMm;X0#*Q z7C?|NG}&<`7K>+8Q%Y4+!gbFy0cBl6XHQSmMj`4Y(R}+1) z2^d6&8Yr$>U)M<$YD81m)!5zBZY{ZV_S$sk5>L9ZG%60zOfO_GkfeZjia6Co*G{e7 zO^!Bfed$^N#$y6Yr>@zyAV~0&QAI~|emCoIgF<)By?&T0ptrp~DU?Xmsv#iO)9#7~$f(LAZr?X)>as$s4X4T*I^?qFH?T0{!~yX7@Hz(cs5bL{i?66<&@Th>-CMg{F7p2=E%hHL^(YfH+ zaM^w(G#c;8S-EF11U_$2V1>wGFItP+Ap}CEu3RS zl`zMqCxSYpR{_>20}^`qI=lEx@+>Emaxed<$bgaj$f0hf^_M*Mo~TO09U&3`L| z4|=n%@YUG@{rgzOA{I-Y*}&&iia&q9zy5f>U9_CWz7;=}KdmYu@>!^IgD6n#M_0&a zFM(+`2fKNNs%rC|Ko&=2mgHDCx3Z)-nxlLu(GfRIEXQ;3h{ zAc}glf9}L9`*>u}Kv=f2>K(Wyz(^F_G(r3G<8|Ga+*bXWHa0W9K~jf+R7Of{;w7rK zlH99!A>=GVC%x#?pSLTK%kR&>>VF+PUq5ai`%SBP)Om|d+jM-#U*7KhuLuQIzQRQG znc1}=im>H|55hKV0_3{S)aw9ypqRxWR9S<7B-W^z|NBc%ck|01*AKfm_5!LY0sr*4 zd5mKxNVj}|MIY$~Qgv+Fk;%4Hb>pKN^thE3f{N3hRn%<<^}UFJW8x-0ceL`G%&sulBOs~%a;ax9HKq-o3+t(I3=^Y37U{tnl3i|LcqqntyU*(fPnZ7qMT4n7*GS8#;^&9j9k2$!%zT7{aJ`(62E#n)G z0S6#<4@3;I)Y&mf$=o@iErxm2mV{Rd3UaNGY0{N(cK~9kO>xXnAP4Bu_#BQM+`uXX9Z6I?n}Qy|Kp=R8WFj9@2KF(No1kO* z2nL7&k{usnK`}d7Mic$C7!Lm;Q0~!wvp?Zy@mhp@ubG9SxB~F`&CX;qjJ8OnX_XUY zM6WDd3Q@N(GD+9|E6t=r3V@eo@3};`=))7U8N-a!)qovCYpQ`3k1a3Lf%&A zQO=koGH6p05tth^0sQxBd?_gO&j!{3LU3IQY;qM)sNWE_x`}_6J_22utZ5++q@WMu2I0oSIHvIDR4SMpfUp6aeY)kpg*TEgwZkML(T_s;R5|| z7jLn$G0cTYRJ?e{V_w|u8B`MYI8>CnHdgAEj^PqIB-6yy9}ISZj=m4kn;67;CW3X$ z-$RtN3_45Md4+iabdf%t7Qyw&R+LsKa1uGR5Ut~;RzSFe4PR!DT8vmo*m3LpL9?r^ zMl!w_X^p@W8%Qvy^IGoaiO9w6?t0v>dfMi#YbybH*Q5ti!AUYkD~QD8faVWV;SQ20 zQQvqrfQ8IYP2J8mBbkWItL&?ocX@7pNh1EFa)oNWH?b^07cqj z#`)LITvMlF6rbDGZpGkO8lrfpNMy12M$$Pq8mDf;4kgZPH8xj=N@LomELQi8<>_c- zL4ZklW!q~!^o>yl$C>|JJ!Umz5cBs>7o z&&GhsMhgMc(4pSfCvsVKA258&5GM1d&R*2t!_*BEPY~zuh&gEJc0yNDKKCdzWj8Ha zI!E111|W#ZZdpXgK&EaoEF^p!XYo4!dYPI~gE01$7zPl4lPl#FMq?bap(>K4peTpn zj3rYAqH=Jbr=}ZTu+}vkR4lvA%1oF#s?1tJK~ExjQ)JoJ0Lg%W#7JZ`IfMr(40ObJ zNIuY3G6~Duv;HubF0eJb)E^UL*G0dKzNQ^EB+IqJlFZqcW zMGP+z;nN}UjY~n0Ugc`0eCW2S7NzOpCSs^k4W1lz7ZefGQE_XtjRmljhEz?yvXR$_N^r;bkvyR|Fo8B zbG!|_BriCp?O*%9KfKYrADl{v5Xk|HK*rbu*`gR(V|?s7&lU{_p-mCq^&@n+oTjx+ zKglvvlVl8)nNwHWXk=Z&$JnJSWvB&bs_rB-;|hvMjc^oE-3#;)c5q~Ca4i_IBB!Wu z`&eOOZt*1;3Y9Qwi(eD2$ebiFL+GIQ7;UL5bB@hWYQsUQlTs`%HEJ1Nr+G5czsWkK{g{$M*JwVsf}E_HhOPQbf|CD@VbNe&>I|ZY&c( z0;?i8c+hIzwQ4f=sZfR<;hv(9YZ(Zmh729&Ip-szio~KkG?7z6d##jeJ7?kiLCrqj zC02U90XwK5JPns#ucme@QbRm7+El&+*1x~E%_ zB@-cazF{tyRDU}U3|xf{JrcY|p>Qn@p~CwSOD#gbsJftfK;~i;h@CuWq974DBnV5) zLfL!f@F3O#+vaIs_rqa4FbD$2yzLzqamx<$;7hy~6Hd`%M zwFA|L$-8!O0syDv)XVGh)5Pt7-B@5pGZ~S`-iyN0f(k6l%qXphz(j?6`(Q0<3Ii54 zQ-dmAxK!#Kr`-^&+`1O4^$q|)WLp}D;h+@GDOcaEPJc>Y`jM$3wGB(d1LT9q5HWy7 z6gXu<6iEd;L464f6dygg7B9$os**YSiih8tFPuNuhUsEwN>cIX!UDg4KcAe8nWIci zdUX@}fciv?r3)yo@u5t@`QkTy{!hlJ3EMQ%oQ!*QC2Lqy3p6!Et$CxSr<>~ZXi!;N zDAPzn#+>1ZWt*~}nFEKa2cDLJxQO~l$+lVG0Zx4A2!IT0$c~Sm z-l-Drwn_DLzoS`RcGEb}AS_ICbwA7oE2DY`yTcU%$r{EO*f}8}mO;HKaa5$8jtF}O zQs`u}kbrm^i6ll0l96k%Vatb-Zn zh0!?Zc?@o)2PGC2IoTB!IfI%M^E7uhj`l3GxTShqE&X$^OL>rcxk4e&@9k zIRl#T*mV08={ra!C%i*Y#sXbzZ3F~%gtd!hltlKittKj06IT)*nF0}hg!s_FGYs4s z!F{oq=wq+EnB$S2R5gf+?&{JicwsA-tb92D<67q`)oq`K%GNXxvg0u~VU zvcpDV{Qk}Pv|o`aBP&)UcRSA;3gdfQMRyRHlm2cT?8vthEfLlQ!2`eu_wbBSK&2-{ z{v^<;pBFAGrFrS}FE66J-i#OC^}ip$QW(NBps3W4$brz$2;}Ggzkx@%#!4 z^9VuV^S~64v>l^XJSp66Z!MqIeWzb#K53OC*kW{`j)w{KE}YTb2RGf6a>c?hFyPfP z+KNDLPT@wbK})@+8ErRDW1l6~iZ(@6cT3T#-(DVf+geQ2v*v`FEmDQb+JX&KQS*py z{}R0(QV0r$|YMx z<{h+e0#xDY4WRPQNpR5IVlzKUv!3B%}4qM22L|<0Nn{$FwZQUX~BDAj_`a zb(F!uPOF7LRXN~5#dZC>Of7RhSRq*r#R4KKME77ikZd_POJ>YAG!|mOgU89__FC=2 zWgfCDqBL-iovB~3%;YCbPGUPLqf7Y&IFl*;v#KI6<5vu=si;1}?T$~wN?&9Nw|mab zT;9R6p|_UmaB)XyXz_?&L^rjW)N?2_ldjo#eanizZcM}Jy!#@S%+b!+-pxO>(LzvJ83VpTbeP=Dzn@jn=1bR+>?*pRgR;X@rbK0tZ>HaZDk2=u5z&wO) zP=vzmT-O(_RCu$i+}de%kO{zC1iFEUpinxfCy~1hr$?nPw%8>u+vndj%$$)Q9WaM- z1{=8pu!N+s!>uU%>9sFJ4}Y|*wk_LPkqeO{)L~3m|EZ3AU??hr?kOucxb0}Zm^mu4 zY6)$h)Q;P?6heHL!;&S8Zi&EF=tANw#h|5HWe~J zI8Wd7)bnZR9ia}As^5_aF039T8z5^mmV_PU6Kk&@p_MZV1E{YSPEOSQZiJ>zDnP>c z)3kxqu5!=Qg*K$?(iV{Qw5ZE`XsgZ5^RFyBN-@0bpjhGd|65u7AaO}w+Tf_S&@rgX zmJ>3#C4GJ1*slClN)aiL$`?g6&?m#;Ps>4Wz3RpK*VhpQru0oNNRb2~#?Hn9X4Tjf0$py5ro;a3U(|s!lT!e?DSiZl9wV zD3kHhOf$adoPtSrErr`alwrOt++vp$gaE)}jtt2B(gB0V1&GY#LSQNQpA*R;Mc}scIlypQo;kCwmZudH@*|d(pbIK@~(j;aTXSe6*^5Q49vrk@$P`BAk;YCx(t4w4LEa72lh z5lt1GGS-OL9$y%3u<8oPBc7f<5-6Ms-iQ-EhcPQg$=#pxSXuqRjZjT97oUzNMv;jV zr4L}Q_4(SpOX)VNb8@8C^Iw9atQzal^nI$Z7vpZ&VFaPzy%d54Xaq2a@@;VPlQaW> zW5tBUzM<+Z)%?w@srfxjQ$B!Vln2COsYOha(L}gRM8zd;T{wN{5SSFhtk@ypLzCxj zaGbN%0TsLbecx0Pg=2hL>AkoLEKBu%E=;J zD^_nyoS7*`-m`0OIaP(}Mz0(51MIkOO4!x`tUY1#v9S>(-HK!@k=+z_4@=$but^-J{T%EfzOD^TM$S1ISCxK=wtCe2v&GJxxDhjxaGUW zyXpu72niPOJ3{>#ny-LpK$|3FS~TTBBH^`J4^6-c(o-m!3mencGBUyiRnB1Ouzeh^ z4EFd{0-7H1+}NHZuzwrfD9YjmgR_cQ&62$^PI7&zw+^i=nyhZDxpXd;sY0sIlP)?i zq=|w$B|=56%uc54$z``{bGI3@u-b%egrp35EGw@9Mt0I;>Lcg!o?RJ1A~|gDF7`Bm zy+<{^5$0;8*id0BLK$OI((1Ryh+}S=O?ZzW;Q6lOhI5&Yi?wU39)yEe7Yd@>h4KQk ztS%K5Q_Ef${3mP1;-nf7v)F4(6Kh`xJ(OT__`Oky`#oleOfi>+-HWHrTLwjEDKwh` z2sOYIGg&G`i>a3UKq@r;CX@r(rre%aUDzXm%2FS`2<4j@(H*vGuiA@SZY5%TNYRX5 zm(ObEsmY73ap^Z)k=d-9yp4_9aEUL-r>o0ZZz`ufH9hDp6<{*$7tI^K#Q={UAK)w% zT~J6ds7-5{1?G>UHgor0gQ()xQs`IhBt7u+ty?)IcU_Z5x;oZ=z#Rki++q zV~kQ=SNUj|Nf4$assm7nr>njGWoiA}`-5e@zzPZ304yTmts&s`iJ3ZfAf~Te$;!r2 zuC+4)b-6-yAExlCLDOVbHJ1&B-7MoGj=YmjqFE_FhlN~P4@5O z<+9C@*@gbiOu5R%$@9FLj;A4LC|MwprEU3O9+e%Ghpt){x+TTqO67$CV03*cNs&#_ z7|%*ajC(+c%r_$&NU+K-sQC5BH^-&kV&de`XXDn`tqyfv<0# z94+>zpE+gU$+W*gWY=#tR5zlC~)kLkL#JttGsz&jO7bn zKt&ald>&CRQ-)8dVFMwrTS*`hTa73NL4OoAr*b?8hIq2NDE?WPPedMA6+Jf+&gKkU zgkSwzCp?i0{YxbD>f@-VsPk;6Kkf(B=ctGQ@YB_1Ewac zvNsq6}FGWT8U zJ=FI>y^lDvaGJ9?+%USX!`H<|^fhOo=f=4?ZF33(tCkKeJ?&AG(>k|2pdLsVYkgtW zH!1!XPs3&0sSPn_GAX>z)nJ;6#;h9iGCK>i&0YyUJh6p#|lcnzGhMFQ+s>$iH{u@mkCtTT)#e=T{Sg|tJt?j4a5Lu*eM(6h|bKM z`t%cVY6aV8MzPnqZH;arJ6&nYiy%4fW#odz$Be9Q!~%zR49d812sCK6nnWpJ)?;bq zPs%B95(8`PqSv9YI7ozEpJ>pAb=zlK&QzA07Ux`XGS3G1dw`8MP9V=2auwek(`dpt)nYj9S z3O}dZZkS~M4|bI0)#?$57NxD?h^kmQ#ha^ZA*o%xbdkKSk8vB}Q&hk2XqqCrZd;|u zSAUaKB_|)CIgkT&O7(^aG>%M|8Fqe;K>W25;ncUjO5K7eTi2~FH-;P}r6A|f6@D|y zc&W(4TE3WtDxQ27I!g0~*p@3R=nJ^r zsU@MyIUYcPYZrXg?ad1=DrCHb{sOhVh#%YQ_3X;kAU13hS4g{b&jeC#yumJpyqh;O zk3&c9+(yB}kM+cx@8(+=ZR@%RRPnMbpZn&@qx)8LsN|JSQ0DHR9zNXc(o~2ll{+hqH6`~s zqnSAK-T@jB&h&IIK>Gf_%h5K!qtxHRQuR^Ca5=NCa=og}3Op?B9@)0lS?~^%*XO^# z>yZzKtkO+?=B*a3am~8404}1s;IE&3=I5s#bz}u$qXX5Nx@jUiU{8Io+}HXqSAg~Y z-Y$5{yJc$`H0jl9EBZA@YX)qV6eiF_m1;rQ?>kH0@tgI}n}KJ4eY}ksD8j4FvsiB; z_+3j=)H~#nER=$;mi5@bbjDdX{^X>gu)IQ9oO~qQ*c7)OW7`se zg(Zlui)C`-yzEiFomZnI3H!1o^Ncp`I?$pP`=hnM%b{{}FIv?f&UD=Cl$%jPLv@BW z67b75V7_0i-U88=yks=5vR1`@Oug*K4OZ19W)r@`yD&G0S`APOTP)+mMIE*%`4*20 z#EpvMyfupO)f2E4_2GcLihD3^auXN9#@8<*>EO;yh{MKsLg;YA=p1j0{L5Ew{O)Qu zm|rooc4@75OD3Ya&mS?dJbML8r1yBND22@$TL2^06@MLR9kCShL+gg0oeGX&VTyYS zkl`m7&hcHzLG!J-)zVjpdWrtB8cvTZa$JDkn!%GA^&lQkCL=hgb|4XRv=ObU*!Y9Q z(s*>O@L4Y4I1rvQ^s$kI%I;37mAL*+#4qa~Yf?T`V0^@aFfh4KlhLx&EI&njqy>b@ z)E(;0gCkp-?7esAY?TwhHE7{t!b|@7{Sl}2BQ3eF?{ZW2kbF0;h7_<1R|}e2Xp7}~ zyW{UsJtyDMrt%#t5h#4k$|p6&;w`1pWVJL`w`7hjZ@vQLkrCDclAnmD1kcFOp#Z$r zMp%NUOzWopu6^?3akJ`eiQiK2J8JQ+w+FHOA+QP`Y%vsB?4aE}Shve=9lY2;DUmeT zNkh<{U9lB(f?avZ&`2FOZvQ<_-}M5n!5yIa6@GmKITCNmYhcH~tA3f6c-R`_rBi8Y zK;=W=MdusD5y6jf9YO!FO=~zFy55OZozT-LKz&6Gz~_K^`xd*V2nvuUas2Y50`X+2&?bNvCAGd3ulk;s>PI@-sFDsFZK;i> z3b`nt2z5`YhzPjy9p`aq>&8HK#2c)mB}H1~?m&eHr)aBFnuwp~v?WoVca)dYVZZ7E zI6r>AiaDRUM{p5QOFzwb<&0Xa1qHLtKmKIbByQ>QHNtsP?H8@EMc)y4e`3p9V~_Er zitHlx<$iy)Td6woCDgLc(Rg0hKzBngl#%z4W!!O*iO0sI_@wNtliH}K=o&geS#NtX zw^6e;Ze1|Op-~b3xSfc%XFF>$@MfeQ`_OkW+d(x3BP(iRgxFD35SH-KN8w#F39C8c zF)`3u*p3HFI-Rq8&kM<#8`jm9>Jv8JE~py-$vtu3O(UNRJV2f{1S?6Ck4YNl5ZnC4Cn&rxx>BvbD>ISbmSdP5xBcS0S7+s7AR;nY= zJ@^#g*(QVyuY_y7scf3|(R^?}gwI02Fi_yOK#rR(qBOsZ4HI|;3!8q}2?87KIo&%N zD;(d=ahsz$Lu8MR)EwjR)()cbKgwq)`*luHhH^wONAA_ow_D*|T= zR<6ee-KvR7_QnEhni^3(#^4S&!Tjl+2H8(?Csp4w zFut~l4iWM?j~$~}-AB4p8xsKDyx8m{_8||5hSlKFCeRYq<-&>_&;!TyC;Br3wCjB6 zzPEs4Zy##fq|o%&#QJSiO^R$J3{37W&kJX9?YpdMs5>cSP7zeF&Za?hC7r*POPLH6Y}FK5Q}b*NkL362>v97 zDw4{;2%NCfK1xFK2$hGmFh|9ocR0cxB}8AeS@71Xq}z`AWfLZOe9~(iXUow!t)j8r zYJpy5c?Yzn#q;A(e@j51`|F^c7B-+Afr_uvNzQiVYO3@^{KeXaCQ>T6Nw>ByjuXt> z(^yo3P7yfAvb15O;T(+f-ZJ4^0LC~?RYz1$h)Y~4y->Iy4FFQC=<;6YtxaYCw_tgu z$G&M)+sW0s*vFjU z!^qcIw@RT3=7(A*<{&r##FJu?iWCC9^lU820>G zlsGTg+`FCt`LJ7t#3N=jIJE-dP-JOqU$Fc|8CHd25wNyfnD~T4QR9wch5fn0;DeJU z;91*_xb&h(TSz!_xaX0_IIodLV8P^*G6G#!yYh0g9lJHI`53~It+M*P;9=qHU$FAC zpZPS447)l-Qc8~O)LQ!LUAKc0MX=ih8dPxxAtsB=D(4w3I$u$^o5fn?p45VEImewz z$-$sHB{-M^jZ|`K4aufxHw3$|x|hjdDox1CxL=Ic)*)jRqAt)V+>#hVQ$;bLf198l zwAd!)n%_)rR!X*ZILYrWk9#|wTo7~To;Tqfk2k<|eK+mHO6O~<_e0=NKC}!{_=?F? zKG!G+{ECCmjRN?TfYU6Uc2rQXS~Hbdfy1_Iq{$>8-G^ON&J00xlwq%;89LLIaQJJr zu^|xz7eI7fL;NU}7MN2ESp&U$M?{ZbGO%HjS+BOkzrsNV+U1LN=3}?%n&7&2-#{%E zLPhyT6i8=9#)6kJEy%(dFOGvXFH2;MW}Bv7mX#LQQQETPolFT(0Zh zNpWGF(YX}()lWVlpW&8 z%x=w0sIXL0yX8VW1bxJnHc#kB*KPOlXMDhhhD6@*AAJjj4}E)a$ZrS%Bo5XBKDTdr zabI4v8wVcQ&$PN<*!gFC_d~Tg|2xY*E8;_bGgC|EQ0?p@zux^kO|;bXx}=*;hN=ui0D6rylv0rE1vlhn&aQuwse;lU1#8 z(Qb+UCd(ID=PUl@4k$e67`xW3P*jJAdc$lH#2Yv)A`o@VYJ%|i#lY39Rd7tyu&zXN*jysv*{*LF%#k%W> zHpQybeh4GC!xjJa4xHs8IfIB`2P>`y%f`=!KQ?yIqXk=Toz+-|pR_&1224^g%22wp5l% zwxfw=dmgaKuNFy!?WS#i7D+;hu0cTTf*4)IxT#2U+yq5a2>bnVB3#V}xFB$|bmTdH zK$9k92w^_W&N%yS&PzzL1|S9f7k0Wz>04af_(PrwDWoRPK+!Dg%F4kx(&hUv(&QF2 zgmvg=J4f;Vz|s?LLD!N(DNsHsKTFU_AxbN5v#*vW{&3!Jnkd z3tMK3&)oJ$$IgaHw-8sW>|J?-l2>5qjOVl_UJP#<)Cqk(jE-p)LZ>3VTPLKhltlu-B`hN8p< z0o_1@6C~=Hi5CaWAs{%>t;@&IazQhr^@eGlzI$?=1*xU95hIJqLPsiO# zR^~)}L?0gDI^t!Dk_56?n<99k9>T)-Qu|~|_~@@^Aw1|qQ}PK+y$Yqc2^Kphj;AP} zo((BJAt8Q!C7&||M1EkITI{WU&=@tZ6)J2prf@;SIi@VUXjN(a5oP2V_SC=JL`WOd zo&#kthUW zgWZaMW;!+sgI$5a+TTp$c zVlvB1@9FL2s~)ZKkAjJkYYgA`c3=i#Z<8~DGw0xC>2w4uiPZmO6+q0q&AkFCZ+FvG3%4?)%Aas|{RNPT?ncMeh$!j=_D?ieEk<9M$|K-mmllZG zxjCJDEEb?Xf(UInfddgNg@Xz=qCzAMNn~=|=q|(e*XI~fC@G9fQ-!-Ls@nK^9mLp)cJh>?9S86EEb?C0F9t;fugy}QjBMU;nMj`VJ8xJ z?;KwF3)yQEUZ|wL^n9FKWT(P&MB-zMndw{g(7&RjD*i%)<02XPO>A9H{4E{3?VWG0gGZ9*x>&sN0nSnDg3H%f@86A^a zXAxodrjmL@6T%CAHXHZ*Z_R-iUZ!Q>DGboX?bU}NMT9TZUF!68YYFznHUgg}anT$? zYGP$ZCr7hDCQ6~@!et(Hs@z`($MEY1n))q}H#lEI_W`b=3r#@pF2e;xi`6|YtYVus zh>e>mFV9cc!8?IOnU(Fe|3_2tPkX;4Fy{0@m#x%QKOi$*7tZX@YV0s<3Lgx73B%SFSWJ9K_QMvSgt=0EyA zzuw3H(|C1o%tmA!~fB2 z6a~Ix^S{2=w;#_n09M3{`0*Mk;kxyT_{{gORAFx6G2wmc?1s47`>t zs^Va(jk&c(V}u8N9kY|ZTXWT-f9y50e7D$zRBhOs{MT!N@3{`h0!;atIdr-Wm5qsY zUBC3EHgqPb5ChxhUpN7F<4DMmPc0w|Pb~u%hFo3)lFRY5KNK;n9LPQmf-qB-y|4k! zR4m?`bIgkC{ENOBC)Y$|36n3MUi7q_l3x?%(a;5JL5^v_>jUB1fCU|@k}1gk5P7X2 zEZ%G6#3N6=mF5x=Pnd2WMoP#-|FSKNfq5g3`%g8v!bAj3<6^xt{z`~QlkmGjf5W$=w419t=zX7#U z%$Ph&Ccrwicu1zwd}0CJ%=_WkyUaruDmS}iIA0oHXUCZTl#GiF)SClHe*IWDQJ==B zF>b-~YHpivBct+4rs}XmcZUTP7>U?*@Aaz)wtViJ4d8!EVk?U0UtT6cN<0c zzo#QqLe44*Gw85mw!Ik&whaRmQc%+eWJ9co)U=FoXK%ePgr%R#?A;-{$=jKbCJXbZ zJ0atRJdJnD*mqf9Am>ADR2i0iV#@2`?~urd?$EGFUGEI8j%XyzL3Tz*UhEr>ht&kz zA>`<4W5}M}t1f?A_-V9C63bq9OXn>w%Q6dCxoexsnOm{nX$6)2Qg;Ya^d`edZJJI8w-4}_O>`Q&Qvj!Bmqczz%EZ$UJyh`KI(4&dxC zuUNDtV|7XEU7|6fmCpV!DcLQ(y*}OHkfSQuG$(|*{_$@{MAjxBj6_X5*fVT_DwhpI zK}2H{C%(=P2Gp)fm0G$wI@K3)>kpf=#VS%|=WC?1SQBBk=MNvBABJvkZLu%4N7N>4 zYEx=Rv42lJXn`i+#YN-AzV0_gN*iywtyVs>Y0GF8^yRfZ6xlX=1ZISzxTP}M#VaEn z>6GRK6X%+@%?9e(B_Dmd5oRo7P#se}0~hdh^E7yn9sZMOU<_|!6SkAKOfoOJw(mB> zd#keQTDFl&7$#nxy=TsHjWD9-sZutUVXR4t^HQx)|M}hURmcso5QX9aM=M` zHvmyq8G1ELn-Cbb5t`RHN;F@adZ6ZaKxOxvF1k6df$ayerGadvWA!yaKLxAW%e=eq ztt*>fr?}g_cFjnC(39e@pf68TJ8~M&DYs8s?m3o zo)ZkuyyKp=*2Ur`-nm}Wi(CLb61;j48RJnLxlYH3@Axu~#L5ymjriIiu85q@}ffYnC)ut@Zg0LaY2Y z$ys%D!%H!sNGySKnY_CB1BFB=X|=ldoZ`U~3boTl9;N>^?4?bBa{N5(-v zNL%ng=9S(H8463hvUA8k9H4l*pAw{Ne?e`2PN}a5C^903v$R)1MQjczmLX!(NgR^D ze|vv*SyjL=0q^VQm5^mj+Mn17u$xcCPGP$foWri8xBpNrCoV2TIU4Glyn+t#bz!;U z!uJrQ?9q~MS4l`r(s>c}JtRZrz9&yf*Y>H5wI!y>rA+0MMX`bq>hJxeh^w(2ig9Kd zt!t9T!B>wk?s{`A*9dse0nRI!w0w5+(pKS7Y)V?Kcf^b7W*3}UYzunvd<(R1t54{2 zDEx|rmZWYsZPdF6b38C)EpD~m5GL-DnZpmULW8lHi6R-T7Jvm=_Kg_s1s>YaS&K`j zQb(KKJa@|`tr;PdtYrgl*?2Z23P{W7fJUZKX^I(Gs|)a?h==~@qWS~kDV&tW1Lx$e zps-%Hsb*3w$ey4*_-=k0=*ngUAElU=7cqIweVPk(=jS=%_auZ89Pg8CrU5Bm7}RWW zPIyQi?%1*S?k2%xGYv>A%32Q(B;Y(>od*I!aKsfvY#j|yuM1JxKh1~W2B)&n%ep@5 zg6b>qV}WeBqjhUKpg3zpo6Leju+n{Y^NO#!C->2pD7a_n5%WhpeqeZ%52wg0rte9@ zrT7MqPsb%A4|vH@E&#R}B&Wk!xARzLpTlyHpim~g&btT?|5Uq@vNOwNx03%#W^=H!CT#)tMm8eYbv?!~d;x!1Zn?skVbadu;CIz)2PwywGD z-aNs>O|j_9Dmz;Pd?tX;!?i$*dPP+ab0p9tyF@LU8?cC4t23(4*myp1R(nY9+H(?Z zX#xr9q}yA5%%!xTB!v7aar1R={rSWi1Zn89SK+$@eG3}a>BI3~pk;Xi7ST3LV=TI; zc0ufZ9eE2jKTzuTpnZuloRlGmGGb~*yMUOsjl>Oc{rRXG2uVdSjCcds=4RiHvSb9c zHMJ%m&a_Q7b=-4f9yyaz7nJTCYWfMeWj72vkS_W^tR0B5w*k?5ujH*<*0~b>0Bx|7 z0gbiMwrZjqIMbcqc;&hO;~Ad^SX6?yCy57UtO1pdZsYUyy|mj zZU~E`c6p|iCDRq%ob|n8kCcrb$8?$bi2PVw5pD641FI&8 zc?=M;yZz(<57Q=Q&V+V1N=I0%nIQOaqh=OYAK;dxnK*JfSL#G`nW;@mREKK_b}uHm zP5jCF#4lSHYEkXgXGw?dQPK+y6?<#vLvVX6v0{GQ+H9h#LX1@Gt*Iez;|lshf3s%6 z^Y(_+ke_y02yr^qPoSQ{DfcBGQ|vMg!ewP8S$Z>a>0+5=7E$FhWBweIyvU0R?mmtp zNg1Oged3Af&c`Gp-!bazya2R38L+ZnNO~~;BxasD8LNVJs!lsE0mi>6g5^Dn2F*)fjT4*zM8v3hin$_v!uJDM_xEL8pZz?o_RO zEaMFEHNCjWuHOE;54GwU_FqY|gPJL(Rj)y#Sb5-XZsPC$ukYPPz48GtY4)GEN%%6reyREN5z_2g?!#)!y7Ga;Vq> z5D`&#eqc?&zYyM8);nyn2x5mzwF@nV{le2!b9vIPa+`7$Cg}vcvxRhm<_iVM!BW`5 zASaU8O*3bDxlqIc4HD`OS1+j;cNiyBs=q2&JBX;_mMeB78p9WA*9$@Yh4f+|?Bk-l z8697#x2FWE=$My=8D7mGv3bN5Y-cRk%2wW`O6-lOvS4SoOYK(T)VsDHyLQQ>_F?o* z76Q`na}=LH46}wA3&M7qd2^KKhdVD}&v(+*R`C%o32=u0<}|FZnIu>jB&}$o`h-^h z?Z0gC%o^-m0`nGdExq#_H&M+*)Hnp~CZ*s=N2i?LBloxyT}|X}9Ix`(OA=dl>vTDj zHLC?Vov$aHnbYcqD)GvT?@EwrfioftWbM*LL%SKY8v`vP@RtiPzl1irD)f^d>Ie^D|NkJQpit zR7tO$@eU+;L5YY2J|hC;`N{IKDAp3%MEs&+Z5SQP&?PA8^G!0pCHaRnDUR_Ldc?sz z#S%<$ndiM=Wr7$qH+P|Cv*du4r>w9PZ-W9g?RN@_OlQ zD{pC%9|8>L0HI}1uV?upd*2(d!;|1P!+r?MZ@z3YI@Clup_Jqsj46lZ1!988(c%A3 zQ(lP;bFOh?*Eb|O33Wt?L8HW$G!9ZQZu*_szr~Kgy2oo)Ear$vV$SvGB*En9bB-E|CZg+s&WOQqB z9hV4mdOe-Hcp6u(!;2Qqlh48JEc}Idy%kdE z^6zwZU2a>qsaThU%~d>1agPkY&)KrgxXN3Rbc&cbu?s-EMIvr;#nj-3?PxQXhgcjU zTQ50pN<>%7>83&2GN5!}C|^z#E@LQ#!0?ts3=sq%c(cMgZn5A2EFsv1N8beDUGJot zEgc+s9CF(lC*^cE2rW(0>ISFdp`Rdum!ZW7#!`9`!mcZm=Bl_-$)x`W2ZKAlO;{&n zct|5`H;K$GL5Le9pP&X6tBaU2&>VwLs+0;pN&gTEiqKNCSHr_o&5=Xh%^fE~u*JPL zva^K}JBGN+1osh%eN;;8v$HcKbgZaul+yJ|$2GFaBj%Ibsli-u1e~`YI!3f&QKNCy zDp`FZ1;CAle}B{+-6Sd;i+BiM@N-1vHWW&K_8fgkM{xKomh{A_**ZMj=WV@SI0)?< z*4g>Lr(@ZvSYKNmatvp{4rY(%ZCiWN)kfrt@$A&6rLA^L4jo;_Dn+?5&6bQ z*ZI)!couS(vnycs2@f8BBwr|r7`(4N=W09O9lQzWOH7topRj45Pm2VbL7~9tVkG8r zsHv@6Z{rXliK)7F&^Pva8k2Q@2!cr0V1$#2EUoFAEm~@{^pZ@);DsNe0vLk24kP%W zxPq6L)?aq42;-Sb%qM2;mdW`V-SG^UH|o$6HKOiFwOXSQQl>_?VMh$^9$zO+j;L0n z_4sy!)iax-wK7pI+z89XJ0B2b4Y&UYYw#c3DVyw5UdtyZH)wiq&w;%IF!Rnf;sGO7 z;ro}g(QPFX16x6Oe1QvF(83fRB?c;r50;g4*PR2FVc=OL^SZ!~ryLlc{e`O-HfIIF z7{gkO4=m4R&DHhR?HoBxud`R-#`Rj9b5INQvGE9R z7<(gi`Jlvs6_^F4Pv-?=P=U#?0L~R*nv|W@Ogy$}Znp^LYIQmtDkV$jsKU+r1qC5GAdPK1n`=}#rgZ+%UsD3 zk(kpd;^@}8L|F2F8rD3X>P&IoNXoozYe`_93r}U`baTqv?1kTDkN!I5mm4k@as`sb zF*lAKj?>$DTN?J$%F>l|i<`1K!Nm`+zweFn=NxO7Fk#r$>OSB0w(l)QT{4wBc9I{c zqX9AU8?&+LF_7927sx`xDWe88EW5|5>Gx%tt;VkE#q3w zW%g`zb+MR*cXh1n%SCQC+1(ZE*Lt{;hqj3&Z~0G6;dfABC?9*jZaZtY=!gH0&Oio& zA=!VKM5tbdOm|fH#c2g{)i|#~PAXhbYQ`6(B+jJDZ>F_qHSeoS9g0k;G(k4GQLZ~j zAs9ae=Rd=uRxoc}NRynF!W2&76+sdC#aBKu$Piz6&u3i`vyfux-2QG8o7lx6PH~A_ zJmM9f_$9zsP)oh~A=E7{h~IA{HZDFvxkcbs_HA*9+de^BK!UQ;Ry*BZf1v4xY1wG# zjNI{Ls@2)a=^T50aLp6NWV!0i&Y#lkEHBFajhu_itLvNFyZeVn0EA!!#c+b8Xolr@ zL6qeE;doM1O*c&Ie7WB4p0c!7s~=(WvR+V)h&?~c3fd+5=r&UCupo$pBJy4b;vb-c_yd0087ZDUzJ z&g#97KKrtf-M@SMyS}H%WOMm~{HX@7&9!}VXkUx$JI=NpyY|%EXV=uZ?wf=AK7|oT z6dHrY;R!^NfgzbfrR{ZvF?^aV_TG4s+*>fefWLJaR;cJ{Xz66yWnlD<#y$(HY#-zb z5hg;o$c`v6qQ5cxHGa4zN}~OCojN$UIC;2r$@J0D9Y6xfl>O`HP<3?oKdQa~jm}`Q z*pMN|h`T>z4><4gXuuW>c+m=_%DD@du3Wou>&`s|OiAGNP}l_iUP>fW>5Sjrf}CUa z`9iT&zJGXps#I(BMzhriM)3J!GqXV{sx?x)9%k_4D*pBP@K^VnJn&m}V)lJ*=!#K^$dU%1scg^7qtUHAKVOtOl z_u3xyxatET_D`-cI215VMd*a={h;xK)MD2+lHNIyqoNje<=MXqKU;`)<9&TKw8Q0b z8wqdL*q_GvPc2CmsopzFT{*k~>j!jfMWOdomb7uhJ|J<&k0K_0R!A}x~EB=k5JdXdWk9twHhm9UHqID(i8vr>QM8t>YL7>iPE z%p;UXAkmz4NkkqyC~m@!&q%7sc1^0%6BAiHYku?XY?gE#r}1~|hc6=E4m#~2Ktw8? zEh1rDsC0=5<3cL!xF%ahgbCw9X~)f0h%hds(vEAgRU%U9G1~?JF`$e{ywbDu#NEq-8|R@nM-WnqygJth)o*`A77~X#Q%Ng zkqy89KNs}}j(@>q{~G094@xFZPoMm)?;3d@UPCynNINaH7q$jG%gIbz*IOGEznob1uwjbvL86A92F0RRag$e=(QROmn# zdeDafXv(M$UHppq$D{&Std%_i1VeCO1g;u;-C3LXaMGt~jEC}qUYfP1X$RNH>7PL4 zHWp;1?Z9N(6Kraf662+UVj??wgi;eYE&Y9f1X>_rBoLUuc_vT<33?S1AfR4hIv!B3 zJBEoiuF*jYHSKn*<4EzZo{qq;A|MFh^adHRxEi-4F*sbDN8m+z*Mc(M>zDrBQ1FYx zz42fY_y9lwYgVfSp+rEC+@To(Br_nk<*o5S~EnYyF18Y}d-zouFqY(kJ7{8Sh*~f^|w{2}k+=6;Bv_MEBrACnw zP%DzDR0T3NYAm1SYKN1h?U*!{3$W{>xoV-eLMbn7!nb%c-h}Mc%l%Och z&^w8~2`i?HVg4X~k)sJ$5+cS&5%@wn2K+ceMaE)i+Jq(~b6ME8ssU5AsundG1mCxs zF;g=%VSPGmLqp6&CVDLj$buqQsm2SI*=Qyp6NVUAvVj__t4Ps|QA1jQ(4hgNV{;X; zi2%5+GT4;9RXmru8P)NceyXX+7f?O;OPQ>?>^_K zrJEnGSo@i!QbhUUv5fooFO=Mz=~MUhiq}W!B}+_$K146R`H|<#yp{7$>*Ym1`rE~? z_4G|v;xWG)7894x7g0DDxHVY*Cfnk92RTy@?JVfKvVHx6WfgD2^;lhN7aqSMF7@|e zX6q4V@6g3c{??&&(*pkOSzRbCqtK-J_|Qoa#zZaI>nZVN3@#Uq0%opcIC4=d>C}#b z2kg&2iq}{Ca(TKw{p$Ss+JDdQ|EsBxN(!}m+<0`=ylZ>A?$jX zuJOrREG8-*%HGDH{xAI9^hf%KpJ%&I*geIOf4{+r9X@xAZffOjvSkR|Ca!R(#c17< zvKZqH$$AG`j38xXYy*d|))M3Wa$J3j%U+ZklpW*%7LJe-^)_3F0j%iccWB{Ejqz9t zbaXW%LIop2g}B1Pp6+D;?)neASts#eaQ#@>;; z#KO>cL7;KN)EPy*b2)VyBAw6takRKGqfz1DzY@JW`+s}a^M5w{pYY4)*Yf|pZ_-#! zN)`P+wu<3qLe2ZS-d7)+pHI}C{ywqs%a#A7*PhFrSTmFP?NiG)yc7B_M#j9``D<0D rzwL|XYrafL|Ml4WJhy$^1)0z5>YegTQn%KB>5uq*)_Mseuz3IgDP=7_ literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/fonts/fontawesome-webfont.eot b/docs/source/_build/html/_static/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..e9f60ca953f93e35eab4108bd414bc02ddcf3928 GIT binary patch literal 165742 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 G*yFsbY~cLNXLP73aA74Mq6M9f^&YV`isWW zU@CY~qxP|&bnWBDi{LM9r0!uDR`&3$@xh)p^>voF;SAaZi_ozepkmLV+&hGKrp0jy9{6cAs)nGCitl6Cw2c%Z0GVz1C zH-$3>en`tRh)Z(8))4y=esC5oyjkopd;K_uLM(K16Uoowyo4@9gTv5u=A_uBd0McB zG~8g=+O1_GWtp;w*7oD;g7xT0>D9KH`rx%cs^JH~P_@+@N5^&vZtAIXZ@TH+Rb$iX zv8(8dKV^46(Z&yFGFn4hNolFPVozn;+&27G?m@2LsJe7YgGEHj?!M`nn`S-w=q$Y4 zB>(63Fnnw_J_&IJT0ztZtSecc!QccI&<3XK0KsV4VV(j@25^A-xlh_$hgq6}Ke~GZ zhiQV3X|Mlv6UKb8uXL$*D>r^GD8;;u+Pi;zrDxZzjvWE#@cNGO`q~o7B+DH$I?5#T zf_t7@)B41BzjIgI68Bcci{s-$P8pU>=kLG8SB$x;c&X=_mE3UN@*eF+YgP|eXQVn) z)pd&9U^7r1QaaX{+Wb-9S8_jQZC19~W) z*_+RuH*MPD=B_m7we#2A@YwQv$kH2gA%qk7H)?k!jWbzcHWK497Ke<$ggzW+IYI2A zFQ_A$Ae4bxFvl4XPu2-7cn1vW-EWQ6?|>Qm*6uI!JNaRLXZFc5@3r48t0~)bwpU*5 z-KNE}N45AiuXh{&18l_quuV$6w|?c-PtzqcPhY)q{d+Hc_@OkartG`dddteZXK&Je zGpYJ-+PmEUR`sOnx42*X$6KT~@9ze#J>YvvaN24jI}4QG3M;w<>~!2i@r)9lI!6N1 z0GN((xJjHUB^|#9vJgy=07qv}Kw>zE+6qQns-L}JIqLFtY3pDu_$~YrZOO$WEpF>3 zXTu#w7J9w+@)x-6oW(5`w;GI8gk@*+!5ew8iD$g=DR*n@|2*R`zxe7azdr7~Z;$%< zSH@*lQ9U(Hx^%Fb|1?Smv({(NaZW+DGsnNWwX(DFUG8)(b6Rn>MzUxlZhNbVe>`mS zl&aJjk3F~9{lT-}y>e~pI}kOf@0^%Vdj&m(iK4LTf6kmF!_0HQ$`f-eBnmdTsf$_3 zR`hz2EjKIKWL6z@jj1}us>ZmY)iQInPifzSiOFN92j9$pX*CuV8SPrD#b%Qa97~TI zS6)?BPUgFnkqG8{{HUwd)%ZsvurI~=Jr8YSkhUA!RANJ;o|D->9S9QB5DxTybH&PGFtc0Z>dLwr|Ah}aX`XwTtE&UssYSEILtNijh)8)WWjMm$uT;+p1|=L z><4lEg%APBLn+FRr&2tGd)7icqrVXFE;+3j`3p~mvsiDMU>yK$19$B@8$Dy4GClfzo4)s_o2NuM3t-WhCrXE>LQ z_CQtR*!a0mhnw#I2S=WxT_H@^Saif`)uhLNJC zq4{bSCwYBd!4>6KGH5y~WZc@7_X~RqtaSN(`jfT!KhgGR)3iN50ecR$!|?Vq8|xa+ zY#*+B=>j4;wypclu7?wd+y06`GlVf2vBXzuPA;JgpfkIa1gXG88sZ*aS`(w z_9`LL4@aT0p!4H7sWP`mwUZRKCu@UWdNi-yebkfmNN+*QU+N*lf6BAJ$FNs^SLmDz z^algGcLq`f>-uKOd_Ws4y^1_2ucQaL>xyaQjy!eVD6OQi>km;_zvHS=ZpZZrw4)}Z zPz(rC?a`hZiQV9o^s>b?f-~ljm1*4IE<3plqCV}_shIiuQl=uKB4vUx2T$RCFr0{u z1v660Y3?>kX@{19i6;*CA}pJsFpo{nculW61+66XAOBZD< z{H|h`mJS5C2;ymL##}U*MC%fL0R97OSQ@lUXQ-j?i{z{=l-!$64H{LlTLo{Ln<|OV zBWq*5LP`KJl74fC{GzzP_Z;;;6i--QpZUrtHC@+RBlt+=_3TyV4gk=4b{TBJAx!GehYbTby(&-R337 zQ%g2)Uc&K|x|eL0yR*VCXDBqZ89C(obOFYYht(k`^q0OaQ*Y{)@7xE~KQ7XN)hGlZ zl5$1<#s!tyf%>mbIG(9WR`R*{Qc_h(ZGT^8>7lXOw^g1iIE2EdRaR^3nx_UUDy#W6 zy!q(v^QLL*42nxBK!$WVOv)I9Z4InlKtv#qJOzoZTxx86<5tQ*v528nxJ^sm+_tRp zT7oVNE7-NgcoqA#NPr*AT|8xEa)x&K#QaWEb{M34!cH-0Ro63!ec@APIJoOuP&|13 z9CFAVMAe@*(L6g{3h&p2m!K zEG?(A$c(3trJ5LHQ@(h3@`CB*ep}GDYSOwpgT=cZU;F&F6(b=V*TLLD z*fq(p>yRHTG1ttB*(Q8xLAl4cZdp^?6=QjcG;_V(q>MY0FOru|-SE}@^WElQTpCQZ zAMJy_$l;GISf1ZmbTzkD(^S!#q?(lDIA?SIrj2H$hs*|^{b|Kp!zXPTcjcCcfA+KN zdlV!rFo2RY@10$^a_d*-?j7HJC;KhfoB%@;*{;(hx_iP`#qI(?qa{b zH|YEvx~cE^RQ4J}dS>z%gK-XYm&uvZcgoyLClEhS(`FJ^zV!Vl&2c{U4N9z_|1($J znob`V2~>KDKA&dTi9YwyS#e-5dYkH?3rN(#;$}@K&5Yu}2s&MGF*w{xhbAzS@z(qi z&k99O!34}xTQ`?X!RRgjc)80Qud0{3UN4(nS5uZ1#K=^l&$CdhVr%4<67S=#uNP z$hnqV471K$Gy&){4ElZt?A?0NLoW2o_3R)!o~sw#>7&;Vq954STsM(+32Z#w^MksO zsrqpE@Js9$)|uQzKbXiMwttapenf8iB|j(wIa2-@GqE@(2P#M09Rvvhdu!sE0Mx&cK&$EtK}}WywYEC~MF5r3cUj%d$|lLwY4>`) z_D++uNojUl@4Cz8YF3nvwp>JWtwGtSG`nnfeNp(_RYv`S2?qhgb_(1$KD6ymTRgnD zx^~3GBD2+4vB9{=V_iMG*kQTX;ycG^`f{n+VxR4Ah!t~JQ6Z?Q;ws}Jw|#YE0jR0S z+36oq6_8xno^4J?Y02d!iad3xPm+8~r^*Vvr4A<|$^#UEbKvJ9YHF=Ch2jF`4!QS# zl8We8%)x>ejzT^IH%ymE#EBe2~-$}ZXtz&vZ_NgVk4kc zOv-dk(6ie2e{lAqYwn9Q$weL#^Nh?MpPUK z#Cb)4d96*6`>t7Zwsz#_qbv6CnswLS9Jt|b`8Mqz?`?H1tT99K#4#d+VwAy}#eC74 z;%UFxaNB!Zw`R9){Pncrny4>k;D}TV2BU0ua-+Fsp>wmcX#SGkn`h0O`pN*`jUj8q zIlnc7x6NRbR)=wP1g`-}2unC>O6ow=s{=NV6pfEo3=tY8 z=*$TKFk8Wv0K8B_**m*Q>+VW*1&gD#{#GSc(h#YQL?*<(ZUx~>L^RyAG3}j0&Q|mJtT7ec|Y7cr~ z+A`Wz!Sqz9bk0u-kftk^q{FPl4N+T(>4(fl@jEEVfNE$b*XSE)(t-A>4>`O^cXfrj zd_nrA-@@u?czM(o3OVDok%p3(((12`76;LwysK$;diTl$BdV)!p5Gj=swpb=j2N>b zqJ1D5E#zO9e(vJ6+rGuy<(PS-B6=gHvFat&)qr%j7T`vT1ju zIvHwGCk5)id{uDi@-e?0J*(-W-RGZs)uhSeqv7TA&h|CUx(R0ysoiQC8XnxL&RXI3 zO`H`8Pe&^ePw*`{rIJhzUg@MuhUL`IONG^*V?R0h5@BRDFgEF45b0jSrg0r{<4X)nw^c)uQ_Ai_p>ic!=K$pmnyqYb=`6fUo40ru#Gh= zMRJxOD(1n?Mjz_|IWyJK5^fh3*n>eI0MmEKq%=-oIdGd4F-LT>RL)Bp5FWxb4aNLNXB^o?YBSXQ`SwN zI*N~(CQW~P$HpzwrMG4IZKI>TVI4nQ$a-#)zV}LE(xgQ5MG@L#e!e@ ziNtg{Ph&qpX9FLaMlqMh>3)Nu%sAO#1NEsbe=#4Vqx0Y;<~+mV!xwj%}Z=xZn= zSqjxSH4T~v>Xd*=2wmHPN?@+9!}aQz-9(UIITZ==EB9}pgY1H4xu^-WdOFSK!ocZc zd-qhN$eZcN#Q^0>8J%)XI$4W(IW6R810*ucIM7Q#`twI|?$LYR1kr>3#{B{Z4X(xm&Cb21d^F9MKiD=wk_r+a=nyK!s^$zdXglCdshbfKBqa5aMwN#LmSNj6+DPhH4K-GxRl;#@=IJc zm{h}JsmQFrHCioWCBGzjr5p9L4$t4`c5#Cz(NJ#+R7q-)Tx2)6>#WZDhLGJD964iJ zJXu`snOYJYy=`<+b*HDiI9XPo8XK$TF86)Ub5=NC@VN#f$~GDsjk01g$;wDY!KqOh zC$x={(PT7CH7c?ZPH{RNz}Tel$>M0p;je4|O2|%Yq8@sCb7gRhgR4a*qf+WGD>E8~ z`wb<@^QX)i-7&*Z>U6qXMt_B2M#tzmqZTA1PNgzcvs|(|-E z4t*ZT-`kgepLl0g1>H!{(h8b`Ko=fR+|!L_Iji>5-Qf34-}z%X8+*Qwe^XrIS4Re$ zWUblH=yEfj!IgeIQ>m}+`V(4u?6c;s&Ym_6+pt|V`IQ1!oAC@R1XC3tL4BQ7`!TnU zWaoqG=nhI@e7dV7)8VzO8ivuC!q{hcxO7fo#2I=<`rktP0OfAO-CQE!ZT@}e7lw;{c) z@2l7RV$@&S5H@{=Bj~^Kp5At=Jq=Y92rXP@{-D4j>U=-a^gM2s-nIZA;u=fbm2BP=Zca5W81_cA>Tr z)x+r@{pu_la2Q(wm`Zqyd@GhNDNT&4oNHb_>w4{jIU}m&iXykMxvi;WL8;y7t}cp& z9CEpR)WlI1qmOq!zg4QTmzv#eP3>NLd7V-+YKmuyLFP533rd>WnvL$F3b}g39PYk; z)^hXQ%5jO(B}-TMio7@t<(V?7M5!ycd)u4Z+~!hym9+KwPVO^Wkhi^Dc7$R@)o$oh z^mRbgQ@5EvalJa}V4Bi3cs^w5pYtbXXz5W|e%+z-K;8M%Lf~BlZRvNI7=)cG6lbjg z?)l8iOw!mU`uaKN@UL4>d#edM9^-ePb(VICy6Cg-H^Ew$n_s801w`A83W!_Z{D+1G z(<9A>WB@>)D%cxw7c?Xv7N}6gg?&TkLX|0@k&VL)YMI~SsE^dzj2^3BKL7SM$!0Lt zj;ytKWw|(58n6_NNH$JVRh!W*wewMr7)H2jOCruuJAIIfPMFpf6j=hL!D3nVT9Dpo zut}|VoG<%v&w;HrQtz<%%T&X##*z5{D!!egoRN}R_Xxuy+E3dhx6!7mlNyuqsKR-P zlP#8EKGt{Ij~8kXY?&*%q)PkPG;rziWPd>HefyPwV49!>f&Q_@Fn{8Cyz{HCXuo+( zJMu<#{Tl}^-dh%nM0IrDa@V zMHgAog4`tk;DNK-c{HwRhx%Fn%ir3mex!XeZQ4QY)vQ_iZ(j4-GcO?@6Z-Y*f?u7_ zmf!}WRoGkI#BO9;5CFvMobtV@Qm?#eNKbbX!O@xEVhnm z6LFnWu=E}6kB82ZEf!g}n5&IuivccTHk-_5cazDAe+O!_j+dQ~aUBy~PM34Eq0X-LOl zjunFnO<4Nq|BL`!xwvyj&g9Q0(A_*xLT~l{^nM&kGzB7+^hP^L&bD7iVdXe3wobJXVX~o*tX$ zI5xthE?gAl!4+v~+ASbN2nYIqNn_#3>!fi2k=g*Hg_%caA#plNQR+RtHTiW>(*OFG*-nzu~6DMCrX>xzP`3sj}D!||8 zf3dk-w(NCUMu^C%k|t?sa>9gU_Ms-R2Hhm~4jNfPPyH!3Zy zV0QFf=MWK%>|(eV$pB5qOkC)uou{oIJwb_i4epV{W95%N)`+uOrLx7fNtD^czsq4B znAWb+Zsk|YX}a?b+sS-!*t2w1JUqU6Ol`&Jrqa5=4eeLWzr1DX1fWW`6MYf+8SOW< z+EMJ|fp${RJ7q9G7J+`pLof$#kBJP^i@%wNnG3fnK?&k>3IUVo3dbs9Nt)x_q|wIB zlBAi#1Xv-<+nr<13SBfkdzI?dJ|3~?-e>MzG(yRsA}I_oEd{HEGZ&7H|Km9mEbL6r z{Ubhh;h6_QXN_?>r(eWJ@CM1-yn6Y#am!aXXW!EfCpu}=btdYT?EJ>j+jeuc%;P2g z5*J%*$9La$^cy>u0DqjO#J%*IdaaPnAX#A6rRQ+sAHhY@o32==Ct3IF&sM14!2`FD zA))>ZKsccTyp$U0)vjABEY_N5lh(@e+Gj>sYOTgf?=82K)zw-?JX2d$x}n2Y0v%SjDtBXDxV2TyyxQmN?2%8zkKkKF*!AA$P$1#qrF%fUu~URt`tp3C_(>^tkcbHhO0Hh0A zpTVQR{DjsD=y-Bsl#nuTVKRxYbjpSJg|K+SEP+^Y*z3S9p(_-s9^YP5Zc?Vz*o(Qx z?f03co`dGfW}0T>UdEZaW>s0XVEzlw@s&bc+B-9;^^AGsx$AE~!1-7?tn9z|p4}_? zRsM&sjg1>#Rb#6jFBRKMeZ>I_4<%=&rF3yqUD&Lik@7<@2*(0rC)UqPj`Gfe8L&{S zhGtB67KhF{GnLZCF}gN0IrIPU_9lQ)mFNEOyl0tx-!qeCCX<;7*??>lNC*Q7`xe43 z2$7wD3MhiII4W*v6;Y775v{FSYqhp+|6)6BZR@Rdz4}#KZR4%=+E%T%_gX8-9KPT4 zo|$Aa1ohtUet#uro3p&@^FHhEX`OcGjq==$UeAQ~<6AZzZ|l75nn<#}+mo0rqWv5$ z1N<|1yMgX+Qmz?53v|%P=^&74bwqfH?xIC`L()W{|G`j^>kbs7q<$hb6fL@S za#nHyi$$TJ7*i!6estChR}QriMs#yy!@Po#AYdeWL~* zUR%)FT#4Q~O-N!O&it}b8zFOmbe=egH*Ka<9jT?dFCMAcagAo<>tKrW%w?P_A_gd& zXwHTn>a>WEWRzimu7EJ*$3~Jfv|@bLg}6iH4mgJB!o60eP#_N!xYrQoMf4&rGLau~D9ila zYGD*3*MNN?v*n6op+dQM!Kkr@qH1|^ zh7skG&aC;+$C$OSR2!ke>7|B6JDpjV%$Jo5hI14PGyx1I=Diw7>h@vzL?PLTzC;`; z?}nkmP%J6$BG!9mxz?+Np zIHbVy&<#H&Ekz1(ksSJ_NDQ+XHyg-!YcW8YvE5v*jFQ->F;|Q-IB@Mw6YP~v=jY$~9n@~8MVO{1g z@g=-I$aXs1BH&>hK(~|d>Y9n*;xRm&07=pLuqVYV-bwyCUIKgMdLSrovEs2f3{b z<++d|UX&}*7)y8){Ntc{RL*udOS8r%JV4EZ64fUF85n7%NAWejYbLV}NB|lS>SnYN z?PFpysSR*OodDcNK;OVKsSbKS^g;|bSdogA=};1?3rYq|Nc_tR!b2ln>=bNTL59uS zZjF^Y1RoS7qF^>LEqt<#Mu0ZjpiUNLtsc5%t*8}5lW4OWwFXfqGn-q~H)5}2mSRZ^ zKpfQxOe+KC(M5V`tz1zQ)@pTTQ2?NgStmwpvPCi&U9wd)m<^I-w&{(`Vb?Q*4ApV5 z(G}DMfgox!S_C+OTa5UkEbB#G$SC<8vLrDPPT_Uq5N~7`%Js5Ut3!o!f@HJm?b;(N zbbv90V6J7=E&)E`b|}N4n`VOOuvo$IEMx`%EkX8mpug0yY80enF3?M57gI zQ((b(;dv_v7PDKFgL|6)q^sb%Gp_aU)wp^uX96>jGEsOmBhyuDZ8}+y{bG?UqGqyDfYMtJ{6@xXI>fVC9g+uG zbQzl4fY>P6VAkv8GEpapl2>quqSIoui)Mr95Nuw@voGBux%Mq zYqG!&A9RXvoI%gZRwI->g2SYPB1tbg0U9UkC70cRFPTKU0L{E!2e?|as;p-wNwA;> zm}yKfYURNzE545Jz^T+srPZUGX{3qx0H&3ol`)Eow3xXj!2lx+DkB=}EoF`(n^)2W z_26hljpwvSdw}akJQN9;WAQnnHTN=3Ko19hR`Qqt#60*^1acxN84Oi8W-4nXd^@w0 zVpMzKqWw_(cHwQ`*uQ>F4F;Ncc?}XU{q867ZF>zihsu1j_i%f38%41S53RkO-5Bq< z<^ffy6fQNDn;z=lDz2OXjU+MMr0ziZ)HseHI3+}-N8v$8UWEK_n5pL6VPUS@YH^ z-F?^bJ%5Vt}@l0B2B$XfpF!7J0KUW$rc!~hPD3+Ms%)ia=pl{0nuS0_) zMk9rt16uqE&;%{gtVGqhUs{u$%()O~zzC_11`vYVVXfdfEU}YwTDn~JYTSiTDRNih z4#ap?$m%48h4*c`rhEH7?VLTW9aCi~b>z~)W0xM$c|y(8H%u~4?Yic=Yr3WyCvBMC z9P;P}Ra`!CY1TVd3~%qgX48EO<*6O5d**2Osm_lAM&ZKw?7XUKU$o?gjCIcqH|%NJ zuxtIAj>_t$YW%D0ShIfD2DzU5%qnHsRN0vm^B3-wcim7D^;K7~Uj8EuKZ;X3tlbVD z(=eh%wxAVAWPvDL3Mmg=TPKpMGzTdG=aT&qTw(TFBIg<;`kFOrB)&>#;&>KE1kb>+ z2B2dhdAN+pj}^ZH_t#P}WOC_RDs4ppbD0<}eknMnviR2G%#`AniYwzKw-y(_5*$-_ zmw5S-TNmxQbkR$TmM>p=*`CF(EG{@lszbazB$k;2MYhTooy&w{`02hJ3>+yIKEOe7 z@JMkSHwDW^-jsRwlSM}sEqQs-p1n(#FUOllp3=O)Tup&?1<^)a@`nk7JGz35N>n$} zBOy~(>fI9qX^_jCE*5|=cn@Q((|dZ4jk)4MmOAk+0xA#wuDRF-%lTtBwIA!9Gr9Ct z$c`7mj%LBTedqC%Rm_T=dk5?Lu6Ta&XaF9q!a$AUtk$ z*e$72Su7q{Rad`o)%w|Sbyv5rzAip{{VH|GtUY1tf`Dk1!6*HuN9YH|>@$Gpvq}N6 zCzbi<_XLxmE|LLdr@JCzPlDyUYO2J>kDK?krp5CY@11*7)8aCVVb&~zrEGE2O>>tojkD`+_dDb1*Ao``HQpP(giSRL)4OKuTMcNVOb@(m7M?noGc?geUJ;8t6u0>WYa5RLDJ>(^Zu~>-DTzEbb z=Pw6=C#Q(ao#It|Sa^jEBWtV8YNL5Ce+KO1 zHqBg6?QNQUAP0QbaOG=Lqb?5ZLlZP3JdqXFBbSG?_!QPegco`UzEDBCfy7n?l|5O(2uWh*{9fh*}OFkZGv)4J9g^Su_Z-y zktO~$6KAdO?4HIhm;a)+gVRbF%BNDw_qH-YUp3>pUiriPU-DaPao4J;%WF%Dllm58 z#~3FQnvO5O$UIv}o~Up(EN-l>@f8Ipwl+*yG^2h|U81N>`H9+~R;Nq6WZk+k_l_|; zqH`}-wki9Eekf?yVOxp~wx$i7mS&wyRfA;|YZ$pD0iFQM7=^Of;Mb5{*g%Q+MV}ZZ z4uCY|_@8q>JQ{}h=B5NG!svf6mRKr5#bVli@?ZR%doi+~75m0rb2XFdcTK&}XtK)Y z#n$?!<(KX3?3gc;rSMQ3)+>e{<=;f)h)dXgJA+DdJ5q_(=fbyjlD zyxOq~%LPEFsh*KmXEIW|_M9hDm%Gdrv97&s&LCvUqb)02CoZ4W(b4X%EB2q(#G5YM z&@wJkH_qwtRocyZt7Y4`(pa=cD4!kEPl#4{yum=*q|U{&O2DV&=)yXRws%3})r>`7 zty6tM=kuW2FpR*(!{^GYty*Jp1woSmG%(Qs4H^#!;!Q>OdkH@{*K(vzM1v#qO$_R{ z7+Jto9d&*4xTs#V1lt-9mM`tTxU{8|32n(X!6M-UNsS#R?m__F|Gn3X9 z&{djT%C$c`e{S8Bi4#KMy0LTS?(Vvq%{y6Caq7xk-@t{Re0DV4heM^6gkrEpL-{{% z)|>$4EU3Gq;JmPH{E@zsRX+#@>gc;qk2i2FwVHuCI??#%xdiMweM zWaT78*EG!|+OV634wd0UaR@TenRhksaP%AUUdHC0VcZ2nT> z|Lq#TX5O&2h!GYviFiX{IRHYEViDCLf^Wf)se&K4oOU>MQK$_!7!L(|E5Bx`dn|^Z z8D!P9pUu^~tYLFpB<~24WRqgt9Jadj5ce6JRV}}8O%6hRA!!0JH5LHs91WhgWWLJ- z!KL(|#^$p^amdJ5g8rZ$Ggy6?%`B;J_Kppf<0XMKcmmW9@>-TJn~gIShXI5aI(xEx zlSd-_6cOeEGR2J$MBqWpK*2%7D7_wEFG0(EP;?Sr1EpZsk|pld3%9nq47KjwNtga; z^X`AUY0HzBudMExSE>hYgVxdT>O;3bbp6&zv#t6lVjtU=7OitgFDbdK>r_jozEYb*t7qdj?MRk%pu)4==CR^bNgHOU-j*emraW7T2WR%b?1^<K?p<`lIUQwM$W=cui|bx}?bTOb6E1v3`QcM^BdcQe z=PpkFc*njs2H)6MH*NX+$l&D3bkD1=@_CF6^b#6m7%YZwDoKJobt%*>6l7EZ=V>@G zzzY{zEr!q?#B%Vk9VD%4E~MxbJ)hcn+q^0Z=@qNy9XNJiUX{8Ns(OzNq-fqrsbhbE ziWT!T7SLhKQavnveOJ`2^uK@O;eGSx?>nsSlq%#_#sdo9iphZ#Jwo|{FhMbfSrS>R zQiwFss8KQy?9j`|&<*8j64q^OVgV#e63^ksE_l^9($wb9f`EyHv4&?kqn<@TAOMm< ze1YGL4dcENbcWZd&n7h~Atmwe(#RoslRpeyDguGF}j}$MRo9?SM8!=4Q2wU($EzceOopeaHDv$UhoQfY3;W=e^g5xM87H z;I{8*GeL)G;HH8ITBt8$#)NOPnG>ql&Qh*h zWt>ty34rm;*F33uigBg#?eg{u7R{5>Q`U$R2j3@_Lkx_M{bOC#*zx1XR_*c*B-IGq(GV|B@o{8hJ3p1*lD@AJn%&$i*n1|9(=hKoMs|KsjeFu0HwhG-gj z6NR02xQ2KllvU2l&Q+ddYuKj6LihSj-&!x-tUR@F>EtCIlkybUel`o1t{IyqKm3Y# z^I%x~1FN64cI~X$=bbnBPUd;Rxn=jXhSG-2Z`jT3lX2q?hsL#({W072*)OlJJQjT){R0dcw$MIV@Im_3E)riYBiU=q`Y_6ca&e9uVeb_jW)Y(*6X`BKYM85 z!b8t)Ui*XT*XL>UuiVO9x8B8yUlNM}WBcAqm)&yESfoE>5R7X!w(jnYSbl8TpaivJ~v3;LD^f$vOykiS%0kDp1GRq zVCg_iC;5ATIf&(~gt_DK_8Vo2`%JbUh z9jfe_*S6Eje-d8cyItyiX=UK|B_;1L?UVG9n?6x~K;xR|0vZ5x!At8OJYq-&B}jT5 z#x}{P70vb-p^szS5EvI&o&q#3;_jrm%4X&6S8u*@Sv#ZVm@V<@Hf3s4l;7vm>@w-r|)yZS%w?(I1*QeIrsG=I+5nepzsGxrc~ z!pSc|SCA)uB~*o*q}1leH+COyX<6)cl^Ly@AOH2^A6)<8mq0BH{PW9E7WVFW74(6f z)`kEd2^SPxr15s^#3*QkxXWqEyk{wqj1GtNbEQ|(J1tK6 zUnIYs&2$CihuMv=&x^lu`v>+G339PrtlYp%HorK*>MU~Tjmr477+hGhviLYl@>d-K zU!uTPY~kv}%w^h&xW}uU?TFq&;?(Rl#6glkWN>Gw4B#URl`pWSWHsaPj-^{T?+Rl%;){@`StD{A2dwJ|V96v& z$16bph~Zles|b2KXKVo$Gy2J6qqP8xDY~bRh4}rn$()b-mt@e#Fwd)MdNQq8Y*-I^ zKqOSY68uyOQhX&e!epDI){mhNNM=IwXQLY2+&brLfPWf!2x1u(hS5ey?BxMlyyvL* z=no!g*pcWU2>q^rYg;4Lqki3-zG)X;d+6E=r*#^~7*m$_EGg_eQ=4jA+oZ8YMYWd6 zb?&a!UGBQcmfE7Cu~J)W?WPsCJoTfeZdoCs5nPtKdb}+(w{hma1+}#c_RZX|z*J-U z`YpG79lHe^?%Xkc?nU**&Cy^m+F0WA*VWfFHrCYF`F$mgbgj9#{-U|#cig$|;T=<^ z?0A^d|2~dA8{jc0T&>LodGPkA2Ce<%xn1wIlX?a%!@Eq4Md6Y$Pjh8C)#tL9&B{-Z zDl*AaMfM==qY6ZMs*j2-_o&#DtOvEgKO^o#a!G8V!FLJa99SgR=R+3-1WD>6kPt4T zQEnn&KOhDe*4&&kDJBfJWl@4anq%Se(e27Iv}pbO#r>3wvWJpUt}zNZYx9klkhS?P zCbrI418eh@4+uTT5z<4YR!}Wu!0bb{)|g-CHs~wgPLx_;gZ}Pe*r4aOmyr#+pp0lb zHFY6iYKHu9A$fn1?OWE+XV41w8uJSK1!e3*OLwh>v1U`ou!Z{BA27G z@n6d|J;N3qwe4uQiV3KTDcpf57p!m?0p3so1Ax@X#2IiaA}2>9&SUXL^1&>Xh8#Oo zQ?C?L-8M|oiJLpU6Q{%GGh;&0K{owhQSY%3!h1qcSn>U|R_L;f`cCNUO-efJ#sSbh zkg5Hb9y)Ys=YeAvt+X|EzTjRz37BGClh(UmXfNBmxvV{Ttan9870vRhk`;uSF?`m! zyWBXXtg*^vTY1s31F*aP^xb!Xf`+yrz9*G!3+V51{2PK^bPhMbp(nxq$mtS*2*~V% z(N&JbY2FYBI?V#24?IeNyZFFOpZ~&zB|@M?sbh`bnlV9zkG}tHdLK zx+5aQXm)byO7#8XHFtDn$5~LO*5aqH%?m z$2wT6nTmGDI)?$JimeWHNO7Kra|S#r4ugug1UgoGf)+&L03keV@p1OHE$p^lBA zt*GJGLDNniq=XZ4I+Mb*82pqbfoQ@+p_JGdB0aQaeTB!Lr#Z$97FjWL@MMe@Z^D+s z&IK)jih;Wbb%1MocDc@#$)|IKVWN*g2&aNVGFMmdoaL`cE`T^;1?Tcf@^i>q-czu= zA7p!sX62V=__ATa&S(g9I0rd{)J6Sdr^qB}JA4(U(1Y-`7)a4D)MA`g7I!Mwm6+KC z^C_nUK7sX}(ukntS*u>(uyyY=UeDi#4Mlus`)o8@(xaLmYhKp;LGw3oP&Rni)G|cQ z7Ur#P!U!VO1g(pNoJAP;`R9fA(}??`-wW?AJpaG_{Fi;Nu)eT^;QuU%IRlFc*+_>_ zx`&U5+e^|ih7FuRhmOU(m+aK71UlNUGH`jW!KA(Xf;sb)=69M;|L@O||H&xL zl74Wt!{fDxvzf&5M8E`Lo>IUfK@P&dqXA1j9Ysfw#32a=jPn2f=>Dps?=)zh0y=nF zlN*J67GXr@2Az6He%|WXWJyrTG^F6<|JoS+k`Xm{tCR{6!43_i__z|&s!LT*4`;a3 zwB^UO!_$ZGtWdT77?_S^7Dqv~y|xiDP)-YnK8%pxr7p+Lxp?4~wPvULd zUmZLLn47GQg>WUt!yAzB$G%F{zYS~B=am%aex&q3x^I|U4B;Xp?}AZk z^YIrlk>Jo6{xrIjl;V~Ot%d0#DhpmMHo+{Xi^Rz)*c5L{kRh`PE-|>;1QQ0h^lDfo zd@>|=U5Y91Dt-M)<#*Gl`Fr}3$-Z}Nfx!+IeZ!v7G% ztcDQl>kp+vdVk8V$G)HSg>V(Daj1A4`JRB+&HA5cq3-~n7Y2oBATKb2YG`uA6X8S{ zY?6>Vt(nsVyAxRF6YnNNtUn~CLrIFaIITfuxMVt=e)j}2Or%oj&|p93A5+|pOZ*pd z#pmb`Sv&G65piAWD5e2SoNSIcgY-cWl#06J$28$_X(YT)8umd{pHg7Zo=kQW0->a_ z7yr))>upwE8ZMWr(itk!ke5-mNGO~-u?owjq}8&~H}EaBRQUYJk_kzaMJ-j~1H#0S z1rxw$&lCSsY5*5Eh9p`{{~@y^&(mjM(r6cji;VSvEmZ0dZ}u7v>WxNaH@lu48ujuc z{04p_HtH?AmEG!dXI$pv!-8`CYpz_XJ(2siAQuczyy!!@pi$wT{)yp>!Xhe@`nl`z z1^zAe8p<`=WnrFL1*!@PPZ=huBJ={PS>a{s$9bBsNe$AX5$!cHKZH|luaOs}hA*pi zw$Rj=>@_5!LqS+x4X9Y`l2I@7_L`@81m(I&E!VL96$Z9khIpPCg?Db=MU?BT)g7f3 z1oR}eOn#rEov2`=TqatC@g-cu`;n}|1~nUG-Vnn;qJfhg6hp5T(E`dSLj-kY;GX6Q zi-z9$l?TDudYiv<9p*t?+4_WO=CNA5llp|}o}F1=q4CAqvoxnl z-+26xjr)Osgn&kH{tC8-tSujYAX&ByDk<0rhH0A)eE8>_MbIX>Z9mf=3Xu{d5DSGe z{bXd;!bUBGMEs02AatuZk6h5A3ny8K=vdpjVylr_0=J@48tARLevxvQQ6xQRF2uMT zDdlo6=qryT!$n?JVgWh91v4nu1G=%?-N5?j)BLSd2l{{#%0EAV&&xf1Dr{4qxZQ5= zL(D1c=mH9)qTh-=!wPQK;G!Plb9%5!QL&)AKmk+G}epRD9NQD(&9O0C6ZElh(DA_jLN=MkxobFd(kGnzu)+M~#d1*vxjpI7N&Q;y&0Q(nt9Ov@ z0UAx~93%#q(<@Bk9CzjhzLPRMRY32Y!M4>0SFb)OeWL#Q0u->@`-CeGuA;1us}BAQ zc@mIQK>2shoeQcVJ#!PiaLyd@Kj_ibnQy2+9_9fE%1-skgH%88v00xH6V6~l&y7;< z3z*+Y;rwAP`&tJ>jA`DJcZ`7&@iupQ%b%(G56`bmS<#9BG;0CU_T(luy zt=;C3Nlc<}xz{ z@bcSeLnyAw`PUGAL>*F~12pf(YnG!XZdkkO7$`Hc?ByN%$Z$rECfLDLP%2`Mw2Lkn z%iuczcuO)T(Vwa}C$&16nxS+qnzVRQ5p9I84;?;p=#nva%=pfXYl&x;$;i_ zP|dt~6wqbsm-{)G2ROAL$rK4<&wrWS4F}$7>VLjZ~K@NB#Cl zO&Qzj{Xrj9Q?1IwthH&{H`*sEN1LX>TEL$T9bDBnzAi-V%H>rqOSs{8i9DPnOQEm? zKnSNAa;HMY+M##OP3;`0pT=G%gsg(SQ~>24N?A+(Cl^G2rTi+Y_Xmo`>Wi*@@Y*8% zxO%^0U>2&c=s7QU*VIcq8^q`sm^J3$P#9i9SGJWj|-YQ|Bbro{q^IrwHjL#@aw6r zO5(p)w}zsz_FT2}`msf*s$lq^*3AS90U;2;%8zQ$AmjS~uU@58ERcbWhv?f>K#BeL zYN8qi*%SY*!e{wB?9^3;*7vWVA<6l3`r<8_4JXqkECB$U^#wWOuf$1XFNlXZ{n58dU(CAELUC!&Oi-&kb(YyL&bkw zFG94K{HSTIT!grnt(x7Mt9azgH#FZz%{*?b|DaQ#z(AfKI!4Z}p<~>Ge#1Se1*{80 z*9-3X((C!(%0GrhVCY#e9J%8rDwB&WM#Ib#hh$(WdygIeQucm3{$#|=Kl+eJTk1Z-(L@12&%MZxw-kLv=48+WES(PWIT1Ks z0C<=YX2Yy?Fc%$1$a>sE6N@S(ydbyNTznjed+MRp# zqQd(Tx2JkitUck{ZkFv%h>+T$y361us*p`!x@ITML#@u!?BZJ-!@DqEXFzk1cNoI{ zJl=+S{D?*ZKK1{XW)YK5yzt`pzw`QU#6SP_sM{sCSn6GMftpB-*B5YYd}6E1T{V8s zBM)6)8@_GeJO87$68vfVhG%-%V?Wnl^6Z65%hMOv_5&oUSnJohv?fUse?PIwpgrjj zbkDBTKUc**{+~4@My+3;_M*cli^%=z;`psm^74d} zCj*Zab%E6QT+owC_c5m2HMR6aD{F5vvrm4M^bRUw2oc1;q9jPZaA_vxsFaP~U?%O27@cleW3dOF$d>Vq0Zl}ZBVHjH ztf_?4md<5`q8EHId=*llqXPIzIAX%~1B?b5_S~HV>kar}&i$g+Smv7ZlTat1QzXxJ z$_Fac3X5RMSd@80O63eVgMA|`7viFSV3ZmRpY_8pOoLm0i@%=q@I7J=7Vq5YX9ffA z{>R`WG+DU(#C;6O|HMaLg9l zl)V7Zh_060KjCS9biA=f=azMILnJ&h}h zly@(WRadr83lyzrB*7h*#Kz%c#TEcwRZLH44Gb)Vv~oEAv$QE>6AfHr(F(C#@+ zLJlGHE;Y1|WL2(ysP_V;dWc_?Nl(dVTAaYOpjag5{{*~1y#T?AsgabJdOGqoA-oeB zE0oxN_!V3X&c0eE1?A93*;A)ACcg=udm8GzJ~h))e_kxCET|AT%Htl--e2VXnV<@TsN3YA17M0e6&-Kk=YQOE2LMDBtsJQIke# z@?QDP5g#LZ(1S@bh&gBDacz8F` zRpD-jIg8-ap`Ym@6rNlM3=JFCvr)2b9N_9ODp{J#8`v;h=Es?IOxlxNiKM<#Q9_2M;_jSYUH}t zqe$Y&x^->4;JRt+*3Xu{ylQW~6s%=u)@ z9}!qmL7OlT#T4rTQru(OPi>~6!BlKwMiZNC$FYcG5yvTlmyw#v=M)cWYQ~gfFJVt> zq~`S7oR)6J2?icV&xW6Z&I8CNu=}8Y!-3V5*oU(pJV!{pyvacr8HA5P0nDoEQ%(JY zi_HlS4K2djpeQwr8f|LDf-$pdJEIqbnAcQ(`R2Mwiz8zq+ZHaqq%>Mu7wuYe%n&tL zfGjDLMa5%lx}tTse#w%qZMbXkq~r%<8NgEgk(yfXgz;U~-7DFX3+bnQ@#AqBY=^OF zLbS7X)|dq=R(4l+ji2DHt%>*r30Rp-(iA+JEy;u?keU%+qc(@`QA$BS9Orf!N}fVd zAL_Iua?ljh5MAJ^c}*yLOiMzDF9{(p(30MIi+m$<`Ua+XOL>c2D0t=$9GupiRQ`FA z{BOl%>K)}7|3O^Dzk_}@em{Rc@>6mR)GzU+fJP3!_lP56}Ebt+|2<0=uUVxPy z3)N6@44izF$8~7*yh5H)fjBg#!VE4emB7mt}4}d2r)5g#{ZnU8q)|NhnorPaQnz>S+LontCn2s+La0 zh$jQ|3fkihRKrX7xJMtz8qh?orW`edrfqDgrtxfxOwvIr^UxInxzk2wXb_tKnHl(z^v|lS3R^;C5-qU z@k^Q^e256y0(|hy8uo+8d0&n6hRC-))pyDz3Z=lgVFfaOs{79aG081CD(x1Z!z{a6rfg{`f{nt;>Z~S~76JTgmet|iqonNy9qSRCrj5SG zE*k8okuHXMA1b|YZ0qc>KB6<%`;DPFQ>HnqYN&4EGLuv20mv@Zt>Scu^WHjG$A{{M zn0_!1B4y#@2tE)shK{KGiRKDSUb&Ams?2};;|q5pJXA^P3}#c(A}>+?UHMSdS`A5u zx!-7KdwaT0vc*icx+RrkWvS1Vqu=l9QLeTd`z1pXyttbcEn$YF%gs^<``o$khc~%U z9?(+A$FHjL21BG2Kpc=@FYF5APed6YZ)jh=UwQm-OL4H}p<%olMV739mlk7y|VeJq6h({N-N`F)AkKU*9A zZncuEumPCb0)>TTg$*!DALN=JPBdym6qG@%J)>S~Clne0KH`mlb{f%P!tPP}AjxA# z93;`Q1V$D?)kIu!LsQfhjw9EQ9F=y_B1`piC?(juo)nIC0- zDn9&Z<}dFxHQlKEWj$Lbgq~n;oLYO|eW)MPm|++FFVI|Qe8Ff4uCPwVdtGoTV=nn! z9Mg!5}_H(v@l9y2_n5lmXZ?=E&S(lJU6Imo&ZWZIn@mAKqMS=Au89C=0ru@=+;YS z)498q9ZI9JWB0j$+}686F?+mvy={HRr$^I7WzrL;!!dIDMD^t8ryc8UdcBwRSe?@Q zeCZwRQ~JDm!Eo-)4?J-5xd4^sKe}D^^(*(gg=;zY{*Cfo)5#lh`mXYC@C%ts-TPOr zx4Ya5jAH>O zc|Naas2cQjC5qX ztN*_ zp0iX-C5(oALou489mBshd<ac}LWi(CgsaDL(eO*GXYH2uLp{vr@SV&-2TX_wJ$c zu;DVWH;0OocbL`LWcxFSsKaT)I-4jmq{X-c2t|aJQkL}QXiTVMz=F`J*S(Tc{UO0! zi%CAn@koN|GR(ehQJ(p;)$Op{@wSOMEh&o|_Qx>8!DwP- z`FJ}oaQjgCpV#o@Nx!OH&py^S(Mo<6#&dsVsr*A}PIAih}WFPR&w zCRp$^BQjucQVv0ZvdTb~5Y%*mLkorYIJsDrg^}#t?y#MKoS(VfIorvSE~hJ+Nkv_H z1NyT0bd&Z4`Byk{k++vY9$qbIp;T4E&6tF`tlp*!>j)C5KxYI&p)K>A@*LYD^nxH$ z?vczftYFCQBHl2#E4np$pk;es%l>Foya6Zs>Eu9EYEz!e5Y{R^h4l>CRPYp*(qm5H z=D~}jc&KkX?%Ns_4@L11PWDH)q8*0URaN#UIU9C%a`k~+cScW=kFDx3OHQ<-c(1A| zhLPT?d~EY|Lya>!Q^W8jeqE%Xq@>T#)`R;Q;n0=BC`ofPQDBM+{rFksZ55a(iGAa) zU*eU+_dJAYMzc*kC0`CJJP^FOO9?7Xpo<{uSO7rZNrA__;wfikngXyqdcC>NU}wp6 zrPBc|2Xff6WKjHOlr*OB8%+b_HySNtDX$lf;WU+r55_k%G}>I?y}14c>;mc66GV=~ zB>p6tL*)LIuB-?uX}lCp$PRoG3NBNh#Q-2Qmv!*o*&zk*WvQ}QR7jc9RyUZv;eI1q z1myA@D>js9##>)#Y7`z3u*P$CtoC0yo8w|Q6F271w2yF)%8KD0_2xTV;x+lRX_)S7 zLESy7mmECL$tj(~EAaM1nhN5QP)RT+`Em;B3)pSP8(VtVYgUKyj>BSg0P|KE5JF0S zre930DlR@=+*Q0v=*uq{`_A#ko)-3hEcA%gLXTvULWp5*D*ZywDm-z#xOi1heo6D& zsfhffDTW$dtI)HAE!7yiAVDOsdl1 z^kJ2l>S9UXuCtekeIpWyAb)r;s3gmj-+uKnaX)3%EDkWLFD+A&-j7eww|&#xTfkW^^2cYa9_rm4Q zin3x4(yLf3=0BYT{IwK{%rJaGAcrfB}x_x6~ z?NgR#`|L{eSv%T*Hvmwtyp-4g+;<#Yu-bvpE@#a&$atCK%V}j(r9`g}0;71P)B2$A z^>07GDy&Am=Vx|<@=_YGAKMS!>s6Le->|zU{Oc`LG~#QV)<2JRJPc{DYNOS8_y_LC zl{@TCrW62$lakMd)^-st?P%lI2t z)Hp`>W4-6c4x>S@{PH(^%>AB~t9w+1&30NhSzJq;*3A}|Fx76iJC$XzW&Y(3cE8JR zb!47(SvFgpOI(&s!0&j{;v!y#gh|u^kVZJ9B^rTLKq!cWhf6jz7>B3{VIyUy6St8` zt}7v#!kob_%sj7rhkZ`%r086h2XZFre!9|+So+}e;-=^KDM@y(a^Sx%DRgARg`+6@ zF2u-VGLQ-ZWzz#K(++!YiRJ=~3|GVj`!3)x5$zUkh)3uGfML}Os*EV|5hF(UJ{A{; zN;^ys#azEYS4VvUT}QTW$g@cuN;(_~!om}CfZ=y>M0q>J?!6&0ot>C}-$GouFs%Hh zTmXOk#{D|~3BT@JuRegi$szQ;LUnyKd=u@?UxB<`_Ui-kIc(E;I{yK`ZY?|iTsd&P z-Ds3oUP!mxQvQ9=j3s~$dYyr~$?Q9b+{-|eMivJd_6zn%Diy*g%^dgph0WMnjlyQm zYvbd%&X(IOX1{WrZT72MGXRGk%-(<@szG$F^a0wjK{JzM4tXi@39NXYNK<*-69LR< zHA_JJax@?fIF6fq^$B30HaB2{+{uk~5)kSg_1^k+EuCO#z)8DSy4iVj*ToiH!~Bac z@4lm}>JH~j*Yjl;)*~sL(K7eK*OTEpx-0KkaM|Wbua?%#Xj@*tK(C(|>l{C&ZhWb0 zMo~pu{jBOKI=QucYE5gb!YQVnoLhYCh8f$YkM&BY2iPFc51wjZM;I&Xyq~eb&xB70 zb!DyRW$vzMsVFjQ1?9U8snP5KICcCp+z|F5YaW9djR7^>S60XQbPOU4qinn+8ToxO zNmqH=nTD{Wfv@awt2Of=f=NR|5D_7WgKt``%4VxKRM|4nPih20e86-edqM8Km6$g( zF)F>V8F&FIKjPI0*Fu5JJohBIjc8gc^_8vam+bbN) z^b&a)S?@-wcXYVkV5Z!+PTi!3PaWYx6x{?3=UUM zy8MhLFoOTujq!`V*3tMSxoiS#=D?7Pp0%n(Q89qC3)`8F5QUBrh37*5=v^&^@-+(> z0htu_oq#P)lq8+7G(S15;V0Pkj8^Mm@ObujJiy12bM!;%^Wpm2hU;Hg%d@u!H?ron zhpV7{3eP3fX1D@MX!O<)`U>hiqBVv!FrlFe?i{Tt*v_Hf&)NWd%*!uj=XwWu1V=%m zC=E2Y%d?O9C>(f5K@*3!6y2GKU?CtUfo5X3XhJ~Qjcg?3QbPGiIU@?a)bx-J>E7bj!{QCXu3mQVoR({~yqt$+}u$pqisO>>~0Lk}B@ByTU1@@rY z>u~r$XBHw_V;CUK2l9wfE-|f+u$d`;80<3WWT;92N!SjR2{H~6qAwgjz)%Q~BE5t{ z5sXHIfmk23I8e_Z=spyPNqq^MSm$uq;)aRIt1IR@rrxz|-rh(cR#D{NJiasR3>XYL zQ?c6>sGBu5Y=Z}>%ZU`B67$U8nWmTEokDOZfCCqnPOb^fozyaELUjAIxk6bm033#B zK)9kPDhNB1%fimKXjQzX&F%7()mOHa`eSoz%C&yCm5&2z3k}+W{3v)^aQ~O=ST2;{ zqh1e}hLNfmPB0wKxK4n)$lD{=B-9?QB4!5iAyd1#&(;uI5^TqO<*$<7Dnfn947Tvt zS#<%IyV#^N7y{04=lIS3qKa4`vUlFHyQVtkR$QH&Xo%Y!jyh4ywM6DmD$Evdk4Gmh zpTE=U_G_b+^J4zew#xc4kIUUw6R(Q4Im646I|U(HBwPXSFjgH1mI-sGZI4bs!_5s5 z3VlxJW8l7`)tX5d8S9bLfPC=@;-9uH}`2fVh;~5}+A$u3Um=pMOMiBA#5(f+jB~MSC zn)!Lx?D_0_9r0+`pq+|DG;S}OtTT^^ggZJy6=Tf00YNken;J_z?vjl`&(-CAEmN*Y zCIyenIJNpZr0o0Xx|%6Qw;Ryo*9)=h0Xy!_Sk9T#&@^8c(nn0QS=duDz9H!G1RKVe zc%JC!;BeL*S`*&RKFe1V{`u~DM2I|G-q7&DbY%s5VEO^&mde^;UG{pRiU8kB^nWzuB+3UUR4BQ7)%rO`tFm8O&c}Ju*E2W7p9T9;I7yo!5lX z(M02^IocHA0|sI3XLKxj9>WcSSUt~xtJ8+~5J5C2jfxN-A*?|}r&Io+23KzE5u-v> z$p^6hGe@ZSLfq%|`r@qnoO1>zZdIP&vYv%jtSCiNV75YUt{d0P9x(tvw|d2j+HuYB z@9tg+vR3!~V7#LD=YyVw>~Aj&yNQK8!ugN z9UCp~oxz?gj&*j#ii=|%ov~uJU}aN%okhQriOygttN7OrFRS%-*41?$TfI8-OZKsH zO_fIsv2DtwH7}(~ORJa!MK2%;=)9#Q0e- z_BW5)m|^T*v&rE5TV+7}mC2O(gmsyWM(^LM{K_LvffdF7!z*rZDzod#Dcu7mwar$` z*4sUU=djGz-40u=a6w4CiClcL>lMlWR2F#kgGfL)E^!$C{h|!XpPfWluYi?|c7qNc3!frpzTKbdDdEx|9tNx80$qoyY*K46?85f0sW& z!7aa2ZZbRGWXiX!R!fDr&>YFc1tlDTfX&`!!oS+D8#!ILKE()Z+kfC_7D`;pT=h~J zBhY)eOM-}%pyjLp^|L}=3dbtO3hGJ%;x`FW2IZS?*ETc@zhv(z#m_v*Cd`@z?SI%G zDz$1|ag-7Xu5}ewtF<)b4}(GsDA&ELygY7vMMZRq|I9nAAvVB{pUSXJ24sg9wMM(o zrY%~PNZvB0^154YNvyzv?6VoQqUfS5)sk!s6`k=rvd$y_Iq}U&@DFME5PHT1kJKP} zEE^;b^Tc&c&>7%g!ecN)VEqyZlqJhD3)xb|seD(iW8I2Rd5A4z ze^$P$IK@fI%gP_wWaYhW%I|O^7V&L8tQdZqg7Tj9rt(MS6=qfbuKb7c6ILP~P=2EP zosEO=Vggafln`{`kuTQ?GZ?HQo+QOOT z9l{$Ong7}-Y~1)3dncttGLMU)9@dYzj8x6t-@Ho*98n&*MR;;==JZ~1Z|3qI;fhoD zo;ZPVIc$SdeJ>VhHsNXxx8JS}#q7!uNUUwQid_t{L=-8{Fsd9E_Udc(|1mz31cb(?I^6JaRZ zOzye$B}*=ydBfR%5-yO9@4d2IXr z(+>fwmj~Z*h2;hVYeof&)GC0`+b19}sRuI!+(055HHC{*^C?{$8X}1Po$Hc}qp<{*!Dk8*^uyoeAHZJU8U%?shoMt&Xib zYl<(OwlbyH9~UkQMhyC~<8{XJKyk#ND=F6NBZJPshK^b8abrb?-d)}l>3Pm>xa~G= zd5ie;1B$=2vDk4S7Tj(w853+Y)IY!XJ2L~drKL7goinzKq9^I6`gfQW4iB zl2x2%Fos>-71gXdzIe8N`N3XMNYqZh`AK(2yynh_YGNH8OI>;CFJ22*)VG*q+r7%> z`^<8{Humn%zh7QzyVl^S-u|WnM2=W>gQWLXXqjH?v~2l46QA&xl}Y1RW&YR{?x?Qw zy0NsUFij`?*r{2|!NL28 zsjd^jAOi;(BavJnJkV5@q6Njrx_pnV*!;-$`QZm=?(7`rmYGiaFE&qk+!E>-H~;02 zBJE6QS+!@+L?QH>z_N2MTvjXVl;wk&Q>BefNa&bv=T|ex#<8>^A^`R?a_9izLs%{U zRyz#ZBUff=dwWf5MPreXAx*?dJ(G)?HgsNDz3k3))2?Or<+tCQr@YKpImX9s`YD@k ztXaBwY0)>8)e|o6og%Pt(%Ag!lmACj$e`|sn$To(P86!}giq}j+a3JN9kL(9`Y z{Ef9%UIYG44HLEL>^n)PM^>{TZ54Di;NP@qDndc2gsadLfSJs%0vZVKL>I%adq*nDoUyd%E&iq!a(OQ%d)xUk{) z(OY-yczEWP&E>UgH_q6-y0LLVWXd7s-ICJD&CSscan9_=7?KCFDf{<77Yc>TaU%cy zy(5Q9OUuirR3tkZR`1yN3+b{+bLLELcAB(Dw{0CG+Tm`l`qF8*ueg}y4qyR}!j*y$ z0Mxzk?aWg8)20S@k!zRW%qtMWj59&|43(l zRJX}G;SP2*@$+4~exA6>qSKlWR#hD|Yju{)(cDwjt*ux`iSPOxO`=Czlrud(#EbK_y0L1SShwjawriLP+%D;20XRBpcdlLLkoHhta{ z^Z{xF;tp98FCrCAgdqm6q(YM3jowOiLFwCZj(R6>PGxJRo2b$0UM!pZ&2S<>8&R`n zUrgV^M@nVkc9Q|AcjZ-*&4_qD$p(`w8qDrlhMGW8GnNH=QI#WB9u9gff}qu! zbQZCAL9^FW=p|LAIrKz`K!ZhG)m9I;zuz}q$8H2&*a%a$KunOLo)9!W|Th6I$ zoiwXyoGBg(hea#1+5+~Vw1K&p){Ik|XtHRPZl(uZm)?Z-H6oK4I$TihaQbaUL3@d@ zTvsiRyTI+9eBZ^Df>e81UA(Ofz7Xx*r4?S!lybd@%#`(wOq^QeLacmJF0J$!MEwC9 z1W4TksMIEu*=ouJ(PUsHE^jHTs*r3}vyWK=vfgKd1B`>24GzQqOWS*Z$5EYa!+WM| z@4c_KuXm)KB}*=Hmz!{J;EH=$7dkdzzy@rv=rM+bVv4~K1p*-uz`UjeUW!S8 z03o3UjIAAi_nDP!;gG<4{nzg@J9DO=Iprz$b3a-so`jY9I1>j66mTJ=@l)$fIt8a- zfa8&};F79ws#SG91uJvZ7d3mNzp6COmD?@8dbisIw|K)Gbrxs4M4>B)vAXKw0(-Mu zFK2j#tW2*P9+68698FNSO)Il33nn{_;Vc!KV{kIS-w>VoX*u#mvr4!&8GV8y#^Wl3 zoNyfBTrAIg#z^Iij%YMePQ$|jqGkzq@_DtxX0-zLY~)PsF1^gC@L183@s-?J4nk@) zXxVCm$~IA@FA9egYEEek1ls&&p4I4bq;|DcrEAt26jFy=nx$o>d1Vbz!&7DL0fk*} z_0V+QbIY5}SCuV&u6up1g?L;!`r&}3Di6xhT1ghHCIw(Tse_keCZxa!8>CMEC@gPmB+B{eEN#oA z1IAc_fg+2Kz<3QQEg&oBsg)HQoGB8eXNjW;IHZ6pDjz~C$4PQ#GK{|bx=oh`b&q|v zz1ET?{889VCXFt+_VV?SFlU^%X2a!uS)_n{=YRe%F?-2%{a;~HXGR@9(J^Ypfr8_`djf#7FG;gj{on>7Lh|!^&$cLg14JiQ18@Y;(tRcsrUG z3+;eso*#O7N`aS=bwnIyon$&@w6X#g2swm6!^;6&2#s}x&kI=yAv+`PiDpH|v|Rwd z7_Chj>zYZtg~AX`Lo5c=K`Me|#9587gAgM8 zsU=O3_6aq+x~*BG8%oC%=ahI#O20kOcJY!%vgm{TTjzJST_v1)a*2NQzy{&z26?Mw zYz=Djv%|PD17Ve!3((nH1d+{kg36>_HLwOjNdpL5V*u z=6|HfKUmY*pv6QRmWYl&qh+8mnc_e+Q7Mrs2td3+mLH7y0U=4O)brQ;?-hu4YAon2 zXoRmw@qPYZJ*BY<5Wu$0BdK|9;HDCKwmrUW+v5bdkX$l;yD&#*1abG51&xgbAU1Ux zb!6{$;b3k>%ws31MT>-#o$a9~Y|A_=ctwsQ&Yq%!2ZUWXT|}Yx++VnbQD=kChukQm zE0T><5$KBlSO>8v$U24N;?uB6nt}y+0ebqEicfM>D5AgY)k3dW-V1sV^3vJoNQr&a zBJpEfLz9H)gYk>jT>&+=S#6;qV-(Ai>2UrO#wOI-Lp9YQd+mhm0yu=YN#_hOpOLq$ z?L9sxnRNOI zjpoF3Dd1?Nq=(lT)F)18^w>*EGJDnP%wFMT?A2>doKTD3JjFkScnu?3s3c6sH9D+G z#SsvhI>TaCS~25#c}SF$Da8i`4r2pcKmRPRctm*N(ELB1MmX8lt1(|jrVAGx-$zr- zu6ULhZ_G0o{S&6_I(gly3$lG$*{67$@<;matPy_w=2j3Nu7BpmZ`Qp`-1}}Mwm)r@ zGTGU_k*}<{?&PjgqfZ+{pU&8%Gd}HH`ZdI%3S+VV-*Eir`nb8|5H<~F?$92LJtrl! zJ4>--?h<1JiKIVCi$pIhx$7(s2YNCi$vWLD?SXxuk)pxS>T{t0Bc@1f1{fD%mj=B; z;XosWnIF(9N?{074C0VzbMT{43=jkn=!aQWX%Cn@nvTK|UT%DjHzyls7Ntt(v{h?$ zkDA?f&?g&Ss5(v`==gmmFs|OmcH9TPRnvXPokB}G^#oBq!5}5`!PT!K7QtkCme*%z zAwPG2$`y@jw66f98#n)Tc`w2!NhEV(<}$+DjO3yxop;e=xQ%bQsx2+kN)znAayW6$Ci4qlA^oC@uqVxC@94?~JFB#t zbTC$N#^8$9-OHxg9m?S1`8#T)ET_vMMzxja^>TBWPVXttjkz_9)TmJM3<5VCH5#Md z8h^YiZgy#93B@mf%WUiBbrG+F z4;Z|sM-ba&`ZK+bYeOii|R4-PiVHNXH+FB6*2!InG{fP0yA<503J#ROk-<} z*re(pQVIiHP7%pk8i5N!42ldDFHjEc5*Nj#@f}fyYvLvaXu%m3ow*%!j)9RDtFd{^ zN;wiMdSnK#*86b&UzRKyQ&{-w!X-1HBlZfXcfBwCuU64Z$gcNcD~PmT{W~Eod@OwX z`qnE_2gv01hI~${)k&pSyit&!&+uBMx^ims%5e^pJlBQ?Gf%3w=Wx8!UPH!DER8Bk z%AIm|sIKnbiS8n`&%OTZ{y>XP>+}bPWx4ihTs+9vd|F;LeQr-EaCpYFsV>jMH9gn0 zXl?)4mHFA(eATx3bxo@uUA%&DsRI|cC$G_}(F&OA+WHk5ElBf>RSTFI)7Mwv?s$g! z9u4kp&*n9wdeSRgPGgCy>rnHsxKZk>D3m%u!f{r%SPlz`iRO!^Gz3wo@Q~UKASs|p znM26XjDgaCXie_?gU|l{;N{N*g3kzh(|>vxFm*2e@SoBTkC-2kxccf7e68T> z7tWjYCb2(3hP{!_5k7fy7TMoVKJvaHpnJl8NM(n0kkb%NNVF^!RizS`MlkbYEY>ox zo`BJov6a(xp04vSIK>Ni=>41)8V-i1I?O*>+L5Jnm0y=NY5M$G(?`|l4ai} zb05i_8yY@+(##2C{mY-fWO=68P?#bXkXFdHkh)j>+6ek`gLtm^RV`%%XTz7+D3Oz z8rxE?({WRsGFyGT%E#D7Ztkk}8qs~&YcG}AstY1av4oRYfPwxyTz3>nZWiOKLHqq)>>1s5FqT!cnZjT$io>v){#=BbB;qt1GGS*1GmWAB z&%t19AH`Ow2g1hGk^bj?K|B~zMNog{pv-Ih4;cdn{JA;*EpNa;bUhgw+xPG312QtX zbQ)xGi=-T*fK3#~AfXu(mi224wJiu1$y#_nBhY* z?N1NAx0fjPJxp@yww1qs5r~VnzUy3`LjI(8{dQJmaFo_hZya`>On5()3JPHE%*d3Y z{4VAjBJkF+(2p_2V93OblQHR1l^OFE#d9IPn|^6L{ve`*S1S+xZA@Ndyo$Rrm>bn( zdAC+Ca4mL~b*L&!bTzu>o}2&j&dH(vBX;YbrE=jLQ%~hP2g?8Wq*^x3-eYendnob0 ziHBgAc9G5fXZ*ve+;EJJ~ zrU!<`Y~@l<3P*n1t2Mp}7=}V)`*iTvs6`=Jt#jIt(Fbxm8m|M=kARQ|rmvt0%^yj> zxl-OAVHRI-ODd@`$*MX#s}Qb~Ox*V~NX`Y*J_Dt(3m;`Vur!6dL3z6sh6)Q<^GFj-iI~arAz&Pyw!emlrWp$-_ zp}bNZYnAnfmWI4V*A)qGL~@D{tON0#93{ueQ3{piG=7I=baJ47K*L2e0PUk^v(nN_Hq_^KsVXqabL;TRA*y^fdwtP8U||3%%{Y4=vh##I+~ z>Jq{W3Hi91!VX>HMvtX-Od@aJf_+YFO;;lC=6GfYfL`VD@$}&MZ5C_I_?o<%7u;d* z?jGlQl| zhSFC)I0?YGN!x?8q>fL7>&Q?L2@6Vzz_an0jg2!4pDI-6C@W%YGFFku?(d6L)P@Tm zj>Nq(RG+Q@?h7HSFnTd&t>j9uqcNq`_YX%#E1Fe(MvxfwdXto>Yv)%Qey0j zk+MS&10M;|?h;B^q@2af*$l)Kh9@n~*|<94%MXPs-}ob$_SRd%rzHLvdtW&H&9$p< zC6+(Y6s0Ni9qCCj|PMBy5(bAJooxH476d1n0HDI&v_AL9~=?{dP|bgwBak5^Q=lfjY7T})HDR;6N|8AhHZu`6`CCI7&a z)qZ;IOB1!)=&Y)X4JU9L+Ftk%#5q(#{Ir)LzB<#hLZw+Y8Jtv@0N+XrnmT|LI?BDrrNiJgMIV>QbpV^ul?g6 zS8sh^IPw10qTy4!!kD(tj1x5OH6R%&dL!^bvZ(b0`Z~3*m53liw3!k(9jMw@VogwD zn@H3IxCMnJpo$<*fgcZRqPqtR4puvWt?OVfJUdEYbg*)*dVQVn&pJKgw53IB*Az>Q z!m+aUc)XqbHr`%_wNov#Lt7uNf1VbG%bo9c9%e)~n_b2)z zS*F+3)#>z7X>qaiHCzmBsXI)sS=LqD66%%`SAMuG-X1S0<}JeWvhHw8aj;6~^6Y%! zg`HUrUF8#JMwUzm#~4G$Q(8|MTd)rG6coo((N;y9Ev+Y7O<~bMO{+(&Ct6{&qEI=J zXabW2{5n5fRj6f34-Jpl(5VMf5_?diiGLo~Xm~xJ^KuTa7leYkg8XDY>B{`R2?&O7 z*-hmKNxqNzU5YGE8n~L9mU#1WYqFgDmj~|oQtI%L(xD3xn0z=?h&`(>c`^FbpfQ6l zKqMbK14|KK5aJ(X0}tWj13;BpA_Lbv8qkkmk~6zk_O5hCTzgh@jalI`n_T3w-Snrs zX60=w$e43%>C9nQ-KeEYMhPF8T`u#QbzRGsjV72(-KO&Q*KIPp+@|$T_xjNYUb^pG z13Mj~ZTR31CYuv-sfG-`;y^)vdyJ51#tr zexk0e628upRT7j{d<|gw%BhSYB(<#F5K+H9`;|;8(G;YFn9Dfnt zV8AqTc76Dt(w~#z>&cBTz4THSV@dy=3>O}w1vfEf>}eIiD!HEfxIddYjD5?5t8h#! zbC`Jl1UAb4uG_or$P}Jg9n!z3T`P$1kwmYf6)whn3|Z6D{v^d;Ln4l5#faO%%*MIh zhqHFXb6xJ7xbUxm6=u`@8_gzLV&aBlrHvc!eqdvJ)8oeywHsO6&>Cc#Q{9LyHjpu? zDfBm8Ow>=YBdcae)7!IOHZcpZ8R~xwtK`Iw>sKksKCO_wgt=p@dd{M$C~Rst#Wl%mQ`*2euFzN+Y!(PRk?B*lRc{ckhUVvz~+7*JzTDEd29}5?fTlJ z@I%r0ZRA!qSXo*DLV{5ZZeduDRGF_f9rG!(*|h`+B*M&K3tLv7H@sqDqSl+J*N6Ar zcjWr>82G~Yu*{?OI>J`Jvp%~6Z9=K{wOcinwHC%1pSI~nGv{1t)$45RLakM!1VV^t zvJ7FXL1$%Sdgr6P#i0Oew(E_iyf$Z+o<)#{FX?u~VvI`n25*t;q!8d4Fr4Rl{muf{ zScM|rO-KisF~bsy+VTyRrVgDVKH<*ia#@8^VJerY`o}qQedPree7=eesUIj3j>1Ku zQ^6LR%V=cGN;A+e=?!Dm(qiE1>6J4&t`XzQKY;@+mrO%eB?*8S8EXjIi3lG@8-ag> zT1PUyOoY^do`PyPu*(Cd0QMT30+cUpM-e#YgN0dcPkh5s;qSsx;p5j+(dw=dU4TaTxMo8oD!HI zMyJ&oq@0=*TJ!VWW5ph9nGFq{NkVGd>IfSs$X@gE9m3y!yLiPPh`V?4 z-5ZvTNP3j=usLRTPad;3;u-1E*oO^Ywdo*6GqAV}$Pix4lHHOu7!P!Ca7F1Spvpla z0tMS91Kq8)q@HDMkg0(C^szET?+_Rva0t4-t(@ix!WmI&PEX)iFtD)+AN8mJybq8! zWo3#2)(BQMHd@cr5t}%0a0R`4ybbq_*Dq}wzh?3!A478$3;qO;D{EIera!rS}GJvcS^Py>|TYrTPiKZcyK#3eS&(>4A)q-m!fF zy(9j5n+{LZ;lb982@3=WJ6tv}rlQ`prcllYx1v z{)$s4m`Bp>+*@-Wp8e;!`NxC;rdBw4OL=VTt}6eyQD4=|m2%GQ=i2UTopJSeoiD5; z*Y}^)rVC^mklrKS2kLJD14XwQR2VO?hz~P+_&76f+O z1UD9EkQx{%tJepaAP{f>-C3BDO1@-_TUy4DVsc!kvFX&TP3J^69sAWIy7Fe=B)K z@;)T7(+G|90VGg=rX8Fy`$I0GF`k2|g{5HO{XcE9Khr*buKk?5pSCAFoY?+EyW{`I z>;GTd=ef^w?lzyK2BA|Dx+HxW`k%AxKmTbh^-B*tdmMuXJ0va8f4cJ76T~&zjFYqh z{vQ@nIPiWD?OakUh2v*V6~6wt)d$ZUFogH$XID>ATA~b}40HBDfA+Ng|HH9EE(TeI z0iH?E_3=IMBO?Agve@K>o2wGOR z(3=6+y(7HS|GWsTO9?3vT310r^Z@sVAJP*(%3$j<_LLOtT{`HWrHE%7gPw?~mg+r_ z9jRUd_&&s(0kH>Z)Jix2Tg7}aFfs)LG-*tD$kEtG!c;RF5T_uYsUwqWJ2uo{*}1+( zxMy5v$F>%6K`viKjE@EC8*`h#sBcWSKf3hpqhxsPq)5&BPP*JcW_ONj+15c9T&!l% z$QAqA=yGrR*yvSD_O*{*z2xS?XM|5z6x4cD-II4sIQHvR$3`xyY2Uj7%eH+h=C2;z zzHiB@(d{=cfo(5|n65sINi;ST@)?Ywbk<3jGOvm^W%`!S$Y(-G))Zp$XDlDT`<~t7 z*)OkoHr)Rr?N)3&{OmQUZ*IQ%8+DNhOg!rz&$iI-kjfA8{@#bcMJTGBUj z_iYgVXF>Nf=|__Z(9+4@JW5QLzIU0yyJT(2-G`oP>%96+chjaR4|iqVwRXh%aaGQN zZ-_4__CGJ|KY4hQRx!`dIsPwd0}_psc=!Sa*}EXAng@P(j2M2DLs!h8(kW9DTVg{b zCyPoM>Ipk0>>!&i?7eDHw0&IX{kN|^@9>iw7-jQtvX@-HC3VLw7r#_@xvH&rnM&YV z79vRhcR%)m3D@-hW5u#ta>|xgj><6zPe0Z@U3lQFW%IK-hAGY4AGmkxC3pNb5F;0? zt7s(3PQ0I}Yl)nWGWcJjkOR)3B`9(;K;?O=1Hi~aHCV*|4!%Qq!Ym2W2(tjx1p^O_ z%O(=pN~8r>y>Qi4FQj+un(uPW?`-h-Zs@RdnX^{4&S#H4v}yB04{hG`&~D*hM}!gT zr?;R)*DA-ba+@6&|HK#D*WtGz@tjzwsk8`KFrG#+`- z5LQc-7OHrJ={KbBC}Zi{(|$)$)6f=07#CmzZ!hm%wyamsuk5Or?kFp$S>v#m)^=IV zU2K2GGjgf|bYX8Tqj_c!X9oMHg(OF^ZJinzx&v$*9lLN@M`iJsNIF$**kVT zzjKEKY~!aVNWTE)Sp%zVKJ?@fltBt^XFv?`wV*&*UC@|W(7P7Utcr;!uwM}7prNrQ zS_7aG2}e!PdA&T%4k|+cTm&TvHk_cqHNG5Dy_Id&F~U^zeU(h72rwh_4qaP+UXhRG zo~eppC$ejr2eTG{K)#HpqEE z@fK$SNBuA-QrH+ZL!f0;6VxAV9ySVLAjgqrY5Ml9?1{;YU6Gb3>+eS9g^QHrKFh_1O$xC6bxt*_Sv@CAs7DRfH_Dn#k5n z1@u25ZbBZ&f{t=rd_M^!E6RV3_YxHlOox8-$OQcqXO@^B0ind_8d&nj0plnk%8*0o zbA*&cC~-ziWY#k}QCj$vDdK#V?85RRvI_`p!;Xj}7<5E-7=Yp?*PdCVz&Vc- zBEtFNV#ruyk>moGM6oafY*=FK5rueA$6$E^r8Ev_ury07HK8;l+7k!M0VKfTb!14a z1UJw7JK>_6a$HtEYx|PF90WGN-4pzW@W&f>7X=+M@479-_Nra$2riCo5+1z&PrWu@ zwom1`=-2y6{ydAxll#&+ejw74Wm*wX0Ymg2Yg0Ya3B0 z3wwPz@^EvlI(y1F&LBceBMs4aEuh% z;i*4`b&}7$ntt3ToaYt3@RCBN)l2q!iNTA$XTbj}6%uZxM2i`gX0)#XW`7)Fd z(F7vK2uy{5NYnCC0Q}GH$gCqE92{t+NJ(NsY%e{|ge`00+^x(m(Z+~SCYJ7|b0Byx z=twZQh1fi+NmeZGV@z>OIkYt(hcp_nDAmydiH+U?#veV=C>5X)A{vF2fa)r&NkQ3(-heM@gEEYzonr^c(YK_IBQTJe5D^-}y z3aOTC5#G00lrlYIG%|Xba=OW+l4A|qa@9dd-XTCLuy zCu%j(TXnB%jZPzxO4Wc6z-|u6`rNxN?Ek06=pNtm4DlM`l^5Q1$5)I>snsge|N2U) zDLclr>*WY%)l1V)lD`wBOr?-%$l}x{g|1v9?Fz%iV9^;;I{r3#nAUQ)exEvgl${dFuG0rse z4kn2ce!=PJJ1fz5F2R_DQ4^DxIBX7xGd7vQPxC1g3bv*$TsYXo=848Dv!H!b{R0k+ zOmGOb^8(^VZLl=vpqfEDhItpSjRhnNEuuhe804@&635@D88L=96vkhecM-U11vsLN zKjMa^>m&eO0C%NedfQIcDAmFr)MOToHA_pt<5gN+b*&dc+(gK7AjFs;wbyawo z)%KMgMOu#AE}Gcr-6?5w%-t+p>QR$Q^+_W_;bNrsq=Xsc^va5@P_94{AM@L*g_ANh z;grtUynKa@Va6}LbW_*fl9~K+`NeyXdnQt`imwg+Pg;F)6_T!}(@*rxML`pvv&Wj+TU*o7~HYmz= zLDV=~8vogvUeI#K{*;Ub@iXDs)c!kKgx9)f@eBig0U~9tUVb&hBlenM_*vb*pxW5f zqVyv2k=d!2+t~o3J(=qfrr2(FT4)|&K1;#))9)*MAj5N-$s<4$p6zd$dKml5>Vbv= z1mPK|rrux#`v&PYo2d+_D5wp%5eh+E2);uT`?Hk*Dmcf8dAyRxOLIt4!7l0`!REea znuJf==W%L;pAb%}TG%1H*Zkzuzn~gETe$F6nMuw`IXGZ%UAT}Kh;z}R{W25B;yUX6 zsFN>+k7zp(u|(o{lX?FNDuMozUMkiA6ifKGp`^g|NSPghL!c82rS<&zcg`ZM(=O}C zX&TjDU(_XBJ(cjQ*Od7x>U_WK1@G3`Qe9)#xJ--EuM;~Eg8r__KHX2fQx4+Xf6+T( z2#UiS#8LGM;dVd!3S6pR(npOSqkES^oc;yRO^`yWkDijk@k@IlwwxL72kkOJFoh+M zhr0{U4A2dLH=coC%g=w8ASGD`Op#&@Fq&c*G=Zic(>gOCMl-1taDwzdTk~JXz!Z`P zF*_E?uX*npxn)*rlr?Zf%=N}0{lJ+&1ctHSLr$Jq1FAM0?{lTKg_1t$Uv zBW3hkVWJzD?=tPL64_~||H7|DLBCXPLZ(Zq2vHpf-fn=p^iVp{3vE`t$hs0m5v7o& zB{%^(_s@P=0wIUyj=T%$S&)q7E2qvD{9vt#Y?xrD`Pr#Z%t9=POLj4>7Og_~o+yw^^Ow9b@)&2% zCAb1oXQun;`x9k1QKIet+xJhvb};1^zF8fO9mQB{qrP*5BO-jo4@vvOI%1#Lya7{&d48vLyz?3}H+{eE)=e&kL-c~re%iXYG_KKc~F5+@dTDxx4 zfmJ(iJ9_BBr>bO*rs@Wxuc{=T{GZ$Em}j4}T`GKit24jI5MO@P2jI=T;FY(9J;E2y z^&I%ea1uM*_pf7p`!^F#9nG3IW@7iODUZK7;L{g!&L@zi zI6P=@hVEwI!;n$XpEH^GVA04J!mWR1rU(xT5C86WY$?{h5gzO$dQ4tlUO`5t@8n+k zo$xTxr0--)1N|>q@+|!?1p;g-R!{&-&IM%N`=Kpc`rjeD4!wWzBab{X?R_#2^pjs~ zAx!8H*(KbVn|?3bmVQs8VFI>n2KkAY03`YMC^;O(gVPt`*Fc7ym}!$#6~k1Q%Rttl z*blLyZ6fX-ehw+k&R9aFO?sHP&&!K2(FnC(X1)n_WwL6?mt6Mw-JFg+)rwHwdp^Hl zs``!#XLODr(TDCL_S?zHKmBUMW%Km)>ZZ;_XJLt7cAX>?j-E zUYR?pp|P!NN&UKenErx4th?h=qWs&P7d&1b&0TR@)lElk6+XXRY8Sp-w{w=cP212^ z9&gTR?&@mJxoY*=o#!o1HkMWn%M|ROuPTnk1O9i)y-A~L5-2|>Xdsk@S1GY20KzCs zM5V|hi)A1xGiH^Gxn+5fz#z@MnR(&gq5n*uu>IiEUH5c7ed?>H-R`HmnMSf9Q}6=G zq>5!{Ki%E^G*Ih5ffUwahnt>CuW(Ss6~VgVm|vPs&W=udbu%CQjA{6 ziC_{jfE}X|4TFc?Ps2B;>6ZrM>A+I~7!h5e3>AoY7lYjkIA}ek)?%;RW*oqlo8*6f z7Qy1NWQCt^8(uQM6OinvTjv6uV0M0vRx>|3(rhAt=-%4vkFuO~l-oToughfe1t8UHkOQTpF4kRD`LB6e|+5u(v^{W#I~k}o*RR`YMNxRWGzrXH)680 zL_$$O(C`mR9q5H*5q-i2YcZ@=G>TCM3kHxtwsIED45bvhV?z@}Y=#UVAKEPGUMx#+ z0bB+H<-lRl@(`GGv0KDm;)Db}MLdf(1%R5*1j9h#rol01f@LTSo?UoUxMg9LC$HhU zcMJ{bzl^oIDre5D^qRVYyu50maLdt(2E#koHRP@PRIB~O*L1kDyQpkxSy6Z8;U?cF zTJ5L)#>3T+$iKURM5jC!ODfChttojbXmuSf?XzWrL{5`p*N{$coiWI znoB+ueveq0-+y??B_EO+#IDqQ_|Q*ukhzW0SMCiImsI{LZ-SaJxNFM%hsaHb{1p}M z*-OtCJ_+3W3W)916Y_plS;9;ioiib4^wiGVnv7p5m0uZ~ZtI*X7ESB8t=agcQu(E^ z`L+%w(#WVLre)fq znR7$!ot>e`T_Yrdo%hfB1z%-qT$6QEyc|2p%~>48|#zg`tjqsOT!yIp5+rt=IdBPbKK5`=jJyB z^+%eLTHa^Rlj|-RWkDrEHt255c-whUEDS7^_m$^s+>R19y? z`@uwlI)&{73vrf%Mpr_D<*3|fDWyLOL+SvlRUAD1mB`<6=uLiGtMn> z{$s}8dCR?fs%xq@Y*x2od`NH+X)?Lu>NK^gr8Bbl=(>0Sk@*c;% z$1&4d=hbzWc;ukYlUgD@(!WX%>MFJ4C)TFF99da4dQ^3lb@u!@?9|$>Yc3%#y`Wa+ zW^aDTCXYmY$S&y3A6qFLbyO~Dzq5wR9)G@@vmY39#o@yKr}8H==S>gzr=<5ze&F}f zSWVBQYBB?C9#3_Y2eUUk#R=DL?XyKz=DJY_3EOv;R3MzL6eK4un;VCI7+OfxSnX`R^TYKhc{kv_@ax7yJ|`TKC_x6 zj4anVF&a`>3>K9h)-b-h%{(?C2Q)nS&-jWlNu6AqlxN@96>MHLuEFe6Rhu~^t1Mch z;W@dnEgNPhkU_p}@|&yl);jeSB)6t9VJWW~*)nT%6+gB~Tc##FPnQ32aqe=RIm_aM zk>;jh=5Rp{XP2I5w3>Jru}D7n2c6~NSk%K?ruP)(t~$t> zPm4U^e#ppeB8M#PqjcC4N2|fra^|Ot2@d8!yhP&y3fQPD5u&Ujlv$3VS8P-w4S{=J zEMb~UvU3|7bF*1TY0Qb>% zWIM|$IRmr#?H7?vp15z{{%N}Y!q+E0e13Sx*Tnnvjve2i{ZPBWY4i z_f3B#ykYcc6(*|?3$tuc3O<7u-#s~(jAmyDfwOmiQ#fo9@BaJWX|tndw$E}>%jfn# zdl|F2|E~kjkeL_D#4&-&ANX<^UAB};h69}+?Ew^0s1(s^4nq%wN%7-Sc41nWF^Gts zVNl^pK$!U9zI%li&IgMBGNn#0YkO_={3kCTGv@Lq=g&OUav4oWEdUi5i+Z;%BBpEi zA@VSNauB?CT!iAWZsB>#&2`Oor9*zXf>F+xkJFFhDy@x|BLOzW64K1vTjnfT_wo&y zENw~f7xci0@}qatLFSW4vb2m|l*2(D@}p?7twMiBvKB?~xd+KL=Qs{|3B>N92MLe< zn{TiVJ1}O0U1!^&eVy0B{Pg*)$B zvno3r67>k$Uns6^Fz*OO5H|rCC80KIiY^@LaUv))!AeSh*>m@uvrV%W(KMB$N9bkx zD5!6M*R8j|_xN$CB%O8qY#|HO>EHoO^7!%oUTP*CEFluGIbfTSq+m2orMMsM5rADi zOBpwCm^cPz#)2^Fx5P@bhoBBA&mKl{%%fpCuV$efV?r(EUkyv*5(%b$Hp>mUmWfXNs11uDEuozE5 zR|)R=%UMtGbm+g-bC-kp+AUH8=NYe{FOd@o&!* zdZ-eIIguCrrV_I<@2wrT2i16TGjJlO|I$$s0Hk zS9X1&pi6~V@`QNp-ho>gjl%}-k0;9DRK>dGfXm01hn0@?Gv}Cq2!Qr71d>OhHa?t? z$^c7171WpRQ!j3h z32zLGMu(A{7+M0T{;BGNu_?m`Rgc+}W(}bhhTD+4?g$+nGG90|Q3CmJ&Ndy<=;-yI z_J`>%KMo51+>t-O-ybjIIg#U`j)R@S%OQZ_M>nV2nOU8}_4{Zu!D7fNll;lz^waJL z!$e%n>7U&FAI>7Fv>F6B~0i|3=)Q5JAE;XFJO2j3kToIaVB2zXbyQnZE z(dgOLT@lxoEv`uV|8NSqT%(-NkU2_?p{!#>XH_^{)j0wVg^6eHIu4h_h3V%OeI#Pr zr7Ug~y#w@wsI8ru005!^HVDDenc9payEPyOfNEis&uDY}nKb~coxp5i;Qm2oXFh?d zhEbYsVkG~SUDp2=r8+_aE|C2Wu5o>7>`(X6nE;661-5jO>Fb9lO)N+P6fUum#PQ>_ z&cvlS#-p8zIw0g+*uOEpa8ZH@Dq@615NL3*5Wmv@4Tps#yL)dJst*ghA0`Vo6yDyu z8<^*X?O|c*XXKj5LasWp0LW(?Q@BAqX-BeEcff)W*J&hkBZdB{HiUf^%J4OnQziArTgI@?1AXGOO^WKk$=5m16h z$|*KrKs&Y=66IEQ!R7}y;~)8MQ}^V}n49`Rv!v6aIQ=Sum@x zbQx)ZrIQH1US3j|6^C5*)H#l)X!!;?=F{vJM!j8VCeV@68m(2)vKr%Z~PMQw{(FsuMxco}qr z6XO~q*v4c;U0kpq(+|PoDc%-gxSk_bi#8@K;ac=yl3AHC zbIpcH%!HsTcbZNaG^T&|eAKM$(8)p1YAuYBIR_i1CWGx=il3r+YN#J4C4RfJ8R3GE zTPyG#@%2P0j}8n}+8g?x%CHF5rMwOZ3>Zr3;Ew}dNIm&9DO@_mOW-db@*hGToZM3Q zzg0ZqK~hUc{{ZAHK|>N!ry&5c67f8&4fx~5-~J@q*Po=L1(!V4=l4apw@-;!RW6yr zsW}pj>v z0P9qg`B6D%j_ummwQ)Yvv3cv}5v*~Ka^&Y9e?C&VM{-)FzVwqD#vj}~yNWUFRst|Z zQe@3`*5l$4TiD%~%0*$``2fDD3jo`oj339Rs}& zqnj86MGcdHK2dc}96-?60JOsp1xRZYN+7H>us~3+yNF1KQ2K?@I#CGZIU+olVECxx zl*P^}g2s@7k8HbW-fx!9joVcOF~y^9EExUXvMai~XB(NZL?yfhEdD2azK59**j%(| z8M|)W8ll#$I&9A(4;Rg& zWJgx1I#GI+zzPovY&Z;g1cdlyTv$vCWGV%9p(#j{a^MSKz^9@jG#Qz-6rmLq_(DY+ z*oVSU;n>mytVpHjwqn_%mut(AAd6L>+*+kd3g0rwj;XuN;9NEQlHU+MeAoQDm>Y(T zUcV1S%|(%#=!6!lt$oSXo0%(%^NI_=u}k_=4c6~|9ej<~-2{8`39&iJu|#r`oeGfD zC)NOmpcyq)XrJ7&+9NQ`mh>iOtKPM0`rP5Rkj0zjS6v+-Yi2KOb_6U|KXJ(SmZuN( zSlijBPl*@f#kOfbQ#UkPA{WsHNoe|$FcQoIK6{;HpX4#gA0!`1en8$k2kI25u*f82 zExZEX8WogD&H?2x!Wh9*kBoapaD*8d)D>*%G+HVc0BSD?XGS#>56Yrgi`z;QtOdN1 z)x=U7Ehz<<2=-^hVU)&8L!#+Ntnd(Gs5q)1id*FaYXMsziXoN`vKW4gOX5^-w-(zh zR*TF{VDJt~k*pVxGflx7H{UzVDI>k00ROHuummRZcA9Ua;~ zeg1M=R4RJC;z3-7z5-k^i2)08g6@mbJC&Zj3$9|N*TqgeBz+a}y64{XM<)#I9DE>I zAc#gM`sHX|Zd{A9yTdXD6I+zl6L7tQvUWzm=4PaBocH9VW5!&1Wd4n*ZPRDmzG>=| z&6}r8owjwx^lhmd=O3Z_o}70hGe>5Su^x_>N_iw&;^ho75rGs%`~z?(OHNs>CZpAA zG?6=N_!e@B74nVAc+wWK*+Q34%p?qIqRkzkN_rNGP9A{|J4>ha*>zs8-|O*v@A7yI zPMT=Mt$VOgYjfDlY7oYF3pIA1!>n=mJ^rn7jmA_|wzX%kH&n%=z z%%6uN`rl$%q#@FnbsCLOiOf|<{fb)9@Ocrt!)UTk%<^Sc93cnY_Fyl43f!LFoq}$$ zjxBCH_Sx-b{Uswpp%L_dbCcd2tBaZK0V%^Nbt=2oZuZkvgVtt1)Q8Mk>&nh{)t2mx z`Ld!WtIn^^isJl^Am`?AqTa3{_K00=*IzMssda<9uV`M^YR<07Hlscmu}0`ah|feh zzVY?218?%t(4j!&i^zC6Oo$TH+0zg%(?`aEVO^jzBK!e()Wr$i7y zsX{nL7IJJ2jE`r!6y`EfL>lZ>qAwYpj`of??RBC<2AoK0hKE2nC@+M?O!TG%29Nl_ ze^M$UujuXK|K>F$l_3wJ&T8Eu>6b~9x&DW-vq#OC(Vk!9ZD=6L?1abSvUu!)?8>~F zP(fI3a$AdRIeD$6Nn#CW7uVMpA6va*#p=h%C8HN~)K#3q|Y|^eR zR~AK>-_x5el#>a^j|=xGD!MD$D}{%y)Q>DI6CS#V37t|`j2v0PeTyX($KekcnBy4a zXx2gxbpvG;fi^k{zOR=hf58aOgZMK99L!80X-dI$MF(SyYhhd5Rz`>4l5pmSWPbQk z#4ZQpvS8E_j0R<(@--Ps0aG$-Iav2mhR`6tErHW4fGLXuWDxnO2S+DNj5cwshxnhs z0PK%@nexFxL(qb|M>8WdoqNSC*%=*I+<|e@Z$ay#|7Btf5-y0AMkfl9!IQ31!a-2} z0FZ#O7{^k?wCJJ}%iwij#X_Vn6!#52CiD=JX}~xQqCVOqrX%XZx0ZVeFim3P#y+Ik zIJ*yF zd2w=HzqN6C<@D{2OB^jLdoEZwzLU8@WpLZ0_H4zb(PNPXgd5%U%K5^(Z@qQHb=UE) zW!lyfN5b*8X_=YvAg!IvmdqZna8x+{8hGT8_ zR)wlYT{m^zcIU;85nC>*m*wbuptyB~JX6m*f7Wt#!s7JBqec}c%12)CR*ipH%u`Fg z_S8fc7Ybj!hCekmL!_C)(|& zY%zr*;3?1dTV@fR7nUb%`@L~RP-j)jW&$wgNw36RD{xolfbbR3rB_ahCl0_=c zav)S9Zttv)n}qpNrRf4WY*^?0h450PKeo87y2Wl*EA(K&Qz-ZC)+=~s`F3upT%#mQ zD+W%{to-*=h#u*r?j>54(1Y}eCSnR&aXTA%|3_0XwXqD0=St`-CBPd^#5lefabH(R z_Gac`OsG`)<%4uFFz*gXoRA!W1u)5q~4m((-dPA8D<{IR3#ij*}=vm()!ss_8(ruR9F%d*4&kGb~_jH*ie$LHKKHPc(_WG2bX zg!DF<1V}Oo5K1V45Qx;!JA__D7&;0lMG!$SE24;s;@U-w?%I`AS6p>1aaUd4RoB;D zT}U#Q@8`LbgrK29ZNvq?a;IcW*mv@~9S511Xthz~oXu+4 zFp$p6jrK_U*x$o~PTU5sSQT_gXMIY>}9Qzx0p<#K&)cJ){SPDfezTqimnj+mM zoIrj5vx-x_$>tH3^EgE9TtV_2qTGct357-r#1Pucf4|Q>5Y{|Ec>yy-9(-saeD)}0 z8Bs~-6G@Mg%&;Iprx4jMu;>ZX)N?!1%3AVNTIn}h6~74f%t=)pEme~m=`I$iHV#i` zq4eR#Y8Eh9nzSf8E zj^v9#kVD9>L69yyLSoSxFyj&NKv#yS+-1|_e$EF)ST}g->eAPxubJu9l)71?N=z$E zn+EMX{n(BDcWRU?mD-M;?kDg9|A~(ZJGY=dgGd_TKV* zUPiS_qv11u$&00@AEE)04PyFH2U23766Kg{;f_L%E%x4as~g|yh#;nrk2f{(%4+j6%Dy|XN}UTnw*;`7TrGS zSEo1sY0KE{J}9a*;tFI4;8uxo?!?{=Re3;q|Dekg{?pTlY3T(#LG8@;Epi?|IX@p% zFekW+^VgKkziUdLo=e?B&MKi5{E%@x+ejxll`_ zMX5L={cGaKvvJ{DTKQVQ9VuQ7$k)opW`8oNEhJyt5-pEX0!=l^7|k+;RCMXup#~(+ ze}@8odR%~fk&*mPIih+_w)F6pDXZ5#GJ#vyr{hWgwmK$A-~Zv-vrBuc`j?a&dl}*? z;Y6=gOsuYGi0rs_{1fZLqq%;??LQ2i?-+Pq`sc(uURxm+_*1-96Z@o5ASBU-XuD*0 zqv^>A)#y4jq`|Erc$GR5B3Y^1$XP1oGqi2BlMiMTI~I}lG&5gyha?&Beq;pe{EJF7 z^3;KzciE=+(;b!Kq9VK2m*~n&jZJqrlG18(vTM^^cBel!HPe;os~s0TnIi9GcV3g7 zQ=69LaHP{UKfOghiw6ScgYqIo|6oLER}3l%)L0W!60N>*+|TZW$*7Z<5S!pIn5=Q} ziAiyBQ0O>tAW=RlZ?RBI^lV~$^z4r=jE_rjw7}fcB89qsO}uGXT}>bTzwzKT&}8-|qV_y-mZug_yK4wtYYKG8WOznTvzQ06iXEq-ZAZAM>rvNOBSoNAMK z;hpe4&d?=fi_`LG7!Tv|MsD$s5!}%%dUe-;eI-tCjt$oDv($L1l=b*`f z!p#u-YLC+XVAoV3&lE1;ME`^*77zY4H7#8uaQSJ)P&-&B`n8?`g|%xr)0F8+=>-X_ zuFsTeXQ_X{h;ZGEN9Xdw#8V5NoM_Ya%~*2H(t~%-Zd#V3PIdH33ziJcn0Ih?PcJX_ z>HSq&y*H85>$tRBqcLq@u{O!Jv{q$mY)DcY6MMyry{mWU?w`4GP=3?n)7kt-7cWeR zT~Isd)bcqe=B>0(?mfP=zdvCI_gPPmFuC8$HeSMxO@>uKaYg3cG*aw)DD@3&xaG_O zSO>5;Ih+Z-1ki3w2zUCiMpwM-6)UY;kZ&H+3MA0?N@wCOolH=NOn$fU&=qfF zQm1=tmnZC=D+(jie{%7_G(gdpv9NX%Di?+a7(3R9J?r<+1$76lu_$2+EXp3CZ1tx)>pbH-6&lgQC%tBZt*^OlOamX;Y zWXAQaWCe$f`PcOy$y*AKjp@eEc!Gti-R;R|qzh;E{Jp;7W)|K&YyWSV`b@0U;Vd%f zpwXVZaq}4_KNnA$a(~5CDKq}g4-mMz1ew1cgH;}GnMJ-tsR?eY@*FASACOl^GAv3p z)OTPGhS|T%o@^zU9|GcnCIeqgcEQIkh>iz7kCYgr%N2~)sfa>?<&(n2oK{DteOQQE zgp&q|sm_kM&Qx)b=yM4^m+vo$wn*5Pm}uj|Hg+EwgChzo!f~@Sr;&MX3`;nznd4-- z9`;`@hJ~F;Nlq#3%E{ptrY9z*Cq~9cj)wy^HGyz+$&GJX#9kP_qHo_7!=>Ic<#}N{ z=9CMV7jg(&fMRse73eEM8ut^!Puqk7C5I7!c+09$2U5b6Bl{G-KMu&==nDGixVjJ7 zqAcWfu5e1f56GVLkBvRH8B7Eo4-3X zn=LI!+hpGKf%Ln(e~{))dz#K}#y-nG@jcr=?Mzw$_vh-u!s@~?V@4OGrWM?D;sNRH z(_P!M9{3-&Iklj^{%+}aA8umW_X^VFJ(mCBCh3Rw3Mj5Z2dAy?F&EOeO+f!&E@O)G zP76RCQ{-6b98?WXVFgZDR8y3^oSd4BS2V9+H)_&C+AxYnLDP_;!X*R?a08@WnT5vO zW5;3O%OLcOW+gOA5GDk9;-QDCE(Z#eY8Gk>hqD}E!MK_yCvlF(mEXtlPb^t}+*c~? zbn)Jln2c2E_1n#EW8c*^c~;wqS({S~PPg7yT9srgJQ~;M;*mceJ_tFWM0$CtHzp>t z|Ja66NhVdS$tWcDFLQ^k@$$m;8nuTTSv=|L(?xDNE{gY}D{g z&mnd^r&qu75#E8LZZ8|*GfXu7O||NbI8LSFw@j6;fiY?F z2dN$3r`@$P-Vi(7T{|^YEFI}pvFFZ{_b@IqZ>S|dpc7pwMTu4*wpguciSdruob3aW zm%3sA*mRCl83KcE8=2w>#mqLxqCYtpEHH$f} zmJ15bbo7xgUV83trX)|T#|MT!`n#9P)G-#WqCzn0)qP)l^NknF)CPm- zaaRI~K-2dH{?#`0aQX+n0EDa&d_fZM%4Cm6$h#2WAuM{pnsx5bNQZxz*@h;g;ocb< zf?PFVkvezyRynt1bCdL~ya9pzjcuQ9Vc{*GZjbWB8&(yNE(EHunOyNqplaRr#`ZTFw{LG0@*1~uk1nC7&_ZepR2CIg z2HG5s&*|9b-Rl*H0+p2kX{O!&a7HC}dl7mPn1}vkIOnbpgHPq) z_et;X`;rBvGtwaG4E!@^At~n zEV=|`@*uL>(@EDb5rVqO%i--v*E5Nz$i2JTf^$q9v)s8}k)8Jas(RwQBa zL)qqWdhtwn3HVj1K^~gJpw+{Q#X?9pP6zLS;|aVUR1PSwaFf#RShtxrSr8iY{ z+BKZlZx&UBfS=0c&}(>~U&94>YpRv0Dvbj7G8fw$*(j;_MMmhfbW?expq7IJfog@zuC+)hx%PnE!D8%j+SHi zCzR!FO#dCn-@9R$$ZfDE3({>GjSZ^@)M{sn#b&d4V%0Hhgph30XxMZy*@kPNXAxMM zkN&PLUPCJY^rqB#3u?!J}DhkzR1Qur{-A8OD~z)M=Qnt zBjzCG)$1W?cOom6?h%Z*`m|DHtEyP#T^~MuTFnPwo;T@FGrdlF`3UR%)kkXS!jPA_ znAT4+fp_{WD>UwsKK(F@ZExq$5O%Z|`~(FlAIYVD_*nY9<9g{cmhk64SF<_Dh+#wv z+%^i5DD_nt|DQ1L6tYpZTMLPA-95e?g^z9G0JiYhrjCDZdQ5oZ!BCErm=mhZ<{LIW z!)CTsZ9aQ;bK1k~9>Oq}Y&rd+^kx(2&2_L)P-gF5=;4BbM<=1+NaQ!C9SE7sqVPs{ zL_&%yR=~g6!6P}Pl(N$HI%|Am6q`PApmc5I`9%}Uo48`>*iz)on3iskK9E8yXYs## z_SCk+3)qm??6sBR+|^Q&^z1cb-(XW-zoBy6;>feowS&g7ja={czHB;YTQOnQDybZa z?`;K@qn)p_nuP~9KhQ}Vkmu`PvhOcZa&prI(?LH_aceO=)r$+=3{xGkEAnxk1YKuw z5aG#mNX`!BEOx499Nx6Xdf-6o z^Y^Zuv--htuiSUvcfsG^eDI?Oo0qJ8bNQRc?|Vg9)vhibfAh`bON9&T=gw`vtF)4j z4BxeDcn6=El{$ZZ3co|R<#1I;U17n@d0?W6k3NpMdA!U;Qv?=djbG9`|Kj;5j|%$I z6KO@JEig2G;Id7$x#WfPsmnHlwy}_K{A%0c_OI@0PrK`@b#t`8T0C=jHp_T=f5$$< zw)>8AAKG0mdnA<}03atUBVW^!-A_xYPTrm?Zy&(&uDiba>aJzaBYbZ0ulhaq*L@xP zt4ch71kLrM4a#L%LI7>2JZ*${lLQ13%GH*QZ0`Yh?Un(xdjS0ThQWWg9x*8sL7iv8 zk983um{!7@bv>-C*8^vCk77TtFpewEV?>bZhg^^~P?_2(dd>OcAD~5@J${susOJx^ z0=V<%e{{ak9{iaroB=wEK>wfo5CbDqf0{5D!p)1Zfhi-k+n)|5qiALTI2{Ial%%{? zDmpGi)Z%SzFLC?1V{I>uL^`ABzY60VV={g&c|F@WVvcdnD*RS=t~)B1FxygQU&?IQ zxV+u|xOXYi3|@Ks+u=*Qp6m5Swr_a+@eLavdrW%I-?x8Xf76tBKDpoIq+m&Euy#bS zSGqlAuo2vNn#N^_cf=$G10JZQc1x$&s7n55$5iQkG5zJ2rFWJty}8H#n^JN;hLoHX z`sqD6DJeOg+(|hpIrN*Di;(s=(|+_%x^KkND-SIlk#@y1@%+@sHbzU!u1o8s0V1|N zzpx@h>&QyZ$yG5O@(u&TtT!|AI$p^k&lb)1Jo?^JjK5uwbxiORzfy(;hx?P@JUQB^ zSY|XP-`;xkXe%!rZN2^WR@PdPec|2gii&LZKvszRE|kR{$gW`9>D*Deuxas8p``6h zRz*dY*q@fa`W2RVBk`f>pkMD{Jr2|hxoTyBC`To83q)1Oqd_b{yfC)Fh_5RWNLu;1Ip0#Av!Ma1gdE@r!@79a%M76=*cZT%+ z`YoSqV+rS0ojT%QLgJtGOF{1dM|zxT+S z!3nE2Z&@`V_}HySo~$VolB{+^Y@lKOvUj$=&P-!>+g+-XuAkmG;=TH&U%;jH|SFgI`+P`8dF_u3_ zmvq3r+u`L-zZO-SnBt5&0YNaQ<9+;H)y0*Tc&Uy*Fwymos|=p&j!Syv;3=-ezC2iIM8-Uz6ITRz89wPj@`WoqSFDhFiqO zNv%>FyM~2fsp|+?dRsa|Ca4F(7LO42@QTPR?$(YDUI+tnGTiYO?pAq&g=b0%ORl*? zVY3MebFPI0egUGPVf*iMJ}6_?z`$wF4R@e)UBp_M*)Lt zRET+5@AxupZ;)ZJXV-q ztVTvqFvKiI`9`p?vLQeN6&?@an2e3(YA871UDHi(_#kw^keTR5XFzTV>ws<~y6aFC zs$4u5YHXy22sbhX$7#n@Pf;bRrc{psUJCx{@Sl$n^*Xpe>(g?qTD>ktr`K9@()3OX zKsm%1o-Tny?;U$rcN|!~SCf=8GBEBP2lw1t<^gH$EZ6+L^Ici)v;pR~o>L{fGpgd6 z3=<*>LKGqu3UdVlr?zsO70@jf4UaT+9(BChrb5Q>xYQINB%~stUX03ygB}68Dow|+ z)i>O*x@^hy3#Y_?5DLY>U!*jne0PSoyxg0yyF8<`Bz@$FPdw|JZ=!h=S}?dc2vdH6a#b?oX$O#h8f&HB~XrkD{U1~xAACR|bs=vIRd9U6P>BO#gY z58pa1D~VGqt^de{7#d$}#AB;oVojJqCx5+k)9#yIx$ySV2c6OjsWyvwUv3r@@M0Kh z@hf%i?4Prq**;XI`?Pt{iv#D?e!4Ni-=!H($X*C~n^2JC2xq&TuEaS@kc0qp&V3aL z@$W_2_bf_wCqtqm#XB_jSE}2i{D%U5D6QaeN6<{@fp3DFd{LoMgJ%%T3I;*tf{B9< z%D@_EHCU)f%)8R#gfvmalyIH1q!_;T_3x#&?_a;RYT2rR@mYeH9N)XKG#$}Mc~dt& z^Y$|vr{?j@m|oi0J3d(yvf>A>T2>{6k=i~Asesn22{0(d8|7SA6*J0`lgnmQLW||r33e72nPH0u+Vy8msqDTzhd(siII)*BiaTYC zPq0gQhxdGNA#-pjEiE)S^8)d39CYSku|tlnfi_5?A_rwcm4{z)RF?=7N0+wFoWr0n z#TOPVX=E$HPY6rzz1K>5Kj;#n4vcOd_{WAA-HuPToMaiNpsGw zuP%>XO*gG$>*U9@g)i5INQtb=5W<*u%c8M!fCW{k;P(BqO&IXO!Uk75P#n+?kPY+} znUbiKU4`b$_nbzf$|Y%(UmM+gPkQh4p5qk=bRA$2G&aD{t;`tGu~6mJR&yZe}0Uc-oX;o4ax2Tw8+abbF_%jM^aDALO~F3YgTeIm?5y ztG$5&f%g7|`cW5wJ_SSo0cgHJSEU36MbCGAjdfS6-~NAWj4?6yt1CWeP+Zz-utc_9 zu9k>?g|CC9#jy3#(U-4YL3ASX;n!HE(@<57%s1_gJ-?Rxt>oC!d4wMF-_(u19n_fJ zki(rLq>G3}hm8}ot`n)a*nMRqh`-zj_{i&uW@zHId0M8K19!R*Rh)1KEQT#}$8??; zS9+A~J^Ej^5_N-@j|LWLnL10Ipk3O8w(jw9=1uB6F|B0Xx}UTn>3%>nloDdrOQ6%Q zfpw8AGY$^v-hbNfJwHQ4sE1(IbRgZj381okfy|I#x&%#Ozz@R1;2~~;*A#U*q)V1! zHvHp&{Q0AF20ZYU{ps5~OngYql?4Y6o0%Cn7l2S#qp&EFnli(eFl|BddSqWdUG*}>I!WtblG7ZD5 z*mK~)0x1tD_<<0k;w)!g7_u;>D1bnWc0+SP67|ai)Wwun^t7QBj%4Y($KH~T^;`bN zzFM{BhCgjv@yBcA{?p^jOMOxv-76nNfa@La<9|o^qvJd?yc+m$8yb>tK?C9dLJ0yN z3XMHS+Goj0cdo~T4&@KJzk&mBTz5^A9munB|didgX&N!xjvh~Tmr(W(Hl?rr0 z#ABp&84c;7g;OPu{(fnxX9;mO2tr)($uRlxCZsU@3Pz#f(WQYp2Mg@h_d- z5O~*^BunpREq9l8bay=|bT?rj$b5=yck2U*;mSEP3Xw!o9SyA>vuE(K$K=n>qvv;O zG&vwbJBMF6pANq-di=ig|9)P5XQwtE576uyapn9v{J!Y%`_9Yl`qO!qyClf-Y^j{j z(E&_n4uEYi>spF~fo=vRAj`U4j-Oplp_jV_7xi&5apCuv|CIF3$t|Dk&=F;6rf=Fj zAzFx6ATYiXttSX&Wr}{b;}fFyyll0;9DUG) z<8p1!2O3B+4nHpc52T1?xdBm7slTo!l0*sbC$W@`k7LD>=Jn zR@DNa$-fV{r);hE3F&?Ljhlb2jLi3hR-28B+e4SD#38E~9uYn9L@PB#E9Rk7ETg-9 zq6eRdzNO>qpUkWBw;}ydl!xr%&uGF#9FU9aDy+;d%0EQ33|ICfEi?&G3jgOz) zFf3H!-6tWkNHn#6Iu zan!s8s1C{3m)4-|wnCmLC&Us3j8`Z&SSBhYsuPT+BXfXN0P`zX2s0c0fKuG;5Qpha z6?9m-V90Q*NQPcZG5=cpJtAi|EzB+5GIjURL5v?5o2ZOcS&eFS!2mI(f63$+t+8qS zmnWuAKk=o6)v6KS9R*ou&R15gdPVy3*590zCU2j=>J_e_K_hBCnf^d|_THv>W7XsP zIe5L@wq0c(tW~K8hXQ#jX+-Bkuv-7>@h^wX7H85!q;t}judJH1mF<7%_qXE79fJ}Bf5jy^ZiQZ)3N zf*V!`W-OmRxnH`u4FAlHLn+A&^}(>}Uvm8l6@+fsRX^&92osReGUO%dP$3U71PV}E zK2nFt7z-+qT)&cW?d6I(+;kdn#ps=v>-oqZ_r%4s4?iVNgF>p60twx_14*) zS5){A8*<2IO-xFR_jcDe^6}3<}_O5Q|AsXT#4L(ySAtzr_v_aV|D}gwKbR9VGwm9aK+asZPABUsxY{yvv z*J0a1XAgvK{{-7%G%)5goRn>$4%y2EfqWhnG{kUY4|x2ZKq2YKk=!s87HDhxu{Erpq?rG%QXz#}!Yv&wJgpc&)_4V`D|!!o+vs~}u1Q7x z3It-3!PCf}ssgGOkmR&NOJ@Qk8czc8{p}B*H<=vmtqzmv{KM_w%f6M9IN`~l^-pc- z2yc8`e8rfaZhS?2d?O#;@>E-koU@6&K`>AB4~=@oyXCR{bMNm;z(nuw&T{&*W%*My zXK5$`tDL;aLXnoADONPqD|?QL73sM{Wdvt&=?2iD75M%XV^5ejXdVzyP=2Sxr zmm~<|+vg#1=a<@Cr?AYHXuPE0XLTH9TCTeNPjSim5BSgcj%NmPYdB+~Qu+>BCX@^9 zj4?@gT!>QWiLVatyB}eyBa76PNb17LsP|i}V)P}Y`cC8?j>akHD*D5+-ocd20`FNb z=zL!`kd0)MfJ3>G{hB?;-h%-~;^0sy5>gteU7(sk7V~H(X1`Avl($KA@+qU&V6MeA z49F>+;5z>3tP31eh+3+04!T|kcxOlSiGtTaX^#<)0C+XHW<-~Oe^XeP{jLG0a&Ev<36z*n$Lg|I&(VWrEFU=#2jo9Du>`K zPD67Pl>^7bF27lcdgCSPR3-95qs&S`(a;eR_#J#PAq)CY8md-tkP0H-1+ItU*OaPM zl*uUol^Z+qJ*oBrFI7ubjNFg-Lw)2&i2z%tRw0jG6rX*h_F3Wr92=E@N)@Sm);PE} z)g?F_rTVcc*+aJFrRTOS(T|C4=5Q~wUa1Kw#lE6Mv1tS{2)9oA$J&HN*R2@IeW$jn z*!Xa9UV|etGV)vJ*nD8>a-vnOj58#tG`hqjm)@C}8gH@bRDlNMPc;tbQhbS`KF7dw z+Fn|t(b=DsFHUsZ)utiN-hjA4TIq!Ryn^&Kxn(o=TyM)L@|4E_3o9_SZ+#jQRltg2 zd~fGq3uem1MSTax0`@#Z1NB6fUQG0*a3c&FbxcD*t70}wd}^Z8;E7MrY1N5(r}VvM zluJlRw7G|;#_9XH^detUXdL1)Wa#V;lk4JH*C>t0nwXHD)L$Q$>NOSy1}7Av)Wao1g6+*LehE>mffHY95VQTk2|n3lIWL8;WGY?Th0dX*Y2 zfO!`OJjZ)CGv{6RG5cW;fM(29#`uy#XzEp3PN`AFAh)blm|H5uxJ*E4{BoSPM+ zHfwq(v60A);qSG&K}_9PTsTJW6n^vk)ZPA*v!lclu+oy%I!*|-_fsiC!Mb!F&{ zHvkdSEW{d+%*JTUFldrFQ_O3>et~Ng8&+lb2AFy6n8MpNJPzM$;`U9!_$vbdV#askxc zE05z3*EuZ7I<3Z$l%&xbY=$ItOd>v+aWJPH5b$M|d(2*KoJB-t0-&4dlN{rDYnk;&aHqm8Q^A7;_Xu9{>B&)C@V@q$n z+h7RIFd4OM=~}-3*8J)2xFm~UO}chRvZ42u45iUDz0zE{c9DR#yk;Kn_wBM;RBGF% zz8tsd__F24k1t;)`Opy)R$x%+_(A=i6dD@P?6%RPL?ic7pOtZHrNwk}61UN*-}OQ; z|G8WBcEC3g#*m7Q%fOIS>+?l5fSvFVrm>l=I>4=&ODi<$9KAj%4b2kSY%mR6p^FL3 zD-P6hT;C5WN*0$DZJ&a~2>|Z0I(2$oUB8sq?e=~7sScjEC-x1q+~O*qhYcHw{u67n z2*~4bc2b|6#q$C&x|P)?Lq3X+#Ms0$^wR(+8T_u1Jf@M)`wGtt=0dx|E+Y_0Qk9E2 zSf%Bt#D6w!pE6~8Wa*Ucjg8wQ<4WgkyZ$%OF0#^hcl`dADcO9+!1-&3JuxF`^2Ek! zU(AR@(&-b@2Om7WacTelp4?2j3AfWy%~kQ;w?-pW2>WmrWpjbCMTx*ZM`xxYLUg1Ur*5EYYXMjx z*hMhU7YgJ>1BFdU5+?v!RS;S9D9Vy2YcEkCZ~N_4aG@i^O%lDU)fB1;r1my1A$`FTbMMpuU(@|ICPy?%-!#(6 z#)+FYO^j~sJ$J6-MtDsSCreATEc!@i>=Yn-Wh)bSH3qzip5CZ1@C9UUibU=%**EsQ&7?sWlHESQ&cHTK}bD|V2`6XBwv)BmjjjHN(+u4VlkgFk?L^BcmCtpha?@Ph| zN8bkm(j`&27P_QFyd4Zvst2wI(Nviv^g@+{P&H!qg#~i@kBu*DZLz20@^sHgFInSb zV$#!NViGLuYozv&(r~y2r`d0DPBdqTtr=#~s-Sl$cyRLYaaAz4oq)B>HV>9=ztRJ@ zQ8#cT0)^%xdD~fxGki#DfsP^+3Q6BKA8`-Dt!SZ zlERb=IC__W^PT_Na0hZdU`aV2Xe)vi!w3s=G|K1(R7y*2s8OH|NrH{)hzj9NKshYn zNzt=bSJn-ohn+QKJ!=U~q!$u)S5+x{FtSqo8;WiXm#IGH7MHTSl6!L+tTlg^5C3-L2$kF}sK336IXvY@)pY|Z7h)zmTIz7~DRZw~%IeSUEh@9z^rajEAGZs8vFbeUdjnShe=^c$F zgGS*XWJ#C*c%VT}X;~B1Za-x!cjPOV~^4 ziH{>)dxxUy)l6|giz|-s=n%}EUcxuyTq7<*CU+`Y30_Sfvl9 zt8Pzrs~BLRUkOnJuoaQp$%zjXqzG&S6Ixl3^jh!1eVU9& zuH{)=q*70Pa;jQY*c5~O^vd+w#$}DQ=}O_o;sGMB?w1p+;vshr=8LbuA0iz}SjM^~ ztb=&Orj}C=FhH${=v%+Jm=XiYNEry&a0^ThBfXyf z>(lt(D>9@PdsBK&`VLQcZ{_XGaO8+IbjSC1HQph;^W?qKA5YG>=PO=$MRnvpr|9O@ zz*~wxnuUKHnMR)Xm*;62(=Td603V?YTlMWwmRj{fNN){Ks%n?H0RgN7#$4CAW|>i- zgN<}q=V4*k<%=h=@@84zN)N+h=vpM%rar1rhp{4G)&M+K>JcRdT?}dI&}1rfuTK4M zO4N(S1AiY16^@#t%Q2&ogR-n57P|CnQHu+7!N7=yGFTvx8bUhhKA>y??NnR@ncx-d z5ko~f*GNoHTZ_#4G^SS=Bs*=gzuBj*ooZ))qn$`aRc>xouCROJjr%t5yK!RmlIgPr z%TS9jd-{^3L(nA5DD>NJhJV3nZuM9q7E;Ww@L>NER{D*cy?}8$CSa#syv>m zWrKA)-+c5*mB*uc^3gYU>aKdUr;allIwu7Kx`4yd9o?G z(6uLqk#lCz+_};ssr_=5Atmm?h}gr#%f}*plh!}<-R8~TJ+wYalh>dA`$nR_MEft7onoo}H(#f-?1*zj(cxMDOJ4*+@NU;S2t! z-{9Os4|N!Jy_}Kp@~$iU)4=~_iBqraPfC@Cut5Hc&UF1e?##UF(XIaTO8lfF74F$n zNImL`?_h*=dobwXk4Q=o4#_!czsI0fAd?iX zC@_o9#dnddy+pL-V29`iXdqPPkfAXtkqjNQ(vmKLWf+%`TXy%RpThV+J86L%RRp#X zoy1s_v=%@m47R+Ohj8Q$<>ge#i&R$ZM_w6-#oGB=`DlUPpux$?0#QA>vb3tt?34ue z^qu+z%BI>#c=UYfwV}JF=|ts@$wfJXgfPG%Cg$}+WMrM|K3cctrb_SnD@g2(>y^eH zPV4mp9d=)rUa97)a>8p0hlwm)kW!qlx@r0kg{9Ka*xcHt<)c~p;F+z{cCpDD?E`46 zQTr&Aji3|xKw?*rVpx`wv5tfKmYRtghgt^B0+~aO5+U)l>&ou7K>Qf;Z17Q*%uo0d zB%Y8upW`Ps9>@to48Lba+qh(Q0B`SI1KdIXk1j!&HcNvu^WAxIYa>je34d`$pGf@^`4QTY`tL|f8FiIz;0siMG!tc|X;FCr^q9f6u`FK39z5-I2W zGH22JQG;1sW-(L*uWe7Gb}ua&kmHkH3Gd1eh_2-Wd|KE7&54_8=N>Ts{lMJF^oAYw zdMEedz#)d9C#On#NLyQQNr8>cdUd?r>nI3mnhinTd_i3kNUt)y6hfHK+!rb`XLcy8 z^|}FB+--rHb)J0b-JJ63oHyR6&QgyIWDGKcVs`dDSsqN2@$t};Fbq3+!ZPOVW>)AU z&<8;!Bt^NC!dKgaF-b;YxeH>%$|KqdyGQ3{v9P{uVH($WMN_SW zgf7ybA|KT@-LsP2nGqQ^eV@9rsaDxCG4dOKsG|}AS0=NzFqsc^v|w93D4Pq9PcIQe zTHtjKsG5YaoNv;zvREXjU>Ma(MM-|gKW=|XIsywr?dhAEYTYaE32&P=VwStM>0%3; zc4R%TFY?8^Q*&&|J~vV`8nSwqq#KPbN#03S?s%W-s6Hp*d0Bxak4f3rumBjWpjkdY z1wG3Pvd0klNdQw!YdN5n?}Q{le7-W3C-3xBOn=d_YwfX#218sw#xg>hWYVVsUPC;L zT~RuS+c3n7eC*X>tF1Hi;xg6RiRMjX>o(fzX4y8@U9-h7VU_AyZP1aIk{>tcKxu&_ z_OH+Pm1*u=zeiK%%M0_L7<+4As{|gLom7>o3zR zi$B0uTvAM~VS7povmNZi1lPpv+WPskMoM?G`$o=MI#zqb#Mo3xp~^J5bh?}8lsEaL z&4tQvo-Z4-1J|>d>|>L@GHebsbv*~h!tpRocdm`z9s2pG!KNv1xM5b z8oA!V5#hu0KHvt}$EvnXdT-eRX?JL3lnl9*@3`Xn+9jA>v4Ji5SG9x^M0-XT5z#LuC5g1AjLkm|MFk(F{VBU>~sj zNl(x)WMHtM7PP7A0f*NfuhwtYR^{MuvnJGDslG5Xv*HC%rJB%7hN^VvZ4G(oz5%=`mjy18Z9Idcz;ACk402(i>I z4i2WdjvcPZXQOQKIaS+Crc6ts^bu{Rxmcsc2CVE^j@ZbG0gH0Jf^olQMKv5~pdTHCG*8;MB7-JsBf`?)9kAvn&##OnR=MDl*tWXA0yo6sz zxLzq($%%cS5Cm`)MIjJG5yNCn9)|oi@Y;FDqTdFuoj>TUKy``JTLr@~rqSxR##mU+ z(`x%Fo90Y5v&3xEYc<2MzR{-nK&$2T!iO5$F1>|sU9Puuye;3HWzjD;SghKP3cXHi zj^Tz%V-bvbZ{(pEvsP>1pN%nFBNt*5RH+&SeVM6Bs8A=4r3R7By`ymm1QHHes~AO< z>*D80ff5Y@0gVSzLUbN5mp?Ck`=jScHSi*T_}d$A{FV*vGNbgYcQ$B^oau_eN)K(2--ihb z97gvLas)}S<?ck0Bl{6I@z&V}9WabcIzcen5?o&E(5a0>yaP-o zozbKY=#9K7D=;ei=HEWY$KXMuRq-4eO8EtXMw zfzu-|kQD_dY{c!Ib_BR|)x7X?AA6;)T(sC!Qj7 zsa4e?x@Dgdg+_3y{2CV2@cy7v1Lsi{<64Q>MH;#06ODr;H*0-X`j~6xnj?+aXRVU^ zS>|b!!dxpUR_TO%868fhi#ji(+dgSzVd~?uyejLB$dAPj(up@Y;fv!8`ZZ$E9|U48 zBKxoGy4>r?L-1uoOQZB9bEc17FZJfL*b7o`WC3vED050*rjO-^UZs+cB1+BK@C+`Y z8^gGzioJka{|AqI29Lvy4S>-5X{RJz^#{<`rJ-%Cuq#BfYz_dD(|83cLe7F+y|T-y z3aoeHTMLSz&_nmc7Uc_&4XzGcBX1!(oSixC(c9@>)F*#KD=7 zHjq3zAes}YPlIBKd_p{O@^fwn9BG1ZTMr5wgTsTt;T`_P&5QA0*s!>E#FE9$9RrRn zU3Tow&yNWkk1bnz3_BekOaJrCb#Jd-`}TFu@b^j*;tZtaZ{Iq8?EZ7yNa;IdK}AXh zwoYK{v&uCK4@nmeZ~3A&ca*N)UHj#h!_tLA3pM3gY{7nZ+n-w54O~L>^+Ar_UOb83 zxp*;?%g`df_!#^A*s;%#N$G4IGp;?~c7Cm(TeNWep|_VWee>WXcs}DWJ_BAW2!-nl zZ+Y@I>B6l|(@L&&toBY@d@EDm_T()%K7DZ$`pir?;2pv|tHHN`zp%m$?`kX%k|mP? za?XKA5aldafi0F1k>M001GOU0F?k*3AmthPA-Mqa2NFUKM0{UqyYvIo0=Y*k9e8}x zrpGt2EWMyl&-O2UX)x2dTrtUGlKZ_ReV;rAo5@T!=+!0u>~vhBP0I^;L|fIMrqc0u zd3~NxUK+O?8K%$RNk5!=Yp{8H>LsxT)FJ6+G)LqtOZ3HoNIFBE%H1< zE>)G1l4M~<#V(e}-Nh0A%b9#`gygz^qCUQT;^v7HH?u-*TAyUCZ|%kv2?@!4(zK5B zeswn$-k9%jXdGpZXO;}ZQsZzuQ?zSzzx07;rGK71i-bUHdP1GTa}Q6N82P~#E5@l~ z)6*=LI5F0i-6tzxD7rDP^8rhTMjv^$$Pmct1FyB1v-C9fMMr4mJ@>5STd>5JC4N4v zd|V8}kB@x#WC2n}V+4RVq(DeDmpO8cjPEH6-O8lOaoazWo_*j!>DkY>PY7|(=BBcn zy#w+g`#&u`otl$BAdT(!h~e>-k&6#XEuU}O_BjhZ$f-gT+TZmMz+(OYkMs&F_6*1` zOp(@-PKTi^2SEd7QJ)hLSp-uBq8Jf;kqSgGkKF()Jq0qWLG6j&77*=G2QIi}`H(?8 z007oP90IAg7V`$`rVB^@7QAHOV%aRdD$i%jwCy6oil9oBb} ze8)J}x1ZfJ-@ULRw*O=nI=|0azQl80|Cx$CVHnsap1sD{j`GNNo>|;u`H@Ro;BfLR zZ+oR+=@`+cF5nV-r}pXCJ-v(_&hWEO0|U4MmdoYjRR6vIJNtwAoGMMpSUy)?AXR&i z`k24y%QwKElgkozwTEh=e638QwXo?d0av@X2gM`F6Cuv5T=3ddXbL1vfNQWy)_;)S zaEhN2%n^+v+9k_NMpAGD36>WUQ!WNyki6b8bAuJ8)F;pYK-_|KZ*x>&V467c@aW0R zT*1ijk9gwZeJKUt4JK)pZ{0DOmyW4cZQePFyJ0q;7$@la4Eb=A34DW+nFbAc@qQL- z)nkxwi;pG`(CWngh6S7_LD0w9Y{ObN8#z6$GY+hH?E!y`&b#Q=a{6N zN8J7J$o|GToYy7jlhXN`Pc|C?BY@Wq>UZvb<}k%5tuZl8hg`T$tkN$i(da`pA8m}` zs0#W)f018~Vq7i|x8W*NmP|8P=iKU0q!2m|Bg>lChtE}2b2oi1{gdr) z(9Mua+D@NtJFQf3Yqoyl*WA6Aow)seX?|qRO*bb=WuA*{{Rd1JJRm(IeHf|RV&E2S zVihZtxZ`vijVr`aLXY&aY)x=0fC&o08i-!Ri_;i_M<`J^mD8_;F|eF$2Z*Z2Jm`0^ za##n^uh3smc0plva0Vvu+oaE=0rPuXst?Z6>6Yj-zFt003L;_x`E0@@3UE#g1_BKN z3@gEV19lb(NCgH!a~fL3Ky>B&G;EOG`26wb4ohFnthq)IuBn;HY=@sazFK3F>&GE^%L86W$bF3xPI@#`Ky@v z=5JX4(~lBw%2sw7qdEnX#WQ9wEY`kV~?+5Xugcq6Z@qbhxwP>8nsJQe{Xm)*G&5Y`~qv!8k{px_ii!V$W zv-FlVkL65d7r1xDcW>JL2X1Uh-rnaYj=ue$Tk4iE)zap^_psSNj6iw|3!BWA#|NiY zEj#%rd$4Y5b?!ZjwzaPvGqG;aM_XU#hTM4eEUFlte^g=2KSn~={;@|`)T(LkG6r^Q z-2&K>XD6IdDXjX7FhGLpz)T4!HNj&O+cm!dqG2$kVCnb!N%+1RecHlxQ|9S@w z!AmJbmtlch`4-uNN#$~2Ui>S{PuE^nRjIJHCD|x;D#;HY0mTb$(2I zRYL!>$Bw-;+}A6lkI^}E^WD=QpthBB*NCfSeMzyd0#g)Kb%*h^E`_6ao)Q-wDGEGr|*4vly)8^c~?~OP2_AX8|njjPUbhCF48aR92 zz|g|YjSp=dyldx+FYOG(a%$xNwI|!n`~sJ&<2*}Wo3mie>UU~KX6Gbpbh>!GMm2Xv z_~tDe5-cEn`i=M8dGLCja&dVmRMFJ5ch;ChwK|dU;|8pqIkmW?B#06Vyw%H%l1r>D zs}fC|(V)^+R+*A4VpXNtl`v$*!Z{;rCrqdvHQS>~Fq;ym^=Eb5_QqM~_U?Pbq$?;? z^Stt=Su?5!)(&crru7@V^})$6?Ap0AkisGTxmt7@xf4d`LMbU@v^8f!?Z`Pz>opP&nU^)=EmtwLTRWs^_e8tTs}dcNkG3}MjAG6F#<;oAT~La7Py=kUbw~=dogF= zk6>!R?E_ZLz-MrnDde~Z!t4Vql z(daPh%QxKm@rsq-JbZk5ids-=^wuK!!%a9$=mQrZ8XzaOWm@MM6teH${P-|f8 zfd8*@Zb8mkX>)?tXVCvSeYn-CGx%0+-@R#ec}c@{t9DK+u&0bw+WQvuwMg%0jazqm z=JY$JRK`UbtE&c&b{YE2UQpRrsZ6q(f+PFomycgQv6sdOggjw+{)1!E-!je1uj^&d zTC;C;s5Cr)iK5A3InI=)RK>7+lB)_bbh=jWFq=*1=rcB5nOAqy_|ZEj4(^qx;nr8W z1DwM(YB>C537(sJ|+!H_AXVCJJHXb@sXt6LfNtIPb%1p9ZbU)Irl#?Mx z6N7^g60wY~F2QKoMIj?SwuNvT94%UjcDBk_^w<;?LyIo^uQU?*ZR}h|ku{=TsXeya zEEIakg?{`b`Jq>|j}bB{wGnx+b(%M2>kDQA2FIme#QyBz*VA45C}v@_Y0*|f7>*$= zR5LDw+)xS;RRvgDcQf#c%i9djOjl{OaM4iKjGLnuM&1$>EkCKVL9YMst2Y#hK$!m( zoqfU&&PDDM-pe3s6vurzlAe&!NEAngqW`mY7)ufOXU;@p%%6Tb8g<^af98y)!~Nei z%`FJbzslp}fPZ?t)cXIey=;)9(t#QRtXO#U6KE2eiW*2>{NFW@=#&)5IwQ44Tjm26 zZL0Rh|E^iMzLEl<%kF4<<7x6^BfbBN#voZb%JU|5(h(B=z^!zyFhzHF|wFm&D|vAM^8g7eqt!jo!d*7tt6EN z-tEP>_@g{Wc`42!s)FjSkf)nCf*;0M=v3cdrlwF~Q-3HVmtN(YTJ5gH^tKlHy`gAS zsvkvRi7q0ERk?*Y~*0% zpw?hDW0%7&H=CR7Zja?c?Tt{jw?xRvssDZBeh77ebca8FZsFLHv6-T-Z;WVtM*qlOdHA`-l z8Y|YS627=%xBY}#$tf&Wy;=z*9jg+|dRxe*hJw+Gx!tBlWB&9Ae@UUWwt-3K88$@l z?DXA99&$q-qR15^_;PZH?bHExWmM@}L!&KAM(an#~5!gihJ+=mfgm_V7GDdeYo}Vf0lzJb?@D4xxYjU z@EV=bA$knn_`JM+{&A6;PBH(z_folKI^Lt)IW%|u7{OHN)Hags1bP`TPe2O?)G}D+ zG{E~oAnmFU>8S(0Vjm>)auK>PctA4L%f+r*voEFD(vdfB+Bh~LHs|2AnWY2DUSreV ze3Ol&3Rl;>AhqRJipE%h7ZFq&!>RJ@y<%OuBad7*8F7#FsByIREWG2Z>ziI3QqVYl zWW{`+QoZ9VX8B6maSDy0exRR04LT#31S8l&b--DYGbsHUraZ9m>-%QRxbJKEJ8A@l z_%HN8CA`%2M5Td2ZDw&uBY`ys@e3woc}d$qF7-!FOYib4Bd1xqaFn*W5z>2f6fMaV zqb{{5?-xUI9J-Q0;m`YcXv$Q65-5Vj4yT3Mkv4JAB07}!Yo)W&uRptSYF5Lbddq@g zu_tnFtDn5gndJyp7S5WX)~_iItzvcUeA`#j6lo+=HM1(F96Hs0OZp9J&4wM)Cu1)D z>R0tU;@R~&HGSi#9#sK(kte@m~gm za=r8h-AnyCs(S`w0bj8C&ii4faRyjLFq+#4(I0o)6VD>%5N2!S9TzNsgO0FD|(zW^%wCkPf)x*s0X2LHS!YHx9LF z^@CZk5O{!84i_Ay3wHFG=NN? zx=)vNGr92N8wqO<*?OV|8N`ptMi`KD@@4SChU^rfpX;9%s z71kh+VDS{59tlUCd@6#4pa+BZfimy?A>Z%XcVTz^o);Hx`f}(W7D~6j@+;~6x7V$E zoB4iqo-LL_+#}0iDF5csE=&2NNOp1jy4(GY+uhkQ+Uy?|t-4|Ng}n=3+*7}L{&n}X ztb1E}AJhYnc!#T&nj;b{_Fd+6>H9CGWz7shBqizS+ivhFt@wt7)zXPa5cDv=8KD?v zAUZQ~U*ymPer($#j|;ck_C>y86Qr1qd)Rb<>TbNH%?lmlQg=RALW16?A z>@=F7uPMaEvi%gq(q2&P;&AWfd+;noWBots-UB?2>gpTcduL{QlXkVMu2oz0w%T14 z+p?PFZp*z}bycit6*r0n#x`K8u^pO?3B83-LJh<~0)&JTLJK6s7*a?=38`Rf{Qb_% z$d(Psn|$x{J^$x#YiI7OB27?qt;@uqGejpF5p{d=MAqr#Fzo z?`}uB*XQ%5JEEZL?tI;0b69aK116lB$mtxvY7i#=08co^1YX{Nz5*jdCAX%rRGdvp z$_5ZJ9SV*l=%tNup#*+LI{2$tXbJOxvjwhIS(SbYm>+mlx+V*J3=vB-(VAW(+9w|| z8chc0iQ6*^olz;?6kk*`c#p~sP(EUhZuV8?7ba#!yS$0{1+ntAo=aDf(9X(BJzcQ{ z`H5avbXH!P-Crlb$6gpEfKsaKCXEZ|9-~wio z|G~t^U@y+by1(J@gz)|^FfLh;NvOoRL<>d-!fV7;1n-cHT)?{~f>;W$p;hfptB&!) zW!m0_jAsBV>Tp`&1wT^D=FIXdEUFCWsVHJQDO7;IuRdgO8ggQ-)|5oEciZdd>^c_i zZS>?+=`)SFx(+{>avNN3Q#-#hVig#l`5EGo!7+>Cr7r zx67O3b;aAFdwZj8@$psB?2#!=F$G1jiGsNzdFHHheztAz*2D$g>U_`K{cr3aSa8LQ zpWSucN1n$%lArrs+>=}Hzbe%hH9fwI@viu)3|ssa^>XYBX}0L9_*~A0}Nt$Vj3PmAMLZh(kbpaUoX5thz%5kMGrcDrx!qhctbY6 z(sNm%sAzoQoDjym1aGoY`sMi#Z{Pm#`5zD8kh=HdzQ@jKh3R5bV!@IPi}MqV-o)Ol z?BN5^1>yDUW+ysEuIS9kS+nbfZChTvV6{IvFPtC6^{)6}Mq#4cu`)BWzAe}6uRnjq zyz|!0E>3fqxoy?xl#t9>$Kv>c ze1D)I&1NWDJ#@+X1y}88sR%CK&|O+MJ1@y>j`oLFgq<$NsupC%`oqOjlHw}D)nyIg z**Gj9_*Lm9RexP~_UQrff-tKUDQ3)aMdwRVN~dkWk!W~!r@6y$WoJH(ou%5%nu!rK znJJ`&*-3f5>giV1Kc7U)sq!{BZ-O@cDQ$S2uZlSf!3knc5BWI3_KCPoM4}P;IpdiZ zovG8#4zcX7_U`>keg{|fDYZwL`zohO2})--{P=hFeswC>0+pZj_0K>XPt&jD(eP_M z2|S>x^P}g)>d7UrBmb_izScjd$4rw)`d7VEruN1uV2DjsWa2fC zo2fUS1e1YS4TPa4!Z&^Jfewg4(^-ze{=Ep4(rnVR13VEPpHOxn3x6cW0XDr*2#QD% zv!#+^9@iDl zG7dXPu9QXM)47l51nHU?#}4CL@dw=s_1^4*Oh*phrN>Kgna9sxcTvQ3+3Gt~dG$M1 zU*?Kjw9Yc401;##{f>ee0`=hdhQg^+3;6*APaNeCsXiQ^F6O|Lc3fID!ssNqS?Q|N z;TXi{i0Skqho_0}%I)m&l>?M$V5K~h-I!la;c~!#DsaiKK_>{XGY=10=>i>o!Q}={ zoXC`0sz97`f{OH0A%YTxkK{TXqWO%|Goe%wa-|TJApE*ot`_8S1I%SsvoeR-ES5|0 z^5csPu}7U|ldwQW=mQ*9A@pOqAtjqxO<^S^o4LpkcT|0UDn#X&h#iHa^M4+VJ*l(W z?MGwf$FRIPS^2~r4@YB}`i{+_ck+u9cdM1=fT-)iIM z!+raO%l7X((ZXJ10sMb${GjgSI*2O#02$aI5avIvOfCMLT<4ft#7SVdK5`vi^JT9sjd@DX z1^Jy`Hp)hO!8Lec{3Cqh#JZvKk#eA4q&vkq(l|;wr(Ut<=OXSGota=O$`oWRYHx7J z(KT;g*EoLo6X$)PS|q%{cKoQz2MDx@KIJ~%tiAaurJE-x$>+%_69x>AxTC)si}%O7 zqb1y))S}S=l1?}|Q$H>}j+t(TyrLIAzu*rBQfOta90(K^Y%gGpN+|5@5@Ju> z2%{ho_6px8KQjLL^K#&MV?Zj77;unrqY$e+8ilG8Ccep*7sG-lO!_tBH}ZDx_)ht! zF?qJ}OND>n$*aJH%5OW0IYFl`=p}3f(wU+|o&~b2EI?NGa2Sl;1GrNl-_n$wS_b+G z{YBiiXf}5EurQ-*&+adq*~)+JyFkuXY#WTVt&+zd+xAMOYo4p}m2Hp7}X9wAD z*}>2Gk)z{ptj*x8X>N043uEUUJ@Vvj9orAS-@THtmEG?j+}?59ljKkyD-Xem>C|{m z?6X|p{^w~r-_VmF&t|kQJ@o_j%Y#dK0}+^5dp$%Pu(DJMf0I^XLV8>{0na#J$oH^i zB$hkgEM!@YK6%&cugkl9Myu5*zGK9e?QwYn-}5V6jxDb`o?W$kd6oE1)pEXZY)p4@ z`*xYEAL!KZiCZbhN!>m7U``s3XQK>p{ec4q+^4gVB}rP3v1tVCr_icIqS^Fck0W(R z>p-lM&P^$XvqFhy`K*WsCqN$qznC!e#D%f0@;$GmWvnu1WmQF1hVo5fe&fjSHFK|n z`;buL{GZB;=WSdvrLu5t7N*fNEcEfEi<2e0&Bp4wV>q7m`cq2^QT^T@Y-KK&jJ_E8hqf+-`xG-=A}!$aLSm( zW8tO)AENO-@f~DMgX~Up;_C{TLGFaS`WRyYGzDav02P<@7c0tk2^;+7stiST=o7TYoY!Yg|)iz zteU9K-fgeQADva9T>K3?DWYNOfxn4YM14F9{fkv+VjtzA$!W+^IbgV#0qpgVQBjQj zQU5zwCS+TQ1>lCLr?RU6PXPf?J<_@LQocAXM=#`82KLjuC9IEC*Iw#de7dc_8s3lvS;ec{O=7#* zyU)0B`#U#Y64`b2D{C(uN?`dbZcdhJS0=sbHAKt5i7BcJ{NBy(>Y`%4dV1QPk-cB- z`~JQ?EBmf~8DB+v#tC|#By?9}UYt76RtaeaqX3X(QxCh9BW{=rQ0!We3<>QBNr+bw zGT}Zr!%F79DyU`B`gV%G6$UjI#fQnVQu4Gszc0zFM8zbOrX+>(R|Lzml1fcZi?P=% z8n%6S!F!*|CqB8SqvM`Wn5f*@)n^mMjVMelmK_T;Rwly*OH0f`2Q>_W(x z182D4#S{OPeRTp!_b77?n?ynJQO@YNfow2h>XGCRq&U+3S#TW-$e{;6^N?szh<#^l z?b@+5?6RqKcKK?^ga`)9Hgxbl@2#{Z~h(BIaQ@v(Qb0~}L2nm_eWFh50i1D(2-ou2Ik>+r4 zP4D=#%w>Pa?vj61W{#Hs7UQz?d>oL8{9drd-uF=@@(9aD<7bgqhz|1aZ}c?%Al^aV7m)?$YO znIZ|y9TJxFV*w_{4J-k|OBgJBV2?q_pQKR1v#0lvy94afhMB~|=)bZ$xPY^WNra4` zd%)P!dq9mN3Jf46296b!2yD1fjuM4!xPf=agR(HfUS@`OeQcUdZuXT-1Yxv{UPSU5c?MK6^2{UzlI(?P>t4ri5w{D*da|pTIgmV@wv|=fNseH+=qH22wy9jj(oy zGjj&*C}o7y)eK~X^M%nSo580U-lTB&S10Df|I({Ot)Ko&`oJuS(KCRud2;~jd5^gHdM4ME6yqmwv?$}RH#jwV~F>Z zEY%c4CLZYy1CLh{Y3Ff0IEsqUfJ=5Nq~51D;1RWJa=4IZFpgt4Hj37@l~L zRbg{0f|YdO- z{><*kjyi0ydw#YrYX8=hg#klKL(w@`WltBS;_Rh!3q!-58S%mcr&7eH7bL~0X+&d2 z+2mBw|E4NtPh{y-7q8~9i9I(|o@z|VN()`6-MJFWqSND}QleP0uw zr(p6IGH_?e#SZD+VHtG5>pV!cfas$M0=uWUUG&&RUF35FK}>%5Bgx3hPRl6u9@s!I zeA5RGe^N?%M$o(FhVf^QjXz~gv)*a7>Z@`2IDTgB1#4clrST&gxbM}#pM6N~?dUFr|q~~c%f~`fdMZP#pPJ<_@esS8$-VJ*jJ*zxc{nTh?;*Jw% zsOf=9h0L4uF6`0AflkF)83}?I^ymjt^YQ>12ni5h7GxE@QF@Vhzvvt~we*5YRXPn+ z7Jw~R73m@{3YYreyV2mKWI!4G_fVShW@UBvMrF(>5)-X%Gj~=yUHl7&QSWK2PPyYT zhu)lI^se9WVDs*qvQ~usx3bj2LLUxz8$)>>$pCo<_Tg7E&UvaIrVuyHlZ41E%RMQs zZQ`r3NhuC*rTmXe@|P?qf;@rMJfDT;uNl9?U}J*Qw9e?t*pss6fos>_adBv@yDpJ= zvjVgHsoB%lZEDUnae@8qSnsiCFL#;bYg^@SX9yKlHp349Lk#Ea+aX^!4L;&_qjyLY z7Jsx0M#&l=kg-1iX@0Irvuhh6ZmD2d7*;GfV*%25AW<8#Yo7 zM%wQRo;CpUl3)?^mz29pdv>7*DN(o#1`ekC65gLyvNzi@OJC#zGxD%0t0L@YqFkL* z0n5`_?1}Mz%jT7mz^kI^0jB+v5^qo_JTv_>>7O*5XT< zlW+ysGheiDn?rOITgx`^oV}sy_tSDqGyfQ8PfML23ys*XVq!AW=eqxVu_Goeb3xQI z5o2;Jlt{~SvdV>~=zZB0cNb2T+kAOqxvxAM@`k>tIaxtgEmh~F7ffAmo}QUez?(B! zq3t~HqE!D&=Vfv~{2oXwWkHiHU1ZQArIGz(OQT7z#vXtXu*Lh zNw7+fr4VU$;|RXmO@;9TSW{6lni!#G=Gd)`=dsz(dKj4wnI7j)oa}DH7CD? zD2vN{Zna!*sLT=m`Kie^r2_o>th`uuuEl!kk#&M)sYzZ@T&B zo8G?WAA3`(suTZy=iQ%ta`&qFwv5)fN90%9ndH0t&e!i>Gb8QrxA|Mgrks=?pSxvy zrfdDxap5VMOXKsCoy#h__w`Mi5ABFaeEfJ_4!FJbpn8EBvj7qk#3|-BTuoTzUAuS7LTxpIY;^$AI-Wkr(@P~uWLq4c4kz2O>nb6I46|* z`PbHj34Yi@MQ%>{CK_tmI^&x`+|e-8vPinV#M+~1)t47m2#TZC15=G|ifk2bV2@2^ zhlwXWbsb5DtfH(;w>8@$8l|X=UCUmW7X?`qYqmKi9d8WPyF8b0qr+(}wWn9-&&k7;+(w6wJ?3birdl`x|+Bn)*X{%^*Hpd zOOqr|p-0MfnUd3!@n>{rOCEOoY(5y%Ilvd(h&}Eaj6aYvfh!HAGWCg808%E#0YNbq zM|8r3J`?o^NtO}nQ9&I&M%qf07bG!7!&X}3t~V<2F|u%An8;%CvaJdn>|Fl* z{Ah4cKuftncqnjiDL2}kwo+SqjS2@f>9(NF;V`mGneL3q03fihtRbms4G5+O7i0hk z{PX?uxHC=#0*jr1pooCLtO9|_l_z)v%UN@Q5pP(rbxl~$E~(@XfII^t;8hIVZZMZ5 zW&b4TiI#-$Rv}~xf}tRWIa-G)AbHEGL=e>`-HgH7kjEpKOTCVUnnq($mwb=>>$N{G zTHtidd~C_ic~5}mHd*xgXC1z=V|!)Y#fx_}=31Hl(vOd@z8_1jicmv&(B8rQr88TC zwdZcG)$0n^Hq6c~(no(%m^9s=uTOc=esAb}XR^VNFxQu9OY!5x-6G$SWQbkGSz=*Y z6!?4kGS&|-LncRB!R*2Z#QDwVTvfAp^PE)mOhvJu+5nn)J?uY|Y#W&T!0(fOX<20k zSS>mIBd$Jh`=lSxBi!Ge@e6XuR??gyl#mhaQslCsi$I62%0znvQ3_Q4C%yiY4_w)AJynX_(SpIo&5*5 zuJg_7z=a^?c*2NfST3Ty zz>Dfnxxv(EbQW#MfJD_4gfzpdeL5n#uusA2qbxPb8wDd{K1!rtFG6~qwzPC?tlX$q zDS#zAi;`p0M_W5(5y!HGy^2DuQyXY0=OFh8(<=?~2ust-)6&W>%$b^haXOXYX&Kj+P>7RPj5xFva7d9tqzzkXkGd18re@WLx*MI|?dk0md8 zaPL5yO>U@et)AXKosZ7_R_pw$%8J)?gjQuh_*I;{jCt#(R?45Q5vSy71(czXqVm zr~>{W*Xs7^bnq95Nhd+b*g%>|I9Ds=XpaNl7$9mbK)DJnAfIGt22BE}FF>f}bV>9+R zYUiLRxWa%uP0bQ>ah)|(A*NZf>WdiUZ1~}Lzr8*&=uNbgms_JU;zKDlP7IeqOX(CG znyKuaPHzJs{0+hYRI(Qx=wTTc8{!p!ys!&Ej^K0q!5knV1}Rw#R0#&CH+%(^2aB;P zrlDcmZT(VHabsm;V6DFYwrvd!F;zy(_)nQ(u|oc06b)U*PRr^q**)(hghsoz=xf9KeN1C;PJI6N2f z$gI9<$wKo8m@G_z9t|(c0LQ}>g^$fFq*Rm|XxyL)&`jd7VF!W!LMG}lSZ$J?%`yt+ zygSYpvvL>C$z&{Z&VqcuwB?R0G&a+iU|Ii$G(UevEMu`V@?jjBms#SUUp-@u{Fcy| z+d$C`xsAfxKdubf4Wu@xnE9X%&N+uY4;NbV=Tez-=ND$=9Xqx%hYytEi_

      5q!RY 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 + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/source/_build/html/_static/fonts/fontawesome-webfont.ttf b/docs/source/_build/html/_static/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..35acda2fa1196aad98c2adf4378a7611dd713aa3 GIT binary patch literal 165548 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 z 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 d0mRO}xo^G_%I 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 SdSQM28?+M|D(2r_;{O0|uQ74} literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/fonts/fontawesome-webfont.woff2 b/docs/source/_build/html/_static/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..4d13fc60404b91e398a37200c4a77b645cfd9586 GIT binary patch literal 77160 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 literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/jquery.js b/docs/source/_build/html/_static/jquery.js new file mode 100644 index 0000000..7e32910 --- /dev/null +++ b/docs/source/_build/html/_static/jquery.js @@ -0,0 +1,10365 @@ +/*! + * jQuery JavaScript Library v3.3.1-dfsg + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2019-04-19T06:52Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. + + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + + + + var preservedScriptAttributes = { + type: true, + src: true, + noModule: true + }; + + function DOMEval( code, doc, node ) { + doc = doc || document; + + var i, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + if ( node[ i ] ) { + script[ i ] = node[ i ]; + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.3.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && Array.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.3 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-08-08 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true && ("form" in elem || "label" in elem); + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + disabledAncestor( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( preferredDoc !== document && + (subWindow = document.defaultView) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( el ) { + el.className = "i"; + return !el.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( el ) { + el.appendChild( document.createComment("") ); + return !el.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID filter and find + if ( support.getById ) { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( (elem = elems[i++]) ) { + node = elem.getAttributeNode("id"); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( el ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll(":enabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll(":disabled").length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( el ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return (sel + "").replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( (oldCache = uniqueCache[ key ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( el ) { + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( el ) { + return el.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( nodeName( elem, "iframe" ) ) { + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + jQuery.contains( elem.ownerDocument, elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + +var swap = function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE <=9 only + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
      " ], + col: [ 2, "", "
      " ], + tr: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + + _default: [ 0, "", "" ] +}; + +// Support: IE <=9 only +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); +var documentElement = document.documentElement; + + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 only +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + // Make a writable jQuery.Event from the native event object + var event = jQuery.event.fix( nativeEvent ); + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + /* eslint-disable max-len */ + + // See https://github.com/eslint/eslint/issues/3229 + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, + + /* eslint-enable */ + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + div.style.position = "absolute"; + scrollboxSizeVal = div.offsetWidth === 36 || "absolute"; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }, + + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; + +// Return a css property mapped to a potentially vendor prefixed property +function vendorPropName( name ) { + + // Shortcut for names that are not vendor prefixed + if ( name in emptyStyle ) { + return name; + } + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a property mapped along what jQuery.cssProps suggests or to +// a vendor prefixed property. +function finalPropName( name ) { + var ret = jQuery.cssProps[ name ]; + if ( !ret ) { + ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + } + return ret; +} + +function setPositiveNumber( elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + ) ); + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + val = curCSS( elem, dimension, styles ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox; + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + // Check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = valueIsBorderBox && + ( support.boxSizingReliable() || val === elem.style[ dimension ] ); + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + if ( val === "auto" || + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) { + + val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ]; + + // offsetWidth/offsetHeight provide border-box values + valueIsBorderBox = true; + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + if ( type === "number" ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra && boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ); + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && support.scrollboxSize() === styles.position ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && + ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || + jQuery.cssHooks[ tween.prop ] ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue && type !== false ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = Date.now(); + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + } + } + match = responseHeaders[ key.toLowerCase() ]; + } + return match == null ? null : match; + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + + +jQuery._evalUrl = function( url ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + "throws": true + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain requests + if ( s.crossDomain ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Index
      • + + +
      • + + + +
      • + +
      + + +
      +
      +
      +
      + + +

      Index

      + +
      + A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | Z + +
      +

      A

      + + + +
      + +

      B

      + + + +
      + +

      C

      + + + +
      + +

      D

      + + + +
      + +

      E

      + + + +
      + +

      F

      + + + +
      + +

      G

      + + + +
      + +

      H

      + + + +
      + +

      I

      + + + +
      + +

      K

      + + + +
      + +

      L

      + + + +
      + +

      M

      + + + +
      + +

      N

      + + + +
      + +

      O

      + + + +
      + +

      P

      + + + +
      + +

      Q

      + + + +
      + +

      R

      + + + +
      + +

      S

      + + + +
      + +

      T

      + + + +
      + +

      U

      + + + +
      + +

      V

      + + + +
      + +

      W

      + + + +
      + +

      Z

      + + +
      + + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/index.html b/docs/source/_build/html/index.html new file mode 100644 index 0000000..07abb56 --- /dev/null +++ b/docs/source/_build/html/index.html @@ -0,0 +1,224 @@ + + + + + + + + + + + Welcome to Lightnion’s documentation! — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      Welcome to Lightnion’s documentation!

      +
      +

      Introduction

      +
      + +
      +

      Lightnion is a JavaScript library that you can include on your webpage to let +any modern browser make anonymous requests. Lightnion uses an untrusted +proxy to interact with the Tor network. This proxy converts between protocols +(Websockets to pure TCP). This repository also contains a Python Lightnion Tor +client that we have been using for testing.

      +

      WARNING: At the moment Lightnion is alpha-level research software. Do not +use it in production, or for anything that really requires anonymity. You are, +however, more than welcome to experiment with Lightnion. Please provide +feedback opening issues or writing to the authors.

      +
      +
      +
      +

      Indices and tables

      + +
      + + +
      + +
      +
      + + + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/install.html b/docs/source/_build/html/install.html new file mode 100644 index 0000000..a40bfa2 --- /dev/null +++ b/docs/source/_build/html/install.html @@ -0,0 +1,192 @@ + + + + + + + + + + + Installation — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      Installation

      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/lightnion.cell.html b/docs/source/_build/html/lightnion.cell.html new file mode 100644 index 0000000..8af380c --- /dev/null +++ b/docs/source/_build/html/lightnion.cell.html @@ -0,0 +1,1183 @@ + + + + + + + + + + + lightnion.cell package — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion.cell package

      + +
      +

      Submodules

      +
      +
      +

      lightnion.cell.address module

      +
      +
      +class lightnion.cell.address.addr_type[source]
      +

      Bases: lightnion.cell.view._anonymous_cached_enum

      +

      An enumeration.

      +
      +
      +ERROR_NON_TRANS = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'addr_type'>>
      +
      + +
      +
      +ERROR_TRANS = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'addr_type'>>
      +
      + +
      +
      +HOSTNAME = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'addr_type'>>
      +
      + +
      +
      +IPV4_ADDR = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'addr_type'>>
      +
      + +
      +
      +IPV6_ADDR = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'addr_type'>>
      +
      + +
      + +
      +
      +class lightnion.cell.address.address_view(*kargs, **kwargs)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      + +
      +
      +lightnion.cell.address.pack(host, type_hint=None)[source]
      +
      + +
      +
      +

      lightnion.cell.certs module

      +
      +
      +class lightnion.cell.certs.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +class lightnion.cell.certs.cert_type[source]
      +

      Bases: lightnion.cell.view._anonymous_enum

      +

      An enumeration.

      +
      +
      +ED_SIGNED_AUTHENTICATE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cert_type'>>
      +
      + +
      +
      +ED_SIGNED_SIGNING_KEY = <bound method enum.<locals>._anonymous_enum.value of <enum 'cert_type'>>
      +
      + +
      + +
      + +
      +
      +RSA_SELF_SIGNED_IDENTITY = <bound method enum.<locals>._anonymous_enum.value of <enum 'cert_type'>>
      +
      + +
      +
      +RSA_SIGNED_AUTHENTICATE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cert_type'>>
      +
      + +
      +
      +RSA_SIGNED_ED_IDENTITY = <bound method enum.<locals>._anonymous_enum.value of <enum 'cert_type'>>
      +
      + +
      + +
      + +
      + +
      +
      +

      lightnion.cell.challenge module

      +
      +
      +class lightnion.cell.challenge.auth_type[source]
      +

      Bases: lightnion.cell.view._anonymous_enum

      +

      An enumeration.

      +
      +
      +ED_AUTH = <bound method enum.<locals>._anonymous_enum.value of <enum 'auth_type'>>
      +
      + +
      +
      +RSA_AUTH = <bound method enum.<locals>._anonymous_enum.value of <enum 'auth_type'>>
      +
      + +
      + +
      +
      +class lightnion.cell.challenge.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.challenge.pack(*methods, challenge=None)[source]
      +
      + +
      +
      +

      lightnion.cell.common module

      +
      +
      +class lightnion.cell.common.length_halved_view(*kargs, **kwargs)[source]
      +

      Bases: lightnion.cell.view.cached_uint

      +
      +
      +cache()[source]
      +
      + +
      +
      +iseven()[source]
      +
      + +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None)[source]
      +
      + +
      + +
      +
      +

      lightnion.cell.create2 module

      +
      +
      +class lightnion.cell.create2.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +class lightnion.cell.create2.create_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      + +
      +
      +lightnion.cell.create2.pack(circuit_id, handshake_data)[source]
      +
      + +
      +
      +

      lightnion.cell.create_fast module

      +
      +
      +class lightnion.cell.create_fast.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.create_fast.pack(circuit_id, material=None)[source]
      +
      + +
      +
      +

      lightnion.cell.created2 module

      +
      +
      +class lightnion.cell.created2.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +class lightnion.cell.created2.created_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      + +
      +
      +

      lightnion.cell.created_fast module

      +
      +
      +class lightnion.cell.created_fast.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.created_fast.pack(circuit_id, material, derivative)[source]
      +
      + +
      +
      +

      lightnion.cell.destroy module

      +
      +
      +class lightnion.cell.destroy.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.destroy.pack(circuit_id, reason)[source]
      +
      + +
      +
      +class lightnion.cell.destroy.reason[source]
      +

      Bases: lightnion.cell.view._anonymous_enum

      +

      An enumeration.

      +
      +
      +CONNECTFAILED = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +DESTROYED = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +FINISHED = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +HIBERNATING = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +INTERNAL = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +NONE = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +NOSUCHSERVICE = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +OR_CONN_CLOSED = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +OR_IDENTITY = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +PROTOCOL = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +REQUESTED = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +RESOURCELIMIT = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      +
      +TIMEOUT = <bound method enum.<locals>._anonymous_enum.value of <enum 'reason'>>
      +
      + +
      + +
      +
      +

      lightnion.cell.netinfo module

      +
      +
      +class lightnion.cell.netinfo.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.netinfo.pack(other_address, *addresses, timestamp=None)[source]
      +
      + +
      +
      +

      lightnion.cell.padding module

      +
      +
      +class lightnion.cell.padding.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.padding.pack()[source]
      +
      + +
      +
      +

      lightnion.cell.relay_early module

      +
      +
      +class lightnion.cell.relay_early.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.relay_early.pack(circuit_id, cmd, data, recognized=b'\x00\x00', *, stream_id, digest)[source]
      +
      + +
      +
      +

      lightnion.cell.versions module

      +
      +
      +class lightnion.cell.versions.cell_view(header=<lightnion.cell.view.fields object>)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +lightnion.cell.versions.pack(versions)[source]
      +
      + +
      +
      +lightnion.cell.versions.recv(peer)[source]
      +
      + +
      +
      +lightnion.cell.versions.send(peer, payload)[source]
      +
      + +
      +
      +

      lightnion.cell.view module

      +
      +
      +class lightnion.cell.view.basic[source]
      +

      Bases: object

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +width(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +lightnion.cell.view.bind(parent_view, parent_wrapper, parent_field=None, init=[])[source]
      +
      + +
      +
      +lightnion.cell.view.cache(base, typename=None, init=None)[source]
      +
      + +
      +
      +class lightnion.cell.view.codec(*codecs, size)[source]
      +

      Bases: lightnion.cell.view.data

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +class lightnion.cell.view.composite[source]
      +

      Bases: lightnion.cell.view.basic

      +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +class lightnion.cell.view.data(size)[source]
      +

      Bases: lightnion.cell.view.basic

      +
      +
      +size
      +
      + +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +width(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +lightnion.cell.view.enum(size, byteorder='big', typename=None, cached=False)[source]
      +
      + +
      +
      +class lightnion.cell.view.fields(**kwargs)[source]
      +

      Bases: lightnion.cell.view.composite

      +
      +
      +list_fields()[source]
      +
      + +
      +
      +offset(payload=b'', field=None)[source]
      +
      + +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +visit(payload=b'', operator=<function fields.<lambda>>)[source]
      +
      + +
      +
      +width(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +class lightnion.cell.view.ip_address(*, version)[source]
      +

      Bases: lightnion.cell.view.data

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +lightnion.cell.view.iscached(item)[source]
      +
      + +
      +
      +lightnion.cell.view.iscomposite(item)[source]
      +
      + +
      +
      +lightnion.cell.view.isview(item)[source]
      +
      + +
      +
      +lightnion.cell.view.like(parent_view, typename=None, init=None)[source]
      +
      + +
      +
      +class lightnion.cell.view.packet(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.fields

      +
      +
      +cache_fields(payload=b'', value=None)[source]
      +
      + +
      +
      +fixed_size
      +
      + +
      +
      +list_fields()[source]
      +
      + +
      +
      +offset(payload=b'', field=None)[source]
      +
      + +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +width(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +class lightnion.cell.view.series(item_view, n)[source]
      +

      Bases: lightnion.cell.view.composite

      +
      +
      +max_quantity = 32
      +
      + +
      +
      +offset(payload=b'', field=None)[source]
      +
      + +
      +
      +quantity
      +
      + +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +width(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +class lightnion.cell.view.uint(size, byteorder='big')[source]
      +

      Bases: lightnion.cell.view.basic

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +width(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +class lightnion.cell.view.union(view_table, union_tag)[source]
      +

      Bases: lightnion.cell.view.composite

      +
      +
      +active_view
      +
      + +
      +
      +offset(payload=b'', field=None)[source]
      +
      + +
      +
      +tag
      +
      + +
      +
      +valid(payload=b'')[source]
      +
      + +
      +
      +value(payload=b'', field=None)[source]
      +
      + +
      +
      +width(payload=b'')[source]
      +
      + +
      +
      +write(payload=b'', value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +class lightnion.cell.view.wrapper(parent_view)[source]
      +

      Bases: object

      +

      This is a view bound to raw bytes.

      +

      See self.fields to list fields within the view. +See help(self._view) for details on the underlying view.

      +
      +
      +fields
      +
      + +
      +
      +finalize(truncate=True)[source]
      +
      + +
      +
      +offset(field)[source]
      +
      + +
      +
      +raw
      +
      + +
      +
      +set(*kargs, **kwargs)[source]
      +
      + +
      +
      +truncated
      +
      + +
      +
      +valid
      +
      + +
      +
      +value(field=None)[source]
      +
      + +
      +
      +width
      +
      + +
      +
      +write(value=None, **kwargs)[source]
      +
      + +
      + +
      +
      +

      Module contents

      +
      +
      +class lightnion.cell.cell_view(header)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +class lightnion.cell.cmd[source]
      +

      Bases: lightnion.cell.view._anonymous_enum

      +

      An enumeration.

      +
      +
      +AUTHENTICATE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +AUTHORIZE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +AUTH_CHALLENGE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +CERTS = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +CREATE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +CREATE2 = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +CREATED = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +CREATED2 = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +CREATED_FAST = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +CREATE_FAST = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +DESTROY = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +NETINFO = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +PADDING = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +PADDING_NEGOTIATE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_EARLY = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +VERSIONS = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +VPADDING = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +is_fixed
      +
      + +
      +
      +is_variable
      +
      + +
      + +
      +
      +lightnion.cell.pad(payload)[source]
      +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/lightnion.cell.relay.html b/docs/source/_build/html/lightnion.cell.relay.html new file mode 100644 index 0000000..8146180 --- /dev/null +++ b/docs/source/_build/html/lightnion.cell.relay.html @@ -0,0 +1,407 @@ + + + + + + + + + + + lightnion.cell.relay package — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion.cell.relay package

      +
      +

      Submodules

      +
      +
      +

      lightnion.cell.relay.extend2 module

      +
      +
      +class lightnion.cell.relay.extend2.extend2_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      + +
      +
      +class lightnion.cell.relay.extend2.handshake_type[source]
      +

      Bases: lightnion.cell.view._anonymous_enum

      +

      An enumeration.

      +
      +
      +NTOR = <bound method enum.<locals>._anonymous_enum.value of <enum 'handshake_type'>>
      +
      + +
      + +
      +
      +class lightnion.cell.relay.extend2.linkspec_type[source]
      +

      Bases: lightnion.cell.view._anonymous_cached_enum

      +

      An enumeration.

      +
      +
      +ED_ID = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'linkspec_type'>>
      +
      + +
      +
      +LEGACY_ID = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'linkspec_type'>>
      +
      + +
      +
      +TLS_TCP_4 = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'linkspec_type'>>
      +
      + +
      +
      +TLS_TCP_6 = <bound method enum.<locals>._anonymous_cached_enum.value of <enum 'linkspec_type'>>
      +
      + +
      + +
      +
      +class lightnion.cell.relay.extend2.linkspec_view(*kargs, **kwargs)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      + +
      +
      +class lightnion.cell.relay.extend2.linkspecs_view(*kargs, **kwargs)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      + +
      +
      +lightnion.cell.relay.extend2.pack(handshake, addresses=[], identities=[])[source]
      +
      + +
      +
      +

      lightnion.cell.relay.extended2 module

      +
      +
      +class lightnion.cell.relay.extended2.extended2_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      + +
      +
      +

      Module contents

      +
      +
      +class lightnion.cell.relay.cell_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      +class lightnion.cell.relay.cmd[source]
      +

      Bases: lightnion.cell.view._anonymous_enum

      +

      An enumeration.

      +
      +
      +RELAY_BEGIN = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_BEGIN_DIR = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_CONNECTED = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_DATA = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_DROP = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_END = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_EXTEND = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_EXTEND2 = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_EXTENDED = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_EXTENDED2 = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_RESOLVE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_RESOLVED = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_SENDME = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_TRUNCATE = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +RELAY_TRUNCATED = <bound method enum.<locals>._anonymous_enum.value of <enum 'cmd'>>
      +
      + +
      +
      +is_backward
      +
      + +
      +
      +is_circuit
      +
      + +
      +
      +is_control
      +
      + +
      +
      +is_forward
      +
      + +
      + +
      +
      +lightnion.cell.relay.pack(circuit_id, cmd, data, recognized=b'\x00\x00', *, stream_id, digest)[source]
      +
      + +
      +
      +class lightnion.cell.relay.relay_view(header_view=None, fixed_size=None, field_name=None, data_name=None, data_view=None, extra_fields=None)[source]
      +

      Bases: lightnion.cell.view.packet

      +
      +
      +valid(payload=b'')[source]
      +
      + +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/lightnion.crypto.html b/docs/source/_build/html/lightnion.crypto.html new file mode 100644 index 0000000..a4d4536 --- /dev/null +++ b/docs/source/_build/html/lightnion.crypto.html @@ -0,0 +1,288 @@ + + + + + + + + + + + lightnion.crypto package — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion.crypto package

      +
      +

      Submodules

      +
      +
      +

      lightnion.crypto.kdf module

      +
      +
      +class lightnion.crypto.kdf.kdf_tor(raw_material)[source]
      +

      Bases: object

      +
      + +
      +
      +

      lightnion.crypto.ntor module

      +
      +
      +lightnion.crypto.ntor.h_mac(data)
      +
      + +
      +
      +lightnion.crypto.ntor.h_verify(data)
      +
      + +
      +
      +lightnion.crypto.ntor.hand(identity, onion_key)[source]
      +
      + +
      +
      +class lightnion.crypto.ntor.hmac[source]
      +

      Bases: object

      +
      +
      +block_size = 64
      +
      + +
      +
      +static digest(key, message)[source]
      +
      + +
      +
      +output_size = 32
      +
      + +
      +
      +prf()
      +
      + +
      +
      +static tweaked(tweak)[source]
      +
      + +
      + +
      +
      +class lightnion.crypto.ntor.kdf(material)[source]
      +

      Bases: object

      +
      +
      +static ntor(material, length)[source]
      +
      + +
      +
      +static rfc5869(material, salt, context, length)[source]
      +
      + +
      + +
      +
      +lightnion.crypto.ntor.server(server_keys, identity, message, length)[source]
      +
      + +
      +
      +lightnion.crypto.ntor.shake(client_keys, message, identity, onion_key, length)[source]
      +
      + +
      +
      +

      Module contents

      +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/lightnion.html b/docs/source/_build/html/lightnion.html new file mode 100644 index 0000000..4af8758 --- /dev/null +++ b/docs/source/_build/html/lightnion.html @@ -0,0 +1,1916 @@ + + + + + + + + + + + lightnion package — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion package

      +
      +

      Subpackages

      +
      + +
      +
      +
      +

      Submodules

      +
      +
      +

      lightnion.cache module

      +
      +
      +class lightnion.cache.consensus[source]
      +

      Bases: object

      +
      +
      +static filename(flavor)[source]
      +
      + +
      +
      +static get(flavor)[source]
      +
      + +
      +
      +static put(fields)[source]
      +
      + +
      + +
      +
      +class lightnion.cache.descriptors[source]
      +

      Bases: object

      +
      +
      +static filename(descriptor, get=False)[source]
      +
      + +
      +
      +static get(flavor, digest)[source]
      +
      + +
      +
      +static put(descriptor)[source]
      +
      + +
      + +
      +
      +lightnion.cache.directory(base_dir=None)[source]
      +
      + +
      +
      +lightnion.cache.purge()[source]
      +
      + +
      +
      +

      lightnion.consensus module

      +
      +
      +lightnion.consensus.consume_dir_sources(consensus)[source]
      +

      Consume directory source listing if present, then returns the remaining +input to be further processed and a set of directory sources (or None, +if none present).

      +
      +
      Will consume the following fields:
      +
        +
      • dir-source
      • +
      • contact
      • +
      • vote-digest
      • +
      +
      +
      + +++ + + + + + +
      Parameters:consensus (str) – input to be processed
      Returns:a tuple (remaining-input, headers-or-None)
      +
      + +
      + +

      Consume consensus footer if present, then returns the remaining input +to be further processed and a set of footers (or None, if none +present).

      +
      +
      Will consume the following fields:
      +
        +
      • directory-footer
      • +
      • bandwidth-weights
      • +
      • directory-signature
      • +
      +
      +
      + +++ + + + + + +
      Parameters:
        +
      • consensus (str) – input to be processed
      • +
      • flavor (str) – consensus flavor (‘unflavored’ or ‘microdesc’)
      • +
      +
      Returns:

      a tuple (remaining-input, headers-or-None)

      +
      +
      + +
      +
      +lightnion.consensus.consume_headers(consensus, flavor='unflavored')[source]
      +

      Consume consensus headers if present, then returns the remaining input +to be further processed and a set of headers (or None, if none +present).

      +
      +
      Will consume the following fields:
      +
        +
      • network-status-version
      • +
      • vote-status
      • +
      • consensus-method
      • +
      • valid-after
      • +
      • fresh-until
      • +
      • valid-until
      • +
      • voting-delay
      • +
      • client-versions
      • +
      • server-versions
      • +
      • known-flags
      • +
      • recommended-client-protocols
      • +
      • recommended-relay-protocols
      • +
      • required-client-protocols
      • +
      • required-relay-protocols
      • +
      • params
      • +
      • shared-rand-previous-value
      • +
      • shared-rand-current-value
      • +
      +
      +
      + +++ + + + + + +
      Parameters:
        +
      • consensus (str) – input to be processed
      • +
      • flavor (str) – consensus flavor (‘unflavored’ or ‘microdesc’)
      • +
      +
      Returns:

      a tuple (remaining-input, headers-or-None)

      +
      +
      + +
      +
      +lightnion.consensus.consume_http(consensus)[source]
      +

      Consume HTTP headers if present, then returns the remaining input to be +further processed and a set of headers (or None, if none present).

      + +++ + + + + + +
      Parameters:consensus (str) – input to be processed
      Returns:a tuple (remaining-input, headers-or-None)
      +
      + +
      +
      +lightnion.consensus.consume_routers(consensus, flavor='unflavored')[source]
      +

      Consume router listing if present, then returns the remaining input to +be further processed and a set of routers (or None, if none present).

      +
      +
      Will consume the following fields:
      +
        +
      • r
      • +
      • m
      • +
      • s
      • +
      • v
      • +
      • pr
      • +
      • w
      • +
      • p (unflavored only)
      • +
      • a (unflavored only)
      • +
      +
      +
      + +++ + + + + + +
      Parameters:
        +
      • consensus (str) – input to be processed
      • +
      • flavor (str) – consensus flavor (‘unflavored’ or ‘microdesc’)
      • +
      +
      Returns:

      a tuple (remaining-input, headers-or-None)

      +
      +
      + +
      +
      +lightnion.consensus.download(state, flavor='microdesc', cache=True)[source]
      +
      + +
      +
      +lightnion.consensus.download_direct(hostname, port, flavor='microdesc')[source]
      +

      Retrieve consensus via a direct HTTP connection. +:param hostname: host name of the node from which to retrieve the consensus. +:param port: port of the node from which to retrieve the consensus. +:param flavor: flavour of the consensus to retrieve. +:param cache: if the retrieved consensus should put in the cache.

      +
      + +
      +
      +lightnion.consensus.download_raw(hostname, port, flavor='unflavored')[source]
      +

      Retrieve raw consensus via a direct HTTP connection. +:param hostname: host name of the node from which to retrieve the consensus. +:param port: port of the node from which to retrieve the consensus. +:param flavor: flavour of the consensus to retrieve.

      +
      + +
      +
      +lightnion.consensus.extract_date(consensus, field)[source]
      +

      Retrieve the value from a date field as a datetime object.

      +
      + +
      +
      +lightnion.consensus.extract_nodes_digests_micro(consensus_raw)[source]
      +

      Retrieve a list of the digests of all routers in the consensus.

      +
      + +
      +
      +lightnion.consensus.extract_nodes_digests_unflavored(consensus_raw)[source]
      +

      Retrieve a list of the digests of all routers in the consensus.

      +
      + +
      +
      +lightnion.consensus.load(file_name, cache=True)[source]
      +

      Load the consensus from a file +:param file_name: the name of the file in consensus_file +:param cache: if we cache the newly downloaded consensus +:return: the parsed consensus

      +
      + +
      +
      +lightnion.consensus.parse(consensus, flavor='unflavored')[source]
      +

      Parse a raw consensus with the given flavor, then returns sanitized +entries as a python dictionary.

      + +++ + + + + + +
      Parameters:
        +
      • consensus (str) – input to be processed
      • +
      • flavor (str) – consensus flavor (‘unflavored’ or ‘microdesc’)
      • +
      +
      Returns:

      a python dictionary

      +
      +
      + +
      +
      +lightnion.consensus.parse_address(address)[source]
      +

      Take a Tor-formatted v4 or v6 IP address with a port, returns a +cleaned-up version.

      + +++ + + + + + +
      Parameters:address (str) – input address to be processed
      Returns:a tuple (address, port, guessed-type) where port is an +integer and guessed-type is 4 or 6 (IPv4 or IPv6).
      +
      + +
      +
      +lightnion.consensus.parse_base64(payload, decode=False)[source]
      +

      Take an input base64 string, decode it, re-encode it.

      +
      +
      For example, we use it to parse “shared-rand-current-value” fields:
      +
      https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L2069
      +
      + +++ + + + + + +
      Parameters:
        +
      • payload (str) – input base64-encoded data
      • +
      • decode (bool) – return raw bytes (default: False)
      • +
      +
      Returns:

      a base64-encoded string equivalent to the input

      +
      +
      + +
      +
      +lightnion.consensus.parse_fingerprint(payload)[source]
      +
      + +
      +
      +lightnion.consensus.parse_params(params)[source]
      +

      Take Tor-formatted parameters, then returns a keyword-based dictionary +of integers.

      +
      +
      For example, we use it to parse “params” fields:
      +
      https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L1820
      +
      + +++ + + + + + +
      Parameters:params (str) – input params to be processed
      Returns:a dictionary with (param-name, param-integer-value) items
      +
      + +
      +
      +lightnion.consensus.parse_range_once(value, expand=True)[source]
      +

      Take Tor-formatted ranges, then returns it as a list of integers if +expanded or a mix of integers and ranges as [low, high] tuples.

      +
      +
      For example, we use it to parse “p” fields:
      +
      https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L2322
      +
      + +++ + + + + + +
      Parameters:
        +
      • value (str) – input value to be processed
      • +
      • expand (bool) – do we expand a range as integers? (default: True)
      • +
      +
      Returns:

      a list of integers or a mix of integers and range list/tuples

      +
      +
      + +
      +
      +lightnion.consensus.parse_ranges(ranges, expand=True)[source]
      +

      Take Tor-formatted named ranges, then returns a keyword-based +dictionary of list of integers or mix of integers and range tuples (as +returned by parse_range_once), expanded or not.

      +
      +
      For example, we use it to parse “recommended-client-protocols” fields:
      +
      https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L780
      +
      + +++ + + + + + +
      Parameters:
        +
      • ranges (str) – input ranges to be processed
      • +
      • expand (bool) – do we expand ranges as integers? (default: True)
      • +
      +
      Returns:

      a dictionary with (range-name, range-content) items

      +
      +
      + +
      +
      +lightnion.consensus.parse_time(timedate)[source]
      +

      Take a Tor-formatted (Y-m-d H:M:S) time, parse it, then returns the +corresponding date, time and datetime object. This function assumes +that the given time uses the UTC timezone – as it’s the timezone used +into Tor consensuses.

      + +++ + + + + + +
      Parameters:timedate (str) – input time and date to be parsed
      Returns:a tuple (date-str, time-str, datetime-object)
      +
      + +
      +
      +lightnion.consensus.scrap(consensus, end_of_field)[source]
      +

      Consume lines upon matching a criterion.

      +
      +
      Returns (consensus-without-first-line, first-line)
      +
      if end_of_field(first-line) returns True, +else returns (consensus-with-first-line, None)
      +
      + +++ + + + + + +
      Parameters:
        +
      • consensus (bytes) – input which first line may be consumed
      • +
      • end_of_field (function) – passed a line, returns True when no match
      • +
      +
      Returns:

      a tuple (updated-consensus, next-field-or-None)

      +
      +
      + +
      +
      +lightnion.consensus.scrap_signature(consensus, fix=b'SIGNATURE')[source]
      +

      Consume a signature field if there is one to consume.

      + +++ + + + + + +
      Parameters:consensus (bytes) – input which may start with a signature.
      Returns:a tuple (updated-consensus, signature-or-None)
      +
      + +
      +
      +

      lightnion.constants module

      +
      +
      +class lightnion.constants.flow[source]
      +

      Bases: object

      +
      +
      +class circuit[source]
      +

      Bases: object

      +
      +
      +default = 1000
      +
      + +
      +
      +increment = 100
      +
      + +
      +
      +lowlimit = 900
      +
      + +
      + +
      +
      +class stream[source]
      +

      Bases: object

      +
      +
      +default = 500
      +
      + +
      +
      +increment = 50
      +
      + +
      +
      +lowlimit = 450
      +
      + +
      + +
      + +
      +
      +

      lightnion.create module

      +
      +
      +class lightnion.create.circuit[source]
      +

      Bases: lightnion.create.circuit

      +
      +
      +destroyed = False
      +
      + +
      +
      +get(block=True)[source]
      +
      + +
      +
      +last_stream_id = 0
      +
      + +
      +
      +put(payload)[source]
      +
      + +
      +
      +queue = None
      +
      + +
      +
      +reason = None
      +
      + +
      +
      +stream_windows = None
      +
      + +
      +
      +window = None
      +
      + +
      + +
      +
      +lightnion.create.fast(link)[source]
      +

      Use a CREATE_FAST cell to initiate a one-hop circuit.

      +

      The expected transcript is:

      +
      +
      +
      (… perform a proper link handshake here …)
      +

      Onion Proxy (client) Onion Router (server)

      +
      +
      / [ 7] :—— CREATE_FAST¹ ——-> [8] +| [10] <—— CREATED_FAST ——-: [9] +| +| Shared circuit key (via KDF-TOR²)
      +
      +
      +
      ¹The initiator picks an available circuit ID (CircID) with its most
      +
      significant bit equal to 1 (v4-or-higher links).
      +
      + +++ + + + + + +
      Parameters:link – a link.link object, see: link.initiate
      Returns:a onion.state object, see: onion.state
      +
      + +
      +
      +lightnion.create.fast_async(link)[source]
      +

      Use a CREATE_FAST cell to initiate a one-hop circuit.

      +

      The expected transcript is:

      +
      +
      +
      (… perform a proper link handshake here …)
      +

      Onion Proxy (client) Onion Router (server)

      +
      +
      / [ 7] :—— CREATE_FAST¹ ——-> [8] +| [10] <—— CREATED_FAST ——-: [9] +| +| Shared circuit key (via KDF-TOR²)
      +
      +
      +
      ¹The initiator picks an available circuit ID (CircID) with its most
      +
      significant bit equal to 1 (v4-or-higher links).
      +
      + +++ + + + + + +
      Parameters:link – a link.link object, see: link.initiate
      Returns:a onion.state object, see: onion.state
      +
      + +
      +
      +lightnion.create.ntor(link, descriptor)[source]
      +
      + +
      +
      +lightnion.create.ntor_async(link, descriptor)[source]
      +
      + +
      +
      +lightnion.create.ntor_handshake(link, circuit_id, handshake, timeout=None)[source]
      +
      + +
      +
      +lightnion.create.ntor_raw(link, payload, timeout=None)[source]
      +
      + +
      +
      +lightnion.create.ntor_raw2(circuit_id, payload)[source]
      +
      + +
      +
      +

      lightnion.descriptors module

      +
      +
      +lightnion.descriptors.batch_query(items, prefix, separator='-', fixed_max_length=3968)[source]
      +
      + +
      +
      +lightnion.descriptors.compute_descriptor_digest(fields, descriptors, entry, flavor)[source]
      +

      (details of the parser – private API)

      +

      Plugs into our consumer to compute extra “digest” fields that expose +the (micro-)descriptor’s (micro-)digest, enabling us to easily fetch +associated entries within a consensus.

      + +++ + + + + + +
      Parameters:
        +
      • fields (list) – “fields” accumulator used by the consumer
      • +
      • descriptors (bytes) – remaining input to be parsed by the consumer
      • +
      • entry (bytes) – last line being parsed by the consumer
      • +
      • flavor (str) – flavor used by the consumer
      • +
      +
      Returns:

      updated (or not) fields accumulator

      +
      +
      + +
      +
      +lightnion.descriptors.consume_descriptors(descriptors, flavor='microdesc')[source]
      +
      + +
      +
      +lightnion.descriptors.download(state, cons=None, flavor='microdesc', cache=True, fail_on_missing=False)[source]
      +
      + +
      +
      +lightnion.descriptors.download_authority(state)[source]
      +
      + +
      +
      +lightnion.descriptors.download_authority_direct(host, port)[source]
      +

      Retrieve authority. +:param host: host from which to retrieve the authority. +:param port: port from which to retrieve the authority. +:return: Authority.

      +
      + +
      +
      +lightnion.descriptors.download_direct(host, port, cons, flavor='unflavored')[source]
      +

      Retrieve descriptor via a direct HTTP connection. +:param host: host from which to retrieve the descriptors. +:param port: port from which to retrieve the descriptors. +:param cons: consensus for which nodes a descriptor need to be retrieved.

      +
      + +
      +
      +lightnion.descriptors.download_raw(host, port, cons, flavor='unflavored')[source]
      +

      Retrieve descriptor via a direct HTTP connection. +:param host: host from which to retrieve the descriptors. +:param port: port from which to retrieve the descriptors. +:param cons: consensus for which nodes a descriptor need to be retrieved.

      +
      + +
      +
      +lightnion.descriptors.download_raw_by_digests_micro(host, port, digests_bytes)[source]
      +

      Retrieve descriptor via a direct HTTP connection. +:param host: host from which to retrieve the descriptors. +:param port: port from which to retrieve the descriptors. +:param digests: Digests (in a binary form) of the nodes for which a descriptor need to be retrieved.

      +
      + +
      +
      +lightnion.descriptors.download_raw_by_digests_unflavored(host, port, digests_bytes)[source]
      +

      Retrieve descriptor via a direct HTTP connection. +:param host: host from which to retrieve the descriptors. +:param port: port from which to retrieve the descriptors. +:param digests: Digests (in a binary form) of the nodes for which a descriptor need to be retrieved.

      +
      + +
      +
      +lightnion.descriptors.download_relay_descriptor(host='127.0.0.1', port=9051)[source]
      +

      Retrieve a relay’s own descriptor.

      +
      + +
      +
      +lightnion.descriptors.filter_descriptors(descriptors, digests, flavor='unflavored')[source]
      +

      Filter out the invalid descriptors. +:param descriptors: Descriptors to be filtered. +:param digests: Digests from the consensus. +:param flavor: Flavor of the descriptor.

      +
      + +
      +
      +lightnion.descriptors.parse_descriptors(descriptors, flavor='microdesc')[source]
      +
      + +
      +
      +

      lightnion.extend module

      +
      +
      +lightnion.extend.circuit(state, descriptor)[source]
      +
      + +
      +
      +

      lightnion.hop module

      +
      +
      +lightnion.hop.directory_query(state, query=None, compression='deflate', timeout=30, **kwargs)[source]
      +
      + +
      +
      +lightnion.hop.recv(state, block=True, once=False, auto_sendme=True)[source]
      +

      Receive one or more RELAY{_EARLY,} cells from state attached circuit.

      + +++ + + + + + +
      Parameters:
        +
      • state – a state object (see onion.state)
      • +
      • block (bool) – block while receiving? (default: True)
      • +
      • block – attempt only receiving once? (default: False)
      • +
      +
      Returns:

      a tuple (updated state, received RELAY{_EARLY,} cells)

      +
      +
      +
      Notes:
      +
        +
      • returns an updated state that MUST be used afterwards.
      • +
      • non-RELAY{_EARLY,} cells within the circuit may be reordered.
      • +
      +
      +
      +
      + +
      +
      +lightnion.hop.send(state, command, payload=b'', stream_id=0)[source]
      +

      Send one RELAY{_EARLY,} cell through state attached circuit.

      + +++ + + + + + +
      Parameters:
        +
      • state – a state object (see onion.state)
      • +
      • command (str) – RELAY{_EARLY,} cell command (see cell.relay.cmd)
      • +
      • payload (bytes) – RELAY{_EARLY,} cell content (default: b’‘)
      • +
      • stream_id (int) – RELAY{_EARLY,} stream ID (default: 0)
      • +
      +
      Returns:

      an updated state

      +
      +

      Note: returns an updated state that *MUST be used afterwards.*

      +
      + +
      +
      +lightnion.hop.zlib_decompress(compressed_data, min_bufsize=32)[source]
      +
      + +
      + +
      +

      lightnion.onion module

      +
      +
      +lightnion.onion.build(state, command, payload=b'', stream_id=0)[source]
      +

      Build a RELAY{_EARLY,} cell.

      + +++ + + + + + +
      Parameters:
        +
      • state – a state object (see onion.state)
      • +
      • command (str) – RELAY{_EARLY,} cell command (see cell.relay.cmd)
      • +
      • payload (bytes) – RELAY{_EARLY,} cell content (default: b’‘)
      • +
      • stream_id (int) – RELAY{_EARLY,} stream ID (default: 0)
      • +
      +
      Returns:

      a tuple (updated state, cell)

      +
      +

      Note: returns an updated state that MUST be used afterwards.

      +
      + +
      +
      +lightnion.onion.core(state, command, payload=b'', stream_id=0)[source]
      +

      Build a RELAY{_EARLY,} cell as an onion core (plaintext w/ state)

      + +++ + + + + + +
      Parameters:
        +
      • state – a state object (see onion.state)
      • +
      • command (str) – RELAY{_EARLY,} cell command (see cell.relay.cmd)
      • +
      • payload (bytes) – RELAY{_EARLY,} cell content (default: b’‘)
      • +
      • stream_id (int) – RELAY{_EARLY,} stream ID (default: 0)
      • +
      +
      Returns:

      a tuple (updated state, cell)

      +
      +

      Note: should not be called explicitly.

      +
      + +
      +
      +lightnion.onion.peel(state, cell)[source]
      +

      Decrypt a RELAY{_EARLY,} cell using provided state.

      + +++ + + + + + +
      Parameters:
        +
      • state – a state object (see onion.state)
      • +
      • cell – a RELAY{_EARLY,} cell object (see cell.relay.cell)
      • +
      +
      Returns:

      a tuple (updated state, decrypted cell)

      +
      +

      Note: returns an updated state that MUST be used afterwards.

      +
      + +
      +
      +lightnion.onion.recognize(state, cell, backward=True)[source]
      +

      Attempt to recognize a RELAY{_EARLY,} cell.

      + +++ + + + + + +
      Parameters:
        +
      • state – a state object (see onion.state)
      • +
      • cell – a RELAY{_EARLY,} cell object (see cell.relay.cell)
      • +
      • backward (bool) – is it backward? or else forward? (default: True)
      • +
      +
      Returns:

      a tuple (updated state, bool)

      +
      +

      Note: returns an updated state that MUST be used afterwards.

      +
      + +
      +
      +class lightnion.onion.state(link, circuit, early_count=8)[source]
      +

      Bases: object

      +

      Handle Tor onion-encryption cryptographic states.

      +

      For now, only handle cryptography as an initiator (as an OP to an OR).

      +

      TODO: add support for __init__(link, circuit, initiator={True,False})

      +
      +
      +
      Status Condition
      +
      +
      backward decryptor provided initiator=True
      +
      +
      encryptor (none) initiator=False
      +
      digest provided
      +
      +
      +
      forward decryptor (none) initiator=False
      +
      +
      encryptor provided initiator=True
      +
      digest provided
      +
      +
      +
      +
      +
      +
      +depth
      +

      Number of inner layers in the onion.

      +
      + +
      +
      +early_count
      +

      Number of remaining RELAY_EARLY cells before sending RELAY cells.

      +
      + +
      +
      +wrap(inner)[source]
      +

      Wraps an inner state w/ self as outer state (see lightnion.extend).

      +
      +
      Usage:
      +
        +
      1. A one-hop circuit is build with stateA.
      2. +
      3. A key exchange is made through stateA to get stateB.
      4. +
      5. Then, call stateA.wrap(stateB) to properly wrap the onion.
      6. +
      +
      +
      Usage:
      +
        +
      1. A two-hop circuit is build with state{A,B}.
      2. +
      3. A key exchange is made through state{A,B} to get stateC.
      4. +
      5. Then, call statea.wrap(stateC) to properly wrap the onion.
      6. +
      +
      +
      +

      Note: should not be called explicitly.

      +
      + +
      + +
      +
      +

      lightnion.path_selection module

      +
      +
      +lightnion.path_selection.in_same_family(r0, r1, r2=None)[source]
      +

      Check if r0 and r1 (and possibly r0 and r2) are in the same family or not +:param r0: the descriptor of the first router (the router we are trying to see if it meets all conditions to be chosen) +:param r1: the descriptor of the second router +:param r2: the descriptor of the third router (possibly none) +:return: a boolean

      +
      + +
      +
      +lightnion.path_selection.keep_exit(router, state)[source]
      +

      Checks that the router is not a bad exit, is not down, is stable, +is valid, does not run an old TOR’s version, has an available ed25519 +identity key and has an ‘accept’ exit policy +:params router: the router we want to check +:state: +:return: tuple (boolean that indicates if we keep it, new state, descriptor)

      +
      + +
      +
      +lightnion.path_selection.keep_exit_with_descr(descr, router, guard)[source]
      +

      Checks that the router is not a bad exit, is not down, is stable, +is valid, does not run an old TOR’s version, has an available ed25519 +identity key and has an ‘accept’ exit policy +:param descr: descriptor of the exit candidate. +:params router: the router we want to check +:param guard: the guard in the path +:return: tuple (boolean that indicates if we keep it, new state, descriptor)

      +
      + +
      +
      +lightnion.path_selection.keep_guard(router, state, exit_node, testing)[source]
      +

      Checks that the given router has the properties to be a guard +:param router: the router that must be inspected +:param state: state +:param exit_node: the previously chosen node +:return: if the router can be kept, the updated state and the descriptor

      +
      + +
      +
      +lightnion.path_selection.keep_guard_with_descr(descr, router, testing)[source]
      +

      Checks that the given router has the properties to be a guard +:param descr: descriptor of the exit candidate. +:param router: the router that must be inspected +:return: if the router can be kept, the updated state and the descriptor

      +
      + +
      +
      +lightnion.path_selection.keep_middle(router, state, exit_node, guard, testing)[source]
      +

      Checks that the given router has the properties to be a middle node +:param router: the router that must be inspected +:param state: state +:param exit_node: the previously chosen exit node +:param guard: the previously chosen guard +:return: if the router can be kept, the updated state and the descriptor

      +
      + +
      +
      +lightnion.path_selection.keep_middle_with_descr(descr, router, exit_node, guard, testing)[source]
      +

      Checks that the given router has the properties to be a middle node +:param descr: descriptor of the exit candidate. +:param router: the router that must be inspected +:param exit_node: the previously chosen exit node +:param guard: the previously chosen guard +:return: if the router can be kept, the updated state and the descriptor

      +
      + +
      +
      +lightnion.path_selection.obey_minimal_constraint(router, exit_node=None, guard=None, testing=False)[source]
      +

      Checks if the given router respects the minimal constraints +:param testing: +:param router: router that must respect the constraints +:param exit_node: the chosen exit node +:param guard: the chosen guard node +:return: boolean

      +
      + +
      +
      +lightnion.path_selection.pick_good_entry(routers, state, exit_node, testing)[source]
      +

      Simplified version of the Guard selection algorithm +:param routers: the routers of the consensus +:param state: the state +:return: updated state and the descriptor of the guard node

      +
      + +
      +
      +lightnion.path_selection.pick_good_entry_from_routers(descr, routers, testing)[source]
      +

      Simplified version of the Guard selection algorithm +:param routers: the routers of the consensus +:param state: the state +:return: updated state and the descriptor of the guard node

      +
      + +
      +
      +lightnion.path_selection.pick_good_exit(routers, state)[source]
      +

      Choose the exit node +:param routers: the routers given by the consensus +:param state: the state +:return: the descriptor of the exit node

      +
      + +
      +
      +lightnion.path_selection.pick_good_exit_from_routers(descr, routers, guard)[source]
      +

      Choose the exit node +:param routers: the routers given by the consensus +:param guard: the guard in the path +:return: the descriptor of the exit node

      +
      + +
      +
      +lightnion.path_selection.pick_good_middle(routers, state, exit_node, guard, testing)[source]
      +

      Choose the middle node given the exit and the guard node +:param routers: the routers of the consensus +:param state: the state +:param exit_node: the previously chosen exit node +:param guard: the previously chosen guard node +:return: updated state and the descriptor of the guard node

      +
      + +
      +
      +lightnion.path_selection.pick_good_middle_from_routers(descr, routers, exit_node, guard, testing)[source]
      +

      Choose the middle node given the exit and the guard node +:param routers: the routers of the consensus +:param exit_node: the previously chosen exit node +:param guard: the previously chosen guard node +:return: updated state and the descriptor of the guard node

      +
      + +
      +
      +lightnion.path_selection.select_end_path_from_consensus(cons, descr, guard, testing=False)[source]
      +

      Handle the selection of the middle and exit nodes +:params routers: list of the routers given by the consensus +:params descr: list of descriptors +:returns: tuple (guard, middle, exit)

      +
      + +
      +
      +lightnion.path_selection.select_guard_from_consensus(cons, descr, testing=False)[source]
      +

      Handle the selection of the guard node +:params routers: list of the routers given by the consensus +:params descr: list of descriptors +:returns: tuple (guard, middle, exit)

      +
      + +
      +
      +lightnion.path_selection.select_path(routers, state, testing=False)[source]
      +

      Handle the path selection +:params routers: list of the routers given by the consensus +:state: +:returns: updated state tuple (guard, middle, exit)

      +
      + +
      +
      +lightnion.path_selection.weighted_random_choice(list_of_possible)[source]
      +

      Choose one of the candidates at random weighted by their (avg) bandwidth +:params list_of_possible: list of descriptors of the candidates +:returns: descriptor of the randomly selected router

      +
      + +
      +
      +

      lightnion.signature module

      +
      +
      +lightnion.signature.get_binary_signature(fingerprint, signatures_and_key_digest)[source]
      +

      This function encodes a signature in base64 pem format into binary +:param fingerprint: the fingerprint of the author of the signature we want to encode +:param signatures_and_key_digest: the mapping from fingerprints to signature (and the signature key digest) +:return: the binary version of the signature

      +
      + +
      +
      +lightnion.signature.get_hash(public_key, signature)[source]
      +

      This functions performs RSA on a binary signature +:param public_key: the key used to compute RSA +:param signature: the signature +:return: the binary digest of the signature

      +
      + +
      +
      +lightnion.signature.get_signature_and_digests(remaining)[source]
      +

      Function that get the signature and the hex digests from the remaining part of the consensus +:param remaining: remaining (without the part that must be hashed) part of the consensus split by authority +:return: dictionary mapping the fingerprint of an authority and both its signature and the hex digest of its public +key

      +
      + +
      +
      +lightnion.signature.verify(raw_cons, keys, minimal=0.5)[source]
      +

      This function verifies the given raw consensus

      +
      +
      Note: TOR does not perform a full PKCS#1 v1.5 signature (RFC 2313) as mentioned in the TOR’s reference.
      +
      The padding of the data that must be signed is done following the reference (see subsection 8.1 of the +RFC 2313 for more details), however the digest is not wrapped into the data structure described in the +subsection 10.1.2. This is the reason why RSA is performed manually and the module PKCS1_v1_5 of pycrypto is +not used.
      +
      + +++ + + + +
      Parameters:
        +
      • raw_cons – the consensus we want to verify
      • +
      • keys – a dictionary of keys as retrieved by the function get_signing_keys_info of tools/keys.py
      • +
      • minimal – the minimal percentage of the authorities whose signatures must be verified in order to accept the
      • +
      +
      +

      given consensus +:return: true if at least the minimal number of signatures are verified

      +
      + +
      +
      +lightnion.signature.verify_format(padded_hash)[source]
      +

      This function verifies that the hash as the good format, i.e: +# 1 byte - [null ‘’] +# 1 byte - [block type identifier ‘’] - Should always be 1 +# N bytes - [padding ‘ÿ’ ] +# 1 byte - [separator ‘’ ] +# M bytes - [message] +:param padded_hash: +:return: true if the format is correct

      +
      + +
      +
      +lightnion.signature.verify_key(actual, hex_digest)[source]
      +

      Function that verify that the downloaded key corresponds to the hex digest of the consensus +:param actual: the key with the format

      +

      —–BEGIN RSA PUBLIC KEY—–

      +

      base64 encoded key split on multiples lines ending with

      +

      —–END RSA PUBLIC KEY—–

      + +++ + + + + + +
      Parameters:hex_digest – the sha1 digest of the key
      Returns:true if the key is verified
      +
      + +
      +
      +

      lightnion.socket module

      +
      +
      +lightnion.socket.cell_slice(payload, once=False)[source]
      +
      + +
      +
      +class lightnion.socket.io(peer, daemon=True, period=0.01, max_fails=32, max_queue=2048, buffer_size=4096)[source]
      +

      Bases: object

      +
      +
      +binding()[source]
      +
      + +
      +
      +close()[source]
      +
      + +
      +
      +dead
      +
      + +
      +
      +pending
      +
      + +
      +
      +recv(block=True)[source]
      +
      + +
      +
      +send(payload, block=True)[source]
      +
      + +
      + +
      +
      +class lightnion.socket.worker(peer, max_fails=32, max_queue=2048, buffer_size=4096)[source]
      +

      Bases: threading.Thread

      +
      +
      +close()[source]
      +
      + +
      +
      +die(e)[source]
      +
      + +
      +
      +main()[source]
      +
      + +
      +
      +recv(block=True)[source]
      +
      + +
      +
      +run()[source]
      +

      Method representing the thread’s activity.

      +

      You may override this method in a subclass. The standard run() method +invokes the callable object passed to the object’s constructor as the +target argument, if any, with sequential and keyword arguments taken +from the args and kwargs arguments, respectively.

      +
      + +
      +
      +send(cell, block=True)[source]
      +
      + +
      + +
      +
      +

      lightnion.utils module

      +
      +
      +exception lightnion.utils.InvalidCellHeaderException(header)[source]
      +

      Bases: Exception

      +
      + +
      +
      +exception lightnion.utils.InvalidCellLengthException[source]
      +

      Bases: Exception

      +
      + +
      +
      +lightnion.utils.cell_get_cid(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_get_cmd(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_get_len(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_is_valid(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_is_variable_length(cmd)[source]
      +
      + +
      +
      +lightnion.utils.cell_netinfo_build(host)[source]
      +
      + +
      +
      +lightnion.utils.cell_pad_null(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_pad_rnd(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_set_cid(cell, cid)[source]
      +
      + +
      +
      +lightnion.utils.cell_slice(payload)[source]
      +

      Retrieve the next cell from the payload and truncate that one. +:param payload: bytearray

      +
      + +
      +
      +lightnion.utils.cell_slice_old(payload)[source]
      +

      Retrieve the next cell from the payload and truncate that one. +:param payload: bytearray

      +
      + +
      +
      +lightnion.utils.cell_to_str(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_version_build(versions)[source]
      +
      + +
      +
      +lightnion.utils.cell_version_get_cmd(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_version_get_len(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_version_get_versions(cell)[source]
      +
      + +
      +
      +lightnion.utils.cell_version_is_valid(cell)[source]
      +
      + +
      +
      +lightnion.utils.cmd_to_str(cmd)[source]
      +
      + +
      +
      +

      Module contents

      +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/lightnion.http.html b/docs/source/_build/html/lightnion.http.html new file mode 100644 index 0000000..8de4a13 --- /dev/null +++ b/docs/source/_build/html/lightnion.http.html @@ -0,0 +1,384 @@ + + + + + + + + + + + lightnion.http package — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion.http package

      +
      +

      Submodules

      +
      +
      +

      lightnion.http.ntor module

      +
      +
      +lightnion.http.ntor.hand(guard, encode=True)[source]
      +
      + +
      +
      +lightnion.http.ntor.shake(payload, material)[source]
      +
      + +
      +
      +

      lightnion.http.polling module

      +
      +
      +class lightnion.http.polling.io(endpoint, period=0.1, daemon=True, max_queue=2048)[source]
      +

      Bases: object

      +
      +
      +close()[source]
      +
      + +
      +
      +dead
      +
      + +
      +
      +recv(block=True)[source]
      +
      + +
      +
      +send(payload, block=True)[source]
      +
      + +
      + +
      +
      +class lightnion.http.polling.worker(endpoint, period, max_queue=2048)[source]
      +

      Bases: threading.Thread

      +
      +
      +close()[source]
      +
      + +
      +
      +die(e)[source]
      +
      + +
      +
      +main()[source]
      +
      + +
      +
      +recv(block=True)[source]
      +
      + +
      +
      +run()[source]
      +

      Method representing the thread’s activity.

      +

      You may override this method in a subclass. The standard run() method +invokes the callable object passed to the object’s constructor as the +target argument, if any, with sequential and keyword arguments taken +from the args and kwargs arguments, respectively.

      +
      + +
      +
      +send(cell, block=True)[source]
      +
      + +
      + +
      +
      +

      lightnion.http.websocket module

      +
      +
      +lightnion.http.websocket.channel_handler(websocket, worker)[source]
      +
      + +
      +
      +lightnion.http.websocket.client(worker)[source]
      +
      + +
      +
      +lightnion.http.websocket.incoming(websocket, worker)[source]
      +
      + +
      +
      +class lightnion.http.websocket.io(endpoint, period=0.1, daemon=True, max_queue=2048)[source]
      +

      Bases: object

      +
      +
      +close()[source]
      +
      + +
      +
      +dead
      +
      + +
      +
      +recv(block=True)[source]
      +
      + +
      +
      +send(payload, block=True)[source]
      +
      + +
      + +
      +
      +lightnion.http.websocket.outcoming(websocket, worker)[source]
      +
      + +
      +
      +class lightnion.http.websocket.worker(endpoint, period, max_queue=2048)[source]
      +

      Bases: threading.Thread

      +
      +
      +close()[source]
      +
      + +
      +
      +die(e)[source]
      +
      + +
      +
      +recv(block=True)[source]
      +
      + +
      +
      +run()[source]
      +

      Method representing the thread’s activity.

      +

      You may override this method in a subclass. The standard run() method +invokes the callable object passed to the object’s constructor as the +target argument, if any, with sequential and keyword arguments taken +from the args and kwargs arguments, respectively.

      +
      + +
      +
      +send(cell, block=True)[source]
      +
      + +
      + +
      +
      +

      Module contents

      +
      +
      +class lightnion.http.channel[source]
      +

      Bases: lightnion.http.channel

      +
      + +
      +
      +lightnion.http.client(host, port=80, *, io, prefix='http', failures=5, **kwargs)[source]
      +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/lightnion.proxy.html b/docs/source/_build/html/lightnion.proxy.html new file mode 100644 index 0000000..7f91973 --- /dev/null +++ b/docs/source/_build/html/lightnion.proxy.html @@ -0,0 +1,675 @@ + + + + + + + + + + + lightnion.proxy package — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion.proxy package

      +
      +

      Submodules

      +
      +
      +

      lightnion.proxy.auth module

      +
      +
      +lightnion.proxy.auth.filename(auth_dir, filename, base_dir=None)[source]
      +
      + +
      +
      +lightnion.proxy.auth.genpkey(auth_dir, base_dir=None)[source]
      +
      + +
      +
      +lightnion.proxy.auth.getpkey(auth_dir, base_dir=None)[source]
      +
      + +
      +
      +class lightnion.proxy.auth.material[source]
      +

      Bases: lightnion.proxy.auth.material

      +
      +
      +perform(client, data)[source]
      +
      + +
      +
      +public
      +
      + +
      +
      +suffix
      +
      + +
      + +
      +
      +

      lightnion.proxy.forward module

      +
      +
      +class lightnion.proxy.forward.clerk(slave_node, control_port, dir_port, compute_path, auth_dir=None)[source]
      +

      Bases: object

      +
      +
      +get_descriptor_unflavoured(router)[source]
      +

      Retrieve a descriptor. +:param router: Router from which we want the descriptor. +:return: the descriptor of the given router.

      +
      + +
      +
      +get_guard()[source]
      +

      Generate a guard +:return: guard node

      +
      + +
      +
      +prepare()[source]
      +
      + +
      +
      +retrieve_consensus()[source]
      +

      Retrieve relays data with direct HTTP connection and schedule its future retrival.

      +
      + +
      +
      +wait_for_consensus()[source]
      +

      Ensure a consensus is present in the clerk, and fetch a new one if it is not.

      +
      + +
      + +
      +
      +lightnion.proxy.forward.create_channel()[source]
      +

      Create a channel.

      +
      + +
      +
      +lightnion.proxy.forward.delete_channel(uid)[source]
      +

      Delete a channel. +:param uid: channel identifier

      +
      + +
      +
      +lightnion.proxy.forward.get_consensus()[source]
      +

      Retrieve consensus.

      +
      + +
      +
      +lightnion.proxy.forward.get_consensus_raw(flavor)[source]
      +

      Retrieve raw consensus.

      +
      + +
      +
      +lightnion.proxy.forward.get_descriptors()[source]
      +
      + +
      +
      +lightnion.proxy.forward.get_descriptors_raw(flavor)[source]
      +
      + +
      +
      +lightnion.proxy.forward.get_guard()[source]
      +

      Retrieve guard descriptor.

      +
      + +
      +
      +lightnion.proxy.forward.get_signing_keys()[source]
      +

      Retrieve signing keys to verify consensus.

      +
      + +
      +
      +lightnion.proxy.forward.loop_signal_handler(signum, loop)[source]
      +

      Handler to stop coroutines.

      +
      + +
      +
      +lightnion.proxy.forward.main(port, slave_node, control_port, dir_port, compute_path, auth_dir=None)[source]
      +

      Entry point

      +
      + +
      +
      +

      lightnion.proxy.jobs module

      +
      +
      +class lightnion.proxy.jobs.Channel(token, cid)[source]
      +

      Bases: object

      +
      + +
      +
      +exception lightnion.proxy.jobs.ChannelDoesNotExistException(channel)[source]
      +

      Bases: Exception

      +
      + +
      +
      +class lightnion.proxy.jobs.ChannelManager[source]
      +

      Bases: object

      +

      Channel manager

      +
      +
      +create_channel(consensus, descriptors, select_path)[source]
      +

      Create a new channel. +:param ntor: First part of the ntor handshake provided by the client. +:param consensus: The current consensus. +:param descriptors: A collection of the current descriptors. +:return: Response to be send to the client

      +
      + +
      +
      +crypto = <lightnion.proxy.parts.crypto object>
      +
      + +
      +
      +delete_channel(channel)[source]
      +

      Delete a given channel if it is managed by the channel manager, do nothing otherwise. +:param channel: Channel to be deleted.

      +
      + +
      +
      +destroy_circuit_from_client(channel)[source]
      +

      Destroy a circuit corresponding to a channel as if the order was comming from the client side. +:param channel: Channel handling the circuit to be destroyed.

      +
      + +
      + +

      Destroy a circuit corresponding to a channel as if the order was comming from the link side. +:param channel: Channel handling the circuit to be destroyed.

      +
      + +
      +
      +gen_token_from_cid(cid)[source]
      +

      Produce a token from a circuit id. +:param cid: circuit id used to generate the token.

      +
      + +
      +
      +get_channel_by_token(token)[source]
      +

      Get a channel by its token. +:param token: Token identifying the channel.

      +
      + +
      + +

      Reset the link used the channel handler. +:param link: Link to use. +:param rnd_gen: Method to generate a random number to initialize the token generator.

      +
      + +
      +
      +schedule_to_send(cell, cid)[source]
      +

      Scedule the data to be send to the correct channel. +:param cell: cell to be send.

      +
      + +
      + +

      Set a link to be used by the channel handler. +:param link: Link to use. +:param rnd_gen: Method to generate a random number to initialize the token generator.

      +
      + +
      + +
      +
      +exception lightnion.proxy.jobs.CircuitDoesNotExistException(cid)[source]
      +

      Bases: Exception

      +
      + +
      +
      +exception lightnion.proxy.jobs.InvalidTokenException(token)[source]
      +

      Bases: Exception

      +
      + +
      +
      +exception lightnion.proxy.jobs.LinkAlreadyInitializedException[source]
      +

      Bases: Exception

      +
      + +
      +
      +exception lightnion.proxy.jobs.LinkNotInitializedException[source]
      +

      Bases: Exception

      +
      + +
      +
      +class lightnion.proxy.jobs.WebsocketManager(host='0.0.0.0', port=8765, timeout=60)[source]
      +

      Bases: object

      +
      +
      +prefix = '/lightnion/api/v0.1/channels/'
      +
      + +
      +
      +prefix_len = 29
      +
      + +
      +
      +serve(loop)[source]
      +

      Create and start a websocket server, then wait for it to close. +:param host: host on which the websocket need to run. +:param port: port on which the websocket is listening.

      +
      + +
      +
      +set_channel_manager(channel_manager)[source]
      +

      Set the channel manager to use for dispatching data. +:param channel_manager: The channel manager to use.

      +
      + +
      +
      +stop()[source]
      +
      + +
      + +
      +
      +lightnion.proxy.jobs.dummy_random_gen()[source]
      +
      + +
      + +
      +

      lightnion.proxy.parts module

      +
      +
      +class lightnion.proxy.parts.crypto[source]
      +

      Bases: object

      +
      +
      +compute_token(circuit_id, binding)[source]
      +
      + +
      +
      +decrypt_token(token, binding)[source]
      +
      + +
      + +
      +
      +

      lightnion.proxy.path module

      +
      +
      +lightnion.proxy.path.convert(*entries, consensus, expect='fetch_format')[source]
      +
      + +
      +
      +lightnion.proxy.path.emitter(output_queue, kill_queue, control_host, control_port, batch=32, target=1024, nb_worker=2)[source]
      +
      + +
      +
      +lightnion.proxy.path.fetch(batch=32, target=1024, nb_worker=2, tor_process=None, socks_port=None, control_host='127.0.0.1', control_port=None)[source]
      +
      + +
      +
      +lightnion.proxy.path.get_tor(control_port=9051, socks_port=9050, msg_handler=None)[source]
      +
      + +
      +
      +class lightnion.proxy.path.producer(process, path_queue, kill_queue, tor_process)[source]
      +

      Bases: object

      +
      +
      +close()[source]
      +
      + +
      +
      +dead
      +
      + +
      +
      +empty
      +
      + +
      +
      +get()[source]
      +
      + +
      + +
      +
      +class lightnion.proxy.path.worker(host, port, barrier, path_queue, batch_size)[source]
      +

      Bases: threading.Thread

      +
      +
      +run()[source]
      +

      Method representing the thread’s activity.

      +

      You may override this method in a subclass. The standard run() method +invokes the callable object passed to the object’s constructor as the +target argument, if any, with sequential and keyword arguments taken +from the args and kwargs arguments, respectively.

      +
      + +
      + +
      +
      +

      lightnion.proxy.relayinfo module

      +
      +
      +lightnion.proxy.relayinfo.get_relay_info(port, password=None, params=None)[source]
      +

      Retrieve some info from the relay.

      +
      + +
      +
      +

      Module contents

      +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/lightnion.tests.html b/docs/source/_build/html/lightnion.tests.html new file mode 100644 index 0000000..a5deebe --- /dev/null +++ b/docs/source/_build/html/lightnion.tests.html @@ -0,0 +1,320 @@ + + + + + + + + + + + lightnion.tests package — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion.tests package

      +
      +

      Submodules

      +
      +
      +

      lightnion.tests.path_selection_test module

      +
      +
      +lightnion.tests.path_selection_test.get_chutney_consensus()[source]
      +

      Get chutney’s consensus

      +
      + +
      +
      +lightnion.tests.path_selection_test.test_keep_exit_works_with_reject_exit_policy(get_chutney_consensus)[source]
      +
      + +
      +
      +lightnion.tests.path_selection_test.test_keep_exit_works_with_suitable_router(get_chutney_consensus)[source]
      +
      + +
      +
      +lightnion.tests.path_selection_test.test_obey_minimal_constraint_with_one_router(get_chutney_consensus)[source]
      +
      + +
      +
      +lightnion.tests.path_selection_test.test_path_selection_works(get_chutney_consensus)[source]
      +
      + +
      +
      +lightnion.tests.path_selection_test.test_pick_good_exit_returns_a_router(get_chutney_consensus)[source]
      +
      + +
      +
      +

      lightnion.tests.test_consensus_chutney module

      +
      +
      +lightnion.tests.test_consensus_chutney.test_download_microdesc()[source]
      +
      + +
      +
      +lightnion.tests.test_consensus_chutney.test_download_unflavored()[source]
      +
      + +
      +
      +

      lightnion.tests.test_create_chutney module

      +
      +
      +lightnion.tests.test_create_chutney.test_fast()[source]
      +
      + +
      +
      +lightnion.tests.test_create_chutney.test_ntor()[source]
      +
      + +
      +
      +

      lightnion.tests.test_descriptors_chutney module

      +
      +
      +lightnion.tests.test_descriptors_chutney.test_download_authority()[source]
      +
      + +
      +
      +lightnion.tests.test_descriptors_chutney.test_download_microdesc()[source]
      +
      + +
      +
      +lightnion.tests.test_descriptors_chutney.test_download_unflavored()[source]
      +
      + +
      +
      +

      lightnion.tests.test_extend_chutney module

      +
      +
      +lightnion.tests.test_extend_chutney.test_circuit()[source]
      +
      + +
      +
      +

      lightnion.tests.test_hop_chutney module

      +
      +
      +lightnion.tests.test_hop_chutney.test_directory_query()[source]
      +
      + +
      + +
      +

      lightnion.tests.test_path_selection_chutney module

      +
      +
      +lightnion.tests.test_path_selection_chutney.test_select_path()[source]
      +
      + +
      +
      +

      Module contents

      +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/modules.html b/docs/source/_build/html/modules.html new file mode 100644 index 0000000..697787a --- /dev/null +++ b/docs/source/_build/html/modules.html @@ -0,0 +1,277 @@ + + + + + + + + + + + lightnion — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + + + + +
      +
      +
      +
      + +
      +

      lightnion

      +
      + +
      +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/objects.inv b/docs/source/_build/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..fb73ac735a12c197784aeee19c2b3bf95a227e47 GIT binary patch literal 4100 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 C?9%=K literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/py-modindex.html b/docs/source/_build/html/py-modindex.html new file mode 100644 index 0000000..6e6cbc4 --- /dev/null +++ b/docs/source/_build/html/py-modindex.html @@ -0,0 +1,480 @@ + + + + + + + + + + + Python Module Index — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Python Module Index
      • + + +
      • + +
      • + +
      + + +
      +
      +
      +
      + + +

      Python Module Index

      + +
      + l +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
       
      + l
      + lightnion +
          + lightnion.cache +
          + lightnion.cell +
          + lightnion.cell.address +
          + lightnion.cell.certs +
          + lightnion.cell.challenge +
          + lightnion.cell.common +
          + lightnion.cell.create2 +
          + lightnion.cell.create_fast +
          + lightnion.cell.created2 +
          + lightnion.cell.created_fast +
          + lightnion.cell.destroy +
          + lightnion.cell.netinfo +
          + lightnion.cell.padding +
          + lightnion.cell.relay +
          + lightnion.cell.relay.extend2 +
          + lightnion.cell.relay.extended2 +
          + lightnion.cell.relay_early +
          + lightnion.cell.versions +
          + lightnion.cell.view +
          + lightnion.consensus +
          + lightnion.constants +
          + lightnion.create +
          + lightnion.crypto +
          + lightnion.crypto.kdf +
          + lightnion.crypto.ntor +
          + lightnion.descriptors +
          + lightnion.extend +
          + lightnion.hop +
          + lightnion.http +
          + lightnion.http.ntor +
          + lightnion.http.polling +
          + lightnion.http.websocket +
          + lightnion.link +
          + lightnion.onion +
          + lightnion.path_selection +
          + lightnion.proxy +
          + lightnion.proxy.auth +
          + lightnion.proxy.forward +
          + lightnion.proxy.jobs +
          + lightnion.proxy.link +
          + lightnion.proxy.parts +
          + lightnion.proxy.path +
          + lightnion.proxy.relayinfo +
          + lightnion.signature +
          + lightnion.socket +
          + lightnion.tests +
          + lightnion.tests.path_selection_test +
          + lightnion.tests.test_consensus_chutney +
          + lightnion.tests.test_create_chutney +
          + lightnion.tests.test_descriptors_chutney +
          + lightnion.tests.test_extend_chutney +
          + lightnion.tests.test_hop_chutney +
          + lightnion.tests.test_link_chutney +
          + lightnion.tests.test_path_selection_chutney +
          + lightnion.utils +
      + + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/search.html b/docs/source/_build/html/search.html new file mode 100644 index 0000000..8b9ae17 --- /dev/null +++ b/docs/source/_build/html/search.html @@ -0,0 +1,206 @@ + + + + + + + + + + + Search — Lightnion documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + + + +
      + +
      + + + + + + + + + + + + + + + + + +
      + +
        + +
      • Docs »
      • + +
      • Search
      • + + +
      • + + + +
      • + +
      + + +
      +
      +
      +
      + + + + +
      + +
      + +
      + +
      +
      + + +
      + +
      +

      + © Copyright 2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu + +

      +
      + Built with Sphinx using a theme provided by Read the Docs. + +
      + +
      +
      + +
      + +
      + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/_build/html/searchindex.js b/docs/source/_build/html/searchindex.js new file mode 100644 index 0000000..1e2a794 --- /dev/null +++ b/docs/source/_build/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["index","install","lightnion","lightnion.cell","lightnion.cell.relay","lightnion.crypto","lightnion.http","lightnion.proxy","lightnion.tests","modules"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,"sphinx.ext.todo":1,"sphinx.ext.viewcode":1,sphinx:55},filenames:["index.rst","install.rst","lightnion.rst","lightnion.cell.rst","lightnion.cell.relay.rst","lightnion.crypto.rst","lightnion.http.rst","lightnion.proxy.rst","lightnion.tests.rst","modules.rst"],objects:{"":{lightnion:[2,0,0,"-"]},"lightnion.cache":{consensus:[2,1,1,""],descriptors:[2,1,1,""],directory:[2,3,1,""],purge:[2,3,1,""]},"lightnion.cache.consensus":{filename:[2,2,1,""],get:[2,2,1,""],put:[2,2,1,""]},"lightnion.cache.descriptors":{filename:[2,2,1,""],get:[2,2,1,""],put:[2,2,1,""]},"lightnion.cell":{address:[3,0,0,"-"],cell_view:[3,1,1,""],certs:[3,0,0,"-"],challenge:[3,0,0,"-"],cmd:[3,1,1,""],common:[3,0,0,"-"],create2:[3,0,0,"-"],create_fast:[3,0,0,"-"],created2:[3,0,0,"-"],created_fast:[3,0,0,"-"],destroy:[3,0,0,"-"],netinfo:[3,0,0,"-"],pad:[3,3,1,""],padding:[3,0,0,"-"],relay:[4,0,0,"-"],relay_early:[3,0,0,"-"],versions:[3,0,0,"-"],view:[3,0,0,"-"]},"lightnion.cell.address":{addr_type:[3,1,1,""],address_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.address.addr_type":{ERROR_NON_TRANS:[3,4,1,""],ERROR_TRANS:[3,4,1,""],HOSTNAME:[3,4,1,""],IPV4_ADDR:[3,4,1,""],IPV6_ADDR:[3,4,1,""]},"lightnion.cell.cell_view":{valid:[3,5,1,""]},"lightnion.cell.certs":{cell_view:[3,1,1,""],cert_type:[3,1,1,""]},"lightnion.cell.certs.cell_view":{valid:[3,5,1,""]},"lightnion.cell.certs.cert_type":{ED_SIGNED_AUTHENTICATE:[3,4,1,""],ED_SIGNED_SIGNING_KEY:[3,4,1,""],ED_SIGNED_TLS_LINK:[3,4,1,""],RSA_SELF_SIGNED_IDENTITY:[3,4,1,""],RSA_SIGNED_AUTHENTICATE:[3,4,1,""],RSA_SIGNED_ED_IDENTITY:[3,4,1,""],RSA_SIGNED_LINK_KEY:[3,4,1,""]},"lightnion.cell.challenge":{auth_type:[3,1,1,""],cell_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.challenge.auth_type":{ED_AUTH:[3,4,1,""],RSA_AUTH:[3,4,1,""]},"lightnion.cell.challenge.cell_view":{valid:[3,5,1,""]},"lightnion.cell.cmd":{AUTHENTICATE:[3,4,1,""],AUTHORIZE:[3,4,1,""],AUTH_CHALLENGE:[3,4,1,""],CERTS:[3,4,1,""],CREATE2:[3,4,1,""],CREATE:[3,4,1,""],CREATED2:[3,4,1,""],CREATED:[3,4,1,""],CREATED_FAST:[3,4,1,""],CREATE_FAST:[3,4,1,""],DESTROY:[3,4,1,""],NETINFO:[3,4,1,""],PADDING:[3,4,1,""],PADDING_NEGOTIATE:[3,4,1,""],RELAY:[3,4,1,""],RELAY_EARLY:[3,4,1,""],VERSIONS:[3,4,1,""],VPADDING:[3,4,1,""],is_fixed:[3,4,1,""],is_variable:[3,4,1,""]},"lightnion.cell.common":{length_halved_view:[3,1,1,""]},"lightnion.cell.common.length_halved_view":{cache:[3,5,1,""],iseven:[3,5,1,""],valid:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.create2":{cell_view:[3,1,1,""],create_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.create2.cell_view":{valid:[3,5,1,""]},"lightnion.cell.create_fast":{cell_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.create_fast.cell_view":{valid:[3,5,1,""]},"lightnion.cell.created2":{cell_view:[3,1,1,""],created_view:[3,1,1,""]},"lightnion.cell.created2.cell_view":{valid:[3,5,1,""]},"lightnion.cell.created_fast":{cell_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.created_fast.cell_view":{valid:[3,5,1,""]},"lightnion.cell.destroy":{cell_view:[3,1,1,""],pack:[3,3,1,""],reason:[3,1,1,""]},"lightnion.cell.destroy.cell_view":{valid:[3,5,1,""]},"lightnion.cell.destroy.reason":{CONNECTFAILED:[3,4,1,""],DESTROYED:[3,4,1,""],FINISHED:[3,4,1,""],HIBERNATING:[3,4,1,""],INTERNAL:[3,4,1,""],NONE:[3,4,1,""],NOSUCHSERVICE:[3,4,1,""],OR_CONN_CLOSED:[3,4,1,""],OR_IDENTITY:[3,4,1,""],PROTOCOL:[3,4,1,""],REQUESTED:[3,4,1,""],RESOURCELIMIT:[3,4,1,""],TIMEOUT:[3,4,1,""]},"lightnion.cell.netinfo":{cell_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.netinfo.cell_view":{valid:[3,5,1,""]},"lightnion.cell.padding":{cell_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.padding.cell_view":{valid:[3,5,1,""]},"lightnion.cell.relay":{cell_view:[4,1,1,""],cmd:[4,1,1,""],extend2:[4,0,0,"-"],extended2:[4,0,0,"-"],pack:[4,3,1,""],relay_view:[4,1,1,""]},"lightnion.cell.relay.cell_view":{valid:[4,5,1,""]},"lightnion.cell.relay.cmd":{RELAY_BEGIN:[4,4,1,""],RELAY_BEGIN_DIR:[4,4,1,""],RELAY_CONNECTED:[4,4,1,""],RELAY_DATA:[4,4,1,""],RELAY_DROP:[4,4,1,""],RELAY_END:[4,4,1,""],RELAY_EXTEND2:[4,4,1,""],RELAY_EXTEND:[4,4,1,""],RELAY_EXTENDED2:[4,4,1,""],RELAY_EXTENDED:[4,4,1,""],RELAY_RESOLVE:[4,4,1,""],RELAY_RESOLVED:[4,4,1,""],RELAY_SENDME:[4,4,1,""],RELAY_TRUNCATE:[4,4,1,""],RELAY_TRUNCATED:[4,4,1,""],is_backward:[4,4,1,""],is_circuit:[4,4,1,""],is_control:[4,4,1,""],is_forward:[4,4,1,""]},"lightnion.cell.relay.extend2":{extend2_view:[4,1,1,""],handshake_type:[4,1,1,""],linkspec_type:[4,1,1,""],linkspec_view:[4,1,1,""],linkspecs_view:[4,1,1,""],pack:[4,3,1,""]},"lightnion.cell.relay.extend2.handshake_type":{NTOR:[4,4,1,""]},"lightnion.cell.relay.extend2.linkspec_type":{ED_ID:[4,4,1,""],LEGACY_ID:[4,4,1,""],TLS_TCP_4:[4,4,1,""],TLS_TCP_6:[4,4,1,""]},"lightnion.cell.relay.extended2":{extended2_view:[4,1,1,""]},"lightnion.cell.relay.relay_view":{valid:[4,5,1,""]},"lightnion.cell.relay_early":{cell_view:[3,1,1,""],pack:[3,3,1,""]},"lightnion.cell.relay_early.cell_view":{valid:[3,5,1,""]},"lightnion.cell.versions":{cell_view:[3,1,1,""],pack:[3,3,1,""],recv:[3,3,1,""],send:[3,3,1,""]},"lightnion.cell.versions.cell_view":{valid:[3,5,1,""]},"lightnion.cell.view":{"enum":[3,3,1,""],basic:[3,1,1,""],bind:[3,3,1,""],cache:[3,3,1,""],codec:[3,1,1,""],composite:[3,1,1,""],data:[3,1,1,""],fields:[3,1,1,""],ip_address:[3,1,1,""],iscached:[3,3,1,""],iscomposite:[3,3,1,""],isview:[3,3,1,""],like:[3,3,1,""],packet:[3,1,1,""],series:[3,1,1,""],uint:[3,1,1,""],union:[3,1,1,""],wrapper:[3,1,1,""]},"lightnion.cell.view.basic":{valid:[3,5,1,""],value:[3,5,1,""],width:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.codec":{valid:[3,5,1,""],value:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.composite":{write:[3,5,1,""]},"lightnion.cell.view.data":{size:[3,4,1,""],valid:[3,5,1,""],value:[3,5,1,""],width:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.fields":{list_fields:[3,5,1,""],offset:[3,5,1,""],valid:[3,5,1,""],value:[3,5,1,""],visit:[3,5,1,""],width:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.ip_address":{valid:[3,5,1,""],value:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.packet":{cache_fields:[3,5,1,""],fixed_size:[3,4,1,""],list_fields:[3,5,1,""],offset:[3,5,1,""],valid:[3,5,1,""],value:[3,5,1,""],width:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.series":{max_quantity:[3,4,1,""],offset:[3,5,1,""],quantity:[3,4,1,""],valid:[3,5,1,""],value:[3,5,1,""],width:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.uint":{valid:[3,5,1,""],value:[3,5,1,""],width:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.union":{active_view:[3,4,1,""],offset:[3,5,1,""],tag:[3,4,1,""],valid:[3,5,1,""],value:[3,5,1,""],width:[3,5,1,""],write:[3,5,1,""]},"lightnion.cell.view.wrapper":{fields:[3,4,1,""],finalize:[3,5,1,""],offset:[3,5,1,""],raw:[3,4,1,""],set:[3,5,1,""],truncated:[3,4,1,""],valid:[3,4,1,""],value:[3,5,1,""],width:[3,4,1,""],write:[3,5,1,""]},"lightnion.consensus":{consume_dir_sources:[2,3,1,""],consume_footer:[2,3,1,""],consume_headers:[2,3,1,""],consume_http:[2,3,1,""],consume_routers:[2,3,1,""],download:[2,3,1,""],download_direct:[2,3,1,""],download_raw:[2,3,1,""],extract_date:[2,3,1,""],extract_nodes_digests_micro:[2,3,1,""],extract_nodes_digests_unflavored:[2,3,1,""],load:[2,3,1,""],parse:[2,3,1,""],parse_address:[2,3,1,""],parse_base64:[2,3,1,""],parse_fingerprint:[2,3,1,""],parse_params:[2,3,1,""],parse_range_once:[2,3,1,""],parse_ranges:[2,3,1,""],parse_time:[2,3,1,""],scrap:[2,3,1,""],scrap_signature:[2,3,1,""]},"lightnion.constants":{flow:[2,1,1,""]},"lightnion.constants.flow":{circuit:[2,1,1,""],stream:[2,1,1,""]},"lightnion.constants.flow.circuit":{"default":[2,4,1,""],increment:[2,4,1,""],lowlimit:[2,4,1,""]},"lightnion.constants.flow.stream":{"default":[2,4,1,""],increment:[2,4,1,""],lowlimit:[2,4,1,""]},"lightnion.create":{circuit:[2,1,1,""],fast:[2,3,1,""],fast_async:[2,3,1,""],ntor:[2,3,1,""],ntor_async:[2,3,1,""],ntor_handshake:[2,3,1,""],ntor_raw2:[2,3,1,""],ntor_raw:[2,3,1,""]},"lightnion.create.circuit":{destroyed:[2,4,1,""],get:[2,5,1,""],last_stream_id:[2,4,1,""],put:[2,5,1,""],queue:[2,4,1,""],reason:[2,4,1,""],stream_windows:[2,4,1,""],window:[2,4,1,""]},"lightnion.crypto":{kdf:[5,0,0,"-"],ntor:[5,0,0,"-"]},"lightnion.crypto.kdf":{kdf_tor:[5,1,1,""]},"lightnion.crypto.ntor":{h_mac:[5,3,1,""],h_verify:[5,3,1,""],hand:[5,3,1,""],hmac:[5,1,1,""],kdf:[5,1,1,""],server:[5,3,1,""],shake:[5,3,1,""]},"lightnion.crypto.ntor.hmac":{block_size:[5,4,1,""],digest:[5,2,1,""],output_size:[5,4,1,""],prf:[5,5,1,""],tweaked:[5,2,1,""]},"lightnion.crypto.ntor.kdf":{ntor:[5,2,1,""],rfc5869:[5,2,1,""]},"lightnion.descriptors":{batch_query:[2,3,1,""],compute_descriptor_digest:[2,3,1,""],consume_descriptors:[2,3,1,""],download:[2,3,1,""],download_authority:[2,3,1,""],download_authority_direct:[2,3,1,""],download_direct:[2,3,1,""],download_raw:[2,3,1,""],download_raw_by_digests_micro:[2,3,1,""],download_raw_by_digests_unflavored:[2,3,1,""],download_relay_descriptor:[2,3,1,""],filter_descriptors:[2,3,1,""],parse_descriptors:[2,3,1,""]},"lightnion.extend":{circuit:[2,3,1,""]},"lightnion.hop":{directory_query:[2,3,1,""],recv:[2,3,1,""],send:[2,3,1,""],zlib_decompress:[2,3,1,""]},"lightnion.http":{channel:[6,1,1,""],client:[6,3,1,""],ntor:[6,0,0,"-"],polling:[6,0,0,"-"],websocket:[6,0,0,"-"]},"lightnion.http.ntor":{hand:[6,3,1,""],shake:[6,3,1,""]},"lightnion.http.polling":{io:[6,1,1,""],worker:[6,1,1,""]},"lightnion.http.polling.io":{close:[6,5,1,""],dead:[6,4,1,""],recv:[6,5,1,""],send:[6,5,1,""]},"lightnion.http.polling.worker":{close:[6,5,1,""],die:[6,5,1,""],main:[6,5,1,""],recv:[6,5,1,""],run:[6,5,1,""],send:[6,5,1,""]},"lightnion.http.websocket":{channel_handler:[6,3,1,""],client:[6,3,1,""],incoming:[6,3,1,""],io:[6,1,1,""],outcoming:[6,3,1,""],worker:[6,1,1,""]},"lightnion.http.websocket.io":{close:[6,5,1,""],dead:[6,4,1,""],recv:[6,5,1,""],send:[6,5,1,""]},"lightnion.http.websocket.worker":{close:[6,5,1,""],die:[6,5,1,""],recv:[6,5,1,""],run:[6,5,1,""],send:[6,5,1,""]},"lightnion.link":{initiate:[2,3,1,""],link:[2,1,1,""],negotiate_version:[2,3,1,""]},"lightnion.link.link":{close:[2,5,1,""],get:[2,5,1,""],pull:[2,5,1,""],put:[2,5,1,""],recv:[2,5,1,""],register:[2,5,1,""],send:[2,5,1,""],unregister:[2,5,1,""]},"lightnion.onion":{build:[2,3,1,""],core:[2,3,1,""],peel:[2,3,1,""],recognize:[2,3,1,""],state:[2,1,1,""]},"lightnion.onion.state":{depth:[2,4,1,""],early_count:[2,4,1,""],wrap:[2,5,1,""]},"lightnion.path_selection":{in_same_family:[2,3,1,""],keep_exit:[2,3,1,""],keep_exit_with_descr:[2,3,1,""],keep_guard:[2,3,1,""],keep_guard_with_descr:[2,3,1,""],keep_middle:[2,3,1,""],keep_middle_with_descr:[2,3,1,""],obey_minimal_constraint:[2,3,1,""],pick_good_entry:[2,3,1,""],pick_good_entry_from_routers:[2,3,1,""],pick_good_exit:[2,3,1,""],pick_good_exit_from_routers:[2,3,1,""],pick_good_middle:[2,3,1,""],pick_good_middle_from_routers:[2,3,1,""],select_end_path_from_consensus:[2,3,1,""],select_guard_from_consensus:[2,3,1,""],select_path:[2,3,1,""],weighted_random_choice:[2,3,1,""]},"lightnion.proxy":{auth:[7,0,0,"-"],forward:[7,0,0,"-"],jobs:[7,0,0,"-"],link:[7,0,0,"-"],parts:[7,0,0,"-"],path:[7,0,0,"-"],relayinfo:[7,0,0,"-"]},"lightnion.proxy.auth":{filename:[7,3,1,""],genpkey:[7,3,1,""],getpkey:[7,3,1,""],material:[7,1,1,""]},"lightnion.proxy.auth.material":{"public":[7,4,1,""],perform:[7,5,1,""],suffix:[7,4,1,""]},"lightnion.proxy.forward":{clerk:[7,1,1,""],create_channel:[7,3,1,""],delete_channel:[7,3,1,""],get_consensus:[7,3,1,""],get_consensus_raw:[7,3,1,""],get_descriptors:[7,3,1,""],get_descriptors_raw:[7,3,1,""],get_guard:[7,3,1,""],get_signing_keys:[7,3,1,""],loop_signal_handler:[7,3,1,""],main:[7,3,1,""]},"lightnion.proxy.forward.clerk":{get_descriptor_unflavoured:[7,5,1,""],get_guard:[7,5,1,""],prepare:[7,5,1,""],retrieve_consensus:[7,5,1,""],wait_for_consensus:[7,5,1,""]},"lightnion.proxy.jobs":{Channel:[7,1,1,""],ChannelDoesNotExistException:[7,6,1,""],ChannelManager:[7,1,1,""],CircuitDoesNotExistException:[7,6,1,""],InvalidTokenException:[7,6,1,""],LinkAlreadyInitializedException:[7,6,1,""],LinkNotInitializedException:[7,6,1,""],WebsocketManager:[7,1,1,""],dummy_random_gen:[7,3,1,""]},"lightnion.proxy.jobs.ChannelManager":{create_channel:[7,5,1,""],crypto:[7,4,1,""],delete_channel:[7,5,1,""],destroy_circuit_from_client:[7,5,1,""],destroy_circuit_from_link:[7,5,1,""],gen_token_from_cid:[7,5,1,""],get_channel_by_token:[7,5,1,""],reset_link:[7,5,1,""],schedule_to_send:[7,5,1,""],set_link:[7,5,1,""]},"lightnion.proxy.jobs.WebsocketManager":{prefix:[7,4,1,""],prefix_len:[7,4,1,""],serve:[7,5,1,""],set_channel_manager:[7,5,1,""],stop:[7,5,1,""]},"lightnion.proxy.link":{InvalidAuthCellException:[7,6,1,""],InvalidCellHeaderException:[7,6,1,""],InvalidCertsCellException:[7,6,1,""],InvalidDestroyCellException:[7,6,1,""],InvalidNetInfoCellException:[7,6,1,""],InvalidVersionCellException:[7,6,1,""],Link:[7,1,1,""],NoSupportedVersionException:[7,6,1,""]},"lightnion.proxy.link.Link":{gen_cid:[7,5,1,""],schedule_to_send:[7,5,1,""],set_channel_manager:[7,5,1,""]},"lightnion.proxy.parts":{crypto:[7,1,1,""]},"lightnion.proxy.parts.crypto":{compute_token:[7,5,1,""],decrypt_token:[7,5,1,""]},"lightnion.proxy.path":{convert:[7,3,1,""],emitter:[7,3,1,""],fetch:[7,3,1,""],get_tor:[7,3,1,""],producer:[7,1,1,""],worker:[7,1,1,""]},"lightnion.proxy.path.producer":{close:[7,5,1,""],dead:[7,4,1,""],empty:[7,4,1,""],get:[7,5,1,""]},"lightnion.proxy.path.worker":{run:[7,5,1,""]},"lightnion.proxy.relayinfo":{get_relay_info:[7,3,1,""]},"lightnion.signature":{get_binary_signature:[2,3,1,""],get_hash:[2,3,1,""],get_signature_and_digests:[2,3,1,""],verify:[2,3,1,""],verify_format:[2,3,1,""],verify_key:[2,3,1,""]},"lightnion.socket":{cell_slice:[2,3,1,""],io:[2,1,1,""],worker:[2,1,1,""]},"lightnion.socket.io":{binding:[2,5,1,""],close:[2,5,1,""],dead:[2,4,1,""],pending:[2,4,1,""],recv:[2,5,1,""],send:[2,5,1,""]},"lightnion.socket.worker":{close:[2,5,1,""],die:[2,5,1,""],main:[2,5,1,""],recv:[2,5,1,""],run:[2,5,1,""],send:[2,5,1,""]},"lightnion.tests":{path_selection_test:[8,0,0,"-"],test_consensus_chutney:[8,0,0,"-"],test_create_chutney:[8,0,0,"-"],test_descriptors_chutney:[8,0,0,"-"],test_extend_chutney:[8,0,0,"-"],test_hop_chutney:[8,0,0,"-"],test_link_chutney:[8,0,0,"-"],test_path_selection_chutney:[8,0,0,"-"]},"lightnion.tests.path_selection_test":{get_chutney_consensus:[8,3,1,""],test_keep_exit_works_with_reject_exit_policy:[8,3,1,""],test_keep_exit_works_with_suitable_router:[8,3,1,""],test_obey_minimal_constraint_with_one_router:[8,3,1,""],test_path_selection_works:[8,3,1,""],test_pick_good_exit_returns_a_router:[8,3,1,""]},"lightnion.tests.test_consensus_chutney":{test_download_microdesc:[8,3,1,""],test_download_unflavored:[8,3,1,""]},"lightnion.tests.test_create_chutney":{test_fast:[8,3,1,""],test_ntor:[8,3,1,""]},"lightnion.tests.test_descriptors_chutney":{test_download_authority:[8,3,1,""],test_download_microdesc:[8,3,1,""],test_download_unflavored:[8,3,1,""]},"lightnion.tests.test_extend_chutney":{test_circuit:[8,3,1,""]},"lightnion.tests.test_hop_chutney":{test_directory_query:[8,3,1,""]},"lightnion.tests.test_link_chutney":{test_initiate:[8,3,1,""]},"lightnion.tests.test_path_selection_chutney":{test_select_path:[8,3,1,""]},"lightnion.utils":{InvalidCellHeaderException:[2,6,1,""],InvalidCellLengthException:[2,6,1,""],cell_get_cid:[2,3,1,""],cell_get_cmd:[2,3,1,""],cell_get_len:[2,3,1,""],cell_is_valid:[2,3,1,""],cell_is_variable_length:[2,3,1,""],cell_netinfo_build:[2,3,1,""],cell_pad_null:[2,3,1,""],cell_pad_rnd:[2,3,1,""],cell_set_cid:[2,3,1,""],cell_slice:[2,3,1,""],cell_slice_old:[2,3,1,""],cell_to_str:[2,3,1,""],cell_version_build:[2,3,1,""],cell_version_get_cmd:[2,3,1,""],cell_version_get_len:[2,3,1,""],cell_version_get_versions:[2,3,1,""],cell_version_is_valid:[2,3,1,""],cmd_to_str:[2,3,1,""]},lightnion:{cache:[2,0,0,"-"],cell:[3,0,0,"-"],consensus:[2,0,0,"-"],constants:[2,0,0,"-"],create:[2,0,0,"-"],crypto:[5,0,0,"-"],descriptors:[2,0,0,"-"],extend:[2,0,0,"-"],hop:[2,0,0,"-"],http:[6,0,0,"-"],link:[2,0,0,"-"],onion:[2,0,0,"-"],path_selection:[2,0,0,"-"],proxy:[7,0,0,"-"],signature:[2,0,0,"-"],socket:[2,0,0,"-"],tests:[8,0,0,"-"],utils:[2,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","staticmethod","Python static method"],"3":["py","function","Python function"],"4":["py","attribute","Python attribute"],"5":["py","method","Python method"],"6":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:class","2":"py:staticmethod","3":"py:function","4":"py:attribute","5":"py:method","6":"py:exception"},terms:{"4d0d42f":2,"\u00b9the":2,"boolean":2,"byte":[2,3],"class":[2,3,4,5,6,7],"create_fast\u00b9":2,"default":2,"enum":[3,4],"final":3,"function":[2,3,7],"import":2,"int":2,"new":[2,7],"null":2,"public":[2,7],"return":[2,7],"static":[2,5],"tor\u00b2":2,"true":[2,3,6],"try":2,"while":2,For:2,TLS:2,The:[2,6,7],Then:2,Use:2,Will:2,__init__:2,_anonymous_cached_enum:[3,4],_anonymous_enum:[3,4],_earli:2,_view:3,accept:2,accumul:2,activ:[2,6,7],active_view:3,actual:2,add:2,addr_typ:3,address:[2,4,9],address_view:3,after:2,afterward:2,algorithm:2,all:2,alpha:0,also:0,altern:2,alwai:2,ani:[0,2,6,7],anonym:0,answer:2,anyth:0,api:[2,7],arg:[2,6,7],argument:[2,6,7],as_initi:2,associ:2,assum:2,attach:2,attempt:2,auth:[2,9],auth_challeng:[2,3],auth_dir:7,auth_typ:3,authent:[2,3],author:[0,2,3],auto_sendm:2,avail:2,avg:2,backward:2,bad:2,bandwidth:2,barrier:7,base64:2,base:[2,3,4,5,6,7],base_dir:[2,7],basic:3,batch:7,batch_queri:2,batch_siz:7,been:0,befor:2,begin:2,being:2,between:0,big:3,binari:2,bind:[2,3,7],bit:2,blob:2,block:[2,6],block_siz:5,bool:2,both:2,bound:[3,4],browser:0,buffer_s:2,build:2,bytearrai:2,byteord:3,cach:[3,9],cache_field:3,cached_uint:3,call:2,callabl:[2,6,7],can:[0,2],candid:2,cell:[2,6,7,9],cell_get_cid:2,cell_get_cmd:2,cell_get_len:2,cell_is_valid:2,cell_is_variable_length:2,cell_netinfo_build:2,cell_pad_nul:2,cell_pad_rnd:2,cell_raw:7,cell_set_cid:2,cell_slic:2,cell_slice_old:2,cell_to_str:2,cell_version_build:2,cell_version_get_cmd:2,cell_version_get_len:2,cell_version_get_vers:2,cell_version_is_valid:2,cell_view:[3,4],cert:[2,9],cert_typ:3,challeng:[2,9],channel:[6,7],channel_handl:6,channel_manag:7,channeldoesnotexistexcept:7,channelmanag:7,check:2,choos:2,chosen:2,chutnei:8,cid:[2,7],circid:2,circuit:[2,7],circuit_id:[2,3,4,7],circuitdoesnotexistexcept:7,clean:2,clerk:7,client:[0,2,6,7],client_kei:5,close:[2,6,7],cmd:[2,3,4],cmd_to_str:2,codec:3,collect:7,com:[2,7],command:2,common:[2,9],composit:3,compress:2,compressed_data:2,comput:2,compute_descriptor_digest:2,compute_path:7,compute_token:7,con:2,condit:2,connect:[2,7],connectfail:3,consensu:[7,8,9],consensus:2,consensus_fil:2,consensus_raw:2,constant:9,constraint:2,constructor:[2,6,7],consum:2,consume_descriptor:2,consume_dir_sourc:2,consume_foot:2,consume_head:2,consume_http:2,consume_rout:2,contact:2,contain:0,content:9,context:5,control_host:7,control_port:7,convert:[0,7],core:2,coroutin:7,correct:[2,7],correspond:[2,7],creat:[3,7,9],create2:[2,9],create_channel:7,create_fast:[2,9],create_view:3,created2:[2,9],created_fast:[2,9],created_view:3,criterion:2,crypto:[2,7,9],cryptograph:2,cryptographi:2,current:[2,7],daemon:[2,6],data:[2,3,4,5,7],data_nam:[3,4],data_view:[3,4],date:2,datetim:2,dead:[2,6,7],decod:2,decrypt:2,decrypt_token:7,decryptor:2,deflat:2,delai:2,delet:7,delete_channel:7,depth:2,deriv:3,descr:2,describ:2,descriptor:[7,9],destroi:[2,7,9],destroy_circuit_from_cli:7,destroy_circuit_from_link:7,detail:[2,3],dictionari:2,die:[2,6],digest:[2,3,4,5],digests_byt:2,dir:2,dir_port:7,direct:[2,7],directori:2,directory_queri:2,dispatch:7,doe:2,don:2,done:2,down:2,download:2,download_author:2,download_authority_direct:2,download_direct:2,download_raw:2,download_raw_by_digests_micro:2,download_raw_by_digests_unflavor:2,download_relay_descriptor:2,dummy_random_gen:7,early_count:2,easili:2,ed25519:2,ed_auth:3,ed_id:4,ed_signed_authent:3,ed_signed_signing_kei:3,ed_signed_tls_link:3,els:2,emitt:7,empti:7,enabl:2,encod:[2,6],encrypt:2,encryptor:2,end:2,end_of_field:2,endpoint:6,ensur:7,entri:[2,7],enumer:[3,4],equal:2,equival:2,error_non_tran:3,error_tran:3,establish:2,exampl:2,except:[2,7],exchang:2,exit:2,exit_nod:2,expand:2,expect:[2,7],experi:0,explicitli:2,expos:2,extend2:[2,3],extend2_view:4,extend:9,extended2:[2,3],extended2_view:4,extra:2,extra_field:[3,4],extract_d:2,extract_nodes_digests_micro:2,extract_nodes_digests_unflavor:2,fail_on_miss:2,failur:6,fals:[2,3],famili:2,fast:2,fast_async:2,feedback:0,fetch:[2,7],fetch_format:7,field:[2,3],field_nam:[3,4],file:2,file_nam:2,filenam:[2,7],filter:2,filter_descriptor:2,fingerprint:2,finish:3,first:[2,7],fix:2,fixed_max_length:2,fixed_s:[3,4],flag:2,flavor:[2,7],flavour:2,flow:2,follow:2,footer:2,form:2,format:2,forward:[2,9],fresh:2,from:[2,6,7],full:2,further:2,futur:7,gen_cid:7,gen_token_from_cid:7,gener:7,genpkei:7,get:[2,7,8],get_binary_signatur:2,get_channel_by_token:7,get_chutney_consensu:8,get_consensu:7,get_consensus_raw:7,get_descriptor:7,get_descriptor_unflavour:7,get_descriptors_raw:7,get_guard:7,get_hash:2,get_relay_info:7,get_signature_and_digest:2,get_signing_kei:7,get_signing_keys_info:2,get_tor:7,getpkei:7,github:2,given:[2,7],good:2,guard:[2,6,7],guess:2,h_mac:5,h_verifi:5,hand:[5,6],handl:[2,7],handler:7,handshak:[2,4,7],handshake_data:3,handshake_typ:4,has:2,hash:2,have:0,header:[2,3],header_view:[3,4],help:3,here:2,hex:2,hex_digest:2,hibern:3,high:2,higher:2,hmac:5,hop:9,host:[2,3,6,7],hostnam:[2,3],howev:[0,2],http:[2,7,9],ident:[2,4,5],identifi:[2,7],in_same_famili:2,includ:0,incom:6,increment:2,index:0,indic:2,info:7,init:3,initi:[2,7],inner:2,input:2,inspect:2,instal:0,instanc:2,integ:2,interact:0,intern:3,invalid:2,invalidauthcellexcept:7,invalidcellheaderexcept:[2,7],invalidcelllengthexcept:2,invalidcertscellexcept:7,invaliddestroycellexcept:7,invalidnetinfocellexcept:7,invalidtokenexcept:7,invalidversioncellexcept:7,invok:[2,6,7],ip_address:3,ipv4:2,ipv4_addr:3,ipv6:2,ipv6_addr:3,is_backward:4,is_circuit:4,is_control:4,is_fix:3,is_forward:4,is_vari:3,iscach:3,iscomposit:3,iseven:3,issu:0,isview:3,item:[2,3],item_view:3,its:[2,7],javascript:0,job:[2,9],karg:[3,4],kdf:[2,9],kdf_tor:5,keep:2,keep_exit:2,keep_exit_with_descr:2,keep_guard:2,keep_guard_with_descr:2,keep_middl:2,keep_middle_with_descr:2,kei:[2,5,7],kept:2,keyword:[2,6,7],kill_queu:7,known:2,kwarg:[2,3,4,6,7],l1820:2,l2069:2,l2322:2,l780:2,lambda:3,last:2,last_stream_id:2,layer:2,least:2,legacy_id:4,length:5,length_halved_view:3,let:0,level:0,librari:0,like:3,line:2,link:9,linkalreadyinitializedexcept:7,linknotinitializedexcept:7,linkspec_typ:4,linkspec_view:4,linkspecs_view:4,list:[2,3],list_field:3,list_of_poss:2,listen:7,lnn:2,load:2,local:[3,4],loop:7,loop_signal_handl:7,low:2,lowlimit:2,made:2,mai:[2,6,7],main:[2,6,7],make:0,manag:7,manual:2,map:2,master:2,match:2,materi:[3,5,6,7],max_fail:2,max_quant:3,max_queu:[2,6],meet:2,mention:2,messag:[2,5],method:[2,3,4,6,7],micro:2,microdesc:2,middl:2,min_bufs:2,minim:2,mix:2,modern:0,modul:[0,9],moment:0,more:[0,2],most:2,msg_handler:7,multipl:2,must:2,name:2,nb_worker:7,need:[2,7],negoti:2,negotiate_vers:2,netinfo:[2,9],network:[0,2],newli:2,next:2,node:[2,7],non:2,none:[2,3,4,7],nosuchservic:3,nosupportedversionexcept:7,note:2,noth:7,now:2,ntor:[2,4,7,9],ntor_async:2,ntor_handshak:2,ntor_raw2:2,ntor_raw:2,number:[2,7],obey_minimal_constraint:2,object:[2,3,5,6,7],offset:3,old:2,onc:2,one:[2,7],onion:9,onion_kei:5,onli:2,open:0,oper:3,or_conn_clos:3,or_ident:3,order:[2,7],orport:2,other_address:3,otherwis:7,our:2,out:2,outcom:6,outer:2,output_queu:7,output_s:5,overrid:[2,6,7],own:2,pack:[2,3,4],packag:9,packet:[3,4],pad:[2,9],padded_hash:2,padding_negoti:3,page:0,param:[2,7],paramet:2,parent_field:3,parent_view:3,parent_wrapp:3,pars:2,parse_address:2,parse_base64:2,parse_descriptor:2,parse_fingerprint:2,parse_param:2,parse_rang:2,parse_range_onc:2,parse_tim:2,parser:2,part:[2,9],pass:[2,6,7],password:7,path:[2,9],path_queu:7,path_select:9,path_selection_test:[2,9],payload:[2,3,4,6],peel:2,peer:[2,3],pem:2,pend:2,percentag:2,perform:[2,7],period:[2,6],pick:2,pick_good_entri:2,pick_good_entry_from_rout:2,pick_good_exit:2,pick_good_exit_from_rout:2,pick_good_middl:2,pick_good_middle_from_rout:2,pkc:2,pkcs1_v1_5:2,plaintext:2,plcp:2,pleas:0,plug:2,point:7,polici:2,poll:[2,9],port:[2,6,7],possibl:2,prefix:[2,6,7],prefix_len:7,prepar:7,present:[2,7],previou:2,previous:2,prf:5,privat:2,process:[2,7],produc:7,product:0,proper:2,properli:2,properti:2,protocol:[0,2,3],provid:[0,2,7],proxi:[0,2,9],public_kei:2,pull:2,pure:0,purg:2,put:2,pycrypto:2,python:[0,2],quantiti:3,queri:2,queue:2,rand:2,random:[2,7],randomli:2,rang:2,raw:[2,3,7],raw_con:2,raw_materi:5,realli:0,reason:[2,3],receiv:2,recogn:[2,3,4],recommend:2,recv:[2,3,6],refer:2,regist:2,relai:[2,3,7],relay_begin:4,relay_begin_dir:4,relay_connect:4,relay_data:4,relay_drop:4,relay_earli:[2,9],relay_end:4,relay_extend2:4,relay_extend:4,relay_extended2:4,relay_resolv:4,relay_sendm:4,relay_trunc:4,relay_view:4,relayinfo:[2,9],remain:2,remot:2,reorder:2,repositori:0,repres:[2,6,7],request:[0,3],requir:[0,2],research:0,reset:7,reset_link:7,resourcelimit:3,respect:[2,6,7],respons:7,retriev:[2,7],retrieve_consensu:7,retriv:7,rfc5869:5,rfc:2,rnd_gen:7,router:[2,7],rsa:2,rsa_auth:3,rsa_self_signed_ident:3,rsa_signed_authent:3,rsa_signed_ed_ident:3,rsa_signed_link_kei:3,run:[2,6,7],salt:5,same:2,sanit:2,scedul:7,schedul:7,schedule_to_send:7,scrap:2,scrap_signatur:2,script:2,search:0,second:2,see:[2,3],select:2,select_end_path_from_consensu:2,select_guard_from_consensu:2,select_path:[2,7],self:[2,3],send:[2,3,6,7],sent:7,separ:2,sequenti:[2,6,7],seri:3,serv:7,server:[2,5,7],server_kei:5,set:[2,3,7],set_channel_manag:7,set_link:7,sha1:2,shake:[5,6],share:2,should:[2,7],side:7,sign:[2,7],signatur:9,signatures_and_key_digest:2,signific:2,signum:7,simplifi:2,size:3,slave_nod:7,socket:9,socks_port:7,softwar:0,some:7,sourc:[2,3,4,5,6,7,8],spec:2,split:2,ssl:2,sslv3:2,stabl:2,standard:[2,6,7],start:[2,7],state:2,statea:2,stateb:2,statec:2,statu:2,stop:7,str:2,stream:2,stream_id:[2,3,4],stream_window:2,string:2,structur:2,subclass:[2,6,7],submodul:9,subpackag:9,subsect:2,suffix:7,support:2,tag:3,take:2,taken:[2,6,7],target:[2,6,7],tcp:0,test:[0,2,9],test_circuit:8,test_consensus_chutnei:[2,9],test_create_chutnei:[2,9],test_descriptors_chutnei:[2,9],test_directory_queri:8,test_download_author:8,test_download_microdesc:8,test_download_unflavor:8,test_extend_chutnei:[2,9],test_fast:8,test_hop_chutnei:[2,9],test_initi:8,test_keep_exit_works_with_reject_exit_polici:8,test_keep_exit_works_with_suitable_rout:8,test_link_chutnei:[2,9],test_ntor:8,test_obey_minimal_constraint_with_one_rout:8,test_path_selection_chutnei:[2,9],test_path_selection_work:8,test_pick_good_exit_returns_a_rout:8,test_select_path:8,than:0,thi:[0,2,3,6,7],third:2,thread:[2,6,7],through:2,time:2,timed:2,timeout:[2,3,7],timestamp:3,timezon:2,tls_tcp_4:4,tls_tcp_6:4,todo:2,token:7,tool:2,tor:[0,2,7],tor_process:7,torspec:2,traffic:7,transcript:2,truncat:[2,3],tupl:2,tweak:5,two:2,txt:2,type:2,type_hint:3,typenam:3,uid:7,uint:3,underli:3,unflavor:2,union:3,union_tag:3,unregist:2,until:2,untrust:0,updat:2,upon:2,usag:2,use:[0,2,7],used:[2,7],uses:[0,2],using:[0,2],utc:2,util:9,valid:[2,3,4],valu:[2,3,4],verifi:[2,7],verify_format:2,verify_kei:2,version:[2,7,9],via:2,view:[2,4,9],view_tabl:3,visit:3,vote:2,vpad:3,wait:7,wait_for_consensu:7,want:[2,7],warn:0,webpag:0,websocket:[0,2,7,9],websocketmanag:7,weight:2,weighted_random_choic:2,when:2,where:2,which:[2,7],whose:2,why:2,width:3,window:2,within:[2,3],without:2,worker:[2,6,7],wrap:2,wrapper:3,write:[0,3],x00:[3,4],you:[0,2,6,7],your:0,zlib_decompress:2},titles:["Welcome to Lightnion\u2019s documentation!","Installation","lightnion package","lightnion.cell package","lightnion.cell.relay package","lightnion.crypto package","lightnion.http package","lightnion.proxy package","lightnion.tests package","lightnion"],titleterms:{address:3,auth:7,cach:2,cell:[3,4],cert:3,challeng:3,common:3,consensu:2,constant:2,content:[2,3,4,5,6,7,8],creat:2,create2:3,create_fast:3,created2:3,created_fast:3,crypto:5,descriptor:2,destroi:3,document:0,extend2:4,extend:2,extended2:4,forward:7,hop:2,http:6,indic:0,instal:1,introduct:0,job:7,kdf:5,lightnion:[0,2,3,4,5,6,7,8,9],link:[2,7],modul:[2,3,4,5,6,7,8],netinfo:3,ntor:[5,6],onion:2,packag:[2,3,4,5,6,7,8],pad:3,part:7,path:7,path_select:2,path_selection_test:8,poll:6,proxi:7,relai:4,relay_earli:3,relayinfo:7,signatur:2,socket:2,submodul:[2,3,4,5,6,7,8],subpackag:[2,3],tabl:0,test:8,test_consensus_chutnei:8,test_create_chutnei:8,test_descriptors_chutnei:8,test_extend_chutnei:8,test_hop_chutnei:8,test_link_chutnei:8,test_path_selection_chutnei:8,util:2,version:3,view:3,websocket:6,welcom:0}}) \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..c9ef3ba --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,187 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../..')) + + +# -- Project information ----------------------------------------------------- + +project = 'Lightnion' +copyright = '2020, Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu' +author = 'Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu' + +# The short X.Y version +version = '' +# The full version, including alpha/beta/rc tags +release = '' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +#html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Lightniondoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Lightnion.tex', 'Lightnion Documentation', + 'Matthieu Daumas, Ricardo Ferreira Ribeiro, Laurent Girod, Shivram N Gowtham, Wouter Lueks, Carmela Troncoso, Chia-An Yu', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'lightnion', 'Lightnion Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Lightnion', 'Lightnion Documentation', + author, 'Lightnion', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True diff --git a/docs/source/deploy.rst b/docs/source/deploy.rst new file mode 100644 index 0000000..1758df6 --- /dev/null +++ b/docs/source/deploy.rst @@ -0,0 +1,87 @@ +========== +Deployment +========== + +**Warning:** Lightnion is an alpha-stage software which is not fit for +production at this point. + +Prerequisites +============= + +Test on local machine +--------------------- + +Any modern hardware should have enough resources to run Lightnion. Chutney can +be used to simulate a Tor network to which Lichtnion can connect. + +Test on real environment +------------------------ + +To test the Lightnion proxy in a real environment, a server with at least 1 GB +of memory and a reasonnable amount of bandwidth is needed. In the mode where +the Tor circuit is computed in the proxy 2 GB of memory are necessary. + +To function properly, the Lightnion proxy needs to interact with a Tor relay, +which will act as the guard of all Tor circuits build with Lightnion. To +install a Tor relay on your system, please refers to the `documentation from +the Tor project `, +or the documentation of your distribution. + +Also, to serve the Javascript client, encrypt, and redirect the proxy ports, +a web server like Nginx is recommended. Please refer to the documentation of +your distribution to install one. + +Installation +============ + +At this stage of the development, there still hasn't any distribution package +for Lightnion. This software needs to be deployed from sources. + +It is advised to use git to retrieve the sources.:: + $ git clone --recurse-submodules https://github.com/spring-epfl/lightnion.git + $ cd lightnion + +It is strongly advised to install Lightnion in a virtual environment.:: + $ virtualenv --python=python3 venv + $ . venv/bin/activate + +The dependances can be installed with `pip`.:: + $ pip install -r requirements.txt -r requirements-proxy.txt + +The minified bundle of the Javacript client needs to be build. A Makefile +exists to simplify its building process:: + $ cd js-client + $ make + +The resulting file `lightnion.bundle.js` can be served by a web server, and +linked in a web page. + +Web Server configuration +======================== + +To Test Lightnion, it is necessary to have a web server to dispatch the +Lightnion Javascript client. This can be done on a local macine by using +Python's HTTP server.:: + $ cd js-client/demo + $ python -m http.server + +For a test on a real environment, a proper web server like Nginx or Apache is +required. + +By default, the connection between the client and proxy server is in clear. +Ideally, this connection should be secure, and this will probably change in the +near future. + +A Typical Nginx configuration for a proxy server will look like this: + +.. literalinclude:: lightnion-nginx-tls.conf + +Automatic Startup and Process Monitoring +======================================== + +To ensure Lightnion is running, systemd or an other init system can be used to +notify the administrator and restart the process if necessary. + +.. literalinclude:: lightnion.service + +.. literalinclude:: lightnion-fail.service \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..ea6c72b --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,31 @@ +===================================== +Welcome to Lightnion's documentation! +===================================== + +Introduction +============ + +Lightnion is a JavaScript library that you can include on your webpage to let +any modern browser make anonymous requests. Lightnion uses an *untrusted* +proxy to interact with the Tor network. This proxy converts between protocols +(Websockets to pure TCP). This repository also contains a Python Lightnion Tor +client that we have been using for testing. + +**WARNING:** At the moment Lightnion is alpha-level research software. Do *not* +use it in production, or for anything that really requires anonymity. You are, +however, more than welcome to experiment with Lightnion. Please provide +feedback opening issues or writing to the authors. + + +Contents +======== + +.. toctree:: + deploy + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` \ No newline at end of file diff --git a/docs/source/lightnion-fail.service b/docs/source/lightnion-fail.service new file mode 100644 index 0000000..3e69365 --- /dev/null +++ b/docs/source/lightnion-fail.service @@ -0,0 +1,6 @@ +[Unit] +Description=Lightnion proxy failure notification + +[Service] +Type=oneshot +ExecStart=/bin/echo 'Lightnion process failed' | /usr/bin/mailx -s "Lightnion process failed" lightnion@lightning-test diff --git a/docs/source/lightnion-nginx-tls.conf b/docs/source/lightnion-nginx-tls.conf new file mode 100644 index 0000000..1f292b4 --- /dev/null +++ b/docs/source/lightnion-nginx-tls.conf @@ -0,0 +1,62 @@ +server { + root /var/www/lightnion; + index index.html; + server_name lightnion.spring-lab.ch; + + location /lightnion/api/v0.1/channels/ { + proxy_pass http://localhost:8765; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + } + + location /lightnion/ { + proxy_pass http://localhost:4990; + } + + location /guard { + proxy_pass http://localhost:4990; + } + + location /channels { + proxy_pass http://localhost:4990; + } + + location /consensus { + proxy_pass http://localhost:4990; + } + + location /descriptors { + proxy_pass http://localhost:4990; + } + + location /signing-keys { + proxy_pass http://localhost:4990; + } + + + location / { + try_files $uri $uri/ =404; + } + + listen 443 default_server ssl; + + ssl_certificate /etc/letsencrypt/live/lightnion.spring-lab.ch/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/lightnion.spring-lab.ch/privkey.pem; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + + ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS"; +} + + +server { + listen 80; + server_name lightnion.spring-lab.ch; + rewrite ^ https://$server_name$request_uri? permanent; +} diff --git a/docs/source/lightnion.cell.relay.rst b/docs/source/lightnion.cell.relay.rst new file mode 100644 index 0000000..a42094d --- /dev/null +++ b/docs/source/lightnion.cell.relay.rst @@ -0,0 +1,30 @@ +lightnion.cell.relay package +============================ + +Submodules +---------- + +lightnion.cell.relay.extend2 module +----------------------------------- + +.. automodule:: lightnion.cell.relay.extend2 + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.relay.extended2 module +------------------------------------- + +.. automodule:: lightnion.cell.relay.extended2 + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.cell.relay + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/lightnion.cell.rst b/docs/source/lightnion.cell.rst new file mode 100644 index 0000000..867233a --- /dev/null +++ b/docs/source/lightnion.cell.rst @@ -0,0 +1,133 @@ +lightnion.cell package +====================== + +Subpackages +----------- + +.. toctree:: + + lightnion.cell.relay + +Submodules +---------- + +lightnion.cell.address module +----------------------------- + +.. automodule:: lightnion.cell.address + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.certs module +--------------------------- + +.. automodule:: lightnion.cell.certs + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.challenge module +------------------------------- + +.. automodule:: lightnion.cell.challenge + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.common module +---------------------------- + +.. automodule:: lightnion.cell.common + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.create2 module +----------------------------- + +.. automodule:: lightnion.cell.create2 + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.create\_fast module +---------------------------------- + +.. automodule:: lightnion.cell.create_fast + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.created2 module +------------------------------ + +.. automodule:: lightnion.cell.created2 + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.created\_fast module +----------------------------------- + +.. automodule:: lightnion.cell.created_fast + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.destroy module +----------------------------- + +.. automodule:: lightnion.cell.destroy + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.netinfo module +----------------------------- + +.. automodule:: lightnion.cell.netinfo + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.padding module +----------------------------- + +.. automodule:: lightnion.cell.padding + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.relay\_early module +---------------------------------- + +.. automodule:: lightnion.cell.relay_early + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.versions module +------------------------------ + +.. automodule:: lightnion.cell.versions + :members: + :undoc-members: + :show-inheritance: + +lightnion.cell.view module +-------------------------- + +.. automodule:: lightnion.cell.view + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.cell + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/lightnion.crypto.rst b/docs/source/lightnion.crypto.rst new file mode 100644 index 0000000..cbec368 --- /dev/null +++ b/docs/source/lightnion.crypto.rst @@ -0,0 +1,30 @@ +lightnion.crypto package +======================== + +Submodules +---------- + +lightnion.crypto.kdf module +--------------------------- + +.. automodule:: lightnion.crypto.kdf + :members: + :undoc-members: + :show-inheritance: + +lightnion.crypto.ntor module +---------------------------- + +.. automodule:: lightnion.crypto.ntor + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.crypto + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/lightnion.http.rst b/docs/source/lightnion.http.rst new file mode 100644 index 0000000..fec8299 --- /dev/null +++ b/docs/source/lightnion.http.rst @@ -0,0 +1,38 @@ +lightnion.http package +====================== + +Submodules +---------- + +lightnion.http.ntor module +-------------------------- + +.. automodule:: lightnion.http.ntor + :members: + :undoc-members: + :show-inheritance: + +lightnion.http.polling module +----------------------------- + +.. automodule:: lightnion.http.polling + :members: + :undoc-members: + :show-inheritance: + +lightnion.http.websocket module +------------------------------- + +.. automodule:: lightnion.http.websocket + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.http + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/lightnion.proxy.rst b/docs/source/lightnion.proxy.rst new file mode 100644 index 0000000..1e24624 --- /dev/null +++ b/docs/source/lightnion.proxy.rst @@ -0,0 +1,70 @@ +lightnion.proxy package +======================= + +Submodules +---------- + +lightnion.proxy.auth module +--------------------------- + +.. automodule:: lightnion.proxy.auth + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.forward module +------------------------------ + +.. automodule:: lightnion.proxy.forward + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.jobs module +--------------------------- + +.. automodule:: lightnion.proxy.jobs + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.link module +--------------------------- + +.. automodule:: lightnion.proxy.link + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.parts module +---------------------------- + +.. automodule:: lightnion.proxy.parts + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.path module +--------------------------- + +.. automodule:: lightnion.proxy.path + :members: + :undoc-members: + :show-inheritance: + +lightnion.proxy.relayinfo module +-------------------------------- + +.. automodule:: lightnion.proxy.relayinfo + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.proxy + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/lightnion.rst b/docs/source/lightnion.rst new file mode 100644 index 0000000..c159b71 --- /dev/null +++ b/docs/source/lightnion.rst @@ -0,0 +1,129 @@ +lightnion package +================= + +Subpackages +----------- + +.. toctree:: + + lightnion.cell + lightnion.crypto + lightnion.http + lightnion.proxy + lightnion.tests + +Submodules +---------- + +lightnion.cache module +---------------------- + +.. automodule:: lightnion.cache + :members: + :undoc-members: + :show-inheritance: + +lightnion.consensus module +-------------------------- + +.. automodule:: lightnion.consensus + :members: + :undoc-members: + :show-inheritance: + +lightnion.constants module +-------------------------- + +.. automodule:: lightnion.constants + :members: + :undoc-members: + :show-inheritance: + +lightnion.create module +----------------------- + +.. automodule:: lightnion.create + :members: + :undoc-members: + :show-inheritance: + +lightnion.descriptors module +---------------------------- + +.. automodule:: lightnion.descriptors + :members: + :undoc-members: + :show-inheritance: + +lightnion.extend module +----------------------- + +.. automodule:: lightnion.extend + :members: + :undoc-members: + :show-inheritance: + +lightnion.hop module +-------------------- + +.. automodule:: lightnion.hop + :members: + :undoc-members: + :show-inheritance: + +lightnion.link module +--------------------- + +.. automodule:: lightnion.link + :members: + :undoc-members: + :show-inheritance: + +lightnion.onion module +---------------------- + +.. automodule:: lightnion.onion + :members: + :undoc-members: + :show-inheritance: + +lightnion.path\_selection module +-------------------------------- + +.. automodule:: lightnion.path_selection + :members: + :undoc-members: + :show-inheritance: + +lightnion.signature module +-------------------------- + +.. automodule:: lightnion.signature + :members: + :undoc-members: + :show-inheritance: + +lightnion.socket module +----------------------- + +.. automodule:: lightnion.socket + :members: + :undoc-members: + :show-inheritance: + +lightnion.utils module +---------------------- + +.. automodule:: lightnion.utils + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/lightnion.service b/docs/source/lightnion.service new file mode 100644 index 0000000..6d7379f --- /dev/null +++ b/docs/source/lightnion.service @@ -0,0 +1,16 @@ +[Unit] +Description=Lightnion proxy +After=network.target + +[Service] +TimeoutStopSec=2 +Restart=on-failure +RestartSec=60 +User=lightnion +Group=www-data +WorkingDirectory=/home/lightnion/lightnion +ExecStart=/home/lightnion/lightnion/venv/bin/python -m lightnion.proxy -vvv -s 127.0.0.1:9050 -c 8000 -d 9051 +OnFailure=lightnion-fail.service + +[Install] +WantedBy=multi-user.target diff --git a/docs/source/lightnion.tests.rst b/docs/source/lightnion.tests.rst new file mode 100644 index 0000000..f9fcfd9 --- /dev/null +++ b/docs/source/lightnion.tests.rst @@ -0,0 +1,78 @@ +lightnion.tests package +======================= + +Submodules +---------- + +lightnion.tests.path\_selection\_test module +-------------------------------------------- + +.. automodule:: lightnion.tests.path_selection_test + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_consensus\_chutney module +----------------------------------------------- + +.. automodule:: lightnion.tests.test_consensus_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_create\_chutney module +-------------------------------------------- + +.. automodule:: lightnion.tests.test_create_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_descriptors\_chutney module +------------------------------------------------- + +.. automodule:: lightnion.tests.test_descriptors_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_extend\_chutney module +-------------------------------------------- + +.. automodule:: lightnion.tests.test_extend_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_hop\_chutney module +----------------------------------------- + +.. automodule:: lightnion.tests.test_hop_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_link\_chutney module +------------------------------------------ + +.. automodule:: lightnion.tests.test_link_chutney + :members: + :undoc-members: + :show-inheritance: + +lightnion.tests.test\_path\_selection\_chutney module +----------------------------------------------------- + +.. automodule:: lightnion.tests.test_path_selection_chutney + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: lightnion.tests + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 0000000..95d6d08 --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,7 @@ +lightnion +========= + +.. toctree:: + :maxdepth: 4 + + lightnion From 27289a337ee9908f60a0d85709fb50decc0df53a Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 3 Mar 2020 14:41:45 +0100 Subject: [PATCH 08/30] Fix borken things. --- js-client/src/api.js | 2 +- js-client/src/endpoint.js | 2 +- js-client/src/post.js | 1 - js-client/src/signature.js | 7 ++++--- lightnion/proxy/jobs.py | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/js-client/src/api.js b/js-client/src/api.js index db3e089..6d67ea1 100644 --- a/js-client/src/api.js +++ b/js-client/src/api.js @@ -93,7 +93,7 @@ export function open(host, port, success, error, io, fast, auth, select_path, tc success: function (endpoint) { console.log('called success cb') endpoint.state = lnn.state.success - info("circuit created") + console.log("circuit created") success(endpoint) endpoint.io.success = function () { } } diff --git a/js-client/src/endpoint.js b/js-client/src/endpoint.js index 0c6ded0..72754cc 100644 --- a/js-client/src/endpoint.js +++ b/js-client/src/endpoint.js @@ -47,7 +47,7 @@ export function endpoint(host, port) { ws: ws, http: http, guard: http + "/guard", - socket: ws + "/channels", + socket: ws + "/channel", channels: http + "/channels", consensus: http + "/consensus", descriptors: http + "/descriptors", diff --git a/js-client/src/post.js b/js-client/src/post.js index fad4d56..d8385b6 100644 --- a/js-client/src/post.js +++ b/js-client/src/post.js @@ -99,7 +99,6 @@ export function circuit_info(endpoint, success, error, select_path, tcp_ports) { endpoint.path = path.select_end_path(endpoint.consensus, endpoint.descriptors, endpoint.guard, true, tcp_ports) console.log(endpoint.guard) console.log(endpoint.path) - inform("Path chosen") } if (success !== undefined) diff --git a/js-client/src/signature.js b/js-client/src/signature.js index b21d299..34f9e7f 100644 --- a/js-client/src/signature.js +++ b/js-client/src/signature.js @@ -33,7 +33,7 @@ export function verify(raw_cons, keys, minimal, flavor = 'microdesc') { throw 'The minimal percentage must be between 0 (not included) and 1' } - keys = lnn.signature.process_raw_keys(keys) + //keys = process_raw_keys(keys) let nbr_verified = 0 let total = 0 @@ -54,6 +54,7 @@ export function verify(raw_cons, keys, minimal, flavor = 'microdesc') { let key = keys[fingerprint] let e = bigInt(key["exponent"]) let n = bigInt(key["modulus"]) + let key_digest = sig_and_keys_digests[fingerprint]["signing-key-digest"] if (key === undefined || !verify_key(key["pem"], key_digest)) continue @@ -68,7 +69,7 @@ export function verify(raw_cons, keys, minimal, flavor = 'microdesc') { return nbr_verified > minimal * total } -lnn.signature.process_raw_keys = function(raw_keys) { +export function process_raw_keys(raw_keys) { var keys = {} var real_tor = true //keep false for chutney!! @@ -226,7 +227,7 @@ export function verify_key(key, key_digest) { return hash.toUpperCase() === key_digest.toUpperCase() } -lnn.signature.compute_digest = function (key) { +export function compute_digest(key) { let raw_key = key.split('\n') let b_index = raw_key.indexOf("-----BEGIN RSA PUBLIC KEY-----") let e_index = raw_key.indexOf("-----END RSA PUBLIC KEY-----") diff --git a/lightnion/proxy/jobs.py b/lightnion/proxy/jobs.py index d7adcf8..6cde3ea 100644 --- a/lightnion/proxy/jobs.py +++ b/lightnion/proxy/jobs.py @@ -276,10 +276,10 @@ async def schedule_to_send(self, cell, cid): class WebsocketManager: - prefix = base_url + '/channels/' + prefix = base_url + '/channel/' prefix_len = len(prefix) - def __init__(self, host='0.0.0.0', port=8765, timeout=60): + def __init__(self, host='127.0.0.1', port=8765, timeout=60): """ Websocket server :param host: host on which the websocket need to run. From 934870185d855586c05835b7a0eb5631c39d79d2 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Thu, 12 Mar 2020 09:44:21 +0100 Subject: [PATCH 09/30] Document deployment. --- docs/source/deploy.rst | 60 +++++++++++++++++++++++----- docs/source/lightnion-nginx-tls.conf | 2 +- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/docs/source/deploy.rst b/docs/source/deploy.rst index 1758df6..743a443 100644 --- a/docs/source/deploy.rst +++ b/docs/source/deploy.rst @@ -35,38 +35,75 @@ Installation ============ At this stage of the development, there still hasn't any distribution package -for Lightnion. This software needs to be deployed from sources. +for Lightnion. This software needs to be deployed from sources. It is +constituted of two parts, a JavaScript client and a proxy between the client +and the Tor network, which can be run either on the same server or on different +machines. It is also advised to run a hidden Tor entry point on the server to +act as the guard relay for the proxy. + + +Installation of the Proxy +------------------------- + +The proxy requires Python 3.7 or superior and the libraries listed in the files +`requirements.txt` and `requirements-proxy.txt`, which can be installed with +`pip`. The proxy was tested on Debian Buster, it likely also work on other +Linux distributions providing Python 3.7, but was not tested on them. It is advised to use git to retrieve the sources.:: $ git clone --recurse-submodules https://github.com/spring-epfl/lightnion.git $ cd lightnion -It is strongly advised to install Lightnion in a virtual environment.:: +It is strongly advised to install the Lightnion proxy in a virtual environment.:: $ virtualenv --python=python3 venv $ . venv/bin/activate The dependances can be installed with `pip`.:: $ pip install -r requirements.txt -r requirements-proxy.txt +To work, the proxy needs to interact with a tor relay, which will be the entry +point in the tor network. Therefore it is adviseable to install a hidden Tor +relay on the machine. To do so, refer to the +`Tor documentation `. + +Installing Chutney (for testing locally) +---------------------------------------- + + + +Building the JavaScript Client +------------------------------ + The minified bundle of the Javacript client needs to be build. A Makefile exists to simplify its building process:: $ cd js-client $ make -The resulting file `lightnion.bundle.js` can be served by a web server, and -linked in a web page. +The resulting file `lightnion.bundle.js` is a bundle containing Lightnion and +all its dependancies. It can be served by a web server, and linked in a web +page as any other JS library. -Web Server configuration -======================== -To Test Lightnion, it is necessary to have a web server to dispatch the -Lightnion Javascript client. This can be done on a local macine by using +Testing Lightnion Locally +========================= + +To Test Lightnion locally, it is necessary to run a local web server to +dispatch the Lightnion Javascript client. This can be done easilly with Python's HTTP server.:: $ cd js-client/demo - $ python -m http.server + $ python -m http.server + +then the proxy can be started with::: + $ source env/bin/activate + (venv)$ python -m lightnion.proxy -vvv -s 127.0.0.1:9050 -c 8000 -d 9051 + + +Web Server configuration +======================== For a test on a real environment, a proper web server like Nginx or Apache is -required. +required, and the demo files copied to the root directory of the web server +along with the Lightnion bundle. By default, the connection between the client and proxy server is in clear. Ideally, this connection should be secure, and this will probably change in the @@ -76,6 +113,7 @@ A Typical Nginx configuration for a proxy server will look like this: .. literalinclude:: lightnion-nginx-tls.conf + Automatic Startup and Process Monitoring ======================================== @@ -84,4 +122,4 @@ notify the administrator and restart the process if necessary. .. literalinclude:: lightnion.service -.. literalinclude:: lightnion-fail.service \ No newline at end of file +.. literalinclude:: lightnion-fail.service diff --git a/docs/source/lightnion-nginx-tls.conf b/docs/source/lightnion-nginx-tls.conf index 1f292b4..9604c70 100644 --- a/docs/source/lightnion-nginx-tls.conf +++ b/docs/source/lightnion-nginx-tls.conf @@ -3,7 +3,7 @@ server { index index.html; server_name lightnion.spring-lab.ch; - location /lightnion/api/v0.1/channels/ { + location /lightnion/api/v0.1/channel/ { proxy_pass http://localhost:8765; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; From 8a1feb3f0fcff5361f440e766f04f5c66e5930bc Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Thu, 12 Mar 2020 13:58:08 +0100 Subject: [PATCH 10/30] Add readthedocs config. --- .readthedocs.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..f1b0768 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,10 @@ +version: 2 + +sphinx: + configuration: docs/conf.py + +formats: all + +python: + version: 3.7 + From 38e8a5f963165fbfe86687a704e4ca05adbed7cf Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Thu, 12 Mar 2020 14:17:55 +0100 Subject: [PATCH 11/30] Correct rtd configuration. --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index f1b0768..d33fdbc 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,7 +1,7 @@ version: 2 sphinx: - configuration: docs/conf.py + configuration: docs/source/conf.py formats: all From 7ddd527f275556549c48fd1eca8d6d43abef7018 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 24 Mar 2020 10:18:22 +0100 Subject: [PATCH 12/30] Remove most of client code. --- .gitmodules | 3 - lightnion/extend.py | 44 ------- lightnion/hop.py | 228 ------------------------------------ lightnion/http/__init__.py | 109 ----------------- lightnion/http/ntor.py | 24 ---- lightnion/http/polling.py | 114 ------------------ lightnion/http/websocket.py | 128 -------------------- lightnion/link.py | 220 ---------------------------------- lightnion/socket.py | 211 --------------------------------- stem | 1 - stem-client | 1 - 11 files changed, 1083 deletions(-) delete mode 100644 lightnion/extend.py delete mode 100644 lightnion/hop.py delete mode 100644 lightnion/http/__init__.py delete mode 100644 lightnion/http/ntor.py delete mode 100644 lightnion/http/polling.py delete mode 100644 lightnion/http/websocket.py delete mode 100644 lightnion/link.py delete mode 100644 lightnion/socket.py delete mode 120000 stem delete mode 160000 stem-client diff --git a/.gitmodules b/.gitmodules index 36fc970..359f3e3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "stem"] - path = stem-client - url = https://git.torproject.org/stem.git [submodule "js-client/vendor/sjcl"] path = js-client/vendor/sjcl url = https://github.com/bitwiseshiftleft/sjcl.git diff --git a/lightnion/extend.py b/lightnion/extend.py deleted file mode 100644 index f73d967..0000000 --- a/lightnion/extend.py +++ /dev/null @@ -1,44 +0,0 @@ -import random -import base64 -import io - -import nacl.public - -import lightnion as lnn - -def circuit(state, descriptor): - onion_key = base64.b64decode(descriptor['ntor-onion-key'] + '====') - eidentity = descriptor['identity']['master-key'] # (assuming ed25519 here) - identity = base64.b64decode(descriptor['router']['identity'] + '====') - addr = descriptor['router']['address'] - port = descriptor['router']['orport'] - - eph_key, hdata = lnn.crypto.ntor.hand(identity, onion_key) - - payload = lnn.cell.relay.extend2.pack( - hdata, [(addr, port)], [identity, eidentity]) - - state = lnn.hop.send(state, - lnn.cell.relay.cmd.RELAY_EXTEND2, payload.raw, stream_id=0) - - state, cells = lnn.hop.recv(state, once=True) - if not len(cells) == 1: - raise RuntimeError('Expected exactly one cell, got: {}'.format(cells)) - - if not cells[0].relay.cmd == lnn.cell.relay.cmd.RELAY_EXTENDED2: - raise RuntimeError('Expected EXTENDED2, got {} here: {}'.format( - cells[0].relay.cmd, cell.relay.truncated)) - - payload = lnn.cell.relay.extended2.payload(cells[0].relay.data) - if not payload.valid: - raise RuntimeError('Invalid EXTENDED2 payload: {}'.format( - payload.truncated)) - - raw_material = lnn.crypto.ntor.shake(eph_key, payload.data, identity, - onion_key, length=92) - - material = lnn.crypto.ntor.kdf(raw_material) - extended = lnn.create.circuit(state.circuit.id, material) - - state.wrap(lnn.onion.state(state.link, extended)) - return state diff --git a/lightnion/hop.py b/lightnion/hop.py deleted file mode 100644 index 5797f95..0000000 --- a/lightnion/hop.py +++ /dev/null @@ -1,228 +0,0 @@ -import zlib -import time -import queue - -import lightnion as lnn - -def recv(state, block=True, once=False, auto_sendme=True): - '''Receive one or more RELAY{_EARLY,} cells from `state` attached circuit. - - :param state: a state object (see onion.state) - :param bool block: block while receiving? (default: True) - :param bool block: attempt only receiving once? (default: False) - - :returns: a tuple (updated state, received RELAY{_EARLY,} cells) - - Notes: - - returns an updated state that *MUST* be used afterwards. - - non-RELAY{_EARLY,} cells within the circuit *may be reordered.* - ''' - - while True: - try: - payload = state.link.get(circuit=state.circuit, block=block) - except queue.Empty: - return state, [] - except KeyError: - raise RuntimeError('Circuit got destroyed, reason: {}'.format( - state.circuit.reason)) - - header = lnn.cell.header(payload) - if header.cmd in [lnn.cell.cmd.RELAY, lnn.cell.cmd.RELAY_EARLY]: - break - - state.link.put(state.circuit, payload) - - cell_type = lnn.cell.relay.cell - if header.cmd is lnn.cell.cmd.RELAY_EARLY: - cell_type = lnn.cell.relay_early.cell - - cell = cell_type(payload) - #import pdb - #pdb.set_trace() - #if not cell.valid: - # raise RuntimeError( - # 'Got invalid (encrypted) RELAY cell: {}'.format(cell.raw)) - - state, cell = lnn.onion.peel(state, cell) - if not cell.valid: - raise RuntimeError( - 'Got invalid (decrypted) RELAY cell: {}'.format(cell.raw)) - - if auto_sendme: - state = _auto_sendme(state, cell) - - cells = [cell] - while not once: - state, new_cells = recv(state, block=False, once=True) - if len(new_cells) == 0: - break - cells += new_cells - return state, cells - -# TODO: better sendme handling -def _auto_sendme(state, cell): - if not cell.relay.cmd == lnn.cell.relay.cmd.RELAY_DATA: - return state - link, circuit, flow = state.link, state.circuit, lnn.constants.flow - - # Circuit-level sendme - # - if circuit.window is None: - circuit.window = flow.circuit.default - - circuit.window -= 1 - if circuit.window < flow.circuit.lowlimit: - circuit.window += flow.circuit.increment - state = send(state, lnn.cell.relay.cmd.RELAY_SENDME) - - # Stream-level sendme - # - if not cell.relay.stream_id > 0: - return state - - if circuit.stream_windows is None: - circuit.stream_windows = dict() - - if not cell.relay.stream_id in circuit.stream_windows: - circuit.stream_windows[cell.relay.stream_id] = flow.stream.default - - circuit.stream_windows[cell.relay.stream_id] -= 1 - if not circuit.stream_windows[cell.relay.stream_id] < flow.stream.lowlimit: - return state - - circuit.stream_windows[cell.relay.stream_id] += flow.stream.increment - state = send(state, lnn.cell.relay.cmd.RELAY_SENDME, - stream_id=cell.relay.stream_id) - - return state - -def send(state, command, payload=b'', stream_id=0): - '''Send one RELAY{_EARLY,} cell through `state` attached circuit. - - :param state: a state object (see onion.state) - :param str command: RELAY{_EARLY,} cell command (see cell.relay.cmd) - :param bytes payload: RELAY{_EARLY,} cell content (default: b'') - :param int stream_id: RELAY{_EARLY,} stream ID (default: 0) - - :returns: an updated state - - *Note: returns an updated state that *MUST* be used afterwards.* - ''' - - # We build our onion - state, cell = lnn.onion.build(state, command, payload, stream_id) - - # Then, we send the encrypted payload. - state.link.send(cell) - return state - -directory_request = '\r\n'.join(( - 'GET {query} HTTP/1.0', - 'Accept-Encoding: {compression}', - )) + '\r\n\r\n' - -def directory_query( - state, - query=None, - compression='deflate', - timeout=30, - **kwargs): - if compression not in ['identity', 'deflate', 'gzip']: - raise NotImplementedError( - 'Compression method "{}" not supported.'.format(compression)) - - if query is None: - query = '/tor/status-vote/current/consensus' - if not query.startswith('/tor/') or any([c in query for c in ' \r\n']): - raise RuntimeError('Invalid query: {}'.format(query)) - - state.circuit.last_stream_id += 1 - stream_id = state.circuit.last_stream_id - - state = send( - state, lnn.cell.relay.cmd.RELAY_BEGIN_DIR, stream_id=stream_id) - state, cells = recv(state) - - if not cells[0].relay.cmd == lnn.cell.relay.cmd.RELAY_CONNECTED: - raise RuntimeError('Expecting RELAY_CONNECTED after RELAY_BEGIN_DIR,' - + ' got {} in cell:'.format(cells[0].relay.cmd, cells[0].raw)) - - - http = directory_request.format(query=query, compression=compression) - - http = bytes(http, 'utf8') - width = lnn.cell.relay.payload_len - while len(http) > 0: - chunk, http = http[:width], http[width:] - state = send(state, lnn.cell.relay.cmd.RELAY_DATA, chunk, - stream_id=stream_id) - - # TODO: proper support for RELAY_END reasons - state, cells = recv(state) - if lnn.cell.relay.cmd.RELAY_END not in [c.relay.cmd for c in cells]: - candidates = [] - diff_time = time.time() - while True: - if time.time() - diff_time > timeout: - break - - state, new_cells = recv(state, block=False) - candidates = [c.relay.cmd for c in new_cells] - cells += new_cells - - if lnn.cell.relay.cmd.RELAY_END in candidates: - break - - if len(candidates) > 0: - diff_time = time.time() - - if time.time() - diff_time > timeout: - raise RuntimeError( - 'Timeout while expecting RELAY_END: {:.2f}s out of {}s'.format( - time.time() - diff_time, timeout)) - - # TODO: proper support for incoming RELAY_SENDME cells - cells = [c for c in cells if not (c.relay.stream_id == 0 - and c.relay.cmd == lnn.cell.relay.cmd.RELAY_SENDME)] - - # TODO: proper support for concurrent streams on the same circuit - if not all([c.relay.stream_id == stream_id for c in cells]): - raise RuntimeError('No proper support for multiple stream!') - - content = b'' - for cell in cells: - if not cell.relay.cmd == lnn.cell.relay.cmd.RELAY_DATA: - continue - content += cell.relay.data - - if compression in ['deflate', 'gzip']: - http_headers, compressed_data = content.split(b'\r\n\r\n', 1) - raw_data = zlib_decompress(compressed_data) - content = http_headers + b'\r\n\r\n' + raw_data - - if not content.startswith(b'HTTP/1.0'): - raise RuntimeError('Unexpected answer to query "{}": {}'.format(query, - content)) - - return state, content - -def zlib_decompress(compressed_data, min_bufsize=32): - data = b'' - buff = b'' - part = None - ilen = len(compressed_data) - olen = 0 - zobj = zlib.decompressobj() - while part is None or len(part) > 0: - buff = zobj.unconsumed_tail - if len(buff) < 1: - nlen = max((len(data) + ilen) // 2, min_bufsize) - buff = compressed_data[olen:nlen] - if len(buff) < 1: - break - - olen += len(buff) - part = zobj.decompress(buff, zlib.MAX_WBITS | 32) - data += part - return data diff --git a/lightnion/http/__init__.py b/lightnion/http/__init__.py deleted file mode 100644 index 1f3ebfe..0000000 --- a/lightnion/http/__init__.py +++ /dev/null @@ -1,109 +0,0 @@ -import collections -import requests -import json - -headers = {'Content-Type': 'application/json'} - -import lightnion as lnn -import lightnion.proxy - -from . import polling, websocket, ntor - -class channel(collections.namedtuple('channel', - ['id', 'guard', 'middle', 'exit'])): - pass - -def client(host, port=80, *, io, prefix='http', failures=5, **kwargs): - base_url = '{}://{}:{}{}'.format(prefix, host, port, lnn.proxy.base_url) - - guard = None - try: - code = 503 - fails = 0 - for _ in range(failures): - rq = requests.get(base_url + '/guard') - if not rq.status_code in [200, 503]: - raise RuntimeError('Error code: {}'.format(rq.status_code)) - - code = rq.status_code - if fails > failures or not code == 503: - break - - fails += 1 - - if code == 503: - raise RuntimeError('Too many failures!') - - guard = json.loads(rq.text) - - except BaseException as e: - raise RuntimeError( - 'Unable retrieve guard at endpoint {}, reason: {}'.format( - base_url + '/guard', e)) - - handshake, material, uid, path = (None, None, None, None) - try: - code = 503 - fails = 0 - for _ in range(failures): - handshake, material = ntor.hand(guard) - data = json.dumps(dict(ntor=handshake)) - - rq = requests.post(base_url + '/channels', - data=data, headers=headers) - if not rq.status_code in [201, 503]: - raise RuntimeError('Error code: {}'.format(rq.status_code)) - - code = rq.status_code - if fails > failures or not code == 503: - break - - fails += 1 - - if code == 503: - raise RuntimeError('Too many failures!') - - data = json.loads(rq.text) - uid, handshake, path = data['id'], data['ntor'], data['path'] - - except BaseException as e: - raise RuntimeError( - 'Unable create channel at endpoint {}, reason: {}'.format( - base_url + '/channels', e)) - - state = None - try: - try: - handshake = ntor.shake(handshake, material) - except TypeError: - raise RuntimeError('Invalid ntor cryptographic material?') - - io = io(endpoint=base_url + '/channels/' + uid, **kwargs) - link = lnn.link.link(io, version='http') - - circuit = lnn.create.circuit(lnn.proxy.fake_circuit_id, handshake) - link.register(circuit) - - state = lnn.onion.state(link, circuit) - - except BaseException as e: - raise RuntimeError( - 'Unable craft local state with {}, reason: {}'.format(io, e)) - - try: - state = lnn.extend.circuit(state, path[0]) - - except BaseException as e: - raise RuntimeError( - 'Unable extend the circuit to middle node {}, reason: {}'.format( - path[0]['router']['nickname'], e)) - - try: - state = lnn.extend.circuit(state, path[1]) - - except BaseException as e: - raise RuntimeError( - 'Unable extend the circuit to exit node {}, reason: {}'.format( - path[0]['router']['nickname'], e)) - - return state, channel(uid, guard, path[0], path[1]) diff --git a/lightnion/http/ntor.py b/lightnion/http/ntor.py deleted file mode 100644 index 8824f4b..0000000 --- a/lightnion/http/ntor.py +++ /dev/null @@ -1,24 +0,0 @@ -import lightnion as lnn - -import nacl.public - -import base64 - -def hand(guard, encode=True): - identity = base64.b64decode(guard['router']['identity'] + '====') - onion_key = base64.b64decode(guard['ntor-onion-key'] + '====') - - ephemeral_key, payload = lnn.crypto.ntor.hand(identity, onion_key) - - if encode: - payload = str(base64.b64encode(payload), 'utf8') - return payload, (onion_key, ephemeral_key, identity) - -def shake(payload, material): - payload = base64.b64decode(payload) - onion_key, ephemeral_key, identity = material - - material = lnn.crypto.ntor.shake(ephemeral_key, payload, - identity, onion_key, length=92) - - return lnn.crypto.ntor.kdf(material) diff --git a/lightnion/http/polling.py b/lightnion/http/polling.py deleted file mode 100644 index 3acd286..0000000 --- a/lightnion/http/polling.py +++ /dev/null @@ -1,114 +0,0 @@ -import threading -import requests -import base64 -import queue -import json -import time - -from .. import http -from .. import proxy - -class worker(threading.Thread): - def __init__(self, endpoint, period, max_queue=2048): - super().__init__() - self.endpoint = endpoint - self.period = period - - self.send_queue = queue.Queue(max_queue) - self.recv_queue = queue.Queue(max_queue) - - self.dead = False - - def close(self): - requests.delete(self.endpoint) - self.dead = True - - def die(self, e): - if self.dead: - return - - self.close() - raise e - - def send(self, cell, block=True): - try: - cell = cell.raw - except AttributeError: - pass - - cell = base64.b64encode(cell) - self.send_queue.put(cell, block) - - def recv(self, block=True): - payload = self.recv_queue.get(block=block) - payload = base64.b64decode(payload) - return payload - - def main(self): - try: - cells = [] - for _ in range(proxy.jobs.request_max_cells): - try: - cells.append(self.send_queue.get(block=False)) - except queue.Empty as e: - if len(cells) == 0: - raise e - - data = json.dumps( - dict(cells=[str(cell, 'utf8') for cell in cells])) - - rq = requests.post(self.endpoint, data=data, headers=http.headers) - if not rq.status_code == 201: - raise RuntimeError( - 'Got {} status (send)!'.format(rq.status_code)) - - answer = json.loads(rq.text) - for cell in answer['cells']: - self.recv_queue.put(cell) - - return - except queue.Empty: - pass - - data = json.dumps(dict(cells=[])) - rq = requests.post(self.endpoint, data=data, headers=http.headers) - if not rq.status_code == 201: - raise RuntimeError('Got {} status! (recv)'.format(rq.status_code)) - - answer = json.loads(rq.text) - for cell in answer['cells']: - self.recv_queue.put(cell) - - time.sleep(self.period) - - def run(self): - try: - while not self.dead: - self.main() - self.dead = True - except BaseException as e: - self.die(e) - -class io: - _join_timeout = 3 - - def __init__(self, endpoint, period=0.1, daemon=True, max_queue=2048): - self.worker = worker(endpoint, period, max_queue) - if daemon: - self.worker.daemon = True - - self.worker.start() - - @property - def dead(self): - return self.worker.dead - - def recv(self, block=True): - return self.worker.recv(block) - - def send(self, payload, block=True): - self.worker.send(payload, block=block) - - def close(self): - self.worker.close() - self.worker.join(self._join_timeout) diff --git a/lightnion/http/websocket.py b/lightnion/http/websocket.py deleted file mode 100644 index fe1d689..0000000 --- a/lightnion/http/websocket.py +++ /dev/null @@ -1,128 +0,0 @@ -import websockets -import threading -import logging -import asyncio -import queue - -from .. import http -from .. import proxy - -async def incoming(websocket, worker): - cell = None - while True: - try: - if cell is None: - cell = await websocket.recv() - worker.recv_queue.put_nowait(cell) - cell = None - - await asyncio.sleep(0) - continue - except (asyncio.QueueEmpty, queue.Full): - pass - - await asyncio.sleep(worker.period) - -async def outcoming(websocket, worker): - cell = None - while True: - try: - if cell is None: - cell = worker.send_queue.get_nowait() - await websocket.send(cell) - cell = None - - await asyncio.sleep(0) - continue - except (asyncio.QueueFull, queue.Empty): - pass - - await asyncio.sleep(worker.period) - -async def channel_handler(websocket, worker): - for task in [incoming, outcoming]: - worker.tasks.append(asyncio.ensure_future(task(websocket, worker))) - - done, pending = await asyncio.wait(worker.tasks, - return_when=asyncio.FIRST_COMPLETED) - - for task in pending: - task.cancel() - worker.dead = True - -async def client(worker): - async with websockets.connect(worker.endpoint) as websocket: - await channel_handler(websocket, worker) - -class worker(threading.Thread): - def __init__(self, endpoint, period, max_queue=2048): - super().__init__() - self.endpoint = endpoint - self.period = period - max_queue = max_queue // 2 - - self.send_queue = queue.Queue(max_queue) - self.recv_queue = queue.Queue(max_queue) - - self.send_async = asyncio.Queue(max_queue) - self.recv_async = asyncio.Queue(max_queue) - - self.tasks = [] - self.dead = False - - def close(self): - for task in self.tasks: - task.cancel() - self.dead = True - - def die(self, e): - if self.dead: - return - - self.close() - raise e - - def send(self, cell, block=True): - try: - cell = cell.raw - except AttributeError: - pass - - self.send_queue.put(cell, block) - - def recv(self, block=True): - payload = self.recv_queue.get(block=block) - return payload - - def run(self): - logging.getLogger(websockets.__name__).setLevel(logging.ERROR) - asyncio.set_event_loop(asyncio.new_event_loop()) - - asyncio.get_event_loop().run_until_complete(client(self)) - -class io: - _join_timeout = 3 - - def __init__(self, endpoint, period=0.1, daemon=True, max_queue=2048): - endpoint = endpoint.replace('http', 'ws') - endpoint = endpoint.replace(':4990/', ':8765/') # TODO: work same port - - self.worker = worker(endpoint, period, max_queue) - if daemon: - self.worker.daemon = True - - self.worker.start() - - @property - def dead(self): - return self.worker.dead - - def recv(self, block=True): - return self.worker.recv(block) - - def send(self, payload, block=True): - self.worker.send(payload, block=block) - - def close(self): - self.worker.close() - self.worker.join(self._join_timeout) diff --git a/lightnion/link.py b/lightnion/link.py deleted file mode 100644 index b216777..0000000 --- a/lightnion/link.py +++ /dev/null @@ -1,220 +0,0 @@ -import logging -import socket -import queue -import ssl - -import lightnion as lnn - -class link: - """An established Tor link, send and receive messages in separate threads. - - :param io: socket.io instance that wraps the TLS/SSLv3 connection - :param int version: link version - - Usage:: - - >>> import lightnion as lnn - >>> link = lnn.link.initiate('127.0.0.1', 5000) - >>> link.version - 5 - >>> link.send(lnn.cell.create_fast.pack(2**31)) - >>> lnn.cell.created_fast.cell(link.get(circuit_id=2**31)).valid - True - >>> link.close() - """ - def __init__(self, io, version, circuits=[0], max_queue=2048): - self.max_queue = 2048 - self.version = version - self.last_id = 0 - self.io = io - - self.circuits = dict() - self.register(lnn.create.circuit(0, None)) - - def pull(self, block=True): - try: - payload = self.io.recv(block=block) - except queue.Empty: - return False - - # We know that receiver.get() will give you a cell with a well-formed - # header, thus we do not validate it one more time. - # - # We doesn't handle VERSIONS cells with shorter circuit_id. - # - header = lnn.cell.header(payload) - if not header.circuit_id in self.circuits: - raise RuntimeError('Got circuit {} outside {}, cell: {}'.format( - header.circuit_id, list(self.circuits), payload)) - - # TODO: property handle DESTROY cells - circuit = self.circuits[header.circuit_id] - if header.cmd is lnn.cell.cmd.DESTROY: - cell = lnn.cell.destroy.cell(payload) - if not cell.valid: - raise RuntimeError('Got invalid DESTROY cell: {}'.format( - cell.truncated)) - - self.put(circuit, payload) - circuit.destroyed = True - circuit.reason = cell.reason - self.unregister(circuit) - logging.debug('Circuit {} got destroyed, reason: {}'.format( - circuit.id, circuit.reason)) - return False - - self.put(circuit, payload) - return True - - def put(self, circuit, payload): - circuits_size = sum([c.queue.qsize() for _, c in self.circuits.items()]) - if circuits_size > self.max_queue: - raise RuntimeError( - 'Link circuit queues are full: {}'.format(circuits_size)) - - if circuit.id not in self.circuits: - raise RuntimeError('Got circuit_id {} outside {}, cell: {}'.format( - circuit.id, list(self.circuits), payload)) - - try: - payload = payload.raw - except AttributeError: - pass - - self.circuits[circuit.id].put(payload) - - def get(self, circuit, block=True): - while block and not self.io.dead: - try: - return self.circuits[circuit.id].get(block=False) - except queue.Empty: - pass - - self.pull() - while self.pull(block=False): - pass - else: - if not self.io.dead: - while self.pull(block=False): - pass - return self.circuits[circuit.id].get(block=False) - raise RuntimeError('Seems that link.io is dead!') - - def register(self, circuit): - if circuit.id in self.circuits: - raise RuntimeError('Circuit {} already registered.'.format( - circuit.id)) - - circuit.queue = queue.Queue(maxsize=self.max_queue) - self.circuits[circuit.id] = circuit - - def unregister(self, circuit): - del self.circuits[circuit.id] - - def recv(self, block=True): - return self.io.recv(block=block) - - def send(self, cell, block=True): - self.io.send(cell, block=block) - - def close(self): - self.io.close() - -def negotiate_version(peer, versions, *, as_initiator): - """Performs a VERSIONS negotiation - - :param peer: ssl.socket instance. - :param list versions: target link versions. - :param bool as_initiator: send VERSIONS cell first. - """ - if as_initiator: - lnn.cell.versions.send(peer, lnn.cell.versions.pack(versions)) - vercell = lnn.cell.versions.recv(peer) - - common_versions = list(set(vercell.versions).intersection(versions)) - if len(common_versions) < 1: - raise RuntimeError('No common supported versions: {} and {}'.format( - list(vercell.versions), versions)) - - version = max(common_versions) - if version < 4: - raise RuntimeError('No support for version 3 or lower, got {}').format( - version) - - if not as_initiator: - lnn.cell.versions.send(peer, lnn.cell.versions.pack(versions)) - return version - -def initiate(address='127.0.0.1', port=9050, versions=[4, 5]): - """Establish a link with the "in-protocol" (v3) handshake as initiator - - The expected transcript is: - - Onion Proxy (client) Onion Router (server) - - / [1] :-------- VERSIONS ---------> [2] - | [4] <-------- VERSIONS ---------: [3] - | - | Negotiated Version - | - | [4] <--------- CERTS -----------: [3] - | <----- AUTH_CHALLENGE ------: - | <-------- NETINFO ----------: - | - | OP don't need to - Link | authenticate - Protocol | - >= 3 | [5] :-------- NETINFO ----------> [6] - | - | Alternative: - | ( We (OR) authenticate ) - | ( ) - | ( [5] :--------- CERTS -----------> [6] ) - | ( :------ AUTHENTICATE -------> ) - | ( ^ ) - | ( (answers AUTH_CHALLENGE) ) - | ( ) - \ - - :param str address: remote relay address (default: 127.0.0.1). - :param int port: remote relay ORPort (default: 9050). - :param list versions: target link versions (default: [4, 5]). - - :returns: a link.link object - - """ - - # Setup context - peer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ctxt = ssl.SSLContext(ssl.PROTOCOL_TLS) - - # https://trac.torproject.org/projects/tor/ticket/28616 - ctxt.options |= ssl.OP_NO_TLSv1_3 - - # Establish connection - peer = ctxt.wrap_socket(peer) - peer.connect((address, port)) - - # VERSIONS handshake - version = negotiate_version(peer, versions, as_initiator=True) - - # Wraps with socket.io - peer = lnn.socket.io(peer) - - # Get CERTS, AUTH_CHALLENGE and NETINFO cells afterwards - certs_cell = lnn.cell.certs.cell(peer.recv()) - auth_cell = lnn.cell.challenge.cell(peer.recv()) - netinfo_cell = lnn.cell.netinfo.cell(peer.recv()) - - # Sanity checks - if not certs_cell.valid: - raise RuntimeError('Invalid CERTS cell: {}'.format(certs_cell.raw)) - if not auth_cell.valid: - raise RuntimeError('Invalid AUTH_CHALLENGE cell:{}'.format( - auth_cell.raw)) - if not netinfo_cell.valid: - raise RuntimeError('Invalid NETINFO cell: {}'.format(netinfo_cell.raw)) - - # Send our NETINFO to say "we don't want to authenticate" - peer.send(lnn.cell.netinfo.pack(address)) - return link(peer, version) diff --git a/lightnion/socket.py b/lightnion/socket.py deleted file mode 100644 index 43d379b..0000000 --- a/lightnion/socket.py +++ /dev/null @@ -1,211 +0,0 @@ -import lightnion as lnn - -import threading -import socket -import queue -import ssl - -# TODO: Better network handling? - -class _stat_peer: - def __init__(self, peer): - self.peer = peer - - self._kbout = 0 - self._kbin = 0 - - def disp(self): - print('Traffic: {:.2f} up {:.2f} down'.format( - self._kbout, self._kbin), end='\r') - - def recv(self, size): - data = self.peer.recv(size) - self._kbin += len(data) / 1000 - self.disp() - return data - - def send(self, data): - bytes_send = self.peer.send(data) - self._kbout += bytes_send / 1000 - self.disp() - return bytes_send - - def sendall(self, data): - bytes_send = self.peer.sendall(data) - self._kbout += bytes_send / 1000 - self.disp() - return bytes_send - - def get_channel_binding(self, *kargs): - return self.peer.get_channel_binding(*kargs) - - def close(self): - return self.peer.close() - -def cell_slice(payload, once=False): - cell_header = lnn.cell.header(payload) - if len(payload) < cell_header.width: # (payload too small, need data) - return [], payload, True - - if not cell_header.valid: - raise RuntimeError('Invalid cell header: {}'.format(cell_header.raw)) - - length = cell_header.width + lnn.constants.payload_len - if not cell_header.cmd.is_fixed: - cell_header = lnn.cell.header_variable(payload) - if len(payload) < cell_header.width: # (payload too small, need data) - return [], payload, True - - if not cell_header.valid: - raise RuntimeError( - 'Invalid variable cell header: {}'.format(cell_header.raw)) - - length = cell_header.width + cell_header.length - - if length > lnn.constants.max_payload_len: - raise RuntimeError('Invalid cell length: {}'.format(length)) - - if len(payload) < length: - return [], payload, True - - cells = [payload[:length]] - payload = payload[length:] - celling = False - - if once: - return cells, payload, celling - - while not celling and len(payload) > 0: - new_cells, payload, celling = cell_slice(payload, once=True) - cells += new_cells - return cells, payload, celling - -class worker(threading.Thread): - def __init__(self, peer, max_fails=32, max_queue=2048, buffer_size=4096): - super().__init__() - - self.buffer_size = buffer_size - self.max_queue = max_queue - self.max_fails = max_fails - self.peer = peer - - self.cell_queue = queue.Queue(max_queue) - self.send_queue = queue.Queue(max_queue) - self.recv_queue = queue.Queue(max_queue) - self.sending = b'' - self.recving = b'' - self.celling = False - self.fails = 0 - self.dead = False - - def close(self): - self.peer.close() - self.dead = True - - def die(self, e): - if self.dead: - return - - self.close() - raise e - - def send(self, cell, block=True): - self.send_queue.put(lnn.cell.pad(cell), block=block) - - def recv(self, block=True): - return self.cell_queue.get(block=block) - - def main(self): - if self.fails > self.max_fails: - cells, _, _ = cell_slice(self.recving) - for cell in cells: - self.cell_queue.put(cell) - self.die(RuntimeError('Too many fails, is the socket dead?')) - - try: - if len(self.sending) < 1: - self.sending = self.send_queue.get(block=False) - except queue.Empty: - pass - - try: - if len(self.sending) > 0: - nbytes = self.peer.send(self.sending) - self.fails = self.fails + 1 if nbytes == 0 else 0 - self.sending = self.sending[nbytes:] - return - except (socket.timeout, ssl.SSLError, BlockingIOError): - pass - - try: - payload = self.peer.recv(self.buffer_size) - self.fails = self.fails + 1 if len(payload) == 0 else 0 - self.recv_queue.put(payload) - if self.recv_queue.qsize() < self.max_queue // 4: - return - except (socket.timeout, ssl.SSLError, BlockingIOError): - pass - - try: - if ((len(self.recving) < 1 or self.celling) - and len(self.recving) <= lnn.constants.max_payload_len): - self.recving += self.recv_queue.get(block=False) - self.celling = False - except queue.Empty: - pass - - if len(self.recving) > 0 and not self.celling: - cells, self.recving, self.celling = cell_slice(self.recving) - for cell in cells: - self.cell_queue.put(cell) - - def run(self): - try: - while not self.dead: - self.main() - self.dead = True - except BaseException as e: - self.die(e) - -class io: - _join_timeout = 3 - - def __init__(self, - peer, - daemon=True, - period=0.01, - max_fails=32, - max_queue=2048, - buffer_size=4096): - peer.settimeout(period) - # peer = _stat_peer(peer) # uncomment for extra statistics - - self.worker = worker(peer, max_fails, max_queue, buffer_size) - if daemon: - self.worker.daemon = True - - self.worker.start() - self.peer = peer - - @property - def dead(self): - return self.worker.dead - - @property - def pending(self): - return self.worker.cell_queue.qsize() - - def recv(self, block=True): - return self.worker.recv(block) - - def send(self, payload, block=True): - self.worker.send(payload, block=block) - - def binding(self): - return self.peer.get_channel_binding() - - def close(self): - self.peer.close() - - self.worker.close() - self.worker.join(self._join_timeout) diff --git a/stem b/stem deleted file mode 120000 index 48c2475..0000000 --- a/stem +++ /dev/null @@ -1 +0,0 @@ -stem-client/stem \ No newline at end of file diff --git a/stem-client b/stem-client deleted file mode 160000 index b48ce68..0000000 --- a/stem-client +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b48ce682ef1a5fc1d4237d106700ec929f49246b From 29d25c7c3c70b5cc45a6a840e160b4b85a2e3a67 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 31 Mar 2020 11:54:06 +0200 Subject: [PATCH 13/30] Remove deprecated cell submodule. --- js-client/demo/lightnion.bundle.js | 1 - .../lightnion-websocket/public/lws.bundle.js | 39585 ---------------- js-client/vendor/sjcl | 1 - lightnion/__init__.py | 4 - lightnion/cell/__init__.py | 89 - lightnion/cell/address.py | 55 - lightnion/cell/certs.py | 42 - lightnion/cell/challenge.py | 49 - lightnion/cell/common.py | 16 - lightnion/cell/create2.py | 34 - lightnion/cell/create_fast.py | 33 - lightnion/cell/created2.py | 22 - lightnion/cell/created_fast.py | 32 - lightnion/cell/destroy.py | 37 - lightnion/cell/netinfo.py | 64 - lightnion/cell/padding.py | 21 - lightnion/cell/relay/__init__.py | 147 - lightnion/cell/relay/extend2.py | 116 - lightnion/cell/relay/extended2.py | 10 - lightnion/cell/relay_early.py | 37 - lightnion/cell/versions.py | 68 - lightnion/cell/view.py | 887 - lightnion/consensus.py | 38 +- lightnion/create.py | 280 - lightnion/descriptors.py | 90 - lightnion/onion.py | 270 - lightnion/proxy/__init__.py | 4 +- lightnion/proxy/cell.py | 243 + lightnion/proxy/forward.py | 31 +- lightnion/proxy/jobs.py | 30 +- lightnion/proxy/link.py | 152 +- lightnion/proxy/parts.py | 4 +- lightnion/utils.py | 229 - tools/.extra/asyncio.py | 221 - tools/.extra/oldread.md | 262 - tools/.extra/spec.txt | 209 - tools/authority_signing_keys.json | 1 - 37 files changed, 314 insertions(+), 43100 deletions(-) delete mode 120000 js-client/demo/lightnion.bundle.js delete mode 100644 js-client/integration-tests/lightnion-websocket/public/lws.bundle.js delete mode 160000 js-client/vendor/sjcl delete mode 100644 lightnion/cell/__init__.py delete mode 100644 lightnion/cell/address.py delete mode 100644 lightnion/cell/certs.py delete mode 100644 lightnion/cell/challenge.py delete mode 100644 lightnion/cell/common.py delete mode 100644 lightnion/cell/create2.py delete mode 100644 lightnion/cell/create_fast.py delete mode 100644 lightnion/cell/created2.py delete mode 100644 lightnion/cell/created_fast.py delete mode 100644 lightnion/cell/destroy.py delete mode 100644 lightnion/cell/netinfo.py delete mode 100644 lightnion/cell/padding.py delete mode 100644 lightnion/cell/relay/__init__.py delete mode 100644 lightnion/cell/relay/extend2.py delete mode 100644 lightnion/cell/relay/extended2.py delete mode 100644 lightnion/cell/relay_early.py delete mode 100644 lightnion/cell/versions.py delete mode 100644 lightnion/cell/view.py delete mode 100644 lightnion/create.py delete mode 100644 lightnion/onion.py create mode 100644 lightnion/proxy/cell.py delete mode 100644 lightnion/utils.py delete mode 100644 tools/.extra/asyncio.py delete mode 100644 tools/.extra/oldread.md delete mode 100644 tools/.extra/spec.txt delete mode 100644 tools/authority_signing_keys.json diff --git a/js-client/demo/lightnion.bundle.js b/js-client/demo/lightnion.bundle.js deleted file mode 120000 index 4398a8a..0000000 --- a/js-client/demo/lightnion.bundle.js +++ /dev/null @@ -1 +0,0 @@ -../lightnion.bundle.js \ No newline at end of file diff --git a/js-client/integration-tests/lightnion-websocket/public/lws.bundle.js b/js-client/integration-tests/lightnion-websocket/public/lws.bundle.js deleted file mode 100644 index 86e5fb0..0000000 --- a/js-client/integration-tests/lightnion-websocket/public/lws.bundle.js +++ /dev/null @@ -1,39585 +0,0 @@ -this.lightnion = this.lightnion || {}; -this.lightnion.bundle = (function (exports) { - 'use strict'; - - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - function commonjsRequire () { - throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs'); - } - - function unwrapExports (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; - } - - function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; - } - - function getCjsExportFromNamespace (n) { - return n && n['default'] || n; - } - - var lib = createCommonjsModule(function (module, exports) { - - Object.defineProperty(exports, "__esModule", { - value: true - }); - - var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - - /* global window self */ - - var isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; - - /* eslint-disable no-restricted-globals */ - var isWebWorker = (typeof self === 'undefined' ? 'undefined' : _typeof(self)) === 'object' && self.constructor && self.constructor.name === 'DedicatedWorkerGlobalScope'; - /* eslint-enable no-restricted-globals */ - - var isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null; - - exports.isBrowser = isBrowser; - exports.isWebWorker = isWebWorker; - exports.isNode = isNode; - }); - - unwrapExports(lib); - var lib_1 = lib.isBrowser; - var lib_2 = lib.isWebWorker; - var lib_3 = lib.isNode; - - /** - * @module header - * @namespace - * @see lnn.open - * @see lnn.stream.tcp - * @see lnn.state - * @example - * lnn.open('proxy.server', 4990, function(endpoint) - * { - * if (endpoint.state != lnn.state.success) - * return - * tcp = lnn.stream.tcp(endpoint, 'api.ipify.org', 80, handler) - * tcp.send('GET / HTTP/1.1\r\nHost: api.ipify.org\r\n\r\n') - * }) - * - * function handler(request) - * { - * switch(request.state) - * { - * case lnn.state.created: console.log('ready') - * return - * case lnn.state.pending: - * console.log(lnn.enc.utf8(request.recv())) - * return - * case lnn.state.success: console.log('closed') - * return - * } - * } - * - */ - - let lnn$1 = {}; - - /** - * Common API constants. - * @namespace - */ - lnn$1.api = {}; - - /** - * Supported API version. - * @readonly - * @default - */ - lnn$1.api.version = "0.1"; - - /** - * Prefix used to craft API endpoints. - * @default - **/ - lnn$1.api.url = "/lightnion/api/v0.1"; - - /** - * Port used to craft websockets. - * @default - **/ - lnn$1.api.ws_port = "8765"; - - /** - * Request state enumeration. - * @enum - * @readonly - **/ - lnn$1.state = { - /** - * operation started - * @type channel - */ - started: 1, - /** - * /guard get success (channel only) - * @type channel - */ - guarded: 2, - /** - * circuit created - * @type channel - */ - created: 3, - /** - * circuit negotiation - * @type channel - */ - pending: 4, - /** circuit extended (channel only) - * @type channel - */ - extpath: 5, - /** - * ready to use - * @type channel - */ - success: 6, - /** - * operation started - * @type stream - */ - started: 1, - /** - * ready to use - * @type stream - */ - created: 3, - /** - * incoming data - * @type stream - */ - pending: 4, - /** - * completed or closed - * @type stream - */ - success: 6 - }; - - var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return "CORRUPT: "+this.message};this.message=a;},invalid:function(a){this.toString=function(){return "INVALID: "+this.message};this.message=a;},bug:function(a){this.toString=function(){return "BUG: "+this.message};this.message=a;},notReady:function(a){this.toString=function(){return "NOT READY: "+this.message};this.message=a;}}}; - sjcl.cipher.aes=function(a){this.A[0][0][0]||this.R();var b,c,d,e,f=this.A[0][4],g=this.A[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c;}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c& - 255]];}; - sjcl.cipher.aes.prototype={encrypt:function(a){return t(this,a,0)},decrypt:function(a){return t(this,a,1)},A:[[[],[],[],[],[]],[[],[],[],[],[]]],R:function(){var a=this.A[0],b=this.A[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,m,n,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1)for(n=g^g<<1^g<<2^g<<3^g<<4,n=n>>8^n&255^99,c[f]=n,d[n]=f,m=h[e=h[l=h[f]]],p=0x1010101*m^0x10001*e^0x101*l^0x1010100*f,m=0x101*h[n]^0x1010100*n,e=0;4>e;e++)a[e][f]=m=m<<24^m>>>8,b[e][n]=p=p<<24^p>>>8;for(e= - 0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0);}}; - function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,m=d.length/4-2,n,p=4,r=[0,0,0,0];h=a.A[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(n=0;n>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(n= - 0;4>n;n++)r[c?3&-n:n]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return r} - sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.aa(a.slice(b/32),32-(b&31)).slice(1);return void 0===c?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return ((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return !1;var c=0,d;for(d=0;d>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}}; - sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d>>8>>>8>>>8),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c>>g)>>>e),gm){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+n+"!");}h>e?(h-=e,f.push(l^m>>>h),l=m<>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.D,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;dh)throw new sjcl.exception.invalid("this isn't base64!");26>>e),g=h<<32-e):(e+=6,g^=h<<32-e);}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}}; - sjcl.codec.bytes={fromBits:function(a){var b=[],c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d>>24),e<<=8;return b},toBits:function(a){var b=[],c,d=0;for(c=0;cb;c++){e=!0;for(d=2;d*d<=c;d++)if(0===c%d){e= - !1;break}e&&(8>b&&(this.H[b]=a(Math.pow(c,.5))),this.b[b]=a(Math.pow(c,1/3)),b++);}},l:function(a){var b,c,d,e=this.g,f=this.b,g=e[0],h=e[1],k=e[2],l=e[3],m=e[4],n=e[5],p=e[6],r=e[7];for(b=0;64>b;b++)16>b?c=a[b]:(c=a[b+1&15],d=a[b+14&15],c=a[b&15]=(c>>>7^c>>>18^c>>>3^c<<25^c<<14)+(d>>>17^d>>>19^d>>>10^d<<15^d<<13)+a[b&15]+a[b+9&15]|0),c=c+r+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(p^m&(n^p))+f[b],r=p,p=n,n=m,m=l+c|0,l=k,k=h,h=g,g=c+(h&k^l&(h^k))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0;e[0]=e[0]+g| - 0;e[1]=e[1]+h|0;e[2]=e[2]+k|0;e[3]=e[3]+l|0;e[4]=e[4]+m|0;e[5]=e[5]+n|0;e[6]=e[6]+p|0;e[7]=e[7]+r|0;}};sjcl.hash.sha1=function(a){a?(this.g=a.g.slice(0),this.f=a.f.slice(0),this.c=a.c):this.reset();};sjcl.hash.sha1.hash=function(a){return (new sjcl.hash.sha1).update(a).finalize()}; - sjcl.hash.sha1.prototype={blockSize:512,reset:function(){this.g=this.H.slice(0);this.f=[];this.c=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.f=sjcl.bitArray.concat(this.f,a);b=this.c;a=this.c=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffffc;c++)k[c]=a[c];else k=a;c=h[0];d=h[1];e=h[2];f=h[3];g=h[4];for(a=0;79>=a;a++)16<=a&&(b=k[a-3]^k[a-8]^k[a-14]^k[a-16],k[a]=b<<1|b>>>31),b=19>=a?d&e|~d&f:39>=a?d^e^f:59>=a?d&e|d&f|e&f:79>=a?d^e^f:void 0,b=(c<<5|c>>>27)+b+g+k[a]+this.b[Math.floor(a/20)]|0,g=f,f=e,e=d<<30|d>>>2,d=c,c=b;h[0]=h[0]+c|0;h[1]=h[1]+d|0;h[2]=h[2]+e|0;h[3]=h[3]+f|0;h[4]=h[4]+g|0;}}; - sjcl.mode.ccm={name:"ccm",I:[],listenProgress:function(a){sjcl.mode.ccm.I.push(a);},unListenProgress:function(a){a=sjcl.mode.ccm.I.indexOf(a);-1k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c, - 8*(15-f));b=sjcl.mode.ccm.X(a,b,c,d,e,f);g=sjcl.mode.ccm.F(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.F(a,k,c,l,e,b);a=sjcl.mode.ccm.X(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match"); - return k.data},oa:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.o;d=[h.partial(8,(b.length?64:0)|d-2<<2|f-1)];d=h.concat(d,c);d[3]|=e;d=a.encrypt(d);if(b.length)for(c=h.bitLength(b)/8,65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c])),g=h.concat(g,b),b=0;be||16m&&(sjcl.mode.ccm.ga(g/ - k),m+=n),c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return {tag:d,data:h.clamp(b,l)}}}; - sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.U,k=sjcl.bitArray,l=k.o,m=[0,0,0,0];c=h(a.encrypt(c));var n,p=[];d=d||[];e=e||64;for(g=0;g+4e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c); - return a.encrypt(f(d(f(h,d(h))),g))},U:function(a){return [a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}}; - sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.F(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.F(!1,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},la:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.o;e=[0,0, - 0,0];f=b.slice(0);for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000);}return e},s:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;de&&(a=b.hash(a));for(d=0;dd||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],m=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(m.concat(b,[k]));for(g=1;gg;g++)e.push(0x100000000*Math.random()|0);for(g=0;g=1<this.w&&(this.w= - f);this.S++;this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.N=new sjcl.cipher.aes(this.b);for(d=0;4>d&&(this.m[d]=this.m[d]+1|0,!this.m[d]);d++);}for(d=0;d>>1;this.h[g].update([d,this.P++,2,b,f,a.length].concat(a));}break;case "string":void 0===b&&(b=a.length);this.h[g].update([d,this.P++,3,b,f,a.length]);this.h[g].update(a);break;default:k=1;}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.u[g]+=b;this.i+=b;h===this.B&&(this.isReady()!==this.B&&z("seeded",Math.max(this.w,this.i)),z("progress",this.getProgress()));}, - isReady:function(a){a=this.V[void 0!==a?a:this.O];return this.w&&this.w>=a?this.u[0]>this.ca&&(new Date).valueOf()>this.$?this.L|this.K:this.K:this.i>=a?this.L|this.B:this.B},getProgress:function(a){a=this.V[a?a:this.O];return this.w>=a?1:this.i>a?1:this.i/a},startCollectors:function(){if(!this.G){this.a={loadTimeCollector:A(this,this.na),mouseCollector:A(this,this.pa),keyboardCollector:A(this,this.ma),accelerometerCollector:A(this,this.fa),touchCollector:A(this,this.ra)};if(window.addEventListener)window.addEventListener("load", - this.a.loadTimeCollector,!1),window.addEventListener("mousemove",this.a.mouseCollector,!1),window.addEventListener("keypress",this.a.keyboardCollector,!1),window.addEventListener("devicemotion",this.a.accelerometerCollector,!1),window.addEventListener("touchmove",this.a.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector);else throw new sjcl.exception.bug("can't attach event"); - this.G=!0;}},stopCollectors:function(){this.G&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,!1),window.removeEventListener("mousemove",this.a.mouseCollector,!1),window.removeEventListener("keypress",this.a.keyboardCollector,!1),window.removeEventListener("devicemotion",this.a.accelerometerCollector,!1),window.removeEventListener("touchmove",this.a.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove", - this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.G=!1);},addEventListener:function(a,b){this.M[a][this.ha++]=b;},removeEventListener:function(a,b){var c,d,e=this.M[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;cb&&(a.m[b]=a.m[b]+1|0,!a.m[b]);b++);return a.N.encrypt(a.m)} - function A(a,b){return function(){b.apply(a,arguments);}}sjcl.random=new sjcl.prng(6); - a:try{var C,D,E,F;if(F="undefined"!==typeof module&&module.exports){var G;try{G=require("crypto");}catch(a){G=null;}F=D=G;}if(F&&D.randomBytes)C=D.randomBytes(128),C=new Uint32Array((new Uint8Array(C)).buffer),sjcl.random.addEntropy(C,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){E=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(E);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(E); - else break a;sjcl.random.addEntropy(E,1024,"crypto['getRandomValues']");}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a));} - sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},ka:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.j({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.j(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length|| - 4=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4> 24) & 0xff; - x[i+1] = (h >> 16) & 0xff; - x[i+2] = (h >> 8) & 0xff; - x[i+3] = h & 0xff; - x[i+4] = (l >> 24) & 0xff; - x[i+5] = (l >> 16) & 0xff; - x[i+6] = (l >> 8) & 0xff; - x[i+7] = l & 0xff; - } - - function vn(x, xi, y, yi, n) { - var i,d = 0; - for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i]; - return (1 & ((d - 1) >>> 8)) - 1; - } - - function crypto_verify_16(x, xi, y, yi) { - return vn(x,xi,y,yi,16); - } - - function crypto_verify_32(x, xi, y, yi) { - return vn(x,xi,y,yi,32); - } - - function core_salsa20(o, p, k, c) { - var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, - j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, - j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, - j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, - j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, - j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, - j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, - j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, - j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, - j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, - j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, - j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, - j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, - j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, - j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, - j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; - - var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, - x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, - x15 = j15, u; - - for (var i = 0; i < 20; i += 2) { - u = x0 + x12 | 0; - x4 ^= u<<7 | u>>>(32-7); - u = x4 + x0 | 0; - x8 ^= u<<9 | u>>>(32-9); - u = x8 + x4 | 0; - x12 ^= u<<13 | u>>>(32-13); - u = x12 + x8 | 0; - x0 ^= u<<18 | u>>>(32-18); - - u = x5 + x1 | 0; - x9 ^= u<<7 | u>>>(32-7); - u = x9 + x5 | 0; - x13 ^= u<<9 | u>>>(32-9); - u = x13 + x9 | 0; - x1 ^= u<<13 | u>>>(32-13); - u = x1 + x13 | 0; - x5 ^= u<<18 | u>>>(32-18); - - u = x10 + x6 | 0; - x14 ^= u<<7 | u>>>(32-7); - u = x14 + x10 | 0; - x2 ^= u<<9 | u>>>(32-9); - u = x2 + x14 | 0; - x6 ^= u<<13 | u>>>(32-13); - u = x6 + x2 | 0; - x10 ^= u<<18 | u>>>(32-18); - - u = x15 + x11 | 0; - x3 ^= u<<7 | u>>>(32-7); - u = x3 + x15 | 0; - x7 ^= u<<9 | u>>>(32-9); - u = x7 + x3 | 0; - x11 ^= u<<13 | u>>>(32-13); - u = x11 + x7 | 0; - x15 ^= u<<18 | u>>>(32-18); - - u = x0 + x3 | 0; - x1 ^= u<<7 | u>>>(32-7); - u = x1 + x0 | 0; - x2 ^= u<<9 | u>>>(32-9); - u = x2 + x1 | 0; - x3 ^= u<<13 | u>>>(32-13); - u = x3 + x2 | 0; - x0 ^= u<<18 | u>>>(32-18); - - u = x5 + x4 | 0; - x6 ^= u<<7 | u>>>(32-7); - u = x6 + x5 | 0; - x7 ^= u<<9 | u>>>(32-9); - u = x7 + x6 | 0; - x4 ^= u<<13 | u>>>(32-13); - u = x4 + x7 | 0; - x5 ^= u<<18 | u>>>(32-18); - - u = x10 + x9 | 0; - x11 ^= u<<7 | u>>>(32-7); - u = x11 + x10 | 0; - x8 ^= u<<9 | u>>>(32-9); - u = x8 + x11 | 0; - x9 ^= u<<13 | u>>>(32-13); - u = x9 + x8 | 0; - x10 ^= u<<18 | u>>>(32-18); - - u = x15 + x14 | 0; - x12 ^= u<<7 | u>>>(32-7); - u = x12 + x15 | 0; - x13 ^= u<<9 | u>>>(32-9); - u = x13 + x12 | 0; - x14 ^= u<<13 | u>>>(32-13); - u = x14 + x13 | 0; - x15 ^= u<<18 | u>>>(32-18); - } - x0 = x0 + j0 | 0; - x1 = x1 + j1 | 0; - x2 = x2 + j2 | 0; - x3 = x3 + j3 | 0; - x4 = x4 + j4 | 0; - x5 = x5 + j5 | 0; - x6 = x6 + j6 | 0; - x7 = x7 + j7 | 0; - x8 = x8 + j8 | 0; - x9 = x9 + j9 | 0; - x10 = x10 + j10 | 0; - x11 = x11 + j11 | 0; - x12 = x12 + j12 | 0; - x13 = x13 + j13 | 0; - x14 = x14 + j14 | 0; - x15 = x15 + j15 | 0; - - o[ 0] = x0 >>> 0 & 0xff; - o[ 1] = x0 >>> 8 & 0xff; - o[ 2] = x0 >>> 16 & 0xff; - o[ 3] = x0 >>> 24 & 0xff; - - o[ 4] = x1 >>> 0 & 0xff; - o[ 5] = x1 >>> 8 & 0xff; - o[ 6] = x1 >>> 16 & 0xff; - o[ 7] = x1 >>> 24 & 0xff; - - o[ 8] = x2 >>> 0 & 0xff; - o[ 9] = x2 >>> 8 & 0xff; - o[10] = x2 >>> 16 & 0xff; - o[11] = x2 >>> 24 & 0xff; - - o[12] = x3 >>> 0 & 0xff; - o[13] = x3 >>> 8 & 0xff; - o[14] = x3 >>> 16 & 0xff; - o[15] = x3 >>> 24 & 0xff; - - o[16] = x4 >>> 0 & 0xff; - o[17] = x4 >>> 8 & 0xff; - o[18] = x4 >>> 16 & 0xff; - o[19] = x4 >>> 24 & 0xff; - - o[20] = x5 >>> 0 & 0xff; - o[21] = x5 >>> 8 & 0xff; - o[22] = x5 >>> 16 & 0xff; - o[23] = x5 >>> 24 & 0xff; - - o[24] = x6 >>> 0 & 0xff; - o[25] = x6 >>> 8 & 0xff; - o[26] = x6 >>> 16 & 0xff; - o[27] = x6 >>> 24 & 0xff; - - o[28] = x7 >>> 0 & 0xff; - o[29] = x7 >>> 8 & 0xff; - o[30] = x7 >>> 16 & 0xff; - o[31] = x7 >>> 24 & 0xff; - - o[32] = x8 >>> 0 & 0xff; - o[33] = x8 >>> 8 & 0xff; - o[34] = x8 >>> 16 & 0xff; - o[35] = x8 >>> 24 & 0xff; - - o[36] = x9 >>> 0 & 0xff; - o[37] = x9 >>> 8 & 0xff; - o[38] = x9 >>> 16 & 0xff; - o[39] = x9 >>> 24 & 0xff; - - o[40] = x10 >>> 0 & 0xff; - o[41] = x10 >>> 8 & 0xff; - o[42] = x10 >>> 16 & 0xff; - o[43] = x10 >>> 24 & 0xff; - - o[44] = x11 >>> 0 & 0xff; - o[45] = x11 >>> 8 & 0xff; - o[46] = x11 >>> 16 & 0xff; - o[47] = x11 >>> 24 & 0xff; - - o[48] = x12 >>> 0 & 0xff; - o[49] = x12 >>> 8 & 0xff; - o[50] = x12 >>> 16 & 0xff; - o[51] = x12 >>> 24 & 0xff; - - o[52] = x13 >>> 0 & 0xff; - o[53] = x13 >>> 8 & 0xff; - o[54] = x13 >>> 16 & 0xff; - o[55] = x13 >>> 24 & 0xff; - - o[56] = x14 >>> 0 & 0xff; - o[57] = x14 >>> 8 & 0xff; - o[58] = x14 >>> 16 & 0xff; - o[59] = x14 >>> 24 & 0xff; - - o[60] = x15 >>> 0 & 0xff; - o[61] = x15 >>> 8 & 0xff; - o[62] = x15 >>> 16 & 0xff; - o[63] = x15 >>> 24 & 0xff; - } - - function core_hsalsa20(o,p,k,c) { - var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24, - j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24, - j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24, - j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24, - j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24, - j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24, - j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24, - j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24, - j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24, - j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24, - j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24, - j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24, - j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24, - j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24, - j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24, - j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24; - - var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, - x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, - x15 = j15, u; - - for (var i = 0; i < 20; i += 2) { - u = x0 + x12 | 0; - x4 ^= u<<7 | u>>>(32-7); - u = x4 + x0 | 0; - x8 ^= u<<9 | u>>>(32-9); - u = x8 + x4 | 0; - x12 ^= u<<13 | u>>>(32-13); - u = x12 + x8 | 0; - x0 ^= u<<18 | u>>>(32-18); - - u = x5 + x1 | 0; - x9 ^= u<<7 | u>>>(32-7); - u = x9 + x5 | 0; - x13 ^= u<<9 | u>>>(32-9); - u = x13 + x9 | 0; - x1 ^= u<<13 | u>>>(32-13); - u = x1 + x13 | 0; - x5 ^= u<<18 | u>>>(32-18); - - u = x10 + x6 | 0; - x14 ^= u<<7 | u>>>(32-7); - u = x14 + x10 | 0; - x2 ^= u<<9 | u>>>(32-9); - u = x2 + x14 | 0; - x6 ^= u<<13 | u>>>(32-13); - u = x6 + x2 | 0; - x10 ^= u<<18 | u>>>(32-18); - - u = x15 + x11 | 0; - x3 ^= u<<7 | u>>>(32-7); - u = x3 + x15 | 0; - x7 ^= u<<9 | u>>>(32-9); - u = x7 + x3 | 0; - x11 ^= u<<13 | u>>>(32-13); - u = x11 + x7 | 0; - x15 ^= u<<18 | u>>>(32-18); - - u = x0 + x3 | 0; - x1 ^= u<<7 | u>>>(32-7); - u = x1 + x0 | 0; - x2 ^= u<<9 | u>>>(32-9); - u = x2 + x1 | 0; - x3 ^= u<<13 | u>>>(32-13); - u = x3 + x2 | 0; - x0 ^= u<<18 | u>>>(32-18); - - u = x5 + x4 | 0; - x6 ^= u<<7 | u>>>(32-7); - u = x6 + x5 | 0; - x7 ^= u<<9 | u>>>(32-9); - u = x7 + x6 | 0; - x4 ^= u<<13 | u>>>(32-13); - u = x4 + x7 | 0; - x5 ^= u<<18 | u>>>(32-18); - - u = x10 + x9 | 0; - x11 ^= u<<7 | u>>>(32-7); - u = x11 + x10 | 0; - x8 ^= u<<9 | u>>>(32-9); - u = x8 + x11 | 0; - x9 ^= u<<13 | u>>>(32-13); - u = x9 + x8 | 0; - x10 ^= u<<18 | u>>>(32-18); - - u = x15 + x14 | 0; - x12 ^= u<<7 | u>>>(32-7); - u = x12 + x15 | 0; - x13 ^= u<<9 | u>>>(32-9); - u = x13 + x12 | 0; - x14 ^= u<<13 | u>>>(32-13); - u = x14 + x13 | 0; - x15 ^= u<<18 | u>>>(32-18); - } - - o[ 0] = x0 >>> 0 & 0xff; - o[ 1] = x0 >>> 8 & 0xff; - o[ 2] = x0 >>> 16 & 0xff; - o[ 3] = x0 >>> 24 & 0xff; - - o[ 4] = x5 >>> 0 & 0xff; - o[ 5] = x5 >>> 8 & 0xff; - o[ 6] = x5 >>> 16 & 0xff; - o[ 7] = x5 >>> 24 & 0xff; - - o[ 8] = x10 >>> 0 & 0xff; - o[ 9] = x10 >>> 8 & 0xff; - o[10] = x10 >>> 16 & 0xff; - o[11] = x10 >>> 24 & 0xff; - - o[12] = x15 >>> 0 & 0xff; - o[13] = x15 >>> 8 & 0xff; - o[14] = x15 >>> 16 & 0xff; - o[15] = x15 >>> 24 & 0xff; - - o[16] = x6 >>> 0 & 0xff; - o[17] = x6 >>> 8 & 0xff; - o[18] = x6 >>> 16 & 0xff; - o[19] = x6 >>> 24 & 0xff; - - o[20] = x7 >>> 0 & 0xff; - o[21] = x7 >>> 8 & 0xff; - o[22] = x7 >>> 16 & 0xff; - o[23] = x7 >>> 24 & 0xff; - - o[24] = x8 >>> 0 & 0xff; - o[25] = x8 >>> 8 & 0xff; - o[26] = x8 >>> 16 & 0xff; - o[27] = x8 >>> 24 & 0xff; - - o[28] = x9 >>> 0 & 0xff; - o[29] = x9 >>> 8 & 0xff; - o[30] = x9 >>> 16 & 0xff; - o[31] = x9 >>> 24 & 0xff; - } - - function crypto_core_salsa20(out,inp,k,c) { - core_salsa20(out,inp,k,c); - } - - function crypto_core_hsalsa20(out,inp,k,c) { - core_hsalsa20(out,inp,k,c); - } - - var sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]); - // "expand 32-byte k" - - function crypto_stream_salsa20_xor(c,cpos,m,mpos,b,n,k) { - var z = new Uint8Array(16), x = new Uint8Array(64); - var u, i; - for (i = 0; i < 16; i++) z[i] = 0; - for (i = 0; i < 8; i++) z[i] = n[i]; - while (b >= 64) { - crypto_core_salsa20(x,z,k,sigma); - for (i = 0; i < 64; i++) c[cpos+i] = m[mpos+i] ^ x[i]; - u = 1; - for (i = 8; i < 16; i++) { - u = u + (z[i] & 0xff) | 0; - z[i] = u & 0xff; - u >>>= 8; - } - b -= 64; - cpos += 64; - mpos += 64; - } - if (b > 0) { - crypto_core_salsa20(x,z,k,sigma); - for (i = 0; i < b; i++) c[cpos+i] = m[mpos+i] ^ x[i]; - } - return 0; - } - - function crypto_stream_salsa20(c,cpos,b,n,k) { - var z = new Uint8Array(16), x = new Uint8Array(64); - var u, i; - for (i = 0; i < 16; i++) z[i] = 0; - for (i = 0; i < 8; i++) z[i] = n[i]; - while (b >= 64) { - crypto_core_salsa20(x,z,k,sigma); - for (i = 0; i < 64; i++) c[cpos+i] = x[i]; - u = 1; - for (i = 8; i < 16; i++) { - u = u + (z[i] & 0xff) | 0; - z[i] = u & 0xff; - u >>>= 8; - } - b -= 64; - cpos += 64; - } - if (b > 0) { - crypto_core_salsa20(x,z,k,sigma); - for (i = 0; i < b; i++) c[cpos+i] = x[i]; - } - return 0; - } - - function crypto_stream(c,cpos,d,n,k) { - var s = new Uint8Array(32); - crypto_core_hsalsa20(s,n,k,sigma); - var sn = new Uint8Array(8); - for (var i = 0; i < 8; i++) sn[i] = n[i+16]; - return crypto_stream_salsa20(c,cpos,d,sn,s); - } - - function crypto_stream_xor(c,cpos,m,mpos,d,n,k) { - var s = new Uint8Array(32); - crypto_core_hsalsa20(s,n,k,sigma); - var sn = new Uint8Array(8); - for (var i = 0; i < 8; i++) sn[i] = n[i+16]; - return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s); - } - - /* - * Port of Andrew Moon's Poly1305-donna-16. Public domain. - * https://github.com/floodyberry/poly1305-donna - */ - - var poly1305 = function(key) { - this.buffer = new Uint8Array(16); - this.r = new Uint16Array(10); - this.h = new Uint16Array(10); - this.pad = new Uint16Array(8); - this.leftover = 0; - this.fin = 0; - - var t0, t1, t2, t3, t4, t5, t6, t7; - - t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff; - t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; - t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; - t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; - t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; - this.r[5] = ((t4 >>> 1)) & 0x1ffe; - t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; - t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; - t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; - this.r[9] = ((t7 >>> 5)) & 0x007f; - - this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8; - this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8; - this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8; - this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8; - this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8; - this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8; - this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8; - this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8; - }; - - poly1305.prototype.blocks = function(m, mpos, bytes) { - var hibit = this.fin ? 0 : (1 << 11); - var t0, t1, t2, t3, t4, t5, t6, t7, c; - var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; - - var h0 = this.h[0], - h1 = this.h[1], - h2 = this.h[2], - h3 = this.h[3], - h4 = this.h[4], - h5 = this.h[5], - h6 = this.h[6], - h7 = this.h[7], - h8 = this.h[8], - h9 = this.h[9]; - - var r0 = this.r[0], - r1 = this.r[1], - r2 = this.r[2], - r3 = this.r[3], - r4 = this.r[4], - r5 = this.r[5], - r6 = this.r[6], - r7 = this.r[7], - r8 = this.r[8], - r9 = this.r[9]; - - while (bytes >= 16) { - t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff; - t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; - t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; - t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; - t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; - h5 += ((t4 >>> 1)) & 0x1fff; - t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; - t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; - t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; - h9 += ((t7 >>> 5)) | hibit; - - c = 0; - - d0 = c; - d0 += h0 * r0; - d0 += h1 * (5 * r9); - d0 += h2 * (5 * r8); - d0 += h3 * (5 * r7); - d0 += h4 * (5 * r6); - c = (d0 >>> 13); d0 &= 0x1fff; - d0 += h5 * (5 * r5); - d0 += h6 * (5 * r4); - d0 += h7 * (5 * r3); - d0 += h8 * (5 * r2); - d0 += h9 * (5 * r1); - c += (d0 >>> 13); d0 &= 0x1fff; - - d1 = c; - d1 += h0 * r1; - d1 += h1 * r0; - d1 += h2 * (5 * r9); - d1 += h3 * (5 * r8); - d1 += h4 * (5 * r7); - c = (d1 >>> 13); d1 &= 0x1fff; - d1 += h5 * (5 * r6); - d1 += h6 * (5 * r5); - d1 += h7 * (5 * r4); - d1 += h8 * (5 * r3); - d1 += h9 * (5 * r2); - c += (d1 >>> 13); d1 &= 0x1fff; - - d2 = c; - d2 += h0 * r2; - d2 += h1 * r1; - d2 += h2 * r0; - d2 += h3 * (5 * r9); - d2 += h4 * (5 * r8); - c = (d2 >>> 13); d2 &= 0x1fff; - d2 += h5 * (5 * r7); - d2 += h6 * (5 * r6); - d2 += h7 * (5 * r5); - d2 += h8 * (5 * r4); - d2 += h9 * (5 * r3); - c += (d2 >>> 13); d2 &= 0x1fff; - - d3 = c; - d3 += h0 * r3; - d3 += h1 * r2; - d3 += h2 * r1; - d3 += h3 * r0; - d3 += h4 * (5 * r9); - c = (d3 >>> 13); d3 &= 0x1fff; - d3 += h5 * (5 * r8); - d3 += h6 * (5 * r7); - d3 += h7 * (5 * r6); - d3 += h8 * (5 * r5); - d3 += h9 * (5 * r4); - c += (d3 >>> 13); d3 &= 0x1fff; - - d4 = c; - d4 += h0 * r4; - d4 += h1 * r3; - d4 += h2 * r2; - d4 += h3 * r1; - d4 += h4 * r0; - c = (d4 >>> 13); d4 &= 0x1fff; - d4 += h5 * (5 * r9); - d4 += h6 * (5 * r8); - d4 += h7 * (5 * r7); - d4 += h8 * (5 * r6); - d4 += h9 * (5 * r5); - c += (d4 >>> 13); d4 &= 0x1fff; - - d5 = c; - d5 += h0 * r5; - d5 += h1 * r4; - d5 += h2 * r3; - d5 += h3 * r2; - d5 += h4 * r1; - c = (d5 >>> 13); d5 &= 0x1fff; - d5 += h5 * r0; - d5 += h6 * (5 * r9); - d5 += h7 * (5 * r8); - d5 += h8 * (5 * r7); - d5 += h9 * (5 * r6); - c += (d5 >>> 13); d5 &= 0x1fff; - - d6 = c; - d6 += h0 * r6; - d6 += h1 * r5; - d6 += h2 * r4; - d6 += h3 * r3; - d6 += h4 * r2; - c = (d6 >>> 13); d6 &= 0x1fff; - d6 += h5 * r1; - d6 += h6 * r0; - d6 += h7 * (5 * r9); - d6 += h8 * (5 * r8); - d6 += h9 * (5 * r7); - c += (d6 >>> 13); d6 &= 0x1fff; - - d7 = c; - d7 += h0 * r7; - d7 += h1 * r6; - d7 += h2 * r5; - d7 += h3 * r4; - d7 += h4 * r3; - c = (d7 >>> 13); d7 &= 0x1fff; - d7 += h5 * r2; - d7 += h6 * r1; - d7 += h7 * r0; - d7 += h8 * (5 * r9); - d7 += h9 * (5 * r8); - c += (d7 >>> 13); d7 &= 0x1fff; - - d8 = c; - d8 += h0 * r8; - d8 += h1 * r7; - d8 += h2 * r6; - d8 += h3 * r5; - d8 += h4 * r4; - c = (d8 >>> 13); d8 &= 0x1fff; - d8 += h5 * r3; - d8 += h6 * r2; - d8 += h7 * r1; - d8 += h8 * r0; - d8 += h9 * (5 * r9); - c += (d8 >>> 13); d8 &= 0x1fff; - - d9 = c; - d9 += h0 * r9; - d9 += h1 * r8; - d9 += h2 * r7; - d9 += h3 * r6; - d9 += h4 * r5; - c = (d9 >>> 13); d9 &= 0x1fff; - d9 += h5 * r4; - d9 += h6 * r3; - d9 += h7 * r2; - d9 += h8 * r1; - d9 += h9 * r0; - c += (d9 >>> 13); d9 &= 0x1fff; - - c = (((c << 2) + c)) | 0; - c = (c + d0) | 0; - d0 = c & 0x1fff; - c = (c >>> 13); - d1 += c; - - h0 = d0; - h1 = d1; - h2 = d2; - h3 = d3; - h4 = d4; - h5 = d5; - h6 = d6; - h7 = d7; - h8 = d8; - h9 = d9; - - mpos += 16; - bytes -= 16; - } - this.h[0] = h0; - this.h[1] = h1; - this.h[2] = h2; - this.h[3] = h3; - this.h[4] = h4; - this.h[5] = h5; - this.h[6] = h6; - this.h[7] = h7; - this.h[8] = h8; - this.h[9] = h9; - }; - - poly1305.prototype.finish = function(mac, macpos) { - var g = new Uint16Array(10); - var c, mask, f, i; - - if (this.leftover) { - i = this.leftover; - this.buffer[i++] = 1; - for (; i < 16; i++) this.buffer[i] = 0; - this.fin = 1; - this.blocks(this.buffer, 0, 16); - } - - c = this.h[1] >>> 13; - this.h[1] &= 0x1fff; - for (i = 2; i < 10; i++) { - this.h[i] += c; - c = this.h[i] >>> 13; - this.h[i] &= 0x1fff; - } - this.h[0] += (c * 5); - c = this.h[0] >>> 13; - this.h[0] &= 0x1fff; - this.h[1] += c; - c = this.h[1] >>> 13; - this.h[1] &= 0x1fff; - this.h[2] += c; - - g[0] = this.h[0] + 5; - c = g[0] >>> 13; - g[0] &= 0x1fff; - for (i = 1; i < 10; i++) { - g[i] = this.h[i] + c; - c = g[i] >>> 13; - g[i] &= 0x1fff; - } - g[9] -= (1 << 13); - - mask = (c ^ 1) - 1; - for (i = 0; i < 10; i++) g[i] &= mask; - mask = ~mask; - for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i]; - - this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff; - this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff; - this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff; - this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff; - this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; - this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff; - this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff; - this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff; - - f = this.h[0] + this.pad[0]; - this.h[0] = f & 0xffff; - for (i = 1; i < 8; i++) { - f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0; - this.h[i] = f & 0xffff; - } - - mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff; - mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff; - mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff; - mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff; - mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff; - mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff; - mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff; - mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff; - mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff; - mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff; - mac[macpos+10] = (this.h[5] >>> 0) & 0xff; - mac[macpos+11] = (this.h[5] >>> 8) & 0xff; - mac[macpos+12] = (this.h[6] >>> 0) & 0xff; - mac[macpos+13] = (this.h[6] >>> 8) & 0xff; - mac[macpos+14] = (this.h[7] >>> 0) & 0xff; - mac[macpos+15] = (this.h[7] >>> 8) & 0xff; - }; - - poly1305.prototype.update = function(m, mpos, bytes) { - var i, want; - - if (this.leftover) { - want = (16 - this.leftover); - if (want > bytes) - want = bytes; - for (i = 0; i < want; i++) - this.buffer[this.leftover + i] = m[mpos+i]; - bytes -= want; - mpos += want; - this.leftover += want; - if (this.leftover < 16) - return; - this.blocks(this.buffer, 0, 16); - this.leftover = 0; - } - - if (bytes >= 16) { - want = bytes - (bytes % 16); - this.blocks(m, mpos, want); - mpos += want; - bytes -= want; - } - - if (bytes) { - for (i = 0; i < bytes; i++) - this.buffer[this.leftover + i] = m[mpos+i]; - this.leftover += bytes; - } - }; - - function crypto_onetimeauth(out, outpos, m, mpos, n, k) { - var s = new poly1305(k); - s.update(m, mpos, n); - s.finish(out, outpos); - return 0; - } - - function crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) { - var x = new Uint8Array(16); - crypto_onetimeauth(x,0,m,mpos,n,k); - return crypto_verify_16(h,hpos,x,0); - } - - function crypto_secretbox(c,m,d,n,k) { - var i; - if (d < 32) return -1; - crypto_stream_xor(c,0,m,0,d,n,k); - crypto_onetimeauth(c, 16, c, 32, d - 32, c); - for (i = 0; i < 16; i++) c[i] = 0; - return 0; - } - - function crypto_secretbox_open(m,c,d,n,k) { - var i; - var x = new Uint8Array(32); - if (d < 32) return -1; - crypto_stream(x,0,32,n,k); - if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1; - crypto_stream_xor(m,0,c,0,d,n,k); - for (i = 0; i < 32; i++) m[i] = 0; - return 0; - } - - function set25519(r, a) { - var i; - for (i = 0; i < 16; i++) r[i] = a[i]|0; - } - - function car25519(o) { - var i, v, c = 1; - for (i = 0; i < 16; i++) { - v = o[i] + c + 65535; - c = Math.floor(v / 65536); - o[i] = v - c * 65536; - } - o[0] += c-1 + 37 * (c-1); - } - - function sel25519(p, q, b) { - var t, c = ~(b-1); - for (var i = 0; i < 16; i++) { - t = c & (p[i] ^ q[i]); - p[i] ^= t; - q[i] ^= t; - } - } - - function pack25519(o, n) { - var i, j, b; - var m = gf(), t = gf(); - for (i = 0; i < 16; i++) t[i] = n[i]; - car25519(t); - car25519(t); - car25519(t); - for (j = 0; j < 2; j++) { - m[0] = t[0] - 0xffed; - for (i = 1; i < 15; i++) { - m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1); - m[i-1] &= 0xffff; - } - m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1); - b = (m[15]>>16) & 1; - m[14] &= 0xffff; - sel25519(t, m, 1-b); - } - for (i = 0; i < 16; i++) { - o[2*i] = t[i] & 0xff; - o[2*i+1] = t[i]>>8; - } - } - - function neq25519(a, b) { - var c = new Uint8Array(32), d = new Uint8Array(32); - pack25519(c, a); - pack25519(d, b); - return crypto_verify_32(c, 0, d, 0); - } - - function par25519(a) { - var d = new Uint8Array(32); - pack25519(d, a); - return d[0] & 1; - } - - function unpack25519(o, n) { - var i; - for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8); - o[15] &= 0x7fff; - } - - function A(o, a, b) { - for (var i = 0; i < 16; i++) o[i] = a[i] + b[i]; - } - - function Z(o, a, b) { - for (var i = 0; i < 16; i++) o[i] = a[i] - b[i]; - } - - function M(o, a, b) { - var v, c, - t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, - t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, - t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, - t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, - b0 = b[0], - b1 = b[1], - b2 = b[2], - b3 = b[3], - b4 = b[4], - b5 = b[5], - b6 = b[6], - b7 = b[7], - b8 = b[8], - b9 = b[9], - b10 = b[10], - b11 = b[11], - b12 = b[12], - b13 = b[13], - b14 = b[14], - b15 = b[15]; - - v = a[0]; - t0 += v * b0; - t1 += v * b1; - t2 += v * b2; - t3 += v * b3; - t4 += v * b4; - t5 += v * b5; - t6 += v * b6; - t7 += v * b7; - t8 += v * b8; - t9 += v * b9; - t10 += v * b10; - t11 += v * b11; - t12 += v * b12; - t13 += v * b13; - t14 += v * b14; - t15 += v * b15; - v = a[1]; - t1 += v * b0; - t2 += v * b1; - t3 += v * b2; - t4 += v * b3; - t5 += v * b4; - t6 += v * b5; - t7 += v * b6; - t8 += v * b7; - t9 += v * b8; - t10 += v * b9; - t11 += v * b10; - t12 += v * b11; - t13 += v * b12; - t14 += v * b13; - t15 += v * b14; - t16 += v * b15; - v = a[2]; - t2 += v * b0; - t3 += v * b1; - t4 += v * b2; - t5 += v * b3; - t6 += v * b4; - t7 += v * b5; - t8 += v * b6; - t9 += v * b7; - t10 += v * b8; - t11 += v * b9; - t12 += v * b10; - t13 += v * b11; - t14 += v * b12; - t15 += v * b13; - t16 += v * b14; - t17 += v * b15; - v = a[3]; - t3 += v * b0; - t4 += v * b1; - t5 += v * b2; - t6 += v * b3; - t7 += v * b4; - t8 += v * b5; - t9 += v * b6; - t10 += v * b7; - t11 += v * b8; - t12 += v * b9; - t13 += v * b10; - t14 += v * b11; - t15 += v * b12; - t16 += v * b13; - t17 += v * b14; - t18 += v * b15; - v = a[4]; - t4 += v * b0; - t5 += v * b1; - t6 += v * b2; - t7 += v * b3; - t8 += v * b4; - t9 += v * b5; - t10 += v * b6; - t11 += v * b7; - t12 += v * b8; - t13 += v * b9; - t14 += v * b10; - t15 += v * b11; - t16 += v * b12; - t17 += v * b13; - t18 += v * b14; - t19 += v * b15; - v = a[5]; - t5 += v * b0; - t6 += v * b1; - t7 += v * b2; - t8 += v * b3; - t9 += v * b4; - t10 += v * b5; - t11 += v * b6; - t12 += v * b7; - t13 += v * b8; - t14 += v * b9; - t15 += v * b10; - t16 += v * b11; - t17 += v * b12; - t18 += v * b13; - t19 += v * b14; - t20 += v * b15; - v = a[6]; - t6 += v * b0; - t7 += v * b1; - t8 += v * b2; - t9 += v * b3; - t10 += v * b4; - t11 += v * b5; - t12 += v * b6; - t13 += v * b7; - t14 += v * b8; - t15 += v * b9; - t16 += v * b10; - t17 += v * b11; - t18 += v * b12; - t19 += v * b13; - t20 += v * b14; - t21 += v * b15; - v = a[7]; - t7 += v * b0; - t8 += v * b1; - t9 += v * b2; - t10 += v * b3; - t11 += v * b4; - t12 += v * b5; - t13 += v * b6; - t14 += v * b7; - t15 += v * b8; - t16 += v * b9; - t17 += v * b10; - t18 += v * b11; - t19 += v * b12; - t20 += v * b13; - t21 += v * b14; - t22 += v * b15; - v = a[8]; - t8 += v * b0; - t9 += v * b1; - t10 += v * b2; - t11 += v * b3; - t12 += v * b4; - t13 += v * b5; - t14 += v * b6; - t15 += v * b7; - t16 += v * b8; - t17 += v * b9; - t18 += v * b10; - t19 += v * b11; - t20 += v * b12; - t21 += v * b13; - t22 += v * b14; - t23 += v * b15; - v = a[9]; - t9 += v * b0; - t10 += v * b1; - t11 += v * b2; - t12 += v * b3; - t13 += v * b4; - t14 += v * b5; - t15 += v * b6; - t16 += v * b7; - t17 += v * b8; - t18 += v * b9; - t19 += v * b10; - t20 += v * b11; - t21 += v * b12; - t22 += v * b13; - t23 += v * b14; - t24 += v * b15; - v = a[10]; - t10 += v * b0; - t11 += v * b1; - t12 += v * b2; - t13 += v * b3; - t14 += v * b4; - t15 += v * b5; - t16 += v * b6; - t17 += v * b7; - t18 += v * b8; - t19 += v * b9; - t20 += v * b10; - t21 += v * b11; - t22 += v * b12; - t23 += v * b13; - t24 += v * b14; - t25 += v * b15; - v = a[11]; - t11 += v * b0; - t12 += v * b1; - t13 += v * b2; - t14 += v * b3; - t15 += v * b4; - t16 += v * b5; - t17 += v * b6; - t18 += v * b7; - t19 += v * b8; - t20 += v * b9; - t21 += v * b10; - t22 += v * b11; - t23 += v * b12; - t24 += v * b13; - t25 += v * b14; - t26 += v * b15; - v = a[12]; - t12 += v * b0; - t13 += v * b1; - t14 += v * b2; - t15 += v * b3; - t16 += v * b4; - t17 += v * b5; - t18 += v * b6; - t19 += v * b7; - t20 += v * b8; - t21 += v * b9; - t22 += v * b10; - t23 += v * b11; - t24 += v * b12; - t25 += v * b13; - t26 += v * b14; - t27 += v * b15; - v = a[13]; - t13 += v * b0; - t14 += v * b1; - t15 += v * b2; - t16 += v * b3; - t17 += v * b4; - t18 += v * b5; - t19 += v * b6; - t20 += v * b7; - t21 += v * b8; - t22 += v * b9; - t23 += v * b10; - t24 += v * b11; - t25 += v * b12; - t26 += v * b13; - t27 += v * b14; - t28 += v * b15; - v = a[14]; - t14 += v * b0; - t15 += v * b1; - t16 += v * b2; - t17 += v * b3; - t18 += v * b4; - t19 += v * b5; - t20 += v * b6; - t21 += v * b7; - t22 += v * b8; - t23 += v * b9; - t24 += v * b10; - t25 += v * b11; - t26 += v * b12; - t27 += v * b13; - t28 += v * b14; - t29 += v * b15; - v = a[15]; - t15 += v * b0; - t16 += v * b1; - t17 += v * b2; - t18 += v * b3; - t19 += v * b4; - t20 += v * b5; - t21 += v * b6; - t22 += v * b7; - t23 += v * b8; - t24 += v * b9; - t25 += v * b10; - t26 += v * b11; - t27 += v * b12; - t28 += v * b13; - t29 += v * b14; - t30 += v * b15; - - t0 += 38 * t16; - t1 += 38 * t17; - t2 += 38 * t18; - t3 += 38 * t19; - t4 += 38 * t20; - t5 += 38 * t21; - t6 += 38 * t22; - t7 += 38 * t23; - t8 += 38 * t24; - t9 += 38 * t25; - t10 += 38 * t26; - t11 += 38 * t27; - t12 += 38 * t28; - t13 += 38 * t29; - t14 += 38 * t30; - // t15 left as is - - // first car - c = 1; - v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; - v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; - v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; - v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; - v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; - v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; - v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; - v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; - v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; - v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; - v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; - v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; - v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; - v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; - v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; - v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; - t0 += c-1 + 37 * (c-1); - - // second car - c = 1; - v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; - v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; - v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; - v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; - v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; - v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; - v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; - v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; - v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; - v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; - v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; - v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; - v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; - v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; - v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; - v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; - t0 += c-1 + 37 * (c-1); - - o[ 0] = t0; - o[ 1] = t1; - o[ 2] = t2; - o[ 3] = t3; - o[ 4] = t4; - o[ 5] = t5; - o[ 6] = t6; - o[ 7] = t7; - o[ 8] = t8; - o[ 9] = t9; - o[10] = t10; - o[11] = t11; - o[12] = t12; - o[13] = t13; - o[14] = t14; - o[15] = t15; - } - - function S(o, a) { - M(o, a, a); - } - - function inv25519(o, i) { - var c = gf(); - var a; - for (a = 0; a < 16; a++) c[a] = i[a]; - for (a = 253; a >= 0; a--) { - S(c, c); - if(a !== 2 && a !== 4) M(c, c, i); - } - for (a = 0; a < 16; a++) o[a] = c[a]; - } - - function pow2523(o, i) { - var c = gf(); - var a; - for (a = 0; a < 16; a++) c[a] = i[a]; - for (a = 250; a >= 0; a--) { - S(c, c); - if(a !== 1) M(c, c, i); - } - for (a = 0; a < 16; a++) o[a] = c[a]; - } - - function crypto_scalarmult(q, n, p) { - var z = new Uint8Array(32); - var x = new Float64Array(80), r, i; - var a = gf(), b = gf(), c = gf(), - d = gf(), e = gf(), f = gf(); - for (i = 0; i < 31; i++) z[i] = n[i]; - z[31]=(n[31]&127)|64; - z[0]&=248; - unpack25519(x,p); - for (i = 0; i < 16; i++) { - b[i]=x[i]; - d[i]=a[i]=c[i]=0; - } - a[0]=d[0]=1; - for (i=254; i>=0; --i) { - r=(z[i>>>3]>>>(i&7))&1; - sel25519(a,b,r); - sel25519(c,d,r); - A(e,a,c); - Z(a,a,c); - A(c,b,d); - Z(b,b,d); - S(d,e); - S(f,a); - M(a,c,a); - M(c,b,e); - A(e,a,c); - Z(a,a,c); - S(b,a); - Z(c,d,f); - M(a,c,_121665); - A(a,a,d); - M(c,c,a); - M(a,d,f); - M(d,b,x); - S(b,e); - sel25519(a,b,r); - sel25519(c,d,r); - } - for (i = 0; i < 16; i++) { - x[i+16]=a[i]; - x[i+32]=c[i]; - x[i+48]=b[i]; - x[i+64]=d[i]; - } - var x32 = x.subarray(32); - var x16 = x.subarray(16); - inv25519(x32,x32); - M(x16,x16,x32); - pack25519(q,x16); - return 0; - } - - function crypto_scalarmult_base(q, n) { - return crypto_scalarmult(q, n, _9); - } - - function crypto_box_keypair(y, x) { - randombytes(x, 32); - return crypto_scalarmult_base(y, x); - } - - function crypto_box_beforenm(k, y, x) { - var s = new Uint8Array(32); - crypto_scalarmult(s, x, y); - return crypto_core_hsalsa20(k, _0, s, sigma); - } - - var crypto_box_afternm = crypto_secretbox; - var crypto_box_open_afternm = crypto_secretbox_open; - - function crypto_box(c, m, d, n, y, x) { - var k = new Uint8Array(32); - crypto_box_beforenm(k, y, x); - return crypto_box_afternm(c, m, d, n, k); - } - - function crypto_box_open(m, c, d, n, y, x) { - var k = new Uint8Array(32); - crypto_box_beforenm(k, y, x); - return crypto_box_open_afternm(m, c, d, n, k); - } - - var K = [ - 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, - 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc, - 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, - 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118, - 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, - 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2, - 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, - 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694, - 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, - 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65, - 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, - 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5, - 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, - 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4, - 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, - 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70, - 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, - 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df, - 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, - 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b, - 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, - 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30, - 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, - 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8, - 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, - 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8, - 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, - 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3, - 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, - 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec, - 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, - 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b, - 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, - 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178, - 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, - 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b, - 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, - 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c, - 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, - 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817 - ]; - - function crypto_hashblocks_hl(hh, hl, m, n) { - var wh = new Int32Array(16), wl = new Int32Array(16), - bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7, - bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7, - th, tl, i, j, h, l, a, b, c, d; - - var ah0 = hh[0], - ah1 = hh[1], - ah2 = hh[2], - ah3 = hh[3], - ah4 = hh[4], - ah5 = hh[5], - ah6 = hh[6], - ah7 = hh[7], - - al0 = hl[0], - al1 = hl[1], - al2 = hl[2], - al3 = hl[3], - al4 = hl[4], - al5 = hl[5], - al6 = hl[6], - al7 = hl[7]; - - var pos = 0; - while (n >= 128) { - for (i = 0; i < 16; i++) { - j = 8 * i + pos; - wh[i] = (m[j+0] << 24) | (m[j+1] << 16) | (m[j+2] << 8) | m[j+3]; - wl[i] = (m[j+4] << 24) | (m[j+5] << 16) | (m[j+6] << 8) | m[j+7]; - } - for (i = 0; i < 80; i++) { - bh0 = ah0; - bh1 = ah1; - bh2 = ah2; - bh3 = ah3; - bh4 = ah4; - bh5 = ah5; - bh6 = ah6; - bh7 = ah7; - - bl0 = al0; - bl1 = al1; - bl2 = al2; - bl3 = al3; - bl4 = al4; - bl5 = al5; - bl6 = al6; - bl7 = al7; - - // add - h = ah7; - l = al7; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - // Sigma1 - h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32)))); - l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32)))); - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - // Ch - h = (ah4 & ah5) ^ (~ah4 & ah6); - l = (al4 & al5) ^ (~al4 & al6); - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - // K - h = K[i*2]; - l = K[i*2+1]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - // w - h = wh[i%16]; - l = wl[i%16]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - th = c & 0xffff | d << 16; - tl = a & 0xffff | b << 16; - - // add - h = th; - l = tl; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - // Sigma0 - h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32)))); - l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32)))); - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - // Maj - h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2); - l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2); - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - bh7 = (c & 0xffff) | (d << 16); - bl7 = (a & 0xffff) | (b << 16); - - // add - h = bh3; - l = bl3; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = th; - l = tl; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - bh3 = (c & 0xffff) | (d << 16); - bl3 = (a & 0xffff) | (b << 16); - - ah1 = bh0; - ah2 = bh1; - ah3 = bh2; - ah4 = bh3; - ah5 = bh4; - ah6 = bh5; - ah7 = bh6; - ah0 = bh7; - - al1 = bl0; - al2 = bl1; - al3 = bl2; - al4 = bl3; - al5 = bl4; - al6 = bl5; - al7 = bl6; - al0 = bl7; - - if (i%16 === 15) { - for (j = 0; j < 16; j++) { - // add - h = wh[j]; - l = wl[j]; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = wh[(j+9)%16]; - l = wl[(j+9)%16]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - // sigma0 - th = wh[(j+1)%16]; - tl = wl[(j+1)%16]; - h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7); - l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7))); - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - // sigma1 - th = wh[(j+14)%16]; - tl = wl[(j+14)%16]; - h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6); - l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6))); - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - wh[j] = (c & 0xffff) | (d << 16); - wl[j] = (a & 0xffff) | (b << 16); - } - } - } - - // add - h = ah0; - l = al0; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[0]; - l = hl[0]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[0] = ah0 = (c & 0xffff) | (d << 16); - hl[0] = al0 = (a & 0xffff) | (b << 16); - - h = ah1; - l = al1; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[1]; - l = hl[1]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[1] = ah1 = (c & 0xffff) | (d << 16); - hl[1] = al1 = (a & 0xffff) | (b << 16); - - h = ah2; - l = al2; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[2]; - l = hl[2]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[2] = ah2 = (c & 0xffff) | (d << 16); - hl[2] = al2 = (a & 0xffff) | (b << 16); - - h = ah3; - l = al3; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[3]; - l = hl[3]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[3] = ah3 = (c & 0xffff) | (d << 16); - hl[3] = al3 = (a & 0xffff) | (b << 16); - - h = ah4; - l = al4; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[4]; - l = hl[4]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[4] = ah4 = (c & 0xffff) | (d << 16); - hl[4] = al4 = (a & 0xffff) | (b << 16); - - h = ah5; - l = al5; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[5]; - l = hl[5]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[5] = ah5 = (c & 0xffff) | (d << 16); - hl[5] = al5 = (a & 0xffff) | (b << 16); - - h = ah6; - l = al6; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[6]; - l = hl[6]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[6] = ah6 = (c & 0xffff) | (d << 16); - hl[6] = al6 = (a & 0xffff) | (b << 16); - - h = ah7; - l = al7; - - a = l & 0xffff; b = l >>> 16; - c = h & 0xffff; d = h >>> 16; - - h = hh[7]; - l = hl[7]; - - a += l & 0xffff; b += l >>> 16; - c += h & 0xffff; d += h >>> 16; - - b += a >>> 16; - c += b >>> 16; - d += c >>> 16; - - hh[7] = ah7 = (c & 0xffff) | (d << 16); - hl[7] = al7 = (a & 0xffff) | (b << 16); - - pos += 128; - n -= 128; - } - - return n; - } - - function crypto_hash(out, m, n) { - var hh = new Int32Array(8), - hl = new Int32Array(8), - x = new Uint8Array(256), - i, b = n; - - hh[0] = 0x6a09e667; - hh[1] = 0xbb67ae85; - hh[2] = 0x3c6ef372; - hh[3] = 0xa54ff53a; - hh[4] = 0x510e527f; - hh[5] = 0x9b05688c; - hh[6] = 0x1f83d9ab; - hh[7] = 0x5be0cd19; - - hl[0] = 0xf3bcc908; - hl[1] = 0x84caa73b; - hl[2] = 0xfe94f82b; - hl[3] = 0x5f1d36f1; - hl[4] = 0xade682d1; - hl[5] = 0x2b3e6c1f; - hl[6] = 0xfb41bd6b; - hl[7] = 0x137e2179; - - crypto_hashblocks_hl(hh, hl, m, n); - n %= 128; - - for (i = 0; i < n; i++) x[i] = m[b-n+i]; - x[n] = 128; - - n = 256-128*(n<112?1:0); - x[n-9] = 0; - ts64(x, n-8, (b / 0x20000000) | 0, b << 3); - crypto_hashblocks_hl(hh, hl, x, n); - - for (i = 0; i < 8; i++) ts64(out, 8*i, hh[i], hl[i]); - - return 0; - } - - function add(p, q) { - var a = gf(), b = gf(), c = gf(), - d = gf(), e = gf(), f = gf(), - g = gf(), h = gf(), t = gf(); - - Z(a, p[1], p[0]); - Z(t, q[1], q[0]); - M(a, a, t); - A(b, p[0], p[1]); - A(t, q[0], q[1]); - M(b, b, t); - M(c, p[3], q[3]); - M(c, c, D2); - M(d, p[2], q[2]); - A(d, d, d); - Z(e, b, a); - Z(f, d, c); - A(g, d, c); - A(h, b, a); - - M(p[0], e, f); - M(p[1], h, g); - M(p[2], g, f); - M(p[3], e, h); - } - - function cswap(p, q, b) { - var i; - for (i = 0; i < 4; i++) { - sel25519(p[i], q[i], b); - } - } - - function pack(r, p) { - var tx = gf(), ty = gf(), zi = gf(); - inv25519(zi, p[2]); - M(tx, p[0], zi); - M(ty, p[1], zi); - pack25519(r, ty); - r[31] ^= par25519(tx) << 7; - } - - function scalarmult(p, q, s) { - var b, i; - set25519(p[0], gf0); - set25519(p[1], gf1); - set25519(p[2], gf1); - set25519(p[3], gf0); - for (i = 255; i >= 0; --i) { - b = (s[(i/8)|0] >> (i&7)) & 1; - cswap(p, q, b); - add(q, p); - add(p, p); - cswap(p, q, b); - } - } - - function scalarbase(p, s) { - var q = [gf(), gf(), gf(), gf()]; - set25519(q[0], X); - set25519(q[1], Y); - set25519(q[2], gf1); - M(q[3], X, Y); - scalarmult(p, q, s); - } - - function crypto_sign_keypair(pk, sk, seeded) { - var d = new Uint8Array(64); - var p = [gf(), gf(), gf(), gf()]; - var i; - - if (!seeded) randombytes(sk, 32); - crypto_hash(d, sk, 32); - d[0] &= 248; - d[31] &= 127; - d[31] |= 64; - - scalarbase(p, d); - pack(pk, p); - - for (i = 0; i < 32; i++) sk[i+32] = pk[i]; - return 0; - } - - var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); - - function modL(r, x) { - var carry, i, j, k; - for (i = 63; i >= 32; --i) { - carry = 0; - for (j = i - 32, k = i - 12; j < k; ++j) { - x[j] += carry - 16 * x[i] * L[j - (i - 32)]; - carry = (x[j] + 128) >> 8; - x[j] -= carry * 256; - } - x[j] += carry; - x[i] = 0; - } - carry = 0; - for (j = 0; j < 32; j++) { - x[j] += carry - (x[31] >> 4) * L[j]; - carry = x[j] >> 8; - x[j] &= 255; - } - for (j = 0; j < 32; j++) x[j] -= carry * L[j]; - for (i = 0; i < 32; i++) { - x[i+1] += x[i] >> 8; - r[i] = x[i] & 255; - } - } - - function reduce(r) { - var x = new Float64Array(64), i; - for (i = 0; i < 64; i++) x[i] = r[i]; - for (i = 0; i < 64; i++) r[i] = 0; - modL(r, x); - } - - // Note: difference from C - smlen returned, not passed as argument. - function crypto_sign(sm, m, n, sk) { - var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64); - var i, j, x = new Float64Array(64); - var p = [gf(), gf(), gf(), gf()]; - - crypto_hash(d, sk, 32); - d[0] &= 248; - d[31] &= 127; - d[31] |= 64; - - var smlen = n + 64; - for (i = 0; i < n; i++) sm[64 + i] = m[i]; - for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i]; - - crypto_hash(r, sm.subarray(32), n+32); - reduce(r); - scalarbase(p, r); - pack(sm, p); - - for (i = 32; i < 64; i++) sm[i] = sk[i]; - crypto_hash(h, sm, n + 64); - reduce(h); - - for (i = 0; i < 64; i++) x[i] = 0; - for (i = 0; i < 32; i++) x[i] = r[i]; - for (i = 0; i < 32; i++) { - for (j = 0; j < 32; j++) { - x[i+j] += h[i] * d[j]; - } - } - - modL(sm.subarray(32), x); - return smlen; - } - - function unpackneg(r, p) { - var t = gf(), chk = gf(), num = gf(), - den = gf(), den2 = gf(), den4 = gf(), - den6 = gf(); - - set25519(r[2], gf1); - unpack25519(r[1], p); - S(num, r[1]); - M(den, num, D); - Z(num, num, r[2]); - A(den, r[2], den); - - S(den2, den); - S(den4, den2); - M(den6, den4, den2); - M(t, den6, num); - M(t, t, den); - - pow2523(t, t); - M(t, t, num); - M(t, t, den); - M(t, t, den); - M(r[0], t, den); - - S(chk, r[0]); - M(chk, chk, den); - if (neq25519(chk, num)) M(r[0], r[0], I); - - S(chk, r[0]); - M(chk, chk, den); - if (neq25519(chk, num)) return -1; - - if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]); - - M(r[3], r[0], r[1]); - return 0; - } - - function crypto_sign_open(m, sm, n, pk) { - var i; - var t = new Uint8Array(32), h = new Uint8Array(64); - var p = [gf(), gf(), gf(), gf()], - q = [gf(), gf(), gf(), gf()]; - - if (n < 64) return -1; - - if (unpackneg(q, pk)) return -1; - - for (i = 0; i < n; i++) m[i] = sm[i]; - for (i = 0; i < 32; i++) m[i+32] = pk[i]; - crypto_hash(h, m, n); - reduce(h); - scalarmult(p, q, h); - - scalarbase(q, sm.subarray(32)); - add(p, q); - pack(t, p); - - n -= 64; - if (crypto_verify_32(sm, 0, t, 0)) { - for (i = 0; i < n; i++) m[i] = 0; - return -1; - } - - for (i = 0; i < n; i++) m[i] = sm[i + 64]; - return n; - } - - var crypto_secretbox_KEYBYTES = 32, - crypto_secretbox_NONCEBYTES = 24, - crypto_secretbox_ZEROBYTES = 32, - crypto_secretbox_BOXZEROBYTES = 16, - crypto_scalarmult_BYTES = 32, - crypto_scalarmult_SCALARBYTES = 32, - crypto_box_PUBLICKEYBYTES = 32, - crypto_box_SECRETKEYBYTES = 32, - crypto_box_BEFORENMBYTES = 32, - crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES, - crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES, - crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES, - crypto_sign_BYTES = 64, - crypto_sign_PUBLICKEYBYTES = 32, - crypto_sign_SECRETKEYBYTES = 64, - crypto_sign_SEEDBYTES = 32, - crypto_hash_BYTES = 64; - - nacl.lowlevel = { - crypto_core_hsalsa20: crypto_core_hsalsa20, - crypto_stream_xor: crypto_stream_xor, - crypto_stream: crypto_stream, - crypto_stream_salsa20_xor: crypto_stream_salsa20_xor, - crypto_stream_salsa20: crypto_stream_salsa20, - crypto_onetimeauth: crypto_onetimeauth, - crypto_onetimeauth_verify: crypto_onetimeauth_verify, - crypto_verify_16: crypto_verify_16, - crypto_verify_32: crypto_verify_32, - crypto_secretbox: crypto_secretbox, - crypto_secretbox_open: crypto_secretbox_open, - crypto_scalarmult: crypto_scalarmult, - crypto_scalarmult_base: crypto_scalarmult_base, - crypto_box_beforenm: crypto_box_beforenm, - crypto_box_afternm: crypto_box_afternm, - crypto_box: crypto_box, - crypto_box_open: crypto_box_open, - crypto_box_keypair: crypto_box_keypair, - crypto_hash: crypto_hash, - crypto_sign: crypto_sign, - crypto_sign_keypair: crypto_sign_keypair, - crypto_sign_open: crypto_sign_open, - - crypto_secretbox_KEYBYTES: crypto_secretbox_KEYBYTES, - crypto_secretbox_NONCEBYTES: crypto_secretbox_NONCEBYTES, - crypto_secretbox_ZEROBYTES: crypto_secretbox_ZEROBYTES, - crypto_secretbox_BOXZEROBYTES: crypto_secretbox_BOXZEROBYTES, - crypto_scalarmult_BYTES: crypto_scalarmult_BYTES, - crypto_scalarmult_SCALARBYTES: crypto_scalarmult_SCALARBYTES, - crypto_box_PUBLICKEYBYTES: crypto_box_PUBLICKEYBYTES, - crypto_box_SECRETKEYBYTES: crypto_box_SECRETKEYBYTES, - crypto_box_BEFORENMBYTES: crypto_box_BEFORENMBYTES, - crypto_box_NONCEBYTES: crypto_box_NONCEBYTES, - crypto_box_ZEROBYTES: crypto_box_ZEROBYTES, - crypto_box_BOXZEROBYTES: crypto_box_BOXZEROBYTES, - crypto_sign_BYTES: crypto_sign_BYTES, - crypto_sign_PUBLICKEYBYTES: crypto_sign_PUBLICKEYBYTES, - crypto_sign_SECRETKEYBYTES: crypto_sign_SECRETKEYBYTES, - crypto_sign_SEEDBYTES: crypto_sign_SEEDBYTES, - crypto_hash_BYTES: crypto_hash_BYTES, - - gf: gf, - D: D, - L: L, - pack25519: pack25519, - unpack25519: unpack25519, - M: M, - A: A, - S: S, - Z: Z, - pow2523: pow2523, - add: add, - set25519: set25519, - modL: modL, - scalarmult: scalarmult, - scalarbase: scalarbase, - }; - - /* High-level API */ - - function checkLengths(k, n) { - if (k.length !== crypto_secretbox_KEYBYTES) throw new Error('bad key size'); - if (n.length !== crypto_secretbox_NONCEBYTES) throw new Error('bad nonce size'); - } - - function checkBoxLengths(pk, sk) { - if (pk.length !== crypto_box_PUBLICKEYBYTES) throw new Error('bad public key size'); - if (sk.length !== crypto_box_SECRETKEYBYTES) throw new Error('bad secret key size'); - } - - function checkArrayTypes() { - for (var i = 0; i < arguments.length; i++) { - if (!(arguments[i] instanceof Uint8Array)) - throw new TypeError('unexpected type, use Uint8Array'); - } - } - - function cleanup(arr) { - for (var i = 0; i < arr.length; i++) arr[i] = 0; - } - - nacl.randomBytes = function(n) { - var b = new Uint8Array(n); - randombytes(b, n); - return b; - }; - - nacl.secretbox = function(msg, nonce, key) { - checkArrayTypes(msg, nonce, key); - checkLengths(key, nonce); - var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length); - var c = new Uint8Array(m.length); - for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i]; - crypto_secretbox(c, m, m.length, nonce, key); - return c.subarray(crypto_secretbox_BOXZEROBYTES); - }; - - nacl.secretbox.open = function(box, nonce, key) { - checkArrayTypes(box, nonce, key); - checkLengths(key, nonce); - var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length); - var m = new Uint8Array(c.length); - for (var i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i]; - if (c.length < 32) return null; - if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return null; - return m.subarray(crypto_secretbox_ZEROBYTES); - }; - - nacl.secretbox.keyLength = crypto_secretbox_KEYBYTES; - nacl.secretbox.nonceLength = crypto_secretbox_NONCEBYTES; - nacl.secretbox.overheadLength = crypto_secretbox_BOXZEROBYTES; - - nacl.scalarMult = function(n, p) { - checkArrayTypes(n, p); - if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); - if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size'); - var q = new Uint8Array(crypto_scalarmult_BYTES); - crypto_scalarmult(q, n, p); - return q; - }; - - nacl.scalarMult.base = function(n) { - checkArrayTypes(n); - if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size'); - var q = new Uint8Array(crypto_scalarmult_BYTES); - crypto_scalarmult_base(q, n); - return q; - }; - - nacl.scalarMult.scalarLength = crypto_scalarmult_SCALARBYTES; - nacl.scalarMult.groupElementLength = crypto_scalarmult_BYTES; - - nacl.box = function(msg, nonce, publicKey, secretKey) { - var k = nacl.box.before(publicKey, secretKey); - return nacl.secretbox(msg, nonce, k); - }; - - nacl.box.before = function(publicKey, secretKey) { - checkArrayTypes(publicKey, secretKey); - checkBoxLengths(publicKey, secretKey); - var k = new Uint8Array(crypto_box_BEFORENMBYTES); - crypto_box_beforenm(k, publicKey, secretKey); - return k; - }; - - nacl.box.after = nacl.secretbox; - - nacl.box.open = function(msg, nonce, publicKey, secretKey) { - var k = nacl.box.before(publicKey, secretKey); - return nacl.secretbox.open(msg, nonce, k); - }; - - nacl.box.open.after = nacl.secretbox.open; - - nacl.box.keyPair = function() { - var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); - var sk = new Uint8Array(crypto_box_SECRETKEYBYTES); - crypto_box_keypair(pk, sk); - return {publicKey: pk, secretKey: sk}; - }; - - nacl.box.keyPair.fromSecretKey = function(secretKey) { - checkArrayTypes(secretKey); - if (secretKey.length !== crypto_box_SECRETKEYBYTES) - throw new Error('bad secret key size'); - var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES); - crypto_scalarmult_base(pk, secretKey); - return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; - }; - - nacl.box.publicKeyLength = crypto_box_PUBLICKEYBYTES; - nacl.box.secretKeyLength = crypto_box_SECRETKEYBYTES; - nacl.box.sharedKeyLength = crypto_box_BEFORENMBYTES; - nacl.box.nonceLength = crypto_box_NONCEBYTES; - nacl.box.overheadLength = nacl.secretbox.overheadLength; - - nacl.sign = function(msg, secretKey) { - checkArrayTypes(msg, secretKey); - if (secretKey.length !== crypto_sign_SECRETKEYBYTES) - throw new Error('bad secret key size'); - var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length); - crypto_sign(signedMsg, msg, msg.length, secretKey); - return signedMsg; - }; - - nacl.sign.open = function(signedMsg, publicKey) { - checkArrayTypes(signedMsg, publicKey); - if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) - throw new Error('bad public key size'); - var tmp = new Uint8Array(signedMsg.length); - var mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey); - if (mlen < 0) return null; - var m = new Uint8Array(mlen); - for (var i = 0; i < m.length; i++) m[i] = tmp[i]; - return m; - }; - - nacl.sign.detached = function(msg, secretKey) { - var signedMsg = nacl.sign(msg, secretKey); - var sig = new Uint8Array(crypto_sign_BYTES); - for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i]; - return sig; - }; - - nacl.sign.detached.verify = function(msg, sig, publicKey) { - checkArrayTypes(msg, sig, publicKey); - if (sig.length !== crypto_sign_BYTES) - throw new Error('bad signature size'); - if (publicKey.length !== crypto_sign_PUBLICKEYBYTES) - throw new Error('bad public key size'); - var sm = new Uint8Array(crypto_sign_BYTES + msg.length); - var m = new Uint8Array(crypto_sign_BYTES + msg.length); - var i; - for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i]; - for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i]; - return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); - }; - - nacl.sign.keyPair = function() { - var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); - var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); - crypto_sign_keypair(pk, sk); - return {publicKey: pk, secretKey: sk}; - }; - - nacl.sign.keyPair.fromSecretKey = function(secretKey) { - checkArrayTypes(secretKey); - if (secretKey.length !== crypto_sign_SECRETKEYBYTES) - throw new Error('bad secret key size'); - var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); - for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i]; - return {publicKey: pk, secretKey: new Uint8Array(secretKey)}; - }; - - nacl.sign.keyPair.fromSeed = function(seed) { - checkArrayTypes(seed); - if (seed.length !== crypto_sign_SEEDBYTES) - throw new Error('bad seed size'); - var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES); - var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES); - for (var i = 0; i < 32; i++) sk[i] = seed[i]; - crypto_sign_keypair(pk, sk, true); - return {publicKey: pk, secretKey: sk}; - }; - - nacl.sign.publicKeyLength = crypto_sign_PUBLICKEYBYTES; - nacl.sign.secretKeyLength = crypto_sign_SECRETKEYBYTES; - nacl.sign.seedLength = crypto_sign_SEEDBYTES; - nacl.sign.signatureLength = crypto_sign_BYTES; - - nacl.hash = function(msg) { - checkArrayTypes(msg); - var h = new Uint8Array(crypto_hash_BYTES); - crypto_hash(h, msg, msg.length); - return h; - }; - - nacl.hash.hashLength = crypto_hash_BYTES; - - nacl.verify = function(x, y) { - checkArrayTypes(x, y); - // Zero length arguments are considered not equal. - if (x.length === 0 || y.length === 0) return false; - if (x.length !== y.length) return false; - return (vn(x, 0, y, 0, x.length) === 0) ? true : false; - }; - - nacl.setPRNG = function(fn) { - randombytes = fn; - }; - - (function() { - // Initialize PRNG if environment provides CSPRNG. - // If not, methods calling randombytes will throw. - var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null; - if (crypto && crypto.getRandomValues) { - // Browsers. - var QUOTA = 65536; - nacl.setPRNG(function(x, n) { - var i, v = new Uint8Array(n); - for (i = 0; i < n; i += QUOTA) { - crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA))); - } - for (i = 0; i < n; i++) x[i] = v[i]; - cleanup(v); - }); - } else if (typeof commonjsRequire !== 'undefined') { - // Node.js. - crypto = require$$7; - if (crypto && crypto.randomBytes) { - nacl.setPRNG(function(x, n) { - var i, v = crypto.randomBytes(n); - for (i = 0; i < n; i++) x[i] = v[i]; - cleanup(v); - }); - } - } - })(); - - })( module.exports ? module.exports : (self.nacl = self.nacl || {})); - }); - - let ntor = {}; - - /** - * Number of bytes to derive from successful ntor handshakes. - * @readonly - * @default - */ - ntor.keybytes = 92; - - /** - * Protocol identifier, prefix tweaks used in ntor handshakes various hashes. - * @readonly - * @default - * - * @see ntor.tweaks - */ - ntor.protoid = "ntor-curve25519-sha256-1"; - - /** - * Tweaks used in ntor handshakes for various hashes and key derivation. - * @enum - * @readonly - * - * @see ntor.hash - */ - ntor.tweaks = { - /** - * rfc5869 Expand {info} - * @type kdf - */ - expand: ntor.protoid + ":key_expand", - /** - * rfc5869 Extract {salt} - * @type kdf - */ - key: ntor.protoid + ":key_extract", - /** - * H({secret_input}, t_verify) - * @type ntor - */ - verify: ntor.protoid + ":verify", - /** - * suffix of {auth_input} - * @type ntor - */ - server: ntor.protoid + "Server", - /** - * H({auth_input}, t_mac) - * @type ntor - */ - mac: ntor.protoid + ":mac" - }; - - /** - * Tweaked pseudo-random function factory, see {@link ntor.hash}. - * - * @param {ntor.tweaks} tweak tweak to use - * @return {hash_t} - * - * @see ntor.hash - */ - ntor.hash_factory = function (tweak) { - tweak = ntor.tweaks[tweak]; - tweak = sjcl.codec.utf8String.toBits(tweak); - - /** - * Tweaked pseudo-random function used by {@link ntor}, returned - * by {@link ntor.hash_factory}. - * - * @interface hash_t - * @see ntor.hash - * - * @property {Object} hmac underlying hmac provider - */ - var hash = { - hmac: new sjcl.misc.hmac(tweak), - /** - * Compute parent tweaked pseudo-random function on provided data. - * - * @function - * @name hash_t#encrypt - * @param {Uint8Array} data input data - */ - encrypt: function (data) { - data = enc.bits(data); - data = hash.hmac.encrypt(data); - return dec.bits(data) - } - }; - return hash - }; - - /** - * Tweaked pseudo-random functions used in ntor handshakes. - * @enum - * @type hash_t - * - * @see ntor.tweaks - */ - ntor.hash = { - /** - * used for H({secret_input}, t_verify) during ntor handshakes - */ - verify: ntor.hash_factory("verify"), - /** - * used for H({auth_input}, t_mac) during ntor handshakes - */ - mac: ntor.hash_factory("mac"), - /** - * used for extraction during ntor handshakes key derivation - */ - prk: ntor.hash_factory("key") - }; - - /** - * Compute ntor key derivation from given material to n bytes. - * - * @param {Uint8Array} material ntor {secret_input} handshake - * @param {int} n number of bytes to output - * @return {Uint8Array} - */ - ntor.kdf = function (material, n) { - material = ntor.hash.prk.encrypt(material); - var hash = new sjcl.misc.hmac(enc.bits(material)); - - var tweak = ntor.tweaks["expand"]; - tweak = sjcl.codec.utf8String.toBits(tweak); - - var idx = 1; - var out = enc.bits([]); - var last = enc.bits([]); - while (sjcl.bitArray.bitLength(out) < n * 8) { - var idxbits = enc.bits([idx]); - var current = sjcl.bitArray.concat(tweak, idxbits); - - last = hash.encrypt(sjcl.bitArray.concat(last, current)); - out = sjcl.bitArray.concat(out, last); - idx = idx + 1; - } - - return dec.bits(sjcl.bitArray.clamp(out, n * 8)) - }; - - - /** - * Compute the first part of a ntor handshake, - * writes a {@link half_t} in {@link endpoint_t#material}. - * - * @param {endpoint_t} endpoint state where to store half-finished material - * @param {Object} descriptor node descriptor to handshake with - * @param {Boolean} encode if true, returns base64 (default: true) - * @return {Uint8Array|string} - * - * @see ntor.shake - */ - ntor.hand = function (endpoint, descriptor, encode) { - if (encode === undefined) - encode = true; - if (descriptor === undefined) - descriptor = endpoint.guard; - - var identity = dec.base64(descriptor.router.identity + "="); - var onionkey = dec.base64(descriptor["ntor-onion-key"]); - - /** - * Internal object, half-finished ntor handshake state in {@link - * endpoint_t#material}, created by: - *
        - *
      • {@link ntor.hand} - *
      • {@link ntor.fast} - *
      • {@link lnn.auth} - *
      - * Captures cryptographic state required to finish the handshake. - * - * @interface half_t - * - * @property {Object} ntor key pair - * @property {Uint8Array} identity node identity - * @property {Uint8Array} onionkey node public key - */ - endpoint.material = { - ntor: naclFast.box.keyPair(), - identity: identity, - onionkey: onionkey - }; - - var pubkey = endpoint.material.ntor.publicKey; - var length = identity.length + onionkey.length + pubkey.length; - - var payload = new Uint8Array(length); - payload.set(identity, 0); - payload.set(onionkey, identity.length); - payload.set(pubkey, identity.length + onionkey.length); - - if (encode) - return enc.base64(payload) - return payload - }; - - /** - * Just as {@link ntor.hand} but without node identity and onion key – used - * by {@link lnn.fast}, writes a {@link half_t} in {@link endpoint_t#material}. - * - *
      Note: always returns base64-encoded handshake.
      - * - * @param {endpoint_t} endpoint state where to store half-finished material - * @return {string} - * - * @see lnn.fast - */ - ntor.fast = function (endpoint) { - endpoint.material = {}; - endpoint.material.ntor = naclFast.box.keyPair(); - endpoint.material.identity = null; - endpoint.material.onionkey = null; - return enc.base64(endpoint.material.ntor.publicKey) - }; - - /** - * Compute the second part of a ntor handshake read - * from {@link endpoint_t#material}, returns derived bytes suitable as - * {@link ntor.slice} input. - * - *
      Note: returns null if handshake is invalid.
      - * - * @param {endpoint_t} endpoint state where to read half-finished material - * @param {Uint8Array|string} data server part of the handshake - * @param {boolean} encoded if true, decode data as base64 - * (default: true) - * @return {Uint8Array|null} - * - * @see ntor.hand - */ - ntor.shake = function (endpoint, data, encoded) { - if (encoded === undefined) - encoded = true; - if (encoded) - data = dec.base64(data); - - var client_pubkey = endpoint.material.ntor.publicKey; - var client_secret = endpoint.material.ntor.secretKey; - var server_pubkey = data.slice(0, naclFast.scalarMult.scalarLength); - var server_auth = data.slice(naclFast.scalarMult.scalarLength); - - var identity = endpoint.material.identity; - var onionkey = endpoint.material.onionkey; - - var exp_share = naclFast.scalarMult(client_secret, server_pubkey); - var exp_onion = naclFast.scalarMult(client_secret, onionkey); - - var protoid = dec.utf8(ntor.protoid); - var length = exp_share.length * 2 + identity.length + onionkey.length * 3; - var off = 0; - - var secret_input = new Uint8Array(length + protoid.length); - secret_input.set(exp_share, off); off += exp_share.length; - secret_input.set(exp_onion, off); off += exp_onion.length; - secret_input.set(identity, off); off += identity.length; - secret_input.set(onionkey, off); off += onionkey.length; - secret_input.set(client_pubkey, off); off += client_pubkey.length; - secret_input.set(server_pubkey, off); off += server_pubkey.length; - secret_input.set(protoid, off); - var verify = ntor.hash.verify.encrypt(secret_input); - - var server = dec.utf8(ntor.tweaks["server"]); - var length = verify.length + identity.length + onionkey.length * 3; - var off = 0; - - var auth_input = new Uint8Array(length + server.length); - auth_input.set(verify, off); off += verify.length; - auth_input.set(identity, off); off += identity.length; - auth_input.set(onionkey, off); off += onionkey.length; - auth_input.set(server_pubkey, off); off += server_pubkey.length; - auth_input.set(client_pubkey, off); off += client_pubkey.length; - auth_input.set(server, off); - var client_auth = ntor.hash.mac.encrypt(auth_input); - - var valid = true; - length = client_auth.length; - for (var i = 0; i < length; i++) { - if (client_auth[i] != server_auth[i]) - valid = false; - } - - var zero_onion = 0; - var zero_share = 0; - length = exp_onion.length; - for (var i = 0; i < length; i++) { - if (exp_onion[i] == 0) - zero_onion = zero_onion + 1; - if (exp_share[i] == 0) - zero_share = zero_share + 1; - } - - if (zero_onion == exp_onion.length || zero_share == exp_share.length) - valid = false; - - if (valid) { - return ntor.kdf(secret_input, ntor.keybytes) - } - return null - }; - - /** - * Build a shared cryptographic {@link material_t} for - * {@link endpoint_t#material} from the output of {@link ntor.shake}. - * - *
      -	 * Note: assume KEY_LEN == 16 (aes256) and HASH_LEN == 20 (sha1) internally.
      -	 * 
      - * - * @param {Uint8Array} material exactly {@link ntor.keybytes} - * bytes - * @return {material_t} - */ - ntor.slice = function (material) { - var k = 16; // KEY_LEN - var h = 20; // HASH_LEN - - /** - * Internal object, stores shared cryptographic material - * as {@link endpoint_t#material}, returned by {@link ntor.slice}. - * - * @interface material_t - * @see ntor.slice - * - * @property {Uint8Array} key_hash unused - * @property {Uint8Array} forward_key used in {@link forward_t} - * @property {Uint8Array} forward_digest used in {@link forward_t} - * @property {Uint8Array} backward_key used in {@link backward_t} - * @property {Uint8Array} backward_digest used in {@link backward_t} - */ - var material = { - key_hash: material.slice(h * 2 + k * 2), - forward_digest: material.slice(0, h), - backward_digest: material.slice(h, h * 2), - forward_key: material.slice(h * 2, h * 2 + k), - backward_key: material.slice(h * 2 + k, h * 2 + k * 2) - }; - return material - }; - - // (function only used for proxy auth, not a part of regular ntor handshake) - - /** - *
      -	 * Note: this function is used for proxy-server authentication and is not a
      -	 * part of regular ntor handshakes nor the Tor specification.
      -	 * 
      - * - * Take an endpoint that uses the proxy-server authentication API (such as one - * configured through {@link lnn.auth}) and the base64-encoded fields "auth" - * and "data" as returned by the proxy-server, then returns the decoded data - * if and only if the authentication succeeded. - * - */ - ntor.auth = function (endpoint, client, data) { - var pending_material = endpoint.material; - endpoint.material = endpoint.auth; - - var data = dec.base64(data); - var material = ntor.shake(endpoint, client); - if (material == null) - throw "Invalid auth." - endpoint.material = pending_material; - - var key = material.slice(0, 32); - var nonce = material.slice(32, 32 + 24); - data = naclFast.secretbox.open(data, nonce, key); - return JSON.parse(enc.utf8(data)) - }; - - /** - * @module relay - */ - - let relay = {}; - relay.payload_len = 509; - relay.data_len = relay.payload_len - 11; - relay.full_len = 5 + relay.payload_len; - relay.cmd = { - "begin": 1, 1: "begin", - "data": 2, 2: "data", - "end": 3, 3: "end", - "connected": 4, 4: "connected", - "sendme": 5, 5: "sendme", - "extend": 6, 6: "extend", - "extended": 7, 7: "extended", - "truncate": 8, 8: "truncate", - "truncated": 9, 9: "truncated", - "drop": 10, 10: "drop", - "resolve": 11, 11: "resolve", - "resolved": 12, 12: "resolved", - "begin_dir": 13, 13: "begin_dir", - "extend2": 14, 14: "extend2", - "extended2": 15, 15: "extended2" - }; - - relay.pack = function (cmd, stream_id, data) { - if (data === undefined) - data = new Uint8Array(0); - if (stream_id === undefined) - stream_id = 0; - - if (typeof (data) == "string") - data = dec.utf8(data); - - var cell = new Uint8Array(relay.full_len); /* padded with \x00 */ - var view = new DataView(cell.buffer); - - view.setUint32(0, 2147483648 /* fake circuit_id */, false); - view.setUint8(4, 3 /* RELAY CELL */, false); - view.setUint8(5, relay.cmd[cmd], false); - view.setUint16(6, 0 /* recognized */, false); - view.setUint16(8, stream_id, false); - // (implicit 4-bytes zeroed digest at offset 10) - view.setUint16(14, data.length, false); - cell.set(data, 16); - - return cell - }; - - relay.extend = function (handshake, host, port, identity, eidentity) { - // (assuming that host is an IPv4) - var addr = new Uint8Array(host.split(".")); - if (addr.join(".") != host) - throw "Invalid extend IPv4 address, fatal." - - port = parseInt(port); - if (typeof (identity) == "string") - identity = dec.base64(identity); - if (typeof (eidentity) == "string") - eidentity = dec.base64(eidentity + "="); - - var nspec = 2; - if (eidentity !== undefined) - nspec += 1; - - var length = (1 // Number of link specifiers - + 1 + 1 + 6 // 1. IPv4 addr+port - + 1 + 1 + identity.length // 2. Legacy identity - + 2 // Client handshake type (0x00002 ntor) - + 2 // Client handshake length - + handshake.length); // Actual handshake content - - if (nspec == 3) - length += 1 + 1 + eidentity.length; // 3. Ed25519 identity - - var off = 0; - var data = new Uint8Array(length); - var view = new DataView(data.buffer); - view.setUint8(off, nspec /* nb of specifiers */, false); off += 1; - - view.setUint8(off, 0 /* TLS-over-TCP IPv4 specifier */, false); off += 1; - view.setUint8(off, 6, false); off += 1; /* length 1 byte */ - data.set(addr, off); off += 4; /* address 4 bytes */ - view.setUint16(off, port, false); off += 2; /* port 2 bytes */ - - view.setUint8(off, 2 /* Legacy identity specifier */, false); off += 1; - view.setUint8(off, identity.length, false); off += 1; - data.set(identity, off); off += identity.length; - - if (nspec == 3) { - view.setUint8(off, 3 /* Ed25519 identity specifier */, false); off += 1; - view.setUint8(off, eidentity.length, false); off += 1; - data.set(eidentity, off); off += eidentity.length; - } - - view.setUint16(off, 2 /* handshake: 0x00002 ntor */, false); off += 2; - view.setUint16(off, handshake.length, false); off += 2; - data.set(handshake, off); - - return data - }; - - relay.begin = function (host, port) { - let valid = false; - if (host.match("(\\d\+\\.){3}\\d\+")) - valid = true; - if (host.match("^\\[[\\d:]*\\]$")) - valid = true; - if (!valid && host.slice(-1) != ".") - host = host + "."; - if (host.match("^([a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)*$")) - valid = true; - if (host.slice(-1) == ".") - host = host.slice(0, -1); - - if (!valid) - throw "Invalid host provided?" - var address = dec.utf8(host + ":" + port); - - var data = new Uint8Array(address.length + 1 + 4); // (1o null, 4o flags) - data.set(address, 0); - data[address.length + 1 + 3] = 5; // flags IPv6 okay+preferred and IPv4 okay - - return data - }; - - /** - * @module onion - */ - - function ctr(key) { - var key = enc.bits(key); - var aes = new sjcl.cipher.aes(key); - - var ctr = { - prf: aes, - nonce: 0, - buffer: new Uint8Array(0), - extend: function (n) { - var length = (Math.floor(n / 16) + 1) * 16; - var remains = ctr.buffer; - ctr.buffer = new Uint8Array(length + remains.length); - ctr.buffer.set(remains, 0); - - for (var idx = remains.length; idx < ctr.buffer.length; idx += 16) { - var nonce = new Uint8Array(16); - new DataView(nonce.buffer).setUint32(12, ctr.nonce, false); - - nonce = enc.bits(nonce); - var pad = dec.bits(ctr.prf.encrypt(nonce)); - - ctr.buffer.set(pad, idx); - ctr.nonce = ctr.nonce + 1; - } - }, - process: function (data) { - if (data.length > ctr.buffer.length) - ctr.extend(data.length); - - var data = data.slice(0); - for (var idx = 0; idx < data.length; idx++) { - data[idx] ^= ctr.buffer[idx]; - } - ctr.buffer = ctr.buffer.slice(data.length); - - return data - } - }; - return ctr - } - - function sha(digest) { - var digest = enc.bits(digest); - - var sha = { - hash: new sjcl.hash.sha1(), - digest: function (data) { - sha.hash.update(enc.bits(data)); - data = new sjcl.hash.sha1(sha.hash).finalize(); - return dec.bits(data) - } - }; - - sha.hash.update(digest); - return sha - } - - function forward(endpoint) { - var early = 8; - var layers = []; - if (endpoint.forward != null) { - layers = endpoint.forward.layers; - layers.push(endpoint.forward); - early = endpoint.forward.early; - } - - var forward = { - iv: 0, - ctr: ctr(endpoint.material.forward_key), - sha: sha(endpoint.material.forward_digest), - early: early, // (first 8 relay cells will be replaced by relay_early) - layers: layers, - encrypt: function (cell) { - if ((cell.length) != relay.full_len) - throw "Invalid size for cell, fatal." - - var body = cell.slice(5); - for (var idx = 0; idx < forward.layers.length; idx++) { - body.set(forward.layers[idx].ctr.process(body), 0); - } - cell.set(forward.ctr.process(body), 5); - - if (forward.early > 0 && cell[4] == 3 /* relay */) { - forward.early = forward.early - 1; - cell[4] = 9; /* relay_early */ - } - return cell - }, - digest: function (cell) { - if ((cell.length) != relay.full_len) - throw "Invalid size for cell, fatal." - - var body = cell.slice(5); - body.set(new Uint8Array(4), 5); - return forward.sha.digest(body).slice(0, 4) - } - }; - return forward - } - - function backward(endpoint) { - var layers = []; - if (endpoint.backward != null) { - layers = endpoint.backward.layers; - layers.push(endpoint.backward); - } - - var backward = { - iv: 0, - ctr: ctr(endpoint.material.backward_key), - sha: sha(endpoint.material.backward_digest), - layers: layers, - decrypt: function (cell) { - if ((cell.length) != relay.full_len) - throw "Invalid size for cell, fatal." - - var body = cell.slice(5); - - for (var idx = 0; idx < backward.layers.length; idx++) { - body.set(backward.layers[idx].ctr.process(body), 0); - - cell.set(body, 5); - - var recognized = cell.slice(6, 8); - if (recognized[0] == recognized[1] && recognized[0] == 0) { - var digest = cell.slice(10, 14); - var expect = backward.layers[idx].digest(cell); - - var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false); - - if (expect[0] == digest[0] && - expect[1] == digest[1] && - expect[2] == digest[2] && - expect[3] == digest[3]) { - if (length <= relay.data_len) { - console.log("Warning: Cell sent by intermediate \ - tor node, after " + (idx + 1) + " hop(s)"); - return cell - } - } - } - } - - cell.set(backward.ctr.process(body), 5); - var digest = cell.slice(10, 14); - cell.set(new Uint8Array(4), 10); - - var recognized = cell.slice(6, 8); - if (!(recognized[0] == recognized[1] && recognized[0] == 0)) { - throw "Invalid cell recognized field." - } - - var expect = backward.digest(cell); - if (!( digest[0] == expect[0] - && digest[1] == expect[1] - && digest[2] == expect[2] - && digest[3] == expect[3])) { - throw "Invalid cell digest." - } - - var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false); - if (length > relay.data_len) { - throw "Invalid cell data length." - } - - return cell - - - }, - digest: function (cell) { - if ((cell.length) != relay.full_len) - throw "Invalid size for cell, fatal." - - var body = cell.slice(5); - body.set(new Uint8Array(4), 5); - return backward.sha.digest(body).slice(0, 4) - } - }; - return backward - } - - function build(endpoint, cmd, stream_id, data) { - var cell = relay.pack(cmd, stream_id, data); - cell.set(endpoint.forward.digest(cell), 10); - return endpoint.forward.encrypt(cell) - } - - function peel(endpoint, cell) { - var cell = endpoint.backward.decrypt(cell); - - - - var length = new DataView(cell.slice(14, 16).buffer).getUint16(0, false); - - var id = new DataView(cell.slice(8, 10).buffer).getUint16(0, false); - var cmd = relay.cmd[cell.slice(5, 6)[0]]; - var data = cell.slice(16, 16 + length); - var relay_ = { cmd: cmd, stream_id: id, data: data }; - - return relay_ - } - - /** - * @module consensusParser - */ - - let consensusParser = {}; - - consensusParser.parse = function (rawText, flavor = 'microdesc') { - if (typeof rawText !== 'string') throw `Error: the consensus must be given as a string` - consensusParser.lines = rawText.split('\n'); - consensusParser.words = consensusParser.lines[0].split(' '); - consensusParser.consensus = {}; - consensusParser.validFlags = ['Authority', 'BadExit', 'Exit', 'Fast', 'Guard', 'HSDir', 'NoEdConsensus', 'Stable', 'StaleDesc', 'Running', 'Valid', 'V2Dir']; - consensusParser.index = 0; - consensusParser.totalLines = consensusParser.lines.length; - - if (flavor != 'unflavored' && flavor != 'microdesc') { - throw 'Error: Unexpected flavor' - } - consensusParser.consensus['flavor'] = flavor; - - consensusParser.consumeHeaders(); - consensusParser.consumeAuthority(); - consensusParser.consumeRouters(); - consensusParser.consumeFooter(); - - return consensusParser.consensus - }; - - //----------------------------------HEADERS PARSER-------------------------------- - - /** - * Function that parses the headers - */ - consensusParser.consumeHeaders = function () { - consensusParser.consumeNetworkStatusVersion(); - consensusParser.consumeVoteStatus(); - consensusParser.consumeConsensusMethod(); - consensusParser.consumeDate('valid-after'); - consensusParser.consumeDate('fresh-until'); - consensusParser.consumeDate('valid-until'); - consensusParser.consumeVotingDelay(); - consensusParser.tryConsumeVersions('client-versions'); - consensusParser.tryConsumeVersions('server-versions'); - - while (consensusParser.words[0] === 'package') { - consensusParser.consumePackage(); - } - - consensusParser.consumeKnownFlags(); - consensusParser.tryConsumeProtocols('recommended-client-protocols'); - consensusParser.tryConsumeProtocols('recommended-relay-protocols'); - consensusParser.tryConsumeProtocols('required-client-protocols'); - consensusParser.tryConsumeProtocols('required-relay-protocols'); - consensusParser.tryConsumeParams(); - consensusParser.tryConsumeShareRand('shared-rand-previous-value'); - consensusParser.tryConsumeShareRand('shared-rand-current-value'); - - }; - - /** - * Parse the field network-status-version - */ - consensusParser.consumeNetworkStatusVersion = function () { - let expectedLength = 2; - if (consensusParser.consensus.flavor == 'microdesc') { - expectedLength = 3; - if (consensusParser.words[2] != 'microdesc') - throw 'Error: Flavor mismatch in header.' - } - - let version = consensusParser.tryParseKeyValueInteger('network-status-version', expectedLength); - consensusParser.consensus['headers'] = { - 'network-status-version': { - 'version': version, - 'flavor': consensusParser.consensus.flavor - } - }; - - consensusParser.nextLine(); - }; - - /** - * Parse the field vote-status - * @throws WrongParameterException if status is not consensus - */ - consensusParser.consumeVoteStatus = function () { - let status = consensusParser.tryParseKeyValueString('vote-status'); - if (status !== 'consensus') throw `WrongParameterException: vote-status must be consensus` - consensusParser.consensus['headers']['vote-status'] = status; - consensusParser.nextLine(); - }; - - /** - * Parse the field consensus-method - */ - consensusParser.consumeConsensusMethod = function () { - consensusParser.consensus['headers']['consensus-method'] = consensusParser.tryParseKeyValueInteger('consensus-method'); - consensusParser.nextLine(); - }; - - /** - * Parse the fields valid-after, fresh-until and valid-until - * @param {strin} word - */ - consensusParser.consumeDate = function (word) { - consensusParser.consensus['headers'][word] = consensusParser.tryParseDate(word); - consensusParser.nextLine(); - }; - - /** - * Parse the field voting-delay - * @throws NotEqualException if consensusParser.words[0] != word - * @throws WrongParameterException if consensusParser.words[1] or consensusParser.words[2] is not a number - * @throws WrongFormatException if consensusParser.words.length is not 3 - */ - consensusParser.consumeVotingDelay = function () { - consensusParser.checkFormat(3, 'voting-delay'); - if (isNaN(consensusParser.words[1])) throw `WrongParameterException: ${words[1]} is not a number` - if (isNaN(consensusParser.words[2])) throw `WrongParameterException: ${words[2]} is not a number` - - consensusParser.consensus['headers']['voting-delay'] = { - 'vote': Number(consensusParser.words[1]), - 'dist': Number(consensusParser.words[2]) - }; - - consensusParser.nextLine(); - }; - - /** - * Try to parse the fields client-versions or server-versions if they are present - * @param {string} word either client-versions or server-versions - */ - consensusParser.tryConsumeVersions = function (word) { - - if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` - if (consensusParser.words[0] === word) { - consensusParser.consensus['headers'][word] = consensusParser.tryParseCommaSeparatedList(word); - consensusParser.nextLine(); - } - }; - - /** - * Parses the field package - * @throws WrongFormatException if consensusParser.words.length is smaller than 5 - */ - consensusParser.consumePackage = function () { - - if (consensusParser.words.length < 5) throw `WrongFormatException: at least 5 fields are expected` - if (consensusParser.consensus['headers']['package'] === undefined) consensusParser.consensus['headers']['package'] = []; - - let pack = { - 'name': consensusParser.words[1], - 'version': consensusParser.words[2], - 'url': consensusParser.words[3] - }; - let remaining = consensusParser.words.splice(4, consensusParser.words.length); - let digests = {}; - - for (let digest of remaining) { - let tmp = digest.split('='); - digests[tmp[0]] = tmp[1]; - } - - pack['digests'] = digests; - consensusParser.consensus['headers']['package'].push(pack); - consensusParser.nextLine(); - }; - - /** - * Parses the field package - * @throws NotValidFlagException if one of the flags is not in the valid flag list - */ - consensusParser.consumeKnownFlags = function () { - consensusParser.consensus['headers']['flags'] = consensusParser.tryParseFlags(); - consensusParser.nextLine(); - }; - - /** - * Try to parse the fields recommended-client-protocols, recommended-relay-protocols, required-client-protocols and required-client-protocols if they are present - * @param {string} word either client-versions or server-versions - */ - consensusParser.tryConsumeProtocols = function (word) { - if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` - if (consensusParser.words[0] === word) { - consensusParser.consensus['headers'][word] = consensusParser.tryParseRanges(consensusParser.words.splice(1, consensusParser.words.length)); - consensusParser.nextLine(); - } - - }; - /** - * Try to parse the field params if it is present - */ - consensusParser.tryConsumeParams = function () { - if (consensusParser.words[0] === 'params') { - consensusParser.consensus['headers']['params'] = consensusParser.tryParseParams(); - consensusParser.nextLine(); - } - }; - - /** - * Try to parse the fields shared-rand-previous-value and shared-rand-current-value if they are present - * @param {string} word specify the field - */ - consensusParser.tryConsumeShareRand = function (word) { - if (consensusParser.consensus['headers'][word] !== undefined) throw `AlreadyPresentException: ${word} can only appear once` - if (consensusParser.words[0] === word) { - let reveals = Number(consensusParser.words[1]); - let value = consensusParser.words[2]; - - if (!consensusParser.isBase64(value)) throw `InvalidParameterException: value ${value} must be in hexadecimal` - - consensusParser.consensus['headers'][word] = { - 'NumReveals': reveals, - 'Value': value - }; - - consensusParser.nextLine(); - } - }; - - //-------------------AUTHORITY PARSER-------------------------------- - /** - * Parses the authority part of the consensus - * @throws InvalidIPException if address or IP are not valid IP addresses - * @throws InvalidPortException if dirport or orport are not valid ports - */ - consensusParser.consumeAuthority = function () { - if (consensusParser.words[0] !== 'dir-source') throw `WrongFieldException: there must be at least one dir-source` - consensusParser.consensus['dir-sources'] = []; - - while (consensusParser.words[0] === 'dir-source') { - consensusParser.consumeDirSource(); - } - }; - - /** - * Parse a dir-source - * @throws InvalidIPException if the IP-address is not valid - * @throws InvalidPortException if dirport or orport are not valid - * @throws InvalidParameterException if the vote-digest is not in hexadecimal - */ - consensusParser.consumeDirSource = function () { - let dirSource = {}; - consensusParser.checkFormat(7, 'dir-source'); - - dirSource['nickname'] = consensusParser.words[1]; - - if (!consensusParser.isHex(consensusParser.words[2])) throw `InvalidParameterException: vote-digest ${consensusParser.words[2]} must be in hexadecimal` - dirSource['identity'] = consensusParser.words[2].toUpperCase(); - - dirSource['hostname'] = consensusParser.words[3]; - - if (!consensusParser.isValidIP(consensusParser.words[4])) throw `InvalidIPException: ${consensusParser.words[4]} is not a valid IP` - - dirSource['address'] = consensusParser.words[4]; - - if (!consensusParser.isValidPort(Number(consensusParser.words[5])) || !consensusParser.isValidPort(Number(consensusParser.words[6]))) throw `InvalidPortException` - - dirSource['dirport'] = Number(consensusParser.words[5]); - dirSource['orport'] = Number(consensusParser.words[6]); - - consensusParser.nextLine(); - dirSource['contact'] = consensusParser.words.splice(1, consensusParser.words.length).join(' '); - consensusParser.nextLine(); - let digest = consensusParser.tryParseKeyValueString('vote-digest').toUpperCase(); - - if (!consensusParser.isHex(digest)) throw `InvalidParameterException: vote-digest ${digest} must be in hexadecimal` - - dirSource['vote-digest'] = digest; - consensusParser.consensus['dir-sources'].push(dirSource); - consensusParser.nextLine(); - - - }; - - //-------------------ROUTER PARSER----------------------------------- - /** - * Consume each router status entry - * @throws WrongFieldException if there is no router entry - */ - consensusParser.consumeRouters = function () { - if (consensusParser.words[0] !== 'r') throw `WrongFieldException: there must be at least one router` - consensusParser.consensus['routers'] = []; - - while (consensusParser.words[0] === 'r') { - let router = {}; - consensusParser.consumeRfield(router); - - if (consensusParser.words[0] === 'a') router['a'] = []; - while (consensusParser.words[0] === 'a') { - consensusParser.consumeAfield(router); - } - - if (consensusParser.consensus.flavor == 'microdesc') { - consensusParser.consumeMfield(router); - } - - consensusParser.consumeSfield(router); - consensusParser.tryConsumeVfield(router); - consensusParser.tryConsumePrField(router); - consensusParser.tryConsumeWfield(router); - consensusParser.tryConsumePfield(router); - - consensusParser.consensus['routers'].push(router); - } - - }; - - /** - * Parses the field 'r' of the router status entry - * @param {} router - * @throws InvalidParameterException if the fields are not valid - */ - consensusParser.consumeRfield = function (router) { - let len = 9; - if (consensusParser.consensus.flavor == 'microdesc') len = 8; - consensusParser.checkFormat(len, 'r'); - - router['nickname'] = consensusParser.words[1]; - - if (!consensusParser.isBase64(consensusParser.words[2] + "=")) throw `InvalidParameterException: identity ${consensusParser.words[2]} must be in base64` - router['identity'] = consensusParser.words[2]; - - let nxt = 3; - if (consensusParser.consensus.flavor == 'unflavored') { - if (!consensusParser.isBase64(consensusParser.words[3] + "=")) throw `InvalidParameterException: digest ${consensusParser.words[3]} must be in base64` - router['digest'] = consensusParser.words[3]; - nxt += 1; - } - - if (!consensusParser.isValidDate(consensusParser.words[nxt])) throw `InvalidParameterException: date ${consensusParser.words[nxt]} must have the format YYYY-MM-DD` - router['date'] = consensusParser.words[nxt]; - - if (!consensusParser.isValidTime(consensusParser.words[nxt + 1])) throw `InvalidParameterException: time ${consensusParser.words[nxt + 1]} must have the format HH:MM:SS` - router['time'] = consensusParser.words[nxt + 1]; - - if (!consensusParser.isValidIP(consensusParser.words[nxt + 2])) throw `InvalidParameterException: IP ${consensusParser.words[nxt + 2]} must be a valid IP address` - router['address'] = consensusParser.words[nxt + 2]; - - if (!consensusParser.isValidPort(Number(consensusParser.words[nxt + 3]))) throw `InvalidParameterException: ORPort ${consensusParser.words[nxt + 3]} must be a valid port` - router['orport'] = Number(consensusParser.words[nxt + 3]); - - if (!consensusParser.isValidPort(Number(consensusParser.words[nxt + 4]))) throw `InvalidParameterException: DirPort ${consensusParser.words[nxt + 4]} must be a valid port` - router['dirport'] = Number(consensusParser.words[nxt + 4]); - - consensusParser.nextLine(); - }; - - /** - * Parses the field 'a' of the router status entry - * @param {} router - * @throws InvalidParameterException if the fields are not valid - */ - consensusParser.consumeAfield = function (router) { - let i = consensusParser.words[1].indexOf("]"); - let address = consensusParser.words[1].slice(1, i); - if (!consensusParser.isValidIP(address)) throw `InvalidParameterException: IP ${address} must be a valid IP address` - - let guessedType = 'IPv6'; - if (consensusParser.isIPv4(address)) { - guessedType = 'IPv4'; - } - - let port = Number(consensusParser.words[1].slice(address.length + 3, consensusParser.words[1].length)); - - if (!consensusParser.isValidPort(port)) throw `InvalidParameterException: port ${port} must be a valid port` - - router['a'].push({ - 'ip': address, - 'port': port, - 'type': guessedType - }); - - consensusParser.nextLine(); - - }; - - /** - * Parses the field 's' of the router status entry - * @param {} router - */ - consensusParser.consumeSfield = function (router) { - router['flags'] = consensusParser.tryParseFlags(); - consensusParser.nextLine(); - }; - - /** - * Tries to parse the field 'v' of the router status entry - * @param {} router - */ - consensusParser.tryConsumeVfield = function (router) { - if (consensusParser.words[0] === 'v') { - consensusParser.checkFormat(3, 'v'); - router['version'] = consensusParser.words.splice(1, consensusParser.words.length).join(' '); - consensusParser.nextLine(); - } - }; - /** - * Tries to parse the field 'v' of the router status entry - * @param {} router - */ - consensusParser.tryConsumePrField = function (router) { - if (consensusParser.words[0] === 'pr') { - router['protocols'] = consensusParser.tryParseRanges(consensusParser.words.splice(1, consensusParser.words.length)); - consensusParser.nextLine(); - } - }; - /** - * Tries to parse the field 'w' of the router status entry - * @param {} router - */ - consensusParser.tryConsumeWfield = function (router) { - if (consensusParser.words[0] === 'w') { - router['w'] = consensusParser.tryParseParams(); - consensusParser.nextLine(); - } - }; - /** - * Tries to parse the field 'p' of the router status entry - * @param {} router - */ - consensusParser.tryConsumePfield = function (router) { - if (consensusParser.words[0] === 'p') { - consensusParser.checkFormat(3, 'p'); - if (consensusParser.words[1] !== 'accept' && consensusParser.words[1] !== 'reject') throw `WrongParameterException: ${consensusParser.words[1]} must be either accept or reject` - - - let portList = consensusParser.parse_range_once(consensusParser.words[2]); - - router['exit-policy'] = { - 'type': consensusParser.words[1], - 'PortList': portList - }; - consensusParser.nextLine(); - } - }; - - /** - * Parses the field 'm' of the router status entry (for microdesc flavor) - * @param {} router - */ - consensusParser.consumeMfield = function (router) { - consensusParser.checkFormat(2, 'm'); - - if (!consensusParser.isBase64(consensusParser.words[1] + "=")) throw `InvalidParameterException: digest ${consensusParser.words[1]} must be in base64` - router['micro-digest'] = consensusParser.words[1]; - - consensusParser.nextLine(); - }; - - - //-------------------FOOTER PARSER ---------------------------------- - - /** - * Consume the footer - * @throws WrongFieldException if there is no footer or no signature - */ - consensusParser.consumeFooter = function () { - if (consensusParser.words[0] !== 'directory-footer') throw `WrongFieldException: there must be a footer` - consensusParser.nextLine(); - consensusParser.consensus['footer'] = {}; - consensusParser.tryConsumeBandwidthWeights(); - - if (consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: there must be at least one signature` - consensusParser.consensus['footer']['directory-signatures'] = []; - - while (consensusParser.words[0] === 'directory-signature') { - consensusParser.consensus['footer']['directory-signatures'].push(consensusParser.consumeSignature()); - } - - }; - - /** - * Tries to consume the bandwidth weights - */ - consensusParser.tryConsumeBandwidthWeights = function () { - if (consensusParser.words[0] === 'bandwidth-weights') { - consensusParser.consensus['footer']['bandwidth-weights'] = consensusParser.tryParseParams(); - consensusParser.nextLine(); - } - }; - - /** - * Consumes the signature - * @throws WrongFieldException if the first field is not directory-signature - * @throws InvalidParameterException if either the identity or the signing-key-digest are not in hexadecimal - */ - consensusParser.consumeSignature = function () { - if (consensusParser.words[0] !== 'directory-signature') throw `WrongFieldException: next field must be directory-signature` - let length = consensusParser.words.length; - - let algo; - let remaining; - if (length === 4) { - algo = consensusParser.words[1]; - remaining = consensusParser.words.splice(2, length); - } else if (length === 3) { - algo = 'sha1'; - remaining = consensusParser.words.splice(1, length); - } - else throw `WrongParameterException: directory-signature has 3 or 4 arguments` - - let identity = remaining[0]; - if (!consensusParser.isHex(identity)) throw `InvalidParameterException: the identity ${identity} must be in hexadecimal` - - let digest = remaining[1]; - if (!consensusParser.isHex(digest)) throw `InvalidParameterException: the signing-key-digest ${digest} must be in hexadecimal` - - consensusParser.nextLine(); - - let signature = consensusParser.parseSignature(); - if (consensusParser.index < consensusParser.totalLines - 1) consensusParser.nextLine(); - - return { - 'Algorithm': algo, - 'identity': identity, - 'signing-key-digest': digest, - 'signature': signature - } - }; - //-------------------GENERAL PARSER----------------------------------- - - /** - * Parses lines with the format "field value" where value is an integer and field must be equal to word and return value. - * @param {string} word indicates to which field we are adding the newly parsed line - * @throws NotEqualException if consensusParser.words[0] != word - * @throws WrongParameterException if consensusParser.words[1] is not a number - * @throws WrongFormatException if consensusParser.words.length is not 2 - */ - consensusParser.tryParseKeyValueInteger = function (word, expectedLength = 2) { - consensusParser.checkFormat(expectedLength, word); - if (isNaN(consensusParser.words[1])) throw `WrongParameterException: ${consensusParser.words[1]} is not a number` - - return Math.floor(consensusParser.words[1]) - }; - - /** - * Parses lines with the format "field value" where value is a string and field must be equal to word and return value. - * @param {string} word indicates to which field we are adding the newly parsed line - * @throws NotEqualException if consensusParser.words[0] != word - * @throws WrongFormatException if consensusParser.words.length is not 2 - */ - consensusParser.tryParseKeyValueString = function (word) { - consensusParser.checkFormat(2, word); - return consensusParser.words[1] - }; - - /** - * Parses lines with the format "field YYYY-MM-DD HH:MM:SS" where field must be equal to word and return a date object - * @param {string} word indicates to which field we are adding the newly parsed line - * @throws NotEqualException if consensusParser.words[0] != word - * @throws WrongFormatException if consensusParser.words.length is not 2 - * @throws NonValidDateException if the date is not valid - * @throws NonValidTimeException if the time is not valid - */ - consensusParser.tryParseDate = function (word) { - consensusParser.checkFormat(3, word); - if (!consensusParser.isValidDate(consensusParser.words[1])) throw `NonValidDateException: ${consensusParser.words[1]} is not a valid date` - if (!consensusParser.isValidTime(consensusParser.words[2])) throw `NonValidTimeException: ${consensusParser.words[2]} is not a valid time` - - return { - "date": consensusParser.words[1], - "time": consensusParser.words[2] - } - }; - - /** - * Parses lines with the format "field list" where list is a comma separated list, returns the list as an array - * @param {string} word indicates to which field we are adding the newly parsed line - * @throws NotEqualException if consensusParser.words[0] != word - * @throws WrongFormatException if consensusParser.words.length is not 2 - */ - consensusParser.tryParseCommaSeparatedList = function (word) { - consensusParser.checkFormat(2, word); - return consensusParser.words[1].split(",") - }; - - /** - * Parse the ranges of the protocols - * @param pairs Array of entries => Keyword=Values where values is the range - */ - consensusParser.tryParseRanges = function (pairs) { - let content = {}; - - for (let pair of pairs) { - if (pair.includes("=")) { - let tmp = pair.split("="); - content[tmp[0]] = consensusParser.parse_range_once(tmp[1]); - } - } - - return content - }; - - /** - * Helper function to parse the ranges of the protocols - * @param value the range we want to parse - */ - consensusParser.parse_range_once = function (value) { - value = value.split(','); - let subvalues = []; - - for (let subvalue of value) { - if (subvalue.includes('-')) { - let lowHigh = subvalue.split('-'); - let low = Number(lowHigh[0]); - let high = Number(lowHigh[1]); - - if (low === high - 1) { - subvalues.push([low, high]); - } else { - subvalues.push([[low, high]]); - } - } else { - subvalues.push([Number(subvalue)]); - } - } - return subvalues - }; - /** - * Parse the flags - * @throws NotValidFlagException if one of the flags is not valid - */ - consensusParser.tryParseFlags = function () { - let flags = consensusParser.words.splice(1, consensusParser.words.length); - - for (let f of flags) { - if (!consensusParser.validFlags.includes(f)) throw `NotValidFlagException: ${f} is not a valid flag` - } - - return flags - }; - - /** - * Parse signature - * @throws WrongFormatException if the line does not start with ----BEGIN - */ - consensusParser.parseSignature = function () { - if (consensusParser.words[0] !== '-----BEGIN') throw `WrongFormatException` - consensusParser.nextLine(); - let signature = ''; - while (consensusParser.lines[consensusParser.index] !== "-----END SIGNATURE-----") { - signature += consensusParser.lines[consensusParser.index]; - consensusParser.nextLine(); - } - return signature - }; - - - /** - * parase parameters - */ - consensusParser.tryParseParams = function () { - let content = {}; - for (let param of consensusParser.words.splice(1, consensusParser.words.length)) { - let tmp = param.split('='); - content[tmp[0]] = Number(tmp[1]); - } - return content - }; - - /** - * Check if the string in date has the format YYYY-MM-DD - * @param {string} time String representing the date - */ - consensusParser.isValidDate = function (date) { - if (typeof date !== 'string') return false - let regex = /^\d{4}[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$/; - return regex.test(date) - }; - - /**Check if the string time has the format HH:MM:SS - * @param {string} time String representing the time - */ - consensusParser.isValidTime = function (time) { - if (typeof time !== 'string') return false - let regex = /^(0[0-9]|1[0-9]|2[0-3])[:][0-5][0-9][:][0-5][0-9]$/; - return regex.test(time) - }; - - /** - * Check if the IP address is valid (either IPv4 or IPv6) - * @param {string} IP the address we want to check - */ - consensusParser.isValidIP = function (IP) { - let regex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$|^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$|^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/; - return regex.test(IP) - }; - - /** - * Check if the IP is an IPv4 address - * @param {string} IP - */ - consensusParser.isIPv4 = function (IP) { - let regex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; - return regex.test(IP) - }; - - /** - * Check if the given port is valid - * @param {number} port - */ - consensusParser.isValidPort = function (port) { - if (isNaN(port)) return false - //TODO: < or <= ? - return port >= 0 && port <= 65535 - }; - - /** - * Check if the given string is in hexadecimal - * @param {string} str - */ - consensusParser.isHex = function (str) { - let regex = /^[a-fA-F0-9]+$/; - return regex.test(str) - }; - - /** - * Check if the given string is in base 64 - * @param {string} str - */ - consensusParser.isBase64 = function (str) { - let regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; - return regex.test(str) - }; - - /** - * Updates consensusParser.index and consensusParser.words - * @throws EndOfFileException if the end of the file has already been reached - */ - consensusParser.nextLine = function () { - if (consensusParser.index >= consensusParser.totalLines) throw `EndOfFileException: there are no lines to parse` - consensusParser.words = consensusParser.lines[++consensusParser.index].split(" "); - }; - - /** - * Checks if words has the expected size and that words[0] is equal to word - * @param {number} expectedLength the expected length of words - * @param {string} expectedWord the expected word[0] - */ - consensusParser.checkFormat = function (expectedLength, expectedWord) { - if (consensusParser.words.length != expectedLength) throw `WrongFormatException: ${expectedLength} fields are expected` - if (consensusParser.words[0] != expectedWord) throw `NotEqualException:b ${expectedWord} is not equal to ${consensusParser.words[0]}` - }; - - /** - * @module parser - */ - - let parser = {}; - - parser.descriptors = { - line_count: 0, - total_lines: -1, - lines: undefined, - valid_bridge_distribution: ["none", "any", "https", "email", "moat", "hyphae"], - - exactly_once: ["router", "bandwidth", "published", "onion-key", "signing-key", "router-signatures"], - exactly_once_mic: ["onion-key", "policy", "ipv6-policy"], - - parse: function (raw_descriptors, flavor = 'microdesc') { - if (flavor != 'unflavored' && flavor != 'microdesc') { - throw 'Error: Unexpected flavor' - } - - let descriptors = []; - parser.descriptors.lines = raw_descriptors.split('\n'); - parser.descriptors.line_count = 0; - parser.descriptors.total_lines = parser.descriptors.lines.length; - parser.descriptors.flavor = flavor; - - while (parser.descriptors.line_count < parser.descriptors.total_lines) { - if (parser.descriptors.lines[parser.descriptors.line_count] === "") { - parser.descriptors.line_count++; - continue - } - - let descriptor = parser.descriptors.consume_one_node(); - descriptor['flavor'] = flavor; - descriptors.push(descriptor); - } - return descriptors - }, - validate: function (descriptors, consensus, flavor = 'microdesc', fail_on_missing = false) { - let digest_name = (flavor == 'unflavored') ? 'digest' : 'micro-digest'; - let digests = []; - for (let idx = 0; idx < consensus['routers'].length; idx++) { - let router = consensus['routers'][idx]; - digests.push(router[digest_name]); - } - - let obtained = []; - for (let idx = 0; idx < descriptors.length; idx++) { - obtained.push(descriptors[idx][digest_name]); - } - - let invalid = []; - console.log(obtained.length); - for (let idx = 0; idx < digests.length; idx++) { - let digest = digests[idx]; - if (obtained.includes(digest)) { - obtained.splice(obtained.indexOf(digest), 1); - } - else - invalid.push(digest); - } - console.log(obtained.length); - - if (obtained.length) { - throw `Invalid descriptors found` - } - - if (fail_on_missing && invalid.length > 0) - throw `Failed to obtain some descriptors` - } - }; - parser.descriptors.consume_one_node = function () { - - if (parser.descriptors.lines[parser.descriptors.line_count].startsWith('@type')) parser.descriptors.line_count++; - if (parser.descriptors.lines[parser.descriptors.line_count] === "") { - parser.descriptors.line_count++; - } - - let descriptor = {}; - let startLine = parser.descriptors.line_count; - - if (parser.descriptors.flavor == 'unflavored') { - descriptor = parser.descriptors.consume_router(descriptor); - descriptor = parser.descriptors.try_consume_identity_ed25519(descriptor); - } else { - descriptor = parser.descriptors.consume_onion_key(descriptor); - } - - let line = parser.descriptors.lines[parser.descriptors.line_count]; - - - while (true) { - if (parser.descriptors.flavor == 'unflavored') { - if (line.startsWith("router-signature")) - break - } else { - if (parser.descriptors.line_count == parser.descriptors.total_lines - || line.startsWith('@type') || line.startsWith('onion-key')) - break - } - - - let index_sp = line.indexOf(" "); - let first_word = (index_sp === -1) ? line : line.substring(0, index_sp); - switch (first_word) { - case "master-key-ed25519": - descriptor = parser.descriptors.consume_master_key_ed25519(descriptor); - break - case "platform": - descriptor = parser.descriptors.consume_platform(descriptor); - break - case "published": - descriptor = parser.descriptors.consume_published(descriptor); - break - case "bandwidth": - descriptor = parser.descriptors.consume_bandwidth(descriptor); - break - case "fingerprint": - descriptor = parser.descriptors.consume_fingerprint(descriptor); - break - case "hibernating": - descriptor = parser.descriptors.consume_hibernating(descriptor); - break - case "uptime": - descriptor = parser.descriptors.consume_uptime(descriptor); - break - case "extra-info-digest": - descriptor = parser.descriptors.consume_extra_info_digest(descriptor); - break - case "caches-extra-info": - descriptor = parser.descriptors.consume_single_word_line("caches-extra-info", descriptor); - break - case "onion-key": - descriptor = parser.descriptors.consume_onion_key(descriptor); - break - case "onion-key-crosscert": - descriptor = parser.descriptors.consume_onion_key_crosscert(descriptor); - break - case "ntor-onion-key": - descriptor = parser.descriptors.consume_base64_digest('ntor-onion-key', descriptor); - break - case "ntor-onion-key-crosscert": - descriptor = parser.descriptors.consume_ntor_onion_key_crosscert(descriptor); - break - case "accept": - descriptor = parser.descriptors.consume_exit_policy("accept", descriptor); - break - case "reject": - descriptor = parser.descriptors.consume_exit_policy("reject", descriptor); - break - case "signing-key": - descriptor = parser.descriptors.consume_signing_key(descriptor); - break - case "ipv6-policy": - descriptor = parser.consume_exit_policy('ipv6-policy', parser.descriptors.lines, parser.descriptors.line_count++, descriptor); - break - case "router-sig-ed25519": - descriptor = parser.descriptors.consume_router_sig_ed25519(descriptor); - break - case "contact": - descriptor = parser.consume_contact(parser.descriptors.lines, parser.descriptors.line_count++, descriptor); - break - case "bridge-distribution": - descriptor = parser.descriptors.consume_bridge_distribution(descriptor); - break - case "family": - descriptor = parser.descriptors.consume_family(descriptor); - break - case "read-history": - descriptor = parser.descriptors.consume_history("read", descriptor); - break - case "write-history": - descriptor = parser.descriptors.consume_history("write", descriptor); - break - case "eventdns": - descriptor = parser.descriptors.consume_eventdns(descriptor); - break - case "hidden-service-dir": - descriptor = parser.descriptors.consume_single_word_line("hidden-service-dir", descriptor); - break - case "allow-single-hop-exits": - descriptor = parser.descriptors.consume_single_word_line("allow-single-hop-exits", descriptor); - break - case "tunnelled-dir-server": - descriptor = parser.descriptors.consume_single_word_line("tunnelled-dir-server", descriptor); - break - case "proto": - descriptor = parser.consume_proto("proto", parser.descriptors.lines, parser.descriptors.line_count++, descriptor); - break - case "p": - descriptor = parser.consume_exit_policy('p', parser.descriptors.lines, parser.descriptors.line_count++, descriptor); - break - case "p6": - descriptor = parser.consume_exit_policy('p6', parser.descriptors.lines, parser.descriptors.line_count++, descriptor); - break - case "id": - descriptor = parser.descriptors.consume_id(descriptor); - break - default: - ++parser.descriptors.line_count; - break - } - line = parser.descriptors.lines[parser.descriptors.line_count]; - - } - - - if (descriptor['ipv6-policy'] === undefined) descriptor['ipv6-policy'] = { - "type": "reject", - "PortList": [[1, 65535]] - }; - if (descriptor['policy'] === undefined) { - descriptor['policy'] = { - "type": "reject", - "PortList": [[1, 65535]] - }; - } - - - let fields = parser.descriptors.exactly_once_mic; - let endLine = parser.descriptors.line_count; //include till router-signature - - if (parser.descriptors.flavor == 'unflavored') { - endLine += 1; //include till router-signature - descriptor = parser.descriptors.consume_router_signature(descriptor); - fields = parser.descriptors.exactly_once; - } - if (!parser.descriptors.check_exactly_once(descriptor, fields)) throw "Invalid descriptor: some mandatory fields are not present" - - let fullDesc = ""; - for (let i = startLine; i < endLine; i++) { - if (parser.descriptors.lines[i] == "") - continue - fullDesc += (parser.descriptors.lines[i] + '\n'); - } - - if (parser.descriptors.flavor == 'unflavored') { - let digest = sjcl.hash.sha1.hash(fullDesc); - digest = enc.base64(dec.bits(digest)); - - - while (digest.length > 0 && digest[digest.length - 1] == '=') - digest = digest.slice(0, -1); - descriptor['digest'] = digest; - } - else { - let mdigest = sjcl.hash.sha256.hash(fullDesc); - mdigest = dec.bits(mdigest); - mdigest = enc.base64(mdigest); - - while (mdigest.length > 0 && mdigest[mdigest.length - 1] == '=') - mdigest = mdigest.slice(0, -1); - descriptor['micro-digest'] = mdigest; - } - return descriptor - }; - - /** - * Checks that all mandatory fields of the descriptor were parsed - */ - parser.descriptors.check_exactly_once = function (descriptor, fields) { - - if (descriptor['ipv6-policy'] === undefined) ; - - let parsed = true; - if (descriptor['identity-ed25519'] !== undefined) { - parsed = descriptor["ntor-onion-key-crosscert"] !== undefined && descriptor["onion-key-crosscert"] !== undefined && descriptor["router-sig-ed25519"] !== undefined; - } else { - parsed = descriptor["router-sig-ed25519"] === undefined; - } - - return parsed && fields.every(field => descriptor[field] !== undefined) - }; - - /** - * Consume the field router of the descriptor - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_router = function (descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); - parser.check_format(6, 'router', words); - - if (!parser.is_valid_nickname(words[1])) throw `Invalid nickname: ${words[1]} contains non-alphanumeric characters` - if (!parser.is_valid_ipv4(words[2])) throw `Invalid address: ${words[2]} is not a valid iPv4 address` - if (!parser.is_valid_port(words[3])) throw `Invalid port: ${words[3]} is not a valid port (0 to 65535)` - if (!parser.is_valid_port(words[4])) throw `Invalid port: ${words[4]} is not a valid port (0 to 65535)` - if (!parser.is_valid_port(words[5])) throw `Invalid port: ${words[5]} is not a valid port (0 to 65535)` - - descriptor['router'] = { - "nickname": words[1], - "address": words[2], - "orport": Number(words[3]), - "socksport": Number(words[4]), - "dirport": Number(words[5]) - }; - - ++parser.descriptors.line_count; - - return descriptor - }; - /** - * Consume try to consume the identity ed25519 certificate and its master key - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.try_consume_identity_ed25519 = function (descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); - if (words[0] === 'identity-ed25519') { - parser.check_format(1, 'identity-ed25519', words); - ++parser.descriptors.line_count; - - let [offset, certificate] = parser.consume_pem(parser.descriptors.lines, parser.descriptors.line_count); - parser.descriptors.line_count += offset + 1; - descriptor['identity'] = { - "type": "ed25519", - "cert": certificate - }; - - return descriptor - } - - return descriptor - }; - - parser.descriptors.consume_id = function (descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); - - parser.check_format(3, 'id', words); - let type = words[1]; - - if (type != 'rsa1024' && type != 'ed25519') - throw `Unexpected identity type ${type}` - - parser.check_reused('identity', descriptor); - if (!parser.is_valid_base64(parser.add_ending(words[2]))) - throw `Invalid master key: the master key ${words[2]} must be in base64` - - descriptor['identity'] = { - "type": type, - "master-key": words[2] - }; - - ++parser.descriptors.line_count; - return descriptor - }; - - /** - * Parse the master-key-ed25519 - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_master_key_ed25519 = function (descriptor) { - - let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); - parser.check_format(2, 'master-key-ed25519', words); - parser.check_reused('master-key-ed25519', descriptor); - let key = words[1]; - if (!parser.is_valid_base64(parser.add_ending(key))) throw `Invalid master key: the master key ${words[1]} must be in base64` - descriptor['identity']['master-key'] = key; - parser.descriptors.line_count++; - - return descriptor - }; - - /** - * Consume the line if it starts with platform - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_platform = function (descriptor) { - parser.check_reused("platform", descriptor); - let line = parser.descriptors.lines[parser.descriptors.line_count]; - let platform = line.substring("platform".length + 1); - descriptor['platform'] = platform; - parser.descriptors.line_count++; - return descriptor - }; - - /** - * Consume the time of the published field - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_published = function (descriptor) { - parser.check_reused('published', descriptor); - descriptor['published'] = parser.consume_date('published', parser.descriptors.lines[parser.descriptors.line_count]); - ++parser.descriptors.line_count; - return descriptor - }; - - /** - * Consume the bandwidth fields - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_bandwidth = function (descriptor) { - parser.check_reused('bandwidth', descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(4, 'bandwidth', words); - - let avg = Number(words[1]); - let burst = Number(words[2]); - let obs = Number(words[3]); - - if (avg < 0 || burst < 0 || obs < 0) throw `Invalid bandwidth: must be non-negative` - - descriptor['bandwidth'] = { - "avg": avg, - "burst": burst, - "observed": obs - }; - - return descriptor - }; - - /** - * Consume the fingerprint field - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_fingerprint = function (descriptor) { - parser.check_reused('fingerprint', descriptor); - let line = parser.descriptors.lines[parser.descriptors.line_count++]; - let index_sp = line.indexOf(" "); - let fingerprint = line.substring(index_sp + 1); - - let bytes = fingerprint.split(" "); - let join_bytes = bytes.join(""); - if (bytes.length != 10) throw `Invalid fingerprint: wrong size` - if (!parser.is_valid_hex(join_bytes)) throw `Invalid fingerprint: not a hex string` - - let identity = sjcl.codec.hex.toBits(join_bytes); - identity = sjcl.codec.base64.fromBits(identity).replace("=", ""); - - descriptor['fingerprint'] = fingerprint; - descriptor['router']['identity'] = identity; - - return descriptor - }; - - /** - * Consume the hibernating field - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_hibernating = function (descriptor) { - parser.check_reused('hibernating', descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(2, 'hibernating', words); - - let b = Number(words[1]); - if (b !== 0 && b !== 1) throw `Invalid boolean` - descriptor['hibernating'] = b; - return descriptor - }; - - /** - * Consume the uptime field - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_uptime = function (descriptor) { - parser.check_reused('uptime', descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(2, 'uptime', words); - - let uptime = Number(words[1]); - - if (uptime < 0) throw `Invalid uptime: uptime must be non-negative` - - descriptor['uptime'] = uptime; - - return descriptor - }; - - /** - * Consume the onion key - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_onion_key = function (descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count].split(" "); - parser.check_reused('onion-key', descriptor); - parser.check_format(1, 'onion-key', words); - return parser.descriptors.consume_key('onion-key', descriptor) - }; - - /** - * Consume the extra info digest - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_extra_info_digest = function (descriptor) { - parser.check_reused('extra-info-digest', descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - if (words.length != 2 && words.length != 3) throw `Invalid format: 1 or 2 fields are expected` - - let sha1 = words[1]; - if (!parser.is_valid_hex(sha1)) throw `Invalid encoding: the sha1 digest must be in hexadecimal` - descriptor["extra-info-digest"] = { - "sha1": sha1 - }; - - if (words.length === 3) { - let sha256 = words[2]; - if (!parser.is_valid_base64(parser.add_ending(sha256))) throw `Invalid encoding: the sha256 digest must base 64` - descriptor['extra-info-digest']['sha256'] = sha256; - } - - return descriptor - }; - - /** - * Consume the single word line - * @param {string} type the field - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_single_word_line = function (type, descriptor) { - parser.check_reused(type, descriptor); - descriptor[type] = 'true'; - ++parser.descriptors.line_count; - - return descriptor - }; - - /** - * Consume the RSA signature generated using the onion-key - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_onion_key_crosscert = function (descriptor) { - parser.check_reused('onion-key-crosscert', descriptor); - return parser.descriptors.consume_key('onion-key-crosscert', descriptor) - }; - - /** - * Consume the ntor onion key of the descriptor - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_ntor_onion_key_crosscert = function (descriptor) { - - parser.check_reused('ntor-onion-key-crosscert', descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count].split(" "); - parser.check_format(2, 'ntor-onion-key-crosscert', words); - - let bit = Number(words[1]); - if (bit != 0 && bit != 1) throw "Invalid bit for ntor-onion-key-crosscert" - - let [offset, cert] = parser.consume_pem(parser.descriptors.lines, ++parser.descriptors.line_count); - parser.descriptors.line_count += offset + 1; - - descriptor['ntor-onion-key-crosscert'] = { - "bit": bit, - "cert": cert - }; - - return descriptor - - }; - - /** - * Consume the ED25519 signature - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_router_sig_ed25519 = function (descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(2, "router-sig-ed25519", words); - parser.check_reused("router-signatures", descriptor); - - let signature = words[1]; - - if (!parser.is_valid_base64(parser.add_ending(signature))) throw "Invalid digest: must be a base 64 string" - - descriptor["router-signatures"] = { - "ed25519": signature, - }; - - return descriptor - }; - - /** - * Consume the PKCS1 padded signature of the descriptor - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_router_signature = function (descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count].split(' '); - if (words[0] === 'router-signature') { - parser.check_format(1, 'router-signature', words); - ++parser.descriptors.line_count; - - let [offset, signature] = parser.consume_pem(parser.descriptors.lines, parser.descriptors.line_count); - parser.descriptors.line_count += offset + 1; - - if (descriptor["router-signatures"] === undefined) { - descriptor["router-signatures"] = {}; - } - - descriptor["router-signatures"]["rsa"] = signature; - - return descriptor - } - }; - - /** - * Consume the field bridge-distribution - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_bridge_distribution = function (descriptor) { - parser.check_reused('bridge-distribution', descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(2, 'bridge-distribution', words); - let dist = words[1]; - if (!parser.descriptors.valid_bridge_distribution.includes(dist)) dist = "none"; - - descriptor['bridge-distribution'] = dist; - - return descriptor - - }; - - /** - * Consume the field family - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_family = function (descriptor) { - parser.check_reused("family", descriptor); - - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - let family = words.splice(1); - - descriptor['family'] = family; - - return descriptor - }; - /** - * Consume the history fields - * @param {string} type the type of history - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_history = function (type, descriptor) { - let field = type + "-history"; - parser.check_reused(field, descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(6, type + "-history", words); - - let date = words[1]; - if (!parser.is_valid_date(date)) throw "Invalid date" - - let time = words[2]; - if (!parser.is_valid_time(time)) throw "Invalid time" - - let interval = Number(words[3].substring(1)); - let bytes = words[5].split(",").map(x => Number(x)); - - descriptor[field] = { - "date": date, - "time": time, - "interval": interval, - "bytes": bytes - }; - - return descriptor - }; - - /** - * Consume the field eventdns - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_eventdns = function (descriptor) { - parser.check_reused("eventdns", descriptor); - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(2, "eventdns", words); - - let bool = Number(words[1]); - - if (bool != 0 && bool != 1) throw "Invalid boolean" - - decriptor["eventdns"] = bool; - return descriptor - }; - - /** - * Consume field with a base 64 digest - * @param {String} field the field we want to parse - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_base64_digest = function (field, descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(2, field, words); - parser.check_reused(field, descriptor); - - let key = words[1]; - - if (!parser.is_valid_base64(parser.add_ending(key))) throw "Invalid digest: must be a base 64 string" - - descriptor[field] = key; - - return descriptor - }; - - /** - * Consume the signing keys - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_signing_key = function (descriptor) { - parser.check_reused('signing-key', descriptor); - return parser.descriptors.consume_key('signing-key', descriptor) - }; - - /** - * Parse the accept and reject exit policies and their exitpattern - * @param {string} type either reject or accept - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_exit_policy = function (type, descriptor) { - let words = parser.descriptors.lines[parser.descriptors.line_count++].split(" "); - parser.check_format(2, type, words); - - if (descriptor['policy'] === undefined) { - descriptor['policy'] = { - "type": "exitpattern", - "rules": [] - }; - } - - let rule = { - "type": type, - "pattern": words[1] - }; - - descriptor['policy']["rules"].push(rule); - - return descriptor - }; - - /** - * Consume the key of the given field and update the descriptor - * @param {string} field the field of the descriptor - * @param {object} descriptor the currently being built decriptors object - * @returns {Object} the updated descriptor - */ - parser.descriptors.consume_key = function (field, descriptor) { - let [offset, key] = parser.consume_pem(parser.descriptors.lines, ++parser.descriptors.line_count); - parser.descriptors.line_count += offset + 1; - descriptor[field] = key; - return descriptor - }; - - /** - * Checks if words has the expected size and that the first word of the line is equal to a given word - * @param {number} expected_length the expected length of the line - * @param {string} expected_word the expected word - * @param {Array} words the line splitted into words - */ - parser.check_format = function (expected_length, expected_word, words) { - if (words.length != expected_length) { - throw `wrong_format_exception: ${expected_length} fields are expected` - } else if (words[0] !== expected_word) { - throw `not_equal_exception: ${expected_word} is not equal to ${words[0]}` - } - }; - - /** - * Check if the IP is an IPv4 address - * @param {string} IP - */ - parser.is_valid_ipv4 = function (IP) { - let regex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; - return regex.test(IP) - }; - - /** - * Check if the given port is valid - * @param {number} port - */ - parser.is_valid_port = function (port) { - if (isNaN(port)) return false - return port >= 0 && port <= 65535 - }; - - /** - * Check if the given nickname is valid - * @param {string} nickname the nickname we want to verify - * @returns {boolean} the validity of the nickname - */ - parser.is_valid_nickname = function (nickname) { - let regex = /^[a-z0-9]+$/i; - return regex.test(nickname) - }; - - /** - * Check if the given string is in base 64 - * @param {string} str - */ - parser.is_valid_base64 = function (str) { - let regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/; - return regex.test(str) - }; - /** - * Check if the given string is in hexadecimal - * @param {string} str - */ - parser.is_valid_hex = function (str) { - let regex = /^[a-fA-F0-9]+$/; - return regex.test(str) - }; - - /** - * Consume a PEM format field - * @param {Array} lines the splitted textfield - * @param {Number} start where the pem starts - * @param {function} base_function optional function to verifiy the base - * @returns {Array} tuple containing the parsed pem and the offset - */ - parser.consume_pem = function (lines, start) { - let offset = 0; - let content = ''; - if (!lines[start].startsWith('-----BEGIN')) throw `Invalid signature, certificate or key: must begin with "-----BEGIN"` - offset++; - while (!lines[start + offset].startsWith("-----END")) { - content += lines[start + offset]; - offset++; - } - - if (!parser.is_valid_base64(content)) throw "Invalid PEM: must be in base 64" - - return [offset, content] - }; - - /** - * Parse ranges - * @param {string} ranges format: Keyword=Values... - * @returns {object} the parsed ranges - */ - parser.parse_range = function (ranges) { - let content = {}; - for (let pair of ranges) { - if (pair.includes("=")) { - let tmp = pair.split("="); - content[tmp[0]] = parser.parse_range_once(tmp[1]); - } - } - return content - }; - - /** - * This function parses ranges with the format nbr,nbr,.. where nbr is either an integer or 2 integers separated by a comma - * @param {string} value the sting we want to parse - * @returns {Array} a list containing the ranges - */ - parser.parse_range_once = function (value) { - value = value.split(','); - let subvalues = []; - - for (let subvalue of value) { - if (subvalue.includes('-')) { - let lowHigh = subvalue.split('-'); - let low = Number(lowHigh[0]); - let high = Number(lowHigh[1]); - - subvalues.push([low, high]); - } else { - subvalues.push([Number(subvalue)]); - } - } - return subvalues - }; - - /** - * This function parses the exit policies formatted as: field (accept/reject) PortList - * @param {string} field the field we want to parse - * @param {Array} lines the raw file split by '\n' - * @param {Number} index the index of the line - * @param {object} node the node we want to update - * @returns the updated node - */ - parser.consume_exit_policy = function (field, lines, index, node) { - parser.check_reused(field, node); - let words = lines[index].split(" "); - parser.check_format(3, field, words); - - let policy = words[1]; - if (policy !== 'accept' && policy !== 'reject') throw "Invalid policy: policy must either be accept or reject" - - let ranges = parser.parse_range_once(words[2]); - - if (field == 'p') field = 'policy'; - if (field == 'p6') field = 'ipv6-policy'; - - node[field] = { - 'type': policy, - 'PortList': ranges - }; - - return node - }; - - /** - * This function parses the contacts - * @param {string} field the field we want to parse - * @param {Array} lines the raw file split by '\n' - * @param {Number} index the index of the line - * @param {object} node the node we want to update - * @returns the updated node - */ - parser.consume_contact = function (lines, index, node) { - parser.check_reused("contact", node); - let contact = lines[index].substring("contact".length + 1); - node["contact"] = contact; - - return node - }; - - - /** - * Check if the string in date has the format YYYY-MM-DD - * @param {string} time String representing the date - */ - parser.is_valid_date = function (date) { - if (typeof date !== 'string') return false - let regex = /^\d{4}[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$/; - return regex.test(date) - }; - - /**Check if the string time has the format HH:MM:SS - * @param {string} time String representing the time - */ - parser.is_valid_time = function (time) { - if (typeof time !== 'string') return false - let regex = /^(0[0-9]|1[0-9]|2[0-3])[:][0-5][0-9][:][0-5][0-9]$/; - return regex.test(time) - }; - - /** - * Consume the line containing a date with the format field YYYY-MM-DD HH:MM:SS - * @param {string} field the field we are consuming - * @param {string} line the line we are consuming - * @returns {object} object containing both the date and the time - */ - parser.consume_date = function (field, line) { - let words = line.split(" "); - parser.check_format(3, field, words); - - if (!parser.is_valid_date(words[1])) throw `Invalid date: ${words[1]} is not a valid date` - if (!parser.is_valid_time(words[2])) throw `Invalid time: ${words[2]} is not a valid time` - - return { - "date": words[1], - "time": words[2] - } - }; - - /** - * Consume the lines of protocols composed by ranges - * @param {string} type either protocols or proto - * @param {Array} lines the raw file split by '\n' - * @param {Number} index the index of the line - * @param {object} node the node we want to update - * @returns the updated node - */ - parser.consume_proto = function (type, lines, index, node) { - parser.check_reused(type, node); - let ranges = lines[index].split(" ").splice(1); - node[type] = parser.parse_range(ranges); - return node - }; - - /** - * Check if the field has already been parsed for the descriptor - * @param {string} field the field we want to verify - * @param {object} node the node for which we don't want a repetition of field - */ - parser.check_reused = function (field, node) { - if (node[field] !== undefined) throw `The field ${field} appears more than once` - }; - - /** - * Add the ending = for a base64 string - * @param {string} str the string we want to modify - * @returns {string} base 64 string with correct ending = - */ - parser.add_ending = function (str) { - if (str.length % 4 !== 0) { - let rem = str.length % 4; - for (let i = 0; i < 4 - rem; i++) str += '='; - } - return str - }; - - /** - * @module path - */ - - let path = {}; - - /** - * This function selects a path from the parsed consensus and parsed descriptors - * Flavor is 'unflavored' - * - * @param {Object} consensus a parsed consensus - * @param {Object} descriptors parsed descriptors of the routers in the consensus - * @param {Bool} isChutney boolean used to indicate if the path selection is done with routers from chutney - */ - path.select = function (consensus, descriptors, isChutney) { - if (isChutney === undefined) { - path["isChutney"] = false; - } else { - path["isChutney"] = isChutney; - } - - //build a hashmap of descriptor where the keys are the identity - path["descriptorsMap"] = {}; - - for (let descriptor of descriptors) { - let identity = descriptor['router'].identity; - path.descriptorsMap[identity] = descriptor; - } - - //pre-process consensus by filering the routers that do not obey - //the minimal constraints - path["consensus"] = consensus['routers'].filter(r => path.obeyMinimalConstraints(r)); - - //path selection - path["exit"] = path.chooseGoodExit(consensus); - path["guard"] = path.chooseGoodGuard(consensus); - path["middle"] = path.chooseGoodMiddle(consensus); - - //TODO: it should create/return a new path and not the descriptors - return [path.guard, path.middle, path.exit] - }; - - //assumes microdesc flavor. - path.select_end_path = function (consensus, descriptors, guard, isChutney, tcp_ports) { - if (isChutney === undefined) { - path["isChutney"] = false; - } else { - path["isChutney"] = isChutney; - } - - //build a hashmap of descriptor where the keys are the identity - let consMap = {}; - for (let router of consensus['routers']) { - consMap[router['micro-digest']] = router; - } - - path["descriptorsMap"] = {}; - - for (let descriptor of descriptors) { - descriptor['router'] = consMap[descriptor['micro-digest']]; - descriptor['bandwidth'] = {}; - descriptor['bandwidth']['avg'] = descriptor['router']['w']['Bandwidth']; - - let identity = descriptor['router'].identity; - path.descriptorsMap[identity] = descriptor; - } - - //pre-process consensus by filering the routers that do not obey - //the minimal constraints - console.log(consensus['routers'].length); - console.log(descriptors.length); - path["consensus"] = consensus['routers'].filter(r => path.obeyMinimalConstraints(r)); - console.log(path["consensus"].length); - - //path selection - path["guard"] = guard; - path["exit"] = path.chooseGoodExitGivenGuard(tcp_ports); - path["middle"] = path.chooseGoodMiddle(); - - //TODO: it should create/return a new path and not the descriptors - return [path.middle, path.exit] - }; - - /** - * This function checks if the given router obeys the minimal constraints needed for a router to be selected - * - * @param {Object} router the router subpart of one of the nodes of the parsed consensus - */ - path.obeyMinimalConstraints = function (router) { - let des = path.descriptorsMap[router['identity']]; - let flags = router['flags']; - - if (des === undefined) return false - if (!flags.includes("Valid")) return false - if (!flags.includes("Running")) return false - if (!router['version'].startsWith("Tor 0.3.")) return false - - if (des['identity']['type'] !== 'ed25519') return false - - return true - }; - - /** - * This function takes candidates and choose one at random weighted by its bandwidth average - * - * @param {Array} candidates the list of candidates - */ - - path.weightedRandomChoice = function (candidates) { - let total = 0; - - for (let candidate of candidates) { - let des = path.descriptorsMap[candidate['identity']]; - if (des !== undefined) { - total += des['bandwidth']['avg']; - } - } - - let r = Math.random() * total; - let upto = 0; - - for (let router of candidates) { - let des = path.descriptorsMap[router['identity']]; - - if (des !== undefined) { - let bandwidth = des['bandwidth']['avg']; - - if (upto + bandwidth >= r) return des - else upto += bandwidth; - } - - } - - throw "No candidate has been chosen" - }; - - /** - * This function checks if 2 routers are part of the same 16-subnet - * - * @param {Object} des1 the descriptor of the first router - * @param {Object} des2 the descriptor of the second router - * - */ - path.inSame16Subnet = function (des1, des2) { - - if (path.isChutney) { - return false - } - - let addr1 = des1['router']['address'].split("."); - let addr2 = des2['router']['address'].split("."); - - return addr1[0] === addr2[0] && addr1[1] === addr2[1] - }; - - /** - * This function checks if 2 routers are part of the same family - * - * @param {Object} des1 the descriptor of the first router - * @param {Object} des2 the descriptor of the second router - */ - path.inSameFamily = function (des1, des2) { - if (des1['family'] != undefined && des2['family'] != undefined) { - for (let fam of des1['family']) { - if (des2['family'].includes(fam)) return true - } - } - - return false - }; - - /** - * This function choose a good exit given the TOR path selection rules - */ - path.chooseGoodExit = function () { - let candidates = path.consensus.filter(path.isGoodExit); - return path.weightedRandomChoice(candidates) - }; - - path.chooseGoodExitGivenGuard = function (tcp_ports) { - let candidates = path.consensus.filter(r => path.isGoodExitGivenGuard(r, tcp_ports)); - console.log("Exit candidates: " + candidates.length); - return path.weightedRandomChoice(candidates) - }; - - /** - * This function checks if the given router is a suitable candidate to become an exit - * - * @param {Object} router the router subpart of one of the nodes of the parsed consensus - */ - path.isGoodExit = function (router) { - let flags = router['flags']; - if (!flags.includes('Exit') || flags.includes('BadExit')) return false - - if (router['exit-policy'] === undefined) - router['exit-policy'] = path.descriptorsMap[router.identity]['policy']; - if (router['exit-policy']['type'] !== 'accept') return false - - return true - - }; - - path.isGoodExitGivenGuard = function (router, tcp_ports) { - let flags = router['flags']; - if (!flags.includes('Exit') || flags.includes('BadExit')) return false - let des = path.descriptorsMap[router.identity]; - - - if (router['exit-policy'] === undefined) - router['exit-policy'] = des['policy']; - - let port_arr = router['exit-policy']['PortList']; - for (let i = 0; i < tcp_ports.length; i++) { - let found = false; - let cur_port = tcp_ports[i]; - - for (let j = 0; j < port_arr.length; j++) { - if (port_arr[j][0] == cur_port) { - found = true; - break - } - else if (port_arr[j].length == 2) { - if (port_arr[j][0] <= cur_port && cur_port <= port_arr[j][1]) { - found = true; - break - } - } - } - - if (router['exit-policy']['type'] == 'accept') { - if (!found) return false - } - else { - if (found) return false - } - } - - if (des === undefined) { - return false - } - - if (des["router"]["identity"] === path.guard["router"]["identity"]) { - return false - } - - if (path.inSame16Subnet(des, path.guard)) return false - if (path.inSameFamily(des, path.guard)) return false - - return true - }; - - /** - * This function choose a good guard given the TOR path selection rules. - * - * Note: this implements a lightweight version of the TOR path selection, where the selection based on the different - * sets is put aside - * - */ - path.chooseGoodGuard = function () { - let candidates = path.consensus.filter(r => path.isGoodGuard(r)); - return path.weightedRandomChoice(candidates) - }; - - /** - * This function checks if the given router is a suitable candidate to become a guard - * - * @param {Object} router the router subpart of one of the nodes of the parsed consensus - */ - path.isGoodGuard = function (router) { - let flags = router['flags']; - let des = path.descriptorsMap[router.identity]; - - if (des === undefined) { - return false - } - - if (des["router"]["identity"] === path.exit["router"]["identity"]) { - return false - } - - if (!flags.includes('Guard')) return false - if (!flags.includes('Stable')) return false - if (!flags.includes('V2Dir')) return false - if (path.inSame16Subnet(des, path.exit)) return false - if (path.inSameFamily(des, path.exit)) return false - - return true - }; - - /** - * This function choose a good middle given the TOR path selection rules - */ - path.chooseGoodMiddle = function () { - let candidates = path.consensus.filter(r => path.isGoodMiddle(r)); - return path.weightedRandomChoice(candidates) - }; - - /** - * This function checks if the given router is a suitable candidate to become a middle node - * - * @param {Object} router the router subpart of one of the nodes of the parsed consensus - */ - path.isGoodMiddle = function (router) { - let des = path.descriptorsMap[router.identity]; - - if (des === undefined) { - return false - } - - if (des["router"]["identity"] === path.exit["router"]["identity"] || des["router"]["identity"] === path.guard["router"]["identity"]) { - return false - } - - if (path.inSame16Subnet(des, path.guard)) return false - if (path.inSame16Subnet(des, path.exit)) return false - if (path.inSameFamily(des, path.guard)) return false - if (path.inSameFamily(des, path.exit)) return false - - return true - }; - - /** - * @module post - */ - - - - function create(endpoint, success, error) { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 201) { - var info = JSON.parse(rq.responseText); - if (endpoint.auth != null) { - info = ntor.auth(endpoint, info["auth"], info["data"]); - } - endpoint.id = info["id"]; - endpoint.url = endpoint.urls.channels + "/" + info["id"]; - endpoint.path = info["path"]; - - if (endpoint.fast) { - endpoint.guard = info["guard"]; - endpoint.material.identity = dec.base64( - info["guard"].router.identity + "="); - endpoint.material.onionkey = dec.base64( - info["guard"]["ntor-onion-key"]); - } - - var material = ntor.shake(endpoint, info["ntor"]); - if (material == null) - throw "Invalid guard handshake." - - material = ntor.slice(material); - endpoint.material = material; - - endpoint.forward = forward(endpoint); - endpoint.backward = backward(endpoint); - if (success !== undefined) - success(endpoint); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - - var payload = null; - if (endpoint.fast) - payload = ntor.fast(endpoint); - else - payload = ntor.hand(endpoint); - - payload = { ntor: payload }; - if (endpoint.auth != null) { - payload["auth"] = enc.base64(endpoint.auth.ntor.publicKey); - } - payload = JSON.stringify(payload); - - rq.open("POST", endpoint.urls.channels, true); - rq.setRequestHeader("Content-type", "application/json"); - rq.send(payload); - } - - - function circuit_info(endpoint, success, error, select_path, tcp_ports) { - if (select_path === undefined) { - select_path = false; - } - - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 201) { - var info = JSON.parse(rq.responseText); - if (endpoint.auth != null) { - info = ntor.auth(endpoint, info["auth"], info["data"]); - } - - endpoint.id = info["id"]; - endpoint.url = endpoint.urls.channels + "/" + info["id"]; - - - if (endpoint.fast) { - endpoint.guard = info["guard"]; - } - - if (!select_path) - endpoint.path = info["path"]; - else { - endpoint.consensus = consensusParser.parse(endpoint.consensus_raw); - endpoint.descriptors = parser.descriptors.parse(endpoint.descriptors_raw); - parser.descriptors.validate(endpoint.descriptors, endpoint.consensus); - - endpoint.path = path.select_end_path(endpoint.consensus, endpoint.descriptors, endpoint.guard, true, tcp_ports); - console.log(endpoint.guard); - console.log(endpoint.path); - } - - if (success !== undefined) - success(endpoint, info); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - - var payload = {}; - /** - if (endpoint.fast) - payload = ntor.fast(endpoint) - else - payload = ntor.hand(endpoint) - - payload = {ntor: payload}*/ - if (endpoint.auth != null) { - payload["auth"] = enc.base64(endpoint.auth.ntor.publicKey); - } - payload["select_path"] = select_path.toString(); - payload = JSON.stringify(payload); - - rq.open("POST", endpoint.urls.channels, true); - rq.setRequestHeader("Content-type", "application/json"); - rq.send(payload); - } - - function handshake(endpoint, info, success, error) { - //var handshake = info['handshake'] - var normal_handler = endpoint.io.handler; - - var handler = function (endpoint, material) { - endpoint.io.handler = normal_handler; - //var material = endpoint.io.recv() - - material = ntor.shake(endpoint, material.slice(7, 7 + 64), false); - - if (material == null) - throw "Invalid guard handshake." - - - material = ntor.slice(material); - endpoint.material = material; - - endpoint.forward = forward(endpoint); - endpoint.backward = backward(endpoint); - - if (success !== undefined) - success(endpoint); - }; - - endpoint.io.handler = handler; - - var handshake = new Uint8Array(relay.full_len); - var payload = ntor.hand(endpoint, endpoint.guard, false); - - - var view = new DataView(handshake.buffer); - view.setUint32(0, 2147483648 /* fake circuit_id */, false); - view.setUint8(4, 10 /* CREATE2 CELL */, false); - view.setUint16(5, 2 /* ntor handshake */, false); - view.setUint16(7, payload.length, false); - handshake.set(payload, 9); - - - endpoint.io.send(handshake); - } - - function channel(endpoint, success, error) { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 201) { - var cells = JSON.parse(rq.responseText)["cells"]; - if (cells === undefined) { - if (endpoint.io.error !== undefined) - endpoint.io.error(endpoint); - return - } - - var pending = endpoint.io.pending; - if (pending > 0 && endpoint.io.success !== undefined) - endpoint.io.success(endpoint); - - if (cells.length > 0) { - endpoint.io.incoming = endpoint.io.incoming.concat(cells); - if (endpoint.io.handler !== undefined) - endpoint.io.handler(endpoint); - } - - endpoint.io.outcoming = endpoint.io.outcoming.slice(pending); - endpoint.io.pending = 0; - - if (success !== undefined) - success(endpoint); - } - else if (rq.readyState == 4) { - if (endpoint.io.error !== undefined) - endpoint.io.error(endpoint); - - if (error !== undefined) - error(endpoint, rq.status); - } - }; - - endpoint.io.pending = endpoint.io.outcoming.length; - - rq.open("POST", endpoint.url, true); - rq.setRequestHeader("Content-type", "application/json"); - rq.send(JSON.stringify({ cells: endpoint.io.outcoming })); - } - - function extend(endpoint, descriptor, success, error) { - var hand = ntor.hand(endpoint, descriptor, false); - - var eidentity = descriptor["identity"]["master-key"]; // (assuming ed25519) - var identity = endpoint.material.identity; - var addr = descriptor["router"]["address"]; - var port = descriptor["router"]["orport"]; - - var data = relay.extend(hand, addr, port, identity, eidentity); - var cell = build(endpoint, "extend2", 0, data); - - var extend_error = error; - var extend_success = success; - var normal_handler = endpoint.io.handler; - - var handler = function (endpoint, data) { - endpoint.io.handler = normal_handler; - - var cell = peel(endpoint, data); - if (cell == null || cell.cmd != "extended2") { - if (extend_error !== undefined) - return extend_error(endpoint) - throw "Invalid answer, expecting extended2 cell, fatal!" - } - - var view = new DataView(cell.data.buffer); - var length = view.getUint16(0, false); - var data = cell.data.slice(2, 2 + length); - - var material = ntor.shake(endpoint, data, false); - material = ntor.slice(material); - endpoint.material = material; - - if (material == null && extend_error !== undefined) - return extend_error(endpoint) - - endpoint.forward = forward(endpoint); - endpoint.backward = backward(endpoint); - - if (extend_success !== undefined) - extend_success(endpoint); - }; - - endpoint.io.handler = handler; - endpoint.io.send(cell); - } - - - function close(endpoint, success, error) { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 202) { - if (success !== undefined) - success("Circuit closed"); - } - else if (rq.readyState == 4 && error !== undefined) { - error("Error in closing circuit"); - } - }; - - rq.open("DELETE", endpoint.url, true); - rq.send(); - } - - /** - * @module io - */ - - const polling = (endpoint, handler, success, error) => new Polling(endpoint, handler, success, error); - - class Polling { - constructor(endpoint, handler, success, error) { - this.incoming = []; - this.outcoming = []; - this.pending = 0; - this.handler = handler; - this.success = success; - this.error = error; - this.cell = null; - - this.endpoint = endpoint; - - endpoint.io = this; - } - - poll() { - setTimeout(function () { - channel(this.endpoint, this.poll); - }, 100); - } - - send(cell) { - this.outcoming.push(enc.base64(cell)); - } - - recv() { - if (this.incoming.length < 1) { return undefined; } - - this.cell = this.incoming.shift(); - return dec.base64(this.cell); - } - - start() { - channel(this.endpoint, this.poll); - } - } - - function socket(endpoint, handler, success, error) { - if (handler === undefined) - handler = function (endpoint) { }; - if (success === undefined) - success = function (endpoint) { }; - if (error === undefined) - error = function (endpoint) { }; - - var io = { - event: null, - socket: null, - closed: false, - incoming: [], - outcoming: [], - handler: handler, - success: success, - error: error, - cell: null, - cell_recv: 0, - //cell_sent: 0, - send: function (cell) { - io.outcoming.push(cell); - - //io.cell_sent += 1 - //var cell_repr = Array.from(cell.slice(0,20)).map(function(x) {return x.toString(16).padStart(2, '0')}).join('') - //console.log("cell ", io.cell_sent.toString(), " sent to wbskt ", cell_repr) - }, - recv: function () { - if (io.incoming.length < 1) - return undefined - - io.cell = io.incoming.shift(); - - io.cell_recv += 1; - var cell_repr = Array.from(io.cell.slice(0, 20)).map(function (x) { return x.toString(16).padStart(2, '0') }).join(''); - console.log("cell recv by wbskt ", cell_repr); - - return io.cell - }, - start: function () { } - }; - var socket = new WebSocket(endpoint.urls.socket + "/" + endpoint.id); - - socket.binaryType = "arraybuffer"; - socket.onopen = function (event) { - io.event = event; - io.success(endpoint); - - while (io.outcoming.length > 0) - io.socket.send(io.outcoming.shift()); - - io.send = function (cell) { - if (io.closed) - throw "Unable to send, connection closed." - io.socket.send(cell.buffer); - - //io.cell_sent += 1 - //var cell_repr = Array.from(cell.slice(0,20)).map(function(x) {return x.toString(16).padStart(2, '0')}).join('') - //console.log("cell ", io.cell_sent.toString(), " sent to wbskt ", cell_repr) - }; - }; - socket.onerror = function (event) { - io.event = event; - io.error(endpoint); - }; - socket.onmessage = function (event) { - io.event = event; - - var data = new Uint8Array(event.data); - - var cell_repr = Array.from(data.slice(0, 20)).map(function (x) { return x.toString(16).padStart(2, '0') }).join(''); - console.log("cell recv by wbskt ", cell_repr); - - // io.incoming.push(data) - io.cell = data; - io.handler(endpoint, data); - }; - socket.onclose = function (event) { - io.event = event; - io.closed = true; - io.error(endpoint); - }; - - endpoint.io = io; - endpoint.io.socket = socket; - return io - } - - /** - * GET operations. - * @module get - * @namespace - * @see lnn.get.guard - */ - - /** - * Perform GET /guard and update endpoint accordingly, - * see {@link endpoint_t#guard}. - * - * @param {endpoint_t} endpoint endpoint in use, stores answer - * @param {callback} success optional, called on success - * @param {callback} error optional, called on error - * @example - * // Note: lnn.open perform these steps for you whenever needed. - * endpoint = lnn.endpoint('localhost', 4990) - * lnn.get.guard(endpoint, function (endpoint) - * { - * console.log('Guard identity:', endpoint.guard.router.identity) - * }) - * // (can also have error callback: function (endpoint, xhttp_status) { }) - */ - function guard(endpoint, success, error) { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 200) { - endpoint.guard = JSON.parse(rq.responseText); - if (success !== undefined) - success(endpoint); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - rq.open("GET", endpoint.urls.guard, true); - rq.send(); - } - - /** - * Perform GET /consensus and update endpoint accordingly, - * see {@link endpoint_t#consensus}. - * - *
      -	 * Note: provided for testing purposes and currently have no use.
      -	 * 
      - * - * Usage and parameters are similar to {@link lnn.get.guard}, stores the - * consensus as parsed from the proxy-server answer. - * - * @param {endpoint_t} endpoint endpoint in use, stores answer - * @param {callback} success optional, called on success - * @param {callback} error optional, called on error - * - * @see lnn.get.guard - */ - function consensus(endpoint, success, error) { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 200) { - endpoint.consensus = JSON.parse(rq.responseText); - if (success !== undefined) - success(endpoint); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - rq.open("GET", endpoint.urls.consensus, true); - rq.send(); - } - - /** - * Perform GET /descriptors - */ - function descriptors(endpoint, success, error) { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 200) { - endpoint.descriptors = JSON.parse(rq.responseText); - - if (success !== undefined) success(endpoint); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - - rq.open("GET", endpoint.urls.descriptors, true); - rq.send(); - } - - function consensus_raw(endpoint, success, error, flavor = 'microdesc') { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 200) { - endpoint.consensus_raw = rq.responseText; - if (success !== undefined) - success(endpoint); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - rq.open("GET", endpoint.urls.consensus + "-raw/" + flavor, true); - rq.send(); - } - - /** - * Perform GET /descriptors - */ - function descriptors_raw(endpoint, success, error, flavor = 'microdesc') { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 200) { - endpoint.descriptors_raw = rq.responseText; - - if (success !== undefined) success(endpoint); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - - rq.open("GET", endpoint.urls.descriptors + "-raw/" + flavor, true); - rq.send(); - } - - function signing_keys(endpoint, success, error) { - var rq = new XMLHttpRequest(); - rq.onreadystatechange = function () { - if (rq.readyState == 4 && rq.status == 200) { - endpoint.signing_keys = JSON.parse(rq.responseText); - - if (success !== undefined) success(endpoint); - } - else if (rq.readyState == 4 && error !== undefined) { - error(endpoint, rq.status); - } - }; - - rq.open("GET", endpoint.urls.signing_keys, true); - rq.send(); - } - - var BigInteger = createCommonjsModule(function (module) { - var bigInt = (function (undefined$1) { - - var BASE = 1e7, - LOG_BASE = 7, - MAX_INT = 9007199254740992, - MAX_INT_ARR = smallToArray(MAX_INT), - DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"; - - var supportsNativeBigInt = typeof BigInt === "function"; - - function Integer(v, radix, alphabet, caseSensitive) { - if (typeof v === "undefined") return Integer[0]; - if (typeof radix !== "undefined") return +radix === 10 && !alphabet ? parseValue(v) : parseBase(v, radix, alphabet, caseSensitive); - return parseValue(v); - } - - function BigInteger(value, sign) { - this.value = value; - this.sign = sign; - this.isSmall = false; - } - BigInteger.prototype = Object.create(Integer.prototype); - - function SmallInteger(value) { - this.value = value; - this.sign = value < 0; - this.isSmall = true; - } - SmallInteger.prototype = Object.create(Integer.prototype); - - function NativeBigInt(value) { - this.value = value; - } - NativeBigInt.prototype = Object.create(Integer.prototype); - - function isPrecise(n) { - return -MAX_INT < n && n < MAX_INT; - } - - function smallToArray(n) { // For performance reasons doesn't reference BASE, need to change this function if BASE changes - if (n < 1e7) - return [n]; - if (n < 1e14) - return [n % 1e7, Math.floor(n / 1e7)]; - return [n % 1e7, Math.floor(n / 1e7) % 1e7, Math.floor(n / 1e14)]; - } - - function arrayToSmall(arr) { // If BASE changes this function may need to change - trim(arr); - var length = arr.length; - if (length < 4 && compareAbs(arr, MAX_INT_ARR) < 0) { - switch (length) { - case 0: return 0; - case 1: return arr[0]; - case 2: return arr[0] + arr[1] * BASE; - default: return arr[0] + (arr[1] + arr[2] * BASE) * BASE; - } - } - return arr; - } - - function trim(v) { - var i = v.length; - while (v[--i] === 0); - v.length = i + 1; - } - - function createArray(length) { // function shamelessly stolen from Yaffle's library https://github.com/Yaffle/BigInteger - var x = new Array(length); - var i = -1; - while (++i < length) { - x[i] = 0; - } - return x; - } - - function truncate(n) { - if (n > 0) return Math.floor(n); - return Math.ceil(n); - } - - function add(a, b) { // assumes a and b are arrays with a.length >= b.length - var l_a = a.length, - l_b = b.length, - r = new Array(l_a), - carry = 0, - base = BASE, - sum, i; - for (i = 0; i < l_b; i++) { - sum = a[i] + b[i] + carry; - carry = sum >= base ? 1 : 0; - r[i] = sum - carry * base; - } - while (i < l_a) { - sum = a[i] + carry; - carry = sum === base ? 1 : 0; - r[i++] = sum - carry * base; - } - if (carry > 0) r.push(carry); - return r; - } - - function addAny(a, b) { - if (a.length >= b.length) return add(a, b); - return add(b, a); - } - - function addSmall(a, carry) { // assumes a is array, carry is number with 0 <= carry < MAX_INT - var l = a.length, - r = new Array(l), - base = BASE, - sum, i; - for (i = 0; i < l; i++) { - sum = a[i] - base + carry; - carry = Math.floor(sum / base); - r[i] = sum - carry * base; - carry += 1; - } - while (carry > 0) { - r[i++] = carry % base; - carry = Math.floor(carry / base); - } - return r; - } - - BigInteger.prototype.add = function (v) { - var n = parseValue(v); - if (this.sign !== n.sign) { - return this.subtract(n.negate()); - } - var a = this.value, b = n.value; - if (n.isSmall) { - return new BigInteger(addSmall(a, Math.abs(b)), this.sign); - } - return new BigInteger(addAny(a, b), this.sign); - }; - BigInteger.prototype.plus = BigInteger.prototype.add; - - SmallInteger.prototype.add = function (v) { - var n = parseValue(v); - var a = this.value; - if (a < 0 !== n.sign) { - return this.subtract(n.negate()); - } - var b = n.value; - if (n.isSmall) { - if (isPrecise(a + b)) return new SmallInteger(a + b); - b = smallToArray(Math.abs(b)); - } - return new BigInteger(addSmall(b, Math.abs(a)), a < 0); - }; - SmallInteger.prototype.plus = SmallInteger.prototype.add; - - NativeBigInt.prototype.add = function (v) { - return new NativeBigInt(this.value + parseValue(v).value); - }; - NativeBigInt.prototype.plus = NativeBigInt.prototype.add; - - function subtract(a, b) { // assumes a and b are arrays with a >= b - var a_l = a.length, - b_l = b.length, - r = new Array(a_l), - borrow = 0, - base = BASE, - i, difference; - for (i = 0; i < b_l; i++) { - difference = a[i] - borrow - b[i]; - if (difference < 0) { - difference += base; - borrow = 1; - } else borrow = 0; - r[i] = difference; - } - for (i = b_l; i < a_l; i++) { - difference = a[i] - borrow; - if (difference < 0) difference += base; - else { - r[i++] = difference; - break; - } - r[i] = difference; - } - for (; i < a_l; i++) { - r[i] = a[i]; - } - trim(r); - return r; - } - - function subtractAny(a, b, sign) { - var value; - if (compareAbs(a, b) >= 0) { - value = subtract(a, b); - } else { - value = subtract(b, a); - sign = !sign; - } - value = arrayToSmall(value); - if (typeof value === "number") { - if (sign) value = -value; - return new SmallInteger(value); - } - return new BigInteger(value, sign); - } - - function subtractSmall(a, b, sign) { // assumes a is array, b is number with 0 <= b < MAX_INT - var l = a.length, - r = new Array(l), - carry = -b, - base = BASE, - i, difference; - for (i = 0; i < l; i++) { - difference = a[i] + carry; - carry = Math.floor(difference / base); - difference %= base; - r[i] = difference < 0 ? difference + base : difference; - } - r = arrayToSmall(r); - if (typeof r === "number") { - if (sign) r = -r; - return new SmallInteger(r); - } return new BigInteger(r, sign); - } - - BigInteger.prototype.subtract = function (v) { - var n = parseValue(v); - if (this.sign !== n.sign) { - return this.add(n.negate()); - } - var a = this.value, b = n.value; - if (n.isSmall) - return subtractSmall(a, Math.abs(b), this.sign); - return subtractAny(a, b, this.sign); - }; - BigInteger.prototype.minus = BigInteger.prototype.subtract; - - SmallInteger.prototype.subtract = function (v) { - var n = parseValue(v); - var a = this.value; - if (a < 0 !== n.sign) { - return this.add(n.negate()); - } - var b = n.value; - if (n.isSmall) { - return new SmallInteger(a - b); - } - return subtractSmall(b, Math.abs(a), a >= 0); - }; - SmallInteger.prototype.minus = SmallInteger.prototype.subtract; - - NativeBigInt.prototype.subtract = function (v) { - return new NativeBigInt(this.value - parseValue(v).value); - }; - NativeBigInt.prototype.minus = NativeBigInt.prototype.subtract; - - BigInteger.prototype.negate = function () { - return new BigInteger(this.value, !this.sign); - }; - SmallInteger.prototype.negate = function () { - var sign = this.sign; - var small = new SmallInteger(-this.value); - small.sign = !sign; - return small; - }; - NativeBigInt.prototype.negate = function () { - return new NativeBigInt(-this.value); - }; - - BigInteger.prototype.abs = function () { - return new BigInteger(this.value, false); - }; - SmallInteger.prototype.abs = function () { - return new SmallInteger(Math.abs(this.value)); - }; - NativeBigInt.prototype.abs = function () { - return new NativeBigInt(this.value >= 0 ? this.value : -this.value); - }; - - - function multiplyLong(a, b) { - var a_l = a.length, - b_l = b.length, - l = a_l + b_l, - r = createArray(l), - base = BASE, - product, carry, i, a_i, b_j; - for (i = 0; i < a_l; ++i) { - a_i = a[i]; - for (var j = 0; j < b_l; ++j) { - b_j = b[j]; - product = a_i * b_j + r[i + j]; - carry = Math.floor(product / base); - r[i + j] = product - carry * base; - r[i + j + 1] += carry; - } - } - trim(r); - return r; - } - - function multiplySmall(a, b) { // assumes a is array, b is number with |b| < BASE - var l = a.length, - r = new Array(l), - base = BASE, - carry = 0, - product, i; - for (i = 0; i < l; i++) { - product = a[i] * b + carry; - carry = Math.floor(product / base); - r[i] = product - carry * base; - } - while (carry > 0) { - r[i++] = carry % base; - carry = Math.floor(carry / base); - } - return r; - } - - function shiftLeft(x, n) { - var r = []; - while (n-- > 0) r.push(0); - return r.concat(x); - } - - function multiplyKaratsuba(x, y) { - var n = Math.max(x.length, y.length); - - if (n <= 30) return multiplyLong(x, y); - n = Math.ceil(n / 2); - - var b = x.slice(n), - a = x.slice(0, n), - d = y.slice(n), - c = y.slice(0, n); - - var ac = multiplyKaratsuba(a, c), - bd = multiplyKaratsuba(b, d), - abcd = multiplyKaratsuba(addAny(a, b), addAny(c, d)); - - var product = addAny(addAny(ac, shiftLeft(subtract(subtract(abcd, ac), bd), n)), shiftLeft(bd, 2 * n)); - trim(product); - return product; - } - - // The following function is derived from a surface fit of a graph plotting the performance difference - // between long multiplication and karatsuba multiplication versus the lengths of the two arrays. - function useKaratsuba(l1, l2) { - return -0.012 * l1 - 0.012 * l2 + 0.000015 * l1 * l2 > 0; - } - - BigInteger.prototype.multiply = function (v) { - var n = parseValue(v), - a = this.value, b = n.value, - sign = this.sign !== n.sign, - abs; - if (n.isSmall) { - if (b === 0) return Integer[0]; - if (b === 1) return this; - if (b === -1) return this.negate(); - abs = Math.abs(b); - if (abs < BASE) { - return new BigInteger(multiplySmall(a, abs), sign); - } - b = smallToArray(abs); - } - if (useKaratsuba(a.length, b.length)) // Karatsuba is only faster for certain array sizes - return new BigInteger(multiplyKaratsuba(a, b), sign); - return new BigInteger(multiplyLong(a, b), sign); - }; - - BigInteger.prototype.times = BigInteger.prototype.multiply; - - function multiplySmallAndArray(a, b, sign) { // a >= 0 - if (a < BASE) { - return new BigInteger(multiplySmall(b, a), sign); - } - return new BigInteger(multiplyLong(b, smallToArray(a)), sign); - } - SmallInteger.prototype._multiplyBySmall = function (a) { - if (isPrecise(a.value * this.value)) { - return new SmallInteger(a.value * this.value); - } - return multiplySmallAndArray(Math.abs(a.value), smallToArray(Math.abs(this.value)), this.sign !== a.sign); - }; - BigInteger.prototype._multiplyBySmall = function (a) { - if (a.value === 0) return Integer[0]; - if (a.value === 1) return this; - if (a.value === -1) return this.negate(); - return multiplySmallAndArray(Math.abs(a.value), this.value, this.sign !== a.sign); - }; - SmallInteger.prototype.multiply = function (v) { - return parseValue(v)._multiplyBySmall(this); - }; - SmallInteger.prototype.times = SmallInteger.prototype.multiply; - - NativeBigInt.prototype.multiply = function (v) { - return new NativeBigInt(this.value * parseValue(v).value); - }; - NativeBigInt.prototype.times = NativeBigInt.prototype.multiply; - - function square(a) { - //console.assert(2 * BASE * BASE < MAX_INT); - var l = a.length, - r = createArray(l + l), - base = BASE, - product, carry, i, a_i, a_j; - for (i = 0; i < l; i++) { - a_i = a[i]; - carry = 0 - a_i * a_i; - for (var j = i; j < l; j++) { - a_j = a[j]; - product = 2 * (a_i * a_j) + r[i + j] + carry; - carry = Math.floor(product / base); - r[i + j] = product - carry * base; - } - r[i + l] = carry; - } - trim(r); - return r; - } - - BigInteger.prototype.square = function () { - return new BigInteger(square(this.value), false); - }; - - SmallInteger.prototype.square = function () { - var value = this.value * this.value; - if (isPrecise(value)) return new SmallInteger(value); - return new BigInteger(square(smallToArray(Math.abs(this.value))), false); - }; - - NativeBigInt.prototype.square = function (v) { - return new NativeBigInt(this.value * this.value); - }; - - function divMod1(a, b) { // Left over from previous version. Performs faster than divMod2 on smaller input sizes. - var a_l = a.length, - b_l = b.length, - base = BASE, - result = createArray(b.length), - divisorMostSignificantDigit = b[b_l - 1], - // normalization - lambda = Math.ceil(base / (2 * divisorMostSignificantDigit)), - remainder = multiplySmall(a, lambda), - divisor = multiplySmall(b, lambda), - quotientDigit, shift, carry, borrow, i, l, q; - if (remainder.length <= a_l) remainder.push(0); - divisor.push(0); - divisorMostSignificantDigit = divisor[b_l - 1]; - for (shift = a_l - b_l; shift >= 0; shift--) { - quotientDigit = base - 1; - if (remainder[shift + b_l] !== divisorMostSignificantDigit) { - quotientDigit = Math.floor((remainder[shift + b_l] * base + remainder[shift + b_l - 1]) / divisorMostSignificantDigit); - } - // quotientDigit <= base - 1 - carry = 0; - borrow = 0; - l = divisor.length; - for (i = 0; i < l; i++) { - carry += quotientDigit * divisor[i]; - q = Math.floor(carry / base); - borrow += remainder[shift + i] - (carry - q * base); - carry = q; - if (borrow < 0) { - remainder[shift + i] = borrow + base; - borrow = -1; - } else { - remainder[shift + i] = borrow; - borrow = 0; - } - } - while (borrow !== 0) { - quotientDigit -= 1; - carry = 0; - for (i = 0; i < l; i++) { - carry += remainder[shift + i] - base + divisor[i]; - if (carry < 0) { - remainder[shift + i] = carry + base; - carry = 0; - } else { - remainder[shift + i] = carry; - carry = 1; - } - } - borrow += carry; - } - result[shift] = quotientDigit; - } - // denormalization - remainder = divModSmall(remainder, lambda)[0]; - return [arrayToSmall(result), arrayToSmall(remainder)]; - } - - function divMod2(a, b) { // Implementation idea shamelessly stolen from Silent Matt's library http://silentmatt.com/biginteger/ - // Performs faster than divMod1 on larger input sizes. - var a_l = a.length, - b_l = b.length, - result = [], - part = [], - base = BASE, - guess, xlen, highx, highy, check; - while (a_l) { - part.unshift(a[--a_l]); - trim(part); - if (compareAbs(part, b) < 0) { - result.push(0); - continue; - } - xlen = part.length; - highx = part[xlen - 1] * base + part[xlen - 2]; - highy = b[b_l - 1] * base + b[b_l - 2]; - if (xlen > b_l) { - highx = (highx + 1) * base; - } - guess = Math.ceil(highx / highy); - do { - check = multiplySmall(b, guess); - if (compareAbs(check, part) <= 0) break; - guess--; - } while (guess); - result.push(guess); - part = subtract(part, check); - } - result.reverse(); - return [arrayToSmall(result), arrayToSmall(part)]; - } - - function divModSmall(value, lambda) { - var length = value.length, - quotient = createArray(length), - base = BASE, - i, q, remainder, divisor; - remainder = 0; - for (i = length - 1; i >= 0; --i) { - divisor = remainder * base + value[i]; - q = truncate(divisor / lambda); - remainder = divisor - q * lambda; - quotient[i] = q | 0; - } - return [quotient, remainder | 0]; - } - - function divModAny(self, v) { - var value, n = parseValue(v); - if (supportsNativeBigInt) { - return [new NativeBigInt(self.value / n.value), new NativeBigInt(self.value % n.value)]; - } - var a = self.value, b = n.value; - var quotient; - if (b === 0) throw new Error("Cannot divide by zero"); - if (self.isSmall) { - if (n.isSmall) { - return [new SmallInteger(truncate(a / b)), new SmallInteger(a % b)]; - } - return [Integer[0], self]; - } - if (n.isSmall) { - if (b === 1) return [self, Integer[0]]; - if (b == -1) return [self.negate(), Integer[0]]; - var abs = Math.abs(b); - if (abs < BASE) { - value = divModSmall(a, abs); - quotient = arrayToSmall(value[0]); - var remainder = value[1]; - if (self.sign) remainder = -remainder; - if (typeof quotient === "number") { - if (self.sign !== n.sign) quotient = -quotient; - return [new SmallInteger(quotient), new SmallInteger(remainder)]; - } - return [new BigInteger(quotient, self.sign !== n.sign), new SmallInteger(remainder)]; - } - b = smallToArray(abs); - } - var comparison = compareAbs(a, b); - if (comparison === -1) return [Integer[0], self]; - if (comparison === 0) return [Integer[self.sign === n.sign ? 1 : -1], Integer[0]]; - - // divMod1 is faster on smaller input sizes - if (a.length + b.length <= 200) - value = divMod1(a, b); - else value = divMod2(a, b); - - quotient = value[0]; - var qSign = self.sign !== n.sign, - mod = value[1], - mSign = self.sign; - if (typeof quotient === "number") { - if (qSign) quotient = -quotient; - quotient = new SmallInteger(quotient); - } else quotient = new BigInteger(quotient, qSign); - if (typeof mod === "number") { - if (mSign) mod = -mod; - mod = new SmallInteger(mod); - } else mod = new BigInteger(mod, mSign); - return [quotient, mod]; - } - - BigInteger.prototype.divmod = function (v) { - var result = divModAny(this, v); - return { - quotient: result[0], - remainder: result[1] - }; - }; - NativeBigInt.prototype.divmod = SmallInteger.prototype.divmod = BigInteger.prototype.divmod; - - - BigInteger.prototype.divide = function (v) { - return divModAny(this, v)[0]; - }; - NativeBigInt.prototype.over = NativeBigInt.prototype.divide = function (v) { - return new NativeBigInt(this.value / parseValue(v).value); - }; - SmallInteger.prototype.over = SmallInteger.prototype.divide = BigInteger.prototype.over = BigInteger.prototype.divide; - - BigInteger.prototype.mod = function (v) { - return divModAny(this, v)[1]; - }; - NativeBigInt.prototype.mod = NativeBigInt.prototype.remainder = function (v) { - return new NativeBigInt(this.value % parseValue(v).value); - }; - SmallInteger.prototype.remainder = SmallInteger.prototype.mod = BigInteger.prototype.remainder = BigInteger.prototype.mod; - - BigInteger.prototype.pow = function (v) { - var n = parseValue(v), - a = this.value, - b = n.value, - value, x, y; - if (b === 0) return Integer[1]; - if (a === 0) return Integer[0]; - if (a === 1) return Integer[1]; - if (a === -1) return n.isEven() ? Integer[1] : Integer[-1]; - if (n.sign) { - return Integer[0]; - } - if (!n.isSmall) throw new Error("The exponent " + n.toString() + " is too large."); - if (this.isSmall) { - if (isPrecise(value = Math.pow(a, b))) - return new SmallInteger(truncate(value)); - } - x = this; - y = Integer[1]; - while (true) { - if (b & 1 === 1) { - y = y.times(x); - --b; - } - if (b === 0) break; - b /= 2; - x = x.square(); - } - return y; - }; - SmallInteger.prototype.pow = BigInteger.prototype.pow; - - NativeBigInt.prototype.pow = function (v) { - var n = parseValue(v); - var a = this.value, b = n.value; - var _0 = BigInt(0), _1 = BigInt(1), _2 = BigInt(2); - if (b === _0) return Integer[1]; - if (a === _0) return Integer[0]; - if (a === _1) return Integer[1]; - if (a === BigInt(-1)) return n.isEven() ? Integer[1] : Integer[-1]; - if (n.isNegative()) return new NativeBigInt(_0); - var x = this; - var y = Integer[1]; - while (true) { - if ((b & _1) === _1) { - y = y.times(x); - --b; - } - if (b === _0) break; - b /= _2; - x = x.square(); - } - return y; - }; - - BigInteger.prototype.modPow = function (exp, mod) { - exp = parseValue(exp); - mod = parseValue(mod); - if (mod.isZero()) throw new Error("Cannot take modPow with modulus 0"); - var r = Integer[1], - base = this.mod(mod); - if (exp.isNegative()) { - exp = exp.multiply(Integer[-1]); - base = base.modInv(mod); - } - while (exp.isPositive()) { - if (base.isZero()) return Integer[0]; - if (exp.isOdd()) r = r.multiply(base).mod(mod); - exp = exp.divide(2); - base = base.square().mod(mod); - } - return r; - }; - NativeBigInt.prototype.modPow = SmallInteger.prototype.modPow = BigInteger.prototype.modPow; - - function compareAbs(a, b) { - if (a.length !== b.length) { - return a.length > b.length ? 1 : -1; - } - for (var i = a.length - 1; i >= 0; i--) { - if (a[i] !== b[i]) return a[i] > b[i] ? 1 : -1; - } - return 0; - } - - BigInteger.prototype.compareAbs = function (v) { - var n = parseValue(v), - a = this.value, - b = n.value; - if (n.isSmall) return 1; - return compareAbs(a, b); - }; - SmallInteger.prototype.compareAbs = function (v) { - var n = parseValue(v), - a = Math.abs(this.value), - b = n.value; - if (n.isSmall) { - b = Math.abs(b); - return a === b ? 0 : a > b ? 1 : -1; - } - return -1; - }; - NativeBigInt.prototype.compareAbs = function (v) { - var a = this.value; - var b = parseValue(v).value; - a = a >= 0 ? a : -a; - b = b >= 0 ? b : -b; - return a === b ? 0 : a > b ? 1 : -1; - }; - - BigInteger.prototype.compare = function (v) { - // See discussion about comparison with Infinity: - // https://github.com/peterolson/BigInteger.js/issues/61 - if (v === Infinity) { - return -1; - } - if (v === -Infinity) { - return 1; - } - - var n = parseValue(v), - a = this.value, - b = n.value; - if (this.sign !== n.sign) { - return n.sign ? 1 : -1; - } - if (n.isSmall) { - return this.sign ? -1 : 1; - } - return compareAbs(a, b) * (this.sign ? -1 : 1); - }; - BigInteger.prototype.compareTo = BigInteger.prototype.compare; - - SmallInteger.prototype.compare = function (v) { - if (v === Infinity) { - return -1; - } - if (v === -Infinity) { - return 1; - } - - var n = parseValue(v), - a = this.value, - b = n.value; - if (n.isSmall) { - return a == b ? 0 : a > b ? 1 : -1; - } - if (a < 0 !== n.sign) { - return a < 0 ? -1 : 1; - } - return a < 0 ? 1 : -1; - }; - SmallInteger.prototype.compareTo = SmallInteger.prototype.compare; - - NativeBigInt.prototype.compare = function (v) { - if (v === Infinity) { - return -1; - } - if (v === -Infinity) { - return 1; - } - var a = this.value; - var b = parseValue(v).value; - return a === b ? 0 : a > b ? 1 : -1; - }; - NativeBigInt.prototype.compareTo = NativeBigInt.prototype.compare; - - BigInteger.prototype.equals = function (v) { - return this.compare(v) === 0; - }; - NativeBigInt.prototype.eq = NativeBigInt.prototype.equals = SmallInteger.prototype.eq = SmallInteger.prototype.equals = BigInteger.prototype.eq = BigInteger.prototype.equals; - - BigInteger.prototype.notEquals = function (v) { - return this.compare(v) !== 0; - }; - NativeBigInt.prototype.neq = NativeBigInt.prototype.notEquals = SmallInteger.prototype.neq = SmallInteger.prototype.notEquals = BigInteger.prototype.neq = BigInteger.prototype.notEquals; - - BigInteger.prototype.greater = function (v) { - return this.compare(v) > 0; - }; - NativeBigInt.prototype.gt = NativeBigInt.prototype.greater = SmallInteger.prototype.gt = SmallInteger.prototype.greater = BigInteger.prototype.gt = BigInteger.prototype.greater; - - BigInteger.prototype.lesser = function (v) { - return this.compare(v) < 0; - }; - NativeBigInt.prototype.lt = NativeBigInt.prototype.lesser = SmallInteger.prototype.lt = SmallInteger.prototype.lesser = BigInteger.prototype.lt = BigInteger.prototype.lesser; - - BigInteger.prototype.greaterOrEquals = function (v) { - return this.compare(v) >= 0; - }; - NativeBigInt.prototype.geq = NativeBigInt.prototype.greaterOrEquals = SmallInteger.prototype.geq = SmallInteger.prototype.greaterOrEquals = BigInteger.prototype.geq = BigInteger.prototype.greaterOrEquals; - - BigInteger.prototype.lesserOrEquals = function (v) { - return this.compare(v) <= 0; - }; - NativeBigInt.prototype.leq = NativeBigInt.prototype.lesserOrEquals = SmallInteger.prototype.leq = SmallInteger.prototype.lesserOrEquals = BigInteger.prototype.leq = BigInteger.prototype.lesserOrEquals; - - BigInteger.prototype.isEven = function () { - return (this.value[0] & 1) === 0; - }; - SmallInteger.prototype.isEven = function () { - return (this.value & 1) === 0; - }; - NativeBigInt.prototype.isEven = function () { - return (this.value & BigInt(1)) === BigInt(0); - }; - - BigInteger.prototype.isOdd = function () { - return (this.value[0] & 1) === 1; - }; - SmallInteger.prototype.isOdd = function () { - return (this.value & 1) === 1; - }; - NativeBigInt.prototype.isOdd = function () { - return (this.value & BigInt(1)) === BigInt(1); - }; - - BigInteger.prototype.isPositive = function () { - return !this.sign; - }; - SmallInteger.prototype.isPositive = function () { - return this.value > 0; - }; - NativeBigInt.prototype.isPositive = SmallInteger.prototype.isPositive; - - BigInteger.prototype.isNegative = function () { - return this.sign; - }; - SmallInteger.prototype.isNegative = function () { - return this.value < 0; - }; - NativeBigInt.prototype.isNegative = SmallInteger.prototype.isNegative; - - BigInteger.prototype.isUnit = function () { - return false; - }; - SmallInteger.prototype.isUnit = function () { - return Math.abs(this.value) === 1; - }; - NativeBigInt.prototype.isUnit = function () { - return this.abs().value === BigInt(1); - }; - - BigInteger.prototype.isZero = function () { - return false; - }; - SmallInteger.prototype.isZero = function () { - return this.value === 0; - }; - NativeBigInt.prototype.isZero = function () { - return this.value === BigInt(0); - }; - - BigInteger.prototype.isDivisibleBy = function (v) { - var n = parseValue(v); - if (n.isZero()) return false; - if (n.isUnit()) return true; - if (n.compareAbs(2) === 0) return this.isEven(); - return this.mod(n).isZero(); - }; - NativeBigInt.prototype.isDivisibleBy = SmallInteger.prototype.isDivisibleBy = BigInteger.prototype.isDivisibleBy; - - function isBasicPrime(v) { - var n = v.abs(); - if (n.isUnit()) return false; - if (n.equals(2) || n.equals(3) || n.equals(5)) return true; - if (n.isEven() || n.isDivisibleBy(3) || n.isDivisibleBy(5)) return false; - if (n.lesser(49)) return true; - // we don't know if it's prime: let the other functions figure it out - } - - function millerRabinTest(n, a) { - var nPrev = n.prev(), - b = nPrev, - r = 0, - d, i, x; - while (b.isEven()) b = b.divide(2), r++; - next: for (i = 0; i < a.length; i++) { - if (n.lesser(a[i])) continue; - x = bigInt(a[i]).modPow(b, n); - if (x.isUnit() || x.equals(nPrev)) continue; - for (d = r - 1; d != 0; d--) { - x = x.square().mod(n); - if (x.isUnit()) return false; - if (x.equals(nPrev)) continue next; - } - return false; - } - return true; - } - - // Set "strict" to true to force GRH-supported lower bound of 2*log(N)^2 - BigInteger.prototype.isPrime = function (strict) { - var isPrime = isBasicPrime(this); - if (isPrime !== undefined$1) return isPrime; - var n = this.abs(); - var bits = n.bitLength(); - if (bits <= 64) - return millerRabinTest(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]); - var logN = Math.log(2) * bits.toJSNumber(); - var t = Math.ceil((strict === true) ? (2 * Math.pow(logN, 2)) : logN); - for (var a = [], i = 0; i < t; i++) { - a.push(bigInt(i + 2)); - } - return millerRabinTest(n, a); - }; - NativeBigInt.prototype.isPrime = SmallInteger.prototype.isPrime = BigInteger.prototype.isPrime; - - BigInteger.prototype.isProbablePrime = function (iterations, rng) { - var isPrime = isBasicPrime(this); - if (isPrime !== undefined$1) return isPrime; - var n = this.abs(); - var t = iterations === undefined$1 ? 5 : iterations; - for (var a = [], i = 0; i < t; i++) { - a.push(bigInt.randBetween(2, n.minus(2), rng)); - } - return millerRabinTest(n, a); - }; - NativeBigInt.prototype.isProbablePrime = SmallInteger.prototype.isProbablePrime = BigInteger.prototype.isProbablePrime; - - BigInteger.prototype.modInv = function (n) { - var t = bigInt.zero, newT = bigInt.one, r = parseValue(n), newR = this.abs(), q, lastT, lastR; - while (!newR.isZero()) { - q = r.divide(newR); - lastT = t; - lastR = r; - t = newT; - r = newR; - newT = lastT.subtract(q.multiply(newT)); - newR = lastR.subtract(q.multiply(newR)); - } - if (!r.isUnit()) throw new Error(this.toString() + " and " + n.toString() + " are not co-prime"); - if (t.compare(0) === -1) { - t = t.add(n); - } - if (this.isNegative()) { - return t.negate(); - } - return t; - }; - - NativeBigInt.prototype.modInv = SmallInteger.prototype.modInv = BigInteger.prototype.modInv; - - BigInteger.prototype.next = function () { - var value = this.value; - if (this.sign) { - return subtractSmall(value, 1, this.sign); - } - return new BigInteger(addSmall(value, 1), this.sign); - }; - SmallInteger.prototype.next = function () { - var value = this.value; - if (value + 1 < MAX_INT) return new SmallInteger(value + 1); - return new BigInteger(MAX_INT_ARR, false); - }; - NativeBigInt.prototype.next = function () { - return new NativeBigInt(this.value + BigInt(1)); - }; - - BigInteger.prototype.prev = function () { - var value = this.value; - if (this.sign) { - return new BigInteger(addSmall(value, 1), true); - } - return subtractSmall(value, 1, this.sign); - }; - SmallInteger.prototype.prev = function () { - var value = this.value; - if (value - 1 > -MAX_INT) return new SmallInteger(value - 1); - return new BigInteger(MAX_INT_ARR, true); - }; - NativeBigInt.prototype.prev = function () { - return new NativeBigInt(this.value - BigInt(1)); - }; - - var powersOfTwo = [1]; - while (2 * powersOfTwo[powersOfTwo.length - 1] <= BASE) powersOfTwo.push(2 * powersOfTwo[powersOfTwo.length - 1]); - var powers2Length = powersOfTwo.length, highestPower2 = powersOfTwo[powers2Length - 1]; - - function shift_isSmall(n) { - return Math.abs(n) <= BASE; - } - - BigInteger.prototype.shiftLeft = function (v) { - var n = parseValue(v).toJSNumber(); - if (!shift_isSmall(n)) { - throw new Error(String(n) + " is too large for shifting."); - } - if (n < 0) return this.shiftRight(-n); - var result = this; - if (result.isZero()) return result; - while (n >= powers2Length) { - result = result.multiply(highestPower2); - n -= powers2Length - 1; - } - return result.multiply(powersOfTwo[n]); - }; - NativeBigInt.prototype.shiftLeft = SmallInteger.prototype.shiftLeft = BigInteger.prototype.shiftLeft; - - BigInteger.prototype.shiftRight = function (v) { - var remQuo; - var n = parseValue(v).toJSNumber(); - if (!shift_isSmall(n)) { - throw new Error(String(n) + " is too large for shifting."); - } - if (n < 0) return this.shiftLeft(-n); - var result = this; - while (n >= powers2Length) { - if (result.isZero() || (result.isNegative() && result.isUnit())) return result; - remQuo = divModAny(result, highestPower2); - result = remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0]; - n -= powers2Length - 1; - } - remQuo = divModAny(result, powersOfTwo[n]); - return remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0]; - }; - NativeBigInt.prototype.shiftRight = SmallInteger.prototype.shiftRight = BigInteger.prototype.shiftRight; - - function bitwise(x, y, fn) { - y = parseValue(y); - var xSign = x.isNegative(), ySign = y.isNegative(); - var xRem = xSign ? x.not() : x, - yRem = ySign ? y.not() : y; - var xDigit = 0, yDigit = 0; - var xDivMod = null, yDivMod = null; - var result = []; - while (!xRem.isZero() || !yRem.isZero()) { - xDivMod = divModAny(xRem, highestPower2); - xDigit = xDivMod[1].toJSNumber(); - if (xSign) { - xDigit = highestPower2 - 1 - xDigit; // two's complement for negative numbers - } - - yDivMod = divModAny(yRem, highestPower2); - yDigit = yDivMod[1].toJSNumber(); - if (ySign) { - yDigit = highestPower2 - 1 - yDigit; // two's complement for negative numbers - } - - xRem = xDivMod[0]; - yRem = yDivMod[0]; - result.push(fn(xDigit, yDigit)); - } - var sum = fn(xSign ? 1 : 0, ySign ? 1 : 0) !== 0 ? bigInt(-1) : bigInt(0); - for (var i = result.length - 1; i >= 0; i -= 1) { - sum = sum.multiply(highestPower2).add(bigInt(result[i])); - } - return sum; - } - - BigInteger.prototype.not = function () { - return this.negate().prev(); - }; - NativeBigInt.prototype.not = SmallInteger.prototype.not = BigInteger.prototype.not; - - BigInteger.prototype.and = function (n) { - return bitwise(this, n, function (a, b) { return a & b; }); - }; - NativeBigInt.prototype.and = SmallInteger.prototype.and = BigInteger.prototype.and; - - BigInteger.prototype.or = function (n) { - return bitwise(this, n, function (a, b) { return a | b; }); - }; - NativeBigInt.prototype.or = SmallInteger.prototype.or = BigInteger.prototype.or; - - BigInteger.prototype.xor = function (n) { - return bitwise(this, n, function (a, b) { return a ^ b; }); - }; - NativeBigInt.prototype.xor = SmallInteger.prototype.xor = BigInteger.prototype.xor; - - var LOBMASK_I = 1 << 30, LOBMASK_BI = (BASE & -BASE) * (BASE & -BASE) | LOBMASK_I; - function roughLOB(n) { // get lowestOneBit (rough) - // SmallInteger: return Min(lowestOneBit(n), 1 << 30) - // BigInteger: return Min(lowestOneBit(n), 1 << 14) [BASE=1e7] - var v = n.value, - x = typeof v === "number" ? v | LOBMASK_I : - typeof v === "bigint" ? v | BigInt(LOBMASK_I) : - v[0] + v[1] * BASE | LOBMASK_BI; - return x & -x; - } - - function integerLogarithm(value, base) { - if (base.compareTo(value) <= 0) { - var tmp = integerLogarithm(value, base.square(base)); - var p = tmp.p; - var e = tmp.e; - var t = p.multiply(base); - return t.compareTo(value) <= 0 ? { p: t, e: e * 2 + 1 } : { p: p, e: e * 2 }; - } - return { p: bigInt(1), e: 0 }; - } - - BigInteger.prototype.bitLength = function () { - var n = this; - if (n.compareTo(bigInt(0)) < 0) { - n = n.negate().subtract(bigInt(1)); - } - if (n.compareTo(bigInt(0)) === 0) { - return bigInt(0); - } - return bigInt(integerLogarithm(n, bigInt(2)).e).add(bigInt(1)); - }; - NativeBigInt.prototype.bitLength = SmallInteger.prototype.bitLength = BigInteger.prototype.bitLength; - - function max(a, b) { - a = parseValue(a); - b = parseValue(b); - return a.greater(b) ? a : b; - } - function min(a, b) { - a = parseValue(a); - b = parseValue(b); - return a.lesser(b) ? a : b; - } - function gcd(a, b) { - a = parseValue(a).abs(); - b = parseValue(b).abs(); - if (a.equals(b)) return a; - if (a.isZero()) return b; - if (b.isZero()) return a; - var c = Integer[1], d, t; - while (a.isEven() && b.isEven()) { - d = min(roughLOB(a), roughLOB(b)); - a = a.divide(d); - b = b.divide(d); - c = c.multiply(d); - } - while (a.isEven()) { - a = a.divide(roughLOB(a)); - } - do { - while (b.isEven()) { - b = b.divide(roughLOB(b)); - } - if (a.greater(b)) { - t = b; b = a; a = t; - } - b = b.subtract(a); - } while (!b.isZero()); - return c.isUnit() ? a : a.multiply(c); - } - function lcm(a, b) { - a = parseValue(a).abs(); - b = parseValue(b).abs(); - return a.divide(gcd(a, b)).multiply(b); - } - function randBetween(a, b, rng) { - a = parseValue(a); - b = parseValue(b); - var usedRNG = rng || Math.random; - var low = min(a, b), high = max(a, b); - var range = high.subtract(low).add(1); - if (range.isSmall) return low.add(Math.floor(usedRNG() * range)); - var digits = toBase(range, BASE).value; - var result = [], restricted = true; - for (var i = 0; i < digits.length; i++) { - var top = restricted ? digits[i] : BASE; - var digit = truncate(usedRNG() * top); - result.push(digit); - if (digit < top) restricted = false; - } - return low.add(Integer.fromArray(result, BASE, false)); - } - - var parseBase = function (text, base, alphabet, caseSensitive) { - alphabet = alphabet || DEFAULT_ALPHABET; - text = String(text); - if (!caseSensitive) { - text = text.toLowerCase(); - alphabet = alphabet.toLowerCase(); - } - var length = text.length; - var i; - var absBase = Math.abs(base); - var alphabetValues = {}; - for (i = 0; i < alphabet.length; i++) { - alphabetValues[alphabet[i]] = i; - } - for (i = 0; i < length; i++) { - var c = text[i]; - if (c === "-") continue; - if (c in alphabetValues) { - if (alphabetValues[c] >= absBase) { - if (c === "1" && absBase === 1) continue; - throw new Error(c + " is not a valid digit in base " + base + "."); - } - } - } - base = parseValue(base); - var digits = []; - var isNegative = text[0] === "-"; - for (i = isNegative ? 1 : 0; i < text.length; i++) { - var c = text[i]; - if (c in alphabetValues) digits.push(parseValue(alphabetValues[c])); - else if (c === "<") { - var start = i; - do { i++; } while (text[i] !== ">" && i < text.length); - digits.push(parseValue(text.slice(start + 1, i))); - } - else throw new Error(c + " is not a valid character"); - } - return parseBaseFromArray(digits, base, isNegative); - }; - - function parseBaseFromArray(digits, base, isNegative) { - var val = Integer[0], pow = Integer[1], i; - for (i = digits.length - 1; i >= 0; i--) { - val = val.add(digits[i].times(pow)); - pow = pow.times(base); - } - return isNegative ? val.negate() : val; - } - - function stringify(digit, alphabet) { - alphabet = alphabet || DEFAULT_ALPHABET; - if (digit < alphabet.length) { - return alphabet[digit]; - } - return "<" + digit + ">"; - } - - function toBase(n, base) { - base = bigInt(base); - if (base.isZero()) { - if (n.isZero()) return { value: [0], isNegative: false }; - throw new Error("Cannot convert nonzero numbers to base 0."); - } - if (base.equals(-1)) { - if (n.isZero()) return { value: [0], isNegative: false }; - if (n.isNegative()) - return { - value: [].concat.apply([], Array.apply(null, Array(-n.toJSNumber())) - .map(Array.prototype.valueOf, [1, 0]) - ), - isNegative: false - }; - - var arr = Array.apply(null, Array(n.toJSNumber() - 1)) - .map(Array.prototype.valueOf, [0, 1]); - arr.unshift([1]); - return { - value: [].concat.apply([], arr), - isNegative: false - }; - } - - var neg = false; - if (n.isNegative() && base.isPositive()) { - neg = true; - n = n.abs(); - } - if (base.isUnit()) { - if (n.isZero()) return { value: [0], isNegative: false }; - - return { - value: Array.apply(null, Array(n.toJSNumber())) - .map(Number.prototype.valueOf, 1), - isNegative: neg - }; - } - var out = []; - var left = n, divmod; - while (left.isNegative() || left.compareAbs(base) >= 0) { - divmod = left.divmod(base); - left = divmod.quotient; - var digit = divmod.remainder; - if (digit.isNegative()) { - digit = base.minus(digit).abs(); - left = left.next(); - } - out.push(digit.toJSNumber()); - } - out.push(left.toJSNumber()); - return { value: out.reverse(), isNegative: neg }; - } - - function toBaseString(n, base, alphabet) { - var arr = toBase(n, base); - return (arr.isNegative ? "-" : "") + arr.value.map(function (x) { - return stringify(x, alphabet); - }).join(''); - } - - BigInteger.prototype.toArray = function (radix) { - return toBase(this, radix); - }; - - SmallInteger.prototype.toArray = function (radix) { - return toBase(this, radix); - }; - - NativeBigInt.prototype.toArray = function (radix) { - return toBase(this, radix); - }; - - BigInteger.prototype.toString = function (radix, alphabet) { - if (radix === undefined$1) radix = 10; - if (radix !== 10) return toBaseString(this, radix, alphabet); - var v = this.value, l = v.length, str = String(v[--l]), zeros = "0000000", digit; - while (--l >= 0) { - digit = String(v[l]); - str += zeros.slice(digit.length) + digit; - } - var sign = this.sign ? "-" : ""; - return sign + str; - }; - - SmallInteger.prototype.toString = function (radix, alphabet) { - if (radix === undefined$1) radix = 10; - if (radix != 10) return toBaseString(this, radix, alphabet); - return String(this.value); - }; - - NativeBigInt.prototype.toString = SmallInteger.prototype.toString; - - NativeBigInt.prototype.toJSON = BigInteger.prototype.toJSON = SmallInteger.prototype.toJSON = function () { return this.toString(); }; - - BigInteger.prototype.valueOf = function () { - return parseInt(this.toString(), 10); - }; - BigInteger.prototype.toJSNumber = BigInteger.prototype.valueOf; - - SmallInteger.prototype.valueOf = function () { - return this.value; - }; - SmallInteger.prototype.toJSNumber = SmallInteger.prototype.valueOf; - NativeBigInt.prototype.valueOf = NativeBigInt.prototype.toJSNumber = function () { - return parseInt(this.toString(), 10); - }; - - function parseStringValue(v) { - if (isPrecise(+v)) { - var x = +v; - if (x === truncate(x)) - return supportsNativeBigInt ? new NativeBigInt(BigInt(x)) : new SmallInteger(x); - throw new Error("Invalid integer: " + v); - } - var sign = v[0] === "-"; - if (sign) v = v.slice(1); - var split = v.split(/e/i); - if (split.length > 2) throw new Error("Invalid integer: " + split.join("e")); - if (split.length === 2) { - var exp = split[1]; - if (exp[0] === "+") exp = exp.slice(1); - exp = +exp; - if (exp !== truncate(exp) || !isPrecise(exp)) throw new Error("Invalid integer: " + exp + " is not a valid exponent."); - var text = split[0]; - var decimalPlace = text.indexOf("."); - if (decimalPlace >= 0) { - exp -= text.length - decimalPlace - 1; - text = text.slice(0, decimalPlace) + text.slice(decimalPlace + 1); - } - if (exp < 0) throw new Error("Cannot include negative exponent part for integers"); - text += (new Array(exp + 1)).join("0"); - v = text; - } - var isValid = /^([0-9][0-9]*)$/.test(v); - if (!isValid) throw new Error("Invalid integer: " + v); - if (supportsNativeBigInt) { - return new NativeBigInt(BigInt(sign ? "-" + v : v)); - } - var r = [], max = v.length, l = LOG_BASE, min = max - l; - while (max > 0) { - r.push(+v.slice(min, max)); - min -= l; - if (min < 0) min = 0; - max -= l; - } - trim(r); - return new BigInteger(r, sign); - } - - function parseNumberValue(v) { - if (supportsNativeBigInt) { - return new NativeBigInt(BigInt(v)); - } - if (isPrecise(v)) { - if (v !== truncate(v)) throw new Error(v + " is not an integer."); - return new SmallInteger(v); - } - return parseStringValue(v.toString()); - } - - function parseValue(v) { - if (typeof v === "number") { - return parseNumberValue(v); - } - if (typeof v === "string") { - return parseStringValue(v); - } - if (typeof v === "bigint") { - return new NativeBigInt(v); - } - return v; - } - // Pre-define numbers in range [-999,999] - for (var i = 0; i < 1000; i++) { - Integer[i] = parseValue(i); - if (i > 0) Integer[-i] = parseValue(-i); - } - // Backwards compatibility - Integer.one = Integer[1]; - Integer.zero = Integer[0]; - Integer.minusOne = Integer[-1]; - Integer.max = max; - Integer.min = min; - Integer.gcd = gcd; - Integer.lcm = lcm; - Integer.isInstance = function (x) { return x instanceof BigInteger || x instanceof SmallInteger || x instanceof NativeBigInt; }; - Integer.randBetween = randBetween; - - Integer.fromArray = function (digits, base, isNegative) { - return parseBaseFromArray(digits.map(parseValue), parseValue(base || 10), isNegative); - }; - - return Integer; - })(); - - // Node.js check - if ( module.hasOwnProperty("exports")) { - module.exports = bigInt; - } - }); - - /** - * @module signature - */ - - /** - * This function verifies the given raw consensus - * - * Note 1: TOR does not perform a full PKCS#1 v1.5 signature (RFC 2313) as mentioned in the TOR's reference. - * The padding of the data that must be signed is done following the reference (see subsection 8.1 of the - * RFC 2313 for more details), however the digest is not wrapped into the data structure described in the - * subsection 10.1.2. This is the reason why RSA is performed manually. - * - * Note 2: must be included in the HTML file using this function. - * - * @param {String} raw_cons the consensus we want to verify - * @param {Object} keys object mapping the authorities' fingerprint to their key with the following format: - * fingerprint:{ - * pem: key_pem //the key in pem format - * modulus: modulus //the modulus of the key as a string - * exponent: exponent //the exponent of the key as a string - * } - * @param {Number} minimal the minimal percentage of the signatures that must be verified in order to verify the consensus - * @returns {Boolean} the result of the verification - */ - function verify(raw_cons, keys, minimal, flavor = 'microdesc') { - if (minimal === undefined) { - minimal = 0.5; - } else if (minimal <= 0 || minimal > 1) { - throw 'The minimal percentage must be between 0 (not included) and 1' - } - - let nbr_verified = 0; - let total = 0; - - //get the hash of the consensus - let split_cons = raw_cons.split('directory-signature '); - raw_cons = split_cons[0] + "directory-signature "; - - let hash = (flavor == 'unflavored') ? sjcl.hash.sha1.hash(raw_cons) : sjcl.hash.sha256.hash(raw_cons); - hash = sjcl.codec.hex.fromBits(hash); - - // Get the signatures and the signing keys - let sig_and_keys_digests = get_sig_and_keys_digests(split_cons.splice(1)); - - for (let fingerprint in sig_and_keys_digests) { - total++; - - let key = keys[fingerprint]; - let e = BigInteger(key["exponent"]); - let n = BigInteger(key["modulus"]); - let key_digest = sig_and_keys_digests[fingerprint]["signing-key-digest"]; - - if (key === undefined || !verify_key(key["pem"], key_digest)) continue - - let signature = sig_and_keys_digests[fingerprint]["signature"]; - let sig_big_int = get_signature_big_int(signature); - let padded_hash = get_hash(sig_big_int, e, n); - let recovered_hash = get_hash_from_rsa_cipher(padded_hash); - - nbr_verified = (recovered_hash === undefined || recovered_hash !== hash) ? nbr_verified : nbr_verified + 1; - } - - return nbr_verified > minimal * total - } - - /** - * This function get the digest encrypted by the RSA corresponding to given the exponent and modulus - * - * @param {BigInteger} signature the encrypted signature - * @param {BigInteger} exponent the exponent of the key - * @param {BigInteger} modulus the modulus of the key - * @returns {String} the padded hash - */ - function get_hash(signature, exponent, modulus) { - let padded_hash = signature.modPow(exponent, modulus).toString(16); - let size = modulus.toString(16).length; - let offset = size - padded_hash.length; - for (let i = 0; i < offset; i++) { - padded_hash = "0" + padded_hash; - } - return padded_hash - } - - /** - * This function verifies that the key corresponds to one that signed the consensus - * - * @param {string} key the key with the format pem - * @param {string} key_digest the hex digest extracted from the consensus - */ - function verify_key(key, key_digest) { - let raw_key = key.split('\n'); - let b_index = raw_key.indexOf("-----BEGIN RSA PUBLIC KEY-----"); - let e_index = raw_key.indexOf("-----END RSA PUBLIC KEY-----"); - - raw_key = raw_key.splice(b_index + 1, e_index - b_index - 1).join(""); - raw_key = sjcl.codec.base64.toBits(raw_key); - let hash = sjcl.hash.sha1.hash(raw_key); - hash = sjcl.codec.hex.fromBits(hash); - return hash.toUpperCase() === key_digest.toUpperCase() - } - - - /** - * This function gets the signatures and the signing key digests from the authority section of the consensus - * - * @param {Array} remaining the remaining part of the consensus after the split by "directory-signature " - * @returns {object} the following mapping: - * fingerprint:{ - * signature-key-digest - * signature - * } - */ - function get_sig_and_keys_digests(remaining) { - let sign_and_digests = {}; - for (let r of remaining) { - if (r !== '') { - let split = r.split('\n'); - let b_index = split.indexOf("-----BEGIN SIGNATURE-----"); - let e_index = split.indexOf("-----END SIGNATURE-----"); - let sign = split.splice(b_index + 1, e_index - b_index - 1).join(""); - let digests = split[0].split(" "); - - let [fingerprint, key_hex_digest] = (digests.length == 2) ? digests : digests.splice(1); - - sign_and_digests[fingerprint] = { - "signing-key-digest": key_hex_digest, - "signature": sign - }; - } - } - return sign_and_digests - } - - /** - * - * This function transforms a signature in base64 into a bigInteger - * @param {string} signature the signature encoded in base64 - * @returns {BigInteger} the integer corresponding to the signature - */ - function get_signature_big_int(signature) { - let sig_hex = sjcl.codec.hex.fromBits(sjcl.codec.base64.toBits(signature)); - let sig = BigInteger(sig_hex, 16); - return sig - } - - /** - * Verifies that the cipher has the required format and extract the substring corresponding to the hash of the consensus - * - * @param {string} cipher the padded hash of the consensus - * @returns {string} the hash of the consensus - */ - function get_hash_from_rsa_cipher(padded_hash) { - - if (!padded_hash.startsWith("0001")) return undefined - padded_hash = padded_hash.substring(4); - let sep_index = padded_hash.indexOf("00"); - - for (let i = 1; i < sep_index; i++) { - if (padded_hash.charAt(i) !== "f") return undefined - } - - return padded_hash.substring(sep_index + 2) - } - - /** - * @module stream - */ - - let stream = {}; - stream.entrancy = 0; - - class Backend { - constructor(error) { - const sendMe = function (cell, endpoint) { - if (cell.cmd == "sendme") { - endpoint.stream.sendme += 1; - endpoint.stream.deliverywindow += 100; - // flush the send queue for the circuit - - while (endpoint.stream.deliverywindow > 0 && endpoint.stream.tosend.length > 0) { - const ncell = endpoint.stream.tosend.shift(); - endpoint.io.send(ncell); - endpoint.stream.deliverywindow -= 1; - } - } else { - error(endpoint); - throw "Got unexpected control cell."; - } - }; - - this.id = 0; - this.tosend = []; - this.sendme = 0; - this.handles = { 0: { callback: sendMe } }; - this.packagewindow = 1000; // circuit-level receiving window - this.deliverywindow = 1000; // circuit level sending window - } - - register(handle) { - this.id += 1; - handle.id = this.id; - handle.packagewindow = 500; // stream-level receiving window - handle.deliverywindow = 500; // stream level sending window - this.handles[this.id] = handle; - return this.id; - } - - send(cell, endpoint) { - if (this.deliverywindow > 0) { - // if we can send - endpoint.io.send(cell); - this.deliverywindow -= 1; - } else { - // add to the send queue, will be sent when "sendme" is received. - this.tosend.push(cell); - } - } - - } - - class Raw { - constructor(endpoint, handler) { - this.id = null; - this.data = []; - this.cell = null; - this.state = lnn$1.state.started; - this.packagewindow = null; - this.deliverywindow = null; - this.tosend = []; - this.endpoint = endpoint; - this.handler = handler; - - // let id = endpoint.stream.register(this); - this.handler(this); - } - - send(cmd, data) { - const cell = build( - this.endpoint, cmd, this.id, data); - - if (cmd != "data") { - this.endpoint.io.send(cell); // non-data cells dont affect congestion control - return; - } - - if (this.deliverywindow > 0) { // send if stream level window is non zero - this.endpoint.stream.send(cell, this.endpoint); // send thru circuit level window - this.deliverywindow -= 1; - } else { - this.tosend.push(cell); // add to queue of stream level window - } - } - - recv() { - const data = this.data; - this.data = []; - return data; - } - - callback(cell) { - if (cell.cmd == "connected") { - this.state = lnn$1.state.created; - } - if (cell.cmd == "end") { - this.state = lnn$1.state.success; - } - - if (cell.cmd == "sendme") { // receive stream level sendme - this.deliverywindow += 50; - while (this.deliverywindow > 0 && this.tosend.length > 0) { - const ncell = this.tosend.shift(); - this.endpoint.stream.send(ncell, this.endpoint); - this.deliverywindow -= 1; - } - } - - this.data.push(cell); - this.handler(this); - - if (cell.cmd == "connected") { - this.state = lnn$1.state.pending; - } - } - } - - class Dir { - constructor(endpoint, path, handler) { - this.id = null; - this.data = ""; - this.cell = null; - this.state = lnn$1.state.started; - this.packagewindow = null; - this.deliverywindow = null; - this.tosend = []; - this.endpoint = endpoint; - - this.handler = handler; - this.path = path; - - const id = endpoint.stream.register(this); - let cell = build(endpoint, "begin_dir", id); - endpoint.io.send(cell); - - let data = "GET " + path + " HTTP/1.0\r\n"; - data += "Accept-Encoding: identity\r\n\r\n"; - data = dec.utf8(data); - - cell = build(endpoint, "data", id, data); - this.deliverywindow -= 1; - endpoint.stream.send(cell, endpoint); - - this.handler(this); - } - - send() { - throw "No send method on directory streams."; - } - - recv() { - const data = this.data; - this.data = ""; - return data; - } - - callback(cell) { - if (cell.cmd == "connected") { - this.state = lnn$1.state.created; - this.handler(this); - this.state = lnn$1.state.pending; - } - if (cell.cmd == "end") { - this.state = lnn$1.state.success; - this.handler(this); - } - if (cell.cmd == "sendme") { - this.deliverywindow += 50; - while (this.deliverywindow > 0 && this.tosend.length > 0) { - const ncell = this.tosend.shift(); - this.endpoint.stream.send(ncell, this.endpoint); - this.deliverywindow -= 1; - } - } - - if (cell.cmd != "data") { return; } - - this.data += enc.utf8(cell.data); - this.handler(this); - } - } - - class TCP { - constructor(endPoint, host, port, handler) { - this.id = null; - this.data = new Uint8Array(0); - this.cell = null; - this.cache = []; - - this.state = lnn$1.state.started; - this.packagewindow = null; - this.deliverywindow = null; - this.tosend = []; - this.endpoint = endPoint; - this.retries = 0; - - this.host = host; - this.port = port; - this.handler = handler; - - // WL: Get new identifier for stream? - const id = endPoint.stream.register(this); - - // WL: Create a BEGIN package containing host and port of the server? - const data = relay.begin(host, port); - - // WL: Construct the cell around it? - const cell = build(endPoint, "begin", id, data); - - // WL: Send that sell to start the process? - this.endpoint.io.send(cell); - - this.handler(this); - - this.send = this.send.bind(this); - - } - - send(send_data) { - if (send_data !== undefined) { - this.cache.push(send_data); - } - - if (this.state == lnn$1.state.started) { // not yet recvd reply for relay begin - return; - } - - while (this.cache.length) { - let data = this.cache.shift(); - - if (typeof (data) == "string") { - data = lnn$1.dec.utf8(data); - } - - const payload = new Uint8Array(lnn$1.relay.data_len); - - while (data.length > payload.length) { - payload.set(data.slice(0, payload.length), 0); - data = data.slice(payload.length); - - const cell = lnn$1.onion.build( - this.endpoint, "data", this.id, payload); - - if (this.deliverywindow > 0) { - this.endpoint.stream.send(cell, this.endpoint); - this.deliverywindow -= 1; - } else { - this.tosend.push(cell); - } - - } - - const cell = lnn$1.onion.build( - this.endpoint, "data", this.id, data); - - if (this.deliverywindow > 0) { - this.endpoint.stream.send(cell, this.endpoint); - this.deliverywindow -= 1; - } else { - this.tosend.push(cell); - } - } - } - - - - callback(cell) { - console.log(cell.cmd); - if (cell.cmd == "connected") { - this.state = lnn$1.state.created; - this.retries = 0; - this.send(); - } - if (cell.cmd == "end") { - if (cell.data[0] == 4) { // REASON EXIT_POLICY - if (this.retries == 3) { // threshold for retrying - console.log('Retries limit exceeded. Cant connect to host. '); - this.state = lnn$1.state.success; - this.retries = 0; - } else { - this.retries += 1; - console.log("Retrying to build circuit, retry#: " + this.retries); - - let ports = [80, 443]; - - if (!ports.includes(this.port)) { - ports.push(this.port); - } - - lnn$1.open( - this.endpoint.host, - this.endpoint.port, - this.success_on_open, - this.error_on_open, - undefined, - this.endpoint.fast, - this.endpoint.auth, - this.endpoint.select_path, - ports - ); - } - } else { - this.state = lnn$1.state.success; - } - } - if (cell.cmd == "data") { - const data = this.data; - this.data = new Uint8Array(data.length + cell.data.length); - this.data.set(data, 0); - this.data.set(cell.data, data.length); - } - if (cell.cmd == "sendme") { - - this.deliverywindow += 50; - while (this.deliverywindow > 0 && this.tosend.length > 0) { - const ncell = this.tosend.shift(); - this.endpoint.stream.send(ncell, this.endpoint); - this.deliverywindow -= 1; - } - } - - this.handler(this); - if (cell.cmd == "connected") { - this.state = lnn$1.state.pending; - } - } - - recv() { - const data = this.data; - this.data = new Uint8Array(0); - return data; - } - - close() { - let data = new Uint8Array(1); - data[0] = 6; // reason done - const cell = build(this.endpoint, "end", this.id, data); - this.endpoint.io.send(cell); - } - - success_on_open(endp) { - if (endp.consensus === null) - endp.consensus = this.endpoint.consensus; - if (endp.descriptors === null) - endp.descriptors = this.endpoint.descriptors; - if (endp.consensus_raw === null) - endp.consensus_raw = this.endpoint.consensus_raw; - if (endp.descriptors_raw === null) - endp.descriptors_raw = this.endpoint.descriptors_raw; - if (endp.signing_keys === null) - endp.signing_keys = this.endpoint.signing_keys; - - this.endpoint = endp; - - const id = this.endpoint.stream.register(this); - const data = lnn$1.relay.begin(this.host, this.port); - const cell = lnn$1.onion.build(this.endpoint, "begin", id, data); - this.endpoint.io.send(cell); - - this.handler(this); - } - - - error_on_open(error_msg) { - throw error_msg; - } - } - - stream.handler = function (endpoint, cell) { - stream.entrancy += 1; - if (stream.entrancy > 1) { - console.log("ENTRANCY BUG"); - } - - if (cell[4] != 3) { // (relay cell only) - console.log("Got non-relay cell, dropped: ", cell[4]); - stream.entrancy -= 1; - return; - } - - cell = peel(endpoint, cell); - if (cell === null) { - console.log("Got invalid cell, dropped."); - stream.entrancy -= 1; - return; - } - - if (!(cell.stream_id in endpoint.stream.handles)) { - console.log("Got cell outside stream, dropped: ", cell.stream_id); - stream.entrancy -= 1; - return; - } - - let handle = endpoint.stream.handles[cell.stream_id]; - if (cell.cmd == "end") - delete endpoint.stream.handles[cell.stream_id]; - - handle.cell = cell; - handle.callback(cell, endpoint); - - /* handle circuit-level sendme */ - - - if (cell.cmd == "data") { - endpoint.stream.packagewindow -= 1; - } - console.log('Update window: ', endpoint.stream.packagewindow); - if (endpoint.stream.packagewindow < 900) { - //console.log("Circuit window is ", endpoint.stream.packagewindow) - //console.log("Sending circuit level sendme cell now ", endpoint.io.counter) - endpoint.io.send(build(endpoint, 'sendme')); - endpoint.stream.packagewindow += 100; - } - - /* handle stream-level sendme */ - if (cell.cmd == "data") { - handle.packagewindow -= 1; - } - if (handle.packagewindow < 450) { - //console.log("Stream window is ", handle.packagewindow) - //console.log("Sending stream level sendme cell now ", endpoint.io.counter) - cell = build(endpoint, 'sendme', handle.id); - endpoint.io.send(cell); - handle.packagewindow += 50; - } - - stream.entrancy -= 1; - }; - - stream.backend = (error) => new Backend(error); - stream.raw = (endpoint, handler) => new Raw(endpoint, handler); - stream.dir = (endpoint, path, handler) => new Dir(endpoint, path, handler); - stream.tcp = (endPoint, host, port, handler) => new TCP(endPoint, host, port, handler); - - /** - * @module api - */ - - function fast(host, port, success, error, io, select_path) { - if (select_path === undefined) - select_path = true; - return open(host, port, success, error, io, true, null, select_path) - } - - function auth(host, port, suffix, success, error, io, select_path) { - if (select_path === undefined) - select_path = true; - if (typeof (suffix) == "string") { - suffix = suffix.replace(/-/g, "+").replace(/_/g, "/"); - suffix = dec.base64(suffix); - } - if (enc.utf8(suffix.slice(0, 5)) != "auth ") - throw "Invalid prefix in auth. suffix!" - - suffix = suffix.slice(5); - if (suffix.length != 20 + 32) - throw "Invalid auth. suffix length!" - - return open(host, port, success, error, io, true, { - identity: suffix.slice(0, 20), - onionkey: suffix.slice(20), - ntor: nacl.box.keyPair() - }, select_path) - } - - function open(host, port, success, error, io, fast, auth, select_path, tcp_ports) { - let endpoint$1 = endpoint(host, port); - if (io === undefined) - io = socket; - if (fast === undefined) - fast = false; - if (error === undefined) - error = function () { }; - if (success === undefined) - success = function () { }; - if (select_path === undefined) - select_path = true; - if (tcp_ports === undefined) - tcp_ports = [80, 443]; - - endpoint$1.fast = fast; - endpoint$1.auth = auth; - endpoint$1.select_path = select_path; - - var cb = { - guard: function (endpoint) { - endpoint.state = lnn.state.guarded; - - - circuit_info(endpoint, cb.startWebSocket, error, select_path, tcp_ports); - }, - startWebSocket: function (endpoint, info) { - console.log('called startWebSocket cb'); - endpoint.stream = stream.backend(error); - io(endpoint, stream.handler, function (endpoint) { - var state = endpoint.state; - - endpoint.state = lnn.state.pending; - - endpoint.state = state; - }, error); - endpoint.io.start(); - - handshake(endpoint, info, cb.create); - }, - create: function (endpoint) { - console.log('called create cb'); - endpoint.state = lnn.state.created; - - - extend(endpoint, endpoint.path[0], cb.extend, error); - }, - extend: function (endpoint) { - console.log('called extend cb'); - endpoint.state = lnn.state.extpath; - - - extend(endpoint, endpoint.path[1], cb.success, error); - }, - success: function (endpoint) { - console.log('called success cb'); - endpoint.state = lnn.state.success; - success(endpoint); - endpoint.io.success = function () { }; - } - }; - - endpoint$1.state = lnn.state.started; - - - if (select_path) { - consensus_raw(endpoint$1, function () { - signing_keys(endpoint$1, function () { - if (!verify(endpoint$1.consensus_raw, endpoint$1.signing_keys, 0.5)) { - throw "signature verification failed." - } - console.log("signature verification success"); - descriptors_raw(endpoint$1, function () { - if (endpoint$1.fast) - circuit_info(endpoint$1, cb.startWebSocket, error, select_path, tcp_ports); - else - guard(endpoint$1, cb.guard, error); - - }, function () { - throw "Failed to fetch raw descriptors" - }); - }, function () { - throw "Failed to fetch signing keys" - }); - }, function () { - throw "Failed to fetch raw consensus!" - }); - } - else { - // fast channel: one-request channel creation (no guard pinning) - if (endpoint$1.fast) - circuit_info(endpoint$1, cb.startWebSocket, error, select_path, tcp_ports); - else - guard(endpoint$1, cb.guard, error); - } - - return endpoint$1 - } - - - /***** high level apis ****/ - - let agents = [ - "curl/7.61.0", - "curl/7.60.0", - "curl/7.59.0", - "curl/7.58.0", - "curl/7.57.0", - "curl/7.56.1", - "curl/7.56.0", - "curl/7.55.1", - "curl/7.55.0", - "curl/7.54.1", - "curl/7.54.0", - "curl/7.53.1", - "curl/7.53.0", - "curl/7.52.1", - "curl/7.52.0", - "curl/7.51.0", - "curl/7.50.3", - "curl/7.50.2", - "curl/7.50.1", - "curl/7.50.0", - "curl/7.50.0", - "curl/7.49.1", - "curl/7.49.0", - "curl/7.48.0", - "curl/7.47.1", - "curl/7.47.0", - "curl/7.46.0", - "curl/7.45.0", - "curl/7.44.0", - "curl/7.43.0", - "curl/7.42.1", - "curl/7.42.0", - "curl/7.41.0", - "curl/7.40.0", - "curl/7.39.0", - "curl/7.38.0" - ]; - - function send_req(endpoint, url, method, data, data_type, success, error) { - var agent = agents[Math.floor(Math.random() * agents.length)]; - - var data_recv = ''; - var length = null; - var rawlen = 0; - var headers = null; - var handler = function (request) { - if (request.state == lnn.state.success) { - error('Connection closed'); - return - } - - if (request.state != lnn.state.pending) - return - - var payload = request.recv(); - rawlen += payload.length; - data_recv += enc.utf8(payload); - - - if (length == null) { - if (data_recv.match('\r\n\r\n')) { - headers = data_recv.split('\r\n\r\n')[0]; - var len = headers.match('Content-Length: ([^\r]*)'); - length = parseInt(len[1]); - } - } - - if (headers == null || length == null || rawlen < headers.length + length) - return - - request.close(); - console.log("Stream closed"); - - success({ - headers: headers, - data: data_recv.slice(headers.length + 4) - }); - success = function (request) { }; - }; - - if (url.slice(0, 7) == "http://") - url = url.slice(7); - else { - error('Urls must start with http://'); - return - } - - var path = "/" + url.split("/").slice(1).join("/"); - var host = null; - if (url.match("/") == null) - host = url; - else - host = url.split("/", 1)[0]; - - var port = "80"; - if (host.match(":") != null) - port = host.split(":", 2)[1]; - - if (method != "GET" && method != "POST") { - error('Unsupported method'); - return - } - - if (data_type != "json" && data_type != "form") { - error('Unsupported content type'); - return - } - - if (data_type == "json") - data_type = "application/json"; - else - data_type = "application/x-www-form-urlencoded"; - - if (method == "GET" && data.length > 0) { - data = "?" + data; - path += data; - path = encodeURI(path); - } - else if (data_type == "application/x-www-form-urlencoded") { - data = encodeURI(data); - } - - var payload = [ - [method, path, "HTTP/1.1"].join(" "), - ["Host:", host].join(" "), - ["User-Agent:", agent].join(" "), - ["Accept:", "*/*"].join(" ")]; - - if (method == "POST") { - payload.push(["Content-Length:", data.length].join(" ")); - payload.push(["Content-Type:", data_type].join(" ")); - payload = payload.join("\r\n") + "\r\n\r\n" + data + "\r\n"; - } - else { - payload = payload.join("\r\n") + "\r\n\r\n"; - } - - - console.log(payload); - - host = host.split(':')[0]; - stream.tcp(endpoint, host, port, handler).send(payload); - } - - function http_request(url, method, data, data_type, success, error, tor_host, tor_port) { - if (tor_host === undefined) - tor_host = 'localhost'; - if (tor_port === undefined) - tor_port = 4990; - if (error === undefined) - error = function () { }; - if (success === undefined) - success = function () { }; - - var closed = false; - - var channel = open( - tor_host, tor_port, function (endpoint) { - if (endpoint.state != lnn.state.success) { - return - } - - send_req(endpoint, url, method, data, data_type, function (request) { - //close circuit here. - if (!closed) { - endpoint.close(function (success_msg) { console.log(success_msg); }); - closed = true; - } - success(request); - }, function (message) { - //close circuit here - if (!closed) { - endpoint.close(function (success_msg) { console.log(success_msg); }); - closed = true; - } - error(message); - }); - - } - , function () { - error("Connection establishment failed"); - } - ); - } - - /** - * @module endpoint - */ - - - /** - * Create an empty endpoint object, consider using {@link lnn.open} first. - * - * @todo TODO: migrate from http+ws to https+wss - * @todo TODO: use only one port for https+wss - * - * @param {string} host (ex: localhost, example.com) - * @param {string} port (ex: 4990, 8080, 5000, 443…) - * @return {endpoint_t} - */ - function endpoint(host, port) { - var http = "http://" + host + ":" + port.toString(); - http += lnn$1.api.url; - - var ws = "ws://" + host + ":" + lnn$1.api.ws_port; - ws += lnn$1.api.url; - - /** - * Internal object, stores API urls used for parent endpoint calls. - * - *
      -	     * Note: {@link lnn.api.ws_port} is inlined in .ws and .socket
      -	     *       (used by {@link lnn.io.socket}).
      -	     * 
      - * - * @interface endpoint_t~urls_t - * @see endpoint_t - * - * @property {string} ws websocket base url - * @property {string} http http calls base url - * @property {string} guard GET /consensus - * @property {string} consensus GET /consensus - * @property {string} socket websocket endpoint - * @property {string} channels POST+DELETE /channels - * @property {string} consensus GET /consensus - */ - var urls = { - ws: ws, - http: http, - guard: http + "/guard", - socket: ws + "/channels", - channels: http + "/channels", - consensus: http + "/consensus", - descriptors: http + "/descriptors", - signing_keys: http + "/signing-keys" - }; - - /** - * Captures the state of a channel, returned by {@link lnn.open}. - * - * @interface endpoint_t - * @see lnn.endpoint - * - * @property {lnn.state} state channel state - * @property {io.io_t} io io adapter in use - * @property {endpoint_t~urls_t} urls static API urls in use - * @property {backend_t} stream stream backend in use - * @property {backward_t} backward backward cryptographic state - * @property {forward_t} forward forward cryptographic state - * @property {material_t|half_t} material shared cryptographic material - * @property {null|half_t} auth stores {@link lnn.auth} - * material - * @property {Boolean} fast is {@link lnn.fast} - * in use? - */ - var endpoint = { - /** - * Host in use, as given to {@link lnn.endpoint} factory. - * - * @name endpoint_t#host - * @readonly - */ - host: host, - /** - * Port in use, as given to {@link lnn.endpoint} factory. - * - * @name endpoint_t#port - * @readonly - */ - port: port, - fast: null, - auth: null, - urls: urls, - io: null, - state: 0, - /** - * Last shared cryptographic material retrieved, written by: - *
        - *
      • {@link lnn.post.create} - *
      • {@link lnn.post.extend} - *
      • {@link lnn.ntor.hand} - *
      • {@link lnn.ntor.fast} - *
      • {@link lnn.ntor.auth} - *
      - * - * Either stores {@link material_t} or {@link half_t}. - * - * @name endpoint_t#material - * @type {material_t|half_t} - * - * @see lnn.ntor.hand - */ - material: null, - forward: null, - backward: null, - /** - * Identifier of the channel in used, written by successful a - * {@link lnn.post.create} call. - * @name endpoint_t#id - * @readonly - * @default null - */ - id: null, - /** - * Polling url endpoint used for polling io requests. - * @see lnn.post.channel - * @see lnn.io.polling - * - * @name endpoint_t#url - * @readonly - * @default null - */ - url: null, - /** - * Middle and Exit nodes descriptors obtained by {@link lnn.open} - * during channel setup. - * - *
      -	         * Note: writing this field will NOT change the path in use.
      -	         * 
      - * - * @name endpoint_t#path - * @readonly - * @default null - */ - path: null, - /** - * Guard descriptor obtained by {@link lnn.open} during channel - * setup, written by {@link lnn.get.guard}. - * - * @name endpoint_t#guard - * @readonly - * @default null - */ - guard: null, - stream: null, - /** - * Consensus obtained by {@link lnn.get.consensus} upon request. - * - * @name endpoint_t#consensus - * @readonly - * @default null - */ - consensus: null, - - /** - * Consensus obtained by {@link lnn.get.descriptors} upon request - * @name endpoint_t#descriptors - * @readonly - * @default null - */ - descriptors: null, - consensus_raw: null, - descriptors_raw: null, - signing_keys: null, - - select_path: false, - - /*perform http get/post request*/ - - http_request: function (url, method, data, data_type, success, error) { - if (error === undefined) - error = function () { }; - if (success === undefined) - success = function () { }; - - send_req(endpoint, url, method, data, data_type, success, error); - }, - - /*destroy the circuit*/ - close: function (success, error) { - close(endpoint, success, error); - } - }; - - return endpoint - } - - /** - * Utility functions. - */ - - - /** - * Parse the given url. - * {@link https://www.w3.org/TR/2012/CR-websockets-20120920/#parse-a-websocket-url-s-components} - * @param {URL} url the url to parse - * @returns [host, port, ressourceName, secure] - * @throws error when url is incorrect for a websocket connection - * @private - */ - function parseURL(url) { - // 1. if the url string is not an absolute URL, then fail this algorithm - const absoluteURLChecker = new RegExp('^(?:[a-z]+:)?//', 'i'); - if (!absoluteURLChecker.test(url.href)) { - throw `url is not absolute: ${url}`; - } - - // 2. resolve the url string, with the URL character encoding set to UTF-8. - - // 3. if url does not have a component whose value - // when converted to ASCII lowercase, is either "ws" or "wss", - // then fail this algorithm. - if (url.protocol !== "ws:" && url.protocol !== "wss:") { - throw `url scheme must be either 'ws:' or 'wss:', but is: ${url.protocol}`; - } - - // 4. f url has a component, then fail this algorithm. - if (url.hash.substr(1) !== "") { - throw `url cannot have a fragment: ${url}`; - } - - // 5. if the component of url is "ws", set secure to false; - // otherwise, the component is "wss", set secure to true. - const secure = url.protocol === "ws:" ? false : true; - - // 6. let host be the value of the component of url, - // converted to ASCII lowercase. - const host = url.hostname.toLowerCase(); - - // 7. If url has a component, then let port be that component's value; - // otherwise, there is no explicit port. - // 8. if there is no explicit port, then: if secure is false, let port be 80, - // otherwise let port be 443. - const port = url.port || (url.protocol === "ws:" ? "80" : "443"); - - // 9. let resource name be the value of the component (which might be empty) of url. - // 10. if resource name is the empty string, set it to a single character U+002F SOLIDUS (/). - let ressourceName = url.pathname || "/"; - - // 11. if url has a component, then append a single U+003F QUESTION MARK character (?) to resource name, - // followed by the value of the component. - if (url.search) { - ressourceName += url.search; - } - - // 12. return host, port, resource name, and secure. - return [host, port, ressourceName, secure]; - } - - /** - * Mask given input with given key, as specified for websocket masking - * @param {Uint8Array} x input to mask/unmask - * @param {Uint8Array} key 4-bytes key - * @private - */ - function maskWithKey(x, key) { - let out = new Uint8Array(x.length); - for (let i = 0; i < x.length; i++) { - out[i] = x[i] ^ key[i % 4]; - } - return out; - } - - /** - * Concatenate Uint8Arrays. - * @private - */ - function concatenate(...arrays) { - let len = 0; - for (let arr of arrays) { - len += arr.length; - } - let result = new Uint8Array(len); - let offset = 0; - for (let arr of arrays) { - result.set(arr, offset); - offset += arr.length; - } - return result; - } - - /** - * Packet crafting for the WebSocket protocol. - * - * WebSocket frame (RFC 6455): - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-------+-+-------------+-------------------------------+ - * |F|R|R|R| opcode|M| Payload len | Extended payload length | - * |I|S|S|S| (4) |A| (7) | (16/64) | - * |N|V|V|V| |S| | (if payload len==126/127) | - * | |1|2|3| |K| | | - * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + - * | Extended payload length continued, if payload len == 127 | - * + - - - - - - - - - - - - - - - +-------------------------------+ - * | |Masking-key, if MASK set to 1 | - * +-------------------------------+-------------------------------+ - * | Masking-key (continued) | Payload Data... | - * +---------------------------------------------------------------| - * - */ - - /** - * Construct the HTTP packet send by the client during the WebSocket handshake. - * @returns {Array} [pkt, nonce] the HTTP client handshake packet as a string, with the Uint8Array SecWebSocketKey nonce used in it - * @private - */ - function clientHandshake(host, port, resourceName, protocols = []) { - // TODO: - // - Sec-WebSocket-Protocol - // - Sec-WebSocket-Extensions - - // create the nonce: base64 encoded 16 random bytes - const nonce = naclFast.randomBytes(16); - const nonceB64 = naclUtil.encodeBase64(nonce); - - // create the http packet - let fields = [ - ["GET", `${resourceName}`, "HTTP/1.1"], - ["Host:", `${host}:${port}`], - ["Connection:", "Upgrade"], - ["Upgrade:", "websocket"], - ["Sec-WebSocket-Key:", `${nonceB64}`], - ["Origin:", `${host}`], - ["Sec-WebSocket-Version:", "13"], - ]; - - if (Array.isArray(protocols) && protocols.length > 0) { - fields.push(["Sec-WebSocket-Protocol:", protocols.join(", ")]); - } - - const pkt = fields.map(s => s.join(" ")).join("\r\n") + "\r\n\r\n"; - - return [pkt, nonce]; - } - - /** - * The GUID used for the Sec-WebSocket verification. - * @private - */ - const GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - - /** - * Construct a pong frame. - * @param {Uint8Array} payload the pong payload, usually the application data of the received ping - * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes - * @private - */ - function pongFrame(payload, maskingKey = undefined) { - return Frame._encapsulate(payload, "1000", opcodes.pong, maskingKey); - } - - /** - * Construct a close frame - * @param {Number} code status code for closing the connection (2bytes) - * @param {reason} string reason for closing the connection - * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes - * @private - */ - function closeFrame(code, reason = undefined, maskingKey = undefined) { - if (code < 0 || code >= 65536) { - throw `cannot encode int ${code} to 2 bytes`; - } - let payload = new Uint8Array([ - code >> 8, - code & 255 - ]); - if (reason) { - payload = concatenate(concatenate, naclUtil.decodeUTF8(reason)); - } - - return Frame._encapsulate(payload, "1000", opcodes.close, maskingKey); - } - - let opcodes = { - continuation: 0, - text: 1, - binary: 2, - // x3-7 reserved for further non-control frames - close: 8, - ping: 9, - pong: 10, - // xB-F reserved for further control frames - }; - - let isControlFrame = (opcode) => (opcode & 8) === 8; - - /** - * Represent a WebSocket frame, not fragmented. - * - * See websocket framing protocol: - * {@link https://tools.ietf.org/html/rfc6455#section-5.2}. - * @private - */ - class Frame { - - /** - * Construct a WebSocket Frame. - * - * @param {Boolean} rsv1 - * @param {Boolean} rsv2 - * @param {Boolean} rsv3 - * @param {Integer} opcode - * @param {Uint8Array} payload - */ - constructor(rsv1, rsv2, rsv3, opcode, payload) { - this.rsv1 = rsv1 ? "1" : "0"; - this.rsv2 = rsv2 ? "1" : "0"; - this.rsv3 = rsv3 ? "1" : "0"; - this.opcode = opcode; - this.payload = payload; - } - - // Return true if the frame represents a control frame - isControl() { - return isControlFrame(this.opcode); - } - - /** - * Encapsulate Frame into a WebSocket packet in byte array format. - * - * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes - * @returns {Uint8Array} packet - */ - encapsulate(maskingKey = undefined) { - const flags = "1".concat(this.rsv1, this.rsv2, this.rsv3); - return Frame._encapsulate(this.payload, flags, this.opcode, maskingKey); - } - - /** - * Fragment frame into several websocket packets. - * To be used in place of the `encapsulate` method when fragmentation is needed. - * - * @param {int} chunkSize the maximum length of a (websocket) payload, in bytes - * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes - * @returns {Array} an array of Uint8Array, that contains in-order websocket-encapsulated packets - */ - fragment(chunkSize, maskingKey = undefined) { - // chunk payload into smaller payloads - let payloads = []; - for (let i = 0; i < this.payload.length; i += chunkSize) { - payloads.push(this.payload.slice(i, i + chunkSize)); - } - - // create packets - let packets = []; - for (let i = 0; i < payloads.length; i++) { - // only the last fragment has the FIN flag set - const finFlag = (i !== (payloads.length - 1)) ? "0" : "1"; - const flags = finFlag.concat(this.rsv1, this.rsv2, this.rsv3); - // only the first fragment has the opcode set - const code = (i === 0) ? this.opcode : opcodes.continuation; - - packets.push(Frame._encapsulate(payloads[i], flags, code, maskingKey)); - } - - return packets; - } - - /** - * Encapsulate given data into a WebSocket packet in byte array format. - * - * @param {Uint8Array} payload the packet payload - * @param {string} flags the first 4 bits of the packet, FIN/RSV1/RSV2/RSV3 in bitstring format - * @param {int} opcode the integer opcode - * @param {Uint8Array} maskingKey 4-bytes key for masking the frame, for testing purposes - * @returns {Uint8Array} packet - */ - static _encapsulate(payload, flags = "1000", opcode = 1, maskingKey = undefined) { - const opcodeBits = opcode.toString(2).padStart(4, '0'); - - let payloadLen; - if (payload.length >= 126) { - if (payload.length < 65536) { - // use next two bytes to encode the payload length - let code = 126; - payloadLen = code.toString(2).padStart(7, '0'); - payloadLen += payload.length.toString(2).padStart(16, '0'); - - } else { - if (payload.length > 2 ^ (8 * 8)) { - throw `Error: payload too large for the websocket protocol`; - } - // use next eight bytes to encode the payload length - let code = 127; - payloadLen = code.toString(2).padStart(7, '0'); - payloadLen += payload.length.toString(2).padStart(64, '0'); - } - } else { - payloadLen = payload.length.toString(2).padStart(7, '0'); - } - - let mask = '1'; - if (maskingKey === undefined) { - // create a nonce - maskingKey = new Uint8Array(naclFast.randomBytes(4)); - } - const maskedPayload = maskWithKey(payload, maskingKey); - - function bitstringToUint8Array(bitstring) { - const len = Math.ceil(bitstring.length / 8); - let out = new Uint8Array(len); - for (let i = 0; i < len; i++) { - out[i] = parseInt(bitstring.slice(8 * i, 8 * i + 8), 2); - } - return out; - } - - let headerStart = bitstringToUint8Array(flags + opcodeBits + mask + payloadLen); - - return Uint8Array.from([...headerStart, ...maskingKey, ...maskedPayload]); - } - } - - /** - * Node.js module for Forge. - * - * @author Dave Longley - * - * Copyright 2011-2016 Digital Bazaar, Inc. - */ - var forge = { - // default options - options: { - usePureJavaScript: false - } - }; - - /** - * Base-N/Base-X encoding/decoding functions. - * - * Original implementation from base-x: - * https://github.com/cryptocoinjs/base-x - * - * Which is MIT licensed: - * - * The MIT License (MIT) - * - * Copyright base-x contributors (c) 2016 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - var api = {}; - var baseN = api; - - // baseN alphabet indexes - var _reverseAlphabets = {}; - - /** - * BaseN-encodes a Uint8Array using the given alphabet. - * - * @param input the Uint8Array to encode. - * @param maxline the maximum number of encoded characters per line to use, - * defaults to none. - * - * @return the baseN-encoded output string. - */ - api.encode = function(input, alphabet, maxline) { - if(typeof alphabet !== 'string') { - throw new TypeError('"alphabet" must be a string.'); - } - if(maxline !== undefined && typeof maxline !== 'number') { - throw new TypeError('"maxline" must be a number.'); - } - - var output = ''; - - if(!(input instanceof Uint8Array)) { - // assume forge byte buffer - output = _encodeWithByteBuffer(input, alphabet); - } else { - var i = 0; - var base = alphabet.length; - var first = alphabet.charAt(0); - var digits = [0]; - for(i = 0; i < input.length; ++i) { - for(var j = 0, carry = input[i]; j < digits.length; ++j) { - carry += digits[j] << 8; - digits[j] = carry % base; - carry = (carry / base) | 0; - } - - while(carry > 0) { - digits.push(carry % base); - carry = (carry / base) | 0; - } - } - - // deal with leading zeros - for(i = 0; input[i] === 0 && i < input.length - 1; ++i) { - output += first; - } - // convert digits to a string - for(i = digits.length - 1; i >= 0; --i) { - output += alphabet[digits[i]]; - } - } - - if(maxline) { - var regex = new RegExp('.{1,' + maxline + '}', 'g'); - output = output.match(regex).join('\r\n'); - } - - return output; - }; - - /** - * Decodes a baseN-encoded (using the given alphabet) string to a - * Uint8Array. - * - * @param input the baseN-encoded input string. - * - * @return the Uint8Array. - */ - api.decode = function(input, alphabet) { - if(typeof input !== 'string') { - throw new TypeError('"input" must be a string.'); - } - if(typeof alphabet !== 'string') { - throw new TypeError('"alphabet" must be a string.'); - } - - var table = _reverseAlphabets[alphabet]; - if(!table) { - // compute reverse alphabet - table = _reverseAlphabets[alphabet] = []; - for(var i = 0; i < alphabet.length; ++i) { - table[alphabet.charCodeAt(i)] = i; - } - } - - // remove whitespace characters - input = input.replace(/\s/g, ''); - - var base = alphabet.length; - var first = alphabet.charAt(0); - var bytes = [0]; - for(var i = 0; i < input.length; i++) { - var value = table[input.charCodeAt(i)]; - if(value === undefined) { - return; - } - - for(var j = 0, carry = value; j < bytes.length; ++j) { - carry += bytes[j] * base; - bytes[j] = carry & 0xff; - carry >>= 8; - } - - while(carry > 0) { - bytes.push(carry & 0xff); - carry >>= 8; - } - } - - // deal with leading zeros - for(var k = 0; input[k] === first && k < input.length - 1; ++k) { - bytes.push(0); - } - - if(typeof Buffer !== 'undefined') { - return Buffer.from(bytes.reverse()); - } - - return new Uint8Array(bytes.reverse()); - }; - - function _encodeWithByteBuffer(input, alphabet) { - var i = 0; - var base = alphabet.length; - var first = alphabet.charAt(0); - var digits = [0]; - for(i = 0; i < input.length(); ++i) { - for(var j = 0, carry = input.at(i); j < digits.length; ++j) { - carry += digits[j] << 8; - digits[j] = carry % base; - carry = (carry / base) | 0; - } - - while(carry > 0) { - digits.push(carry % base); - carry = (carry / base) | 0; - } - } - - var output = ''; - - // deal with leading zeros - for(i = 0; input.at(i) === 0 && i < input.length() - 1; ++i) { - output += first; - } - // convert digits to a string - for(i = digits.length - 1; i >= 0; --i) { - output += alphabet[digits[i]]; - } - - return output; - } - - var util_1 = createCommonjsModule(function (module) { - /** - * Utility functions for web applications. - * - * @author Dave Longley - * - * Copyright (c) 2010-2018 Digital Bazaar, Inc. - */ - - - - /* Utilities API */ - var util = module.exports = forge.util = forge.util || {}; - - // define setImmediate and nextTick - (function() { - // use native nextTick (unless we're in webpack) - // webpack (or better node-libs-browser polyfill) sets process.browser. - // this way we can detect webpack properly - if(typeof process !== 'undefined' && process.nextTick && !process.browser) { - util.nextTick = process.nextTick; - if(typeof setImmediate === 'function') { - util.setImmediate = setImmediate; - } else { - // polyfill setImmediate with nextTick, older versions of node - // (those w/o setImmediate) won't totally starve IO - util.setImmediate = util.nextTick; - } - return; - } - - // polyfill nextTick with native setImmediate - if(typeof setImmediate === 'function') { - util.setImmediate = function() { return setImmediate.apply(undefined, arguments); }; - util.nextTick = function(callback) { - return setImmediate(callback); - }; - return; - } - - /* Note: A polyfill upgrade pattern is used here to allow combining - polyfills. For example, MutationObserver is fast, but blocks UI updates, - so it needs to allow UI updates periodically, so it falls back on - postMessage or setTimeout. */ - - // polyfill with setTimeout - util.setImmediate = function(callback) { - setTimeout(callback, 0); - }; - - // upgrade polyfill to use postMessage - if(typeof window !== 'undefined' && - typeof window.postMessage === 'function') { - var msg = 'forge.setImmediate'; - var callbacks = []; - util.setImmediate = function(callback) { - callbacks.push(callback); - // only send message when one hasn't been sent in - // the current turn of the event loop - if(callbacks.length === 1) { - window.postMessage(msg, '*'); - } - }; - function handler(event) { - if(event.source === window && event.data === msg) { - event.stopPropagation(); - var copy = callbacks.slice(); - callbacks.length = 0; - copy.forEach(function(callback) { - callback(); - }); - } - } - window.addEventListener('message', handler, true); - } - - // upgrade polyfill to use MutationObserver - if(typeof MutationObserver !== 'undefined') { - // polyfill with MutationObserver - var now = Date.now(); - var attr = true; - var div = document.createElement('div'); - var callbacks = []; - new MutationObserver(function() { - var copy = callbacks.slice(); - callbacks.length = 0; - copy.forEach(function(callback) { - callback(); - }); - }).observe(div, {attributes: true}); - var oldSetImmediate = util.setImmediate; - util.setImmediate = function(callback) { - if(Date.now() - now > 15) { - now = Date.now(); - oldSetImmediate(callback); - } else { - callbacks.push(callback); - // only trigger observer when it hasn't been triggered in - // the current turn of the event loop - if(callbacks.length === 1) { - div.setAttribute('a', attr = !attr); - } - } - }; - } - - util.nextTick = util.setImmediate; - })(); - - // check if running under Node.js - util.isNodejs = - typeof process !== 'undefined' && process.versions && process.versions.node; - - - // 'self' will also work in Web Workers (instance of WorkerGlobalScope) while - // it will point to `window` in the main thread. - // To remain compatible with older browsers, we fall back to 'window' if 'self' - // is not available. - util.globalScope = (function() { - if(util.isNodejs) { - return commonjsGlobal; - } - - return typeof self === 'undefined' ? window : self; - })(); - - // define isArray - util.isArray = Array.isArray || function(x) { - return Object.prototype.toString.call(x) === '[object Array]'; - }; - - // define isArrayBuffer - util.isArrayBuffer = function(x) { - return typeof ArrayBuffer !== 'undefined' && x instanceof ArrayBuffer; - }; - - // define isArrayBufferView - util.isArrayBufferView = function(x) { - return x && util.isArrayBuffer(x.buffer) && x.byteLength !== undefined; - }; - - /** - * Ensure a bits param is 8, 16, 24, or 32. Used to validate input for - * algorithms where bit manipulation, JavaScript limitations, and/or algorithm - * design only allow for byte operations of a limited size. - * - * @param n number of bits. - * - * Throw Error if n invalid. - */ - function _checkBitsParam(n) { - if(!(n === 8 || n === 16 || n === 24 || n === 32)) { - throw new Error('Only 8, 16, 24, or 32 bits supported: ' + n); - } - } - - // TODO: set ByteBuffer to best available backing - util.ByteBuffer = ByteStringBuffer; - - /** Buffer w/BinaryString backing */ - - /** - * Constructor for a binary string backed byte buffer. - * - * @param [b] the bytes to wrap (either encoded as string, one byte per - * character, or as an ArrayBuffer or Typed Array). - */ - function ByteStringBuffer(b) { - // TODO: update to match DataBuffer API - - // the data in this buffer - this.data = ''; - // the pointer for reading from this buffer - this.read = 0; - - if(typeof b === 'string') { - this.data = b; - } else if(util.isArrayBuffer(b) || util.isArrayBufferView(b)) { - if(typeof Buffer !== 'undefined' && b instanceof Buffer) { - this.data = b.toString('binary'); - } else { - // convert native buffer to forge buffer - // FIXME: support native buffers internally instead - var arr = new Uint8Array(b); - try { - this.data = String.fromCharCode.apply(null, arr); - } catch(e) { - for(var i = 0; i < arr.length; ++i) { - this.putByte(arr[i]); - } - } - } - } else if(b instanceof ByteStringBuffer || - (typeof b === 'object' && typeof b.data === 'string' && - typeof b.read === 'number')) { - // copy existing buffer - this.data = b.data; - this.read = b.read; - } - - // used for v8 optimization - this._constructedStringLength = 0; - } - util.ByteStringBuffer = ByteStringBuffer; - - /* Note: This is an optimization for V8-based browsers. When V8 concatenates - a string, the strings are only joined logically using a "cons string" or - "constructed/concatenated string". These containers keep references to one - another and can result in very large memory usage. For example, if a 2MB - string is constructed by concatenating 4 bytes together at a time, the - memory usage will be ~44MB; so ~22x increase. The strings are only joined - together when an operation requiring their joining takes place, such as - substr(). This function is called when adding data to this buffer to ensure - these types of strings are periodically joined to reduce the memory - footprint. */ - var _MAX_CONSTRUCTED_STRING_LENGTH = 4096; - util.ByteStringBuffer.prototype._optimizeConstructedString = function(x) { - this._constructedStringLength += x; - if(this._constructedStringLength > _MAX_CONSTRUCTED_STRING_LENGTH) { - // this substr() should cause the constructed string to join - this.data.substr(0, 1); - this._constructedStringLength = 0; - } - }; - - /** - * Gets the number of bytes in this buffer. - * - * @return the number of bytes in this buffer. - */ - util.ByteStringBuffer.prototype.length = function() { - return this.data.length - this.read; - }; - - /** - * Gets whether or not this buffer is empty. - * - * @return true if this buffer is empty, false if not. - */ - util.ByteStringBuffer.prototype.isEmpty = function() { - return this.length() <= 0; - }; - - /** - * Puts a byte in this buffer. - * - * @param b the byte to put. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putByte = function(b) { - return this.putBytes(String.fromCharCode(b)); - }; - - /** - * Puts a byte in this buffer N times. - * - * @param b the byte to put. - * @param n the number of bytes of value b to put. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.fillWithByte = function(b, n) { - b = String.fromCharCode(b); - var d = this.data; - while(n > 0) { - if(n & 1) { - d += b; - } - n >>>= 1; - if(n > 0) { - b += b; - } - } - this.data = d; - this._optimizeConstructedString(n); - return this; - }; - - /** - * Puts bytes in this buffer. - * - * @param bytes the bytes (as a binary encoded string) to put. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putBytes = function(bytes) { - this.data += bytes; - this._optimizeConstructedString(bytes.length); - return this; - }; - - /** - * Puts a UTF-16 encoded string into this buffer. - * - * @param str the string to put. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putString = function(str) { - return this.putBytes(util.encodeUtf8(str)); - }; - - /** - * Puts a 16-bit integer in this buffer in big-endian order. - * - * @param i the 16-bit integer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putInt16 = function(i) { - return this.putBytes( - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF)); - }; - - /** - * Puts a 24-bit integer in this buffer in big-endian order. - * - * @param i the 24-bit integer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putInt24 = function(i) { - return this.putBytes( - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF)); - }; - - /** - * Puts a 32-bit integer in this buffer in big-endian order. - * - * @param i the 32-bit integer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putInt32 = function(i) { - return this.putBytes( - String.fromCharCode(i >> 24 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF)); - }; - - /** - * Puts a 16-bit integer in this buffer in little-endian order. - * - * @param i the 16-bit integer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putInt16Le = function(i) { - return this.putBytes( - String.fromCharCode(i & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF)); - }; - - /** - * Puts a 24-bit integer in this buffer in little-endian order. - * - * @param i the 24-bit integer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putInt24Le = function(i) { - return this.putBytes( - String.fromCharCode(i & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF)); - }; - - /** - * Puts a 32-bit integer in this buffer in little-endian order. - * - * @param i the 32-bit integer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putInt32Le = function(i) { - return this.putBytes( - String.fromCharCode(i & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 24 & 0xFF)); - }; - - /** - * Puts an n-bit integer in this buffer in big-endian order. - * - * @param i the n-bit integer. - * @param n the number of bits in the integer (8, 16, 24, or 32). - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putInt = function(i, n) { - _checkBitsParam(n); - var bytes = ''; - do { - n -= 8; - bytes += String.fromCharCode((i >> n) & 0xFF); - } while(n > 0); - return this.putBytes(bytes); - }; - - /** - * Puts a signed n-bit integer in this buffer in big-endian order. Two's - * complement representation is used. - * - * @param i the n-bit integer. - * @param n the number of bits in the integer (8, 16, 24, or 32). - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putSignedInt = function(i, n) { - // putInt checks n - if(i < 0) { - i += 2 << (n - 1); - } - return this.putInt(i, n); - }; - - /** - * Puts the given buffer into this buffer. - * - * @param buffer the buffer to put into this one. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.putBuffer = function(buffer) { - return this.putBytes(buffer.getBytes()); - }; - - /** - * Gets a byte from this buffer and advances the read pointer by 1. - * - * @return the byte. - */ - util.ByteStringBuffer.prototype.getByte = function() { - return this.data.charCodeAt(this.read++); - }; - - /** - * Gets a uint16 from this buffer in big-endian order and advances the read - * pointer by 2. - * - * @return the uint16. - */ - util.ByteStringBuffer.prototype.getInt16 = function() { - var rval = ( - this.data.charCodeAt(this.read) << 8 ^ - this.data.charCodeAt(this.read + 1)); - this.read += 2; - return rval; - }; - - /** - * Gets a uint24 from this buffer in big-endian order and advances the read - * pointer by 3. - * - * @return the uint24. - */ - util.ByteStringBuffer.prototype.getInt24 = function() { - var rval = ( - this.data.charCodeAt(this.read) << 16 ^ - this.data.charCodeAt(this.read + 1) << 8 ^ - this.data.charCodeAt(this.read + 2)); - this.read += 3; - return rval; - }; - - /** - * Gets a uint32 from this buffer in big-endian order and advances the read - * pointer by 4. - * - * @return the word. - */ - util.ByteStringBuffer.prototype.getInt32 = function() { - var rval = ( - this.data.charCodeAt(this.read) << 24 ^ - this.data.charCodeAt(this.read + 1) << 16 ^ - this.data.charCodeAt(this.read + 2) << 8 ^ - this.data.charCodeAt(this.read + 3)); - this.read += 4; - return rval; - }; - - /** - * Gets a uint16 from this buffer in little-endian order and advances the read - * pointer by 2. - * - * @return the uint16. - */ - util.ByteStringBuffer.prototype.getInt16Le = function() { - var rval = ( - this.data.charCodeAt(this.read) ^ - this.data.charCodeAt(this.read + 1) << 8); - this.read += 2; - return rval; - }; - - /** - * Gets a uint24 from this buffer in little-endian order and advances the read - * pointer by 3. - * - * @return the uint24. - */ - util.ByteStringBuffer.prototype.getInt24Le = function() { - var rval = ( - this.data.charCodeAt(this.read) ^ - this.data.charCodeAt(this.read + 1) << 8 ^ - this.data.charCodeAt(this.read + 2) << 16); - this.read += 3; - return rval; - }; - - /** - * Gets a uint32 from this buffer in little-endian order and advances the read - * pointer by 4. - * - * @return the word. - */ - util.ByteStringBuffer.prototype.getInt32Le = function() { - var rval = ( - this.data.charCodeAt(this.read) ^ - this.data.charCodeAt(this.read + 1) << 8 ^ - this.data.charCodeAt(this.read + 2) << 16 ^ - this.data.charCodeAt(this.read + 3) << 24); - this.read += 4; - return rval; - }; - - /** - * Gets an n-bit integer from this buffer in big-endian order and advances the - * read pointer by ceil(n/8). - * - * @param n the number of bits in the integer (8, 16, 24, or 32). - * - * @return the integer. - */ - util.ByteStringBuffer.prototype.getInt = function(n) { - _checkBitsParam(n); - var rval = 0; - do { - // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits. - rval = (rval << 8) + this.data.charCodeAt(this.read++); - n -= 8; - } while(n > 0); - return rval; - }; - - /** - * Gets a signed n-bit integer from this buffer in big-endian order, using - * two's complement, and advances the read pointer by n/8. - * - * @param n the number of bits in the integer (8, 16, 24, or 32). - * - * @return the integer. - */ - util.ByteStringBuffer.prototype.getSignedInt = function(n) { - // getInt checks n - var x = this.getInt(n); - var max = 2 << (n - 2); - if(x >= max) { - x -= max << 1; - } - return x; - }; - - /** - * Reads bytes out as a binary encoded string and clears them from the - * buffer. Note that the resulting string is binary encoded (in node.js this - * encoding is referred to as `binary`, it is *not* `utf8`). - * - * @param count the number of bytes to read, undefined or null for all. - * - * @return a binary encoded string of bytes. - */ - util.ByteStringBuffer.prototype.getBytes = function(count) { - var rval; - if(count) { - // read count bytes - count = Math.min(this.length(), count); - rval = this.data.slice(this.read, this.read + count); - this.read += count; - } else if(count === 0) { - rval = ''; - } else { - // read all bytes, optimize to only copy when needed - rval = (this.read === 0) ? this.data : this.data.slice(this.read); - this.clear(); - } - return rval; - }; - - /** - * Gets a binary encoded string of the bytes from this buffer without - * modifying the read pointer. - * - * @param count the number of bytes to get, omit to get all. - * - * @return a string full of binary encoded characters. - */ - util.ByteStringBuffer.prototype.bytes = function(count) { - return (typeof(count) === 'undefined' ? - this.data.slice(this.read) : - this.data.slice(this.read, this.read + count)); - }; - - /** - * Gets a byte at the given index without modifying the read pointer. - * - * @param i the byte index. - * - * @return the byte. - */ - util.ByteStringBuffer.prototype.at = function(i) { - return this.data.charCodeAt(this.read + i); - }; - - /** - * Puts a byte at the given index without modifying the read pointer. - * - * @param i the byte index. - * @param b the byte to put. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.setAt = function(i, b) { - this.data = this.data.substr(0, this.read + i) + - String.fromCharCode(b) + - this.data.substr(this.read + i + 1); - return this; - }; - - /** - * Gets the last byte without modifying the read pointer. - * - * @return the last byte. - */ - util.ByteStringBuffer.prototype.last = function() { - return this.data.charCodeAt(this.data.length - 1); - }; - - /** - * Creates a copy of this buffer. - * - * @return the copy. - */ - util.ByteStringBuffer.prototype.copy = function() { - var c = util.createBuffer(this.data); - c.read = this.read; - return c; - }; - - /** - * Compacts this buffer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.compact = function() { - if(this.read > 0) { - this.data = this.data.slice(this.read); - this.read = 0; - } - return this; - }; - - /** - * Clears this buffer. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.clear = function() { - this.data = ''; - this.read = 0; - return this; - }; - - /** - * Shortens this buffer by triming bytes off of the end of this buffer. - * - * @param count the number of bytes to trim off. - * - * @return this buffer. - */ - util.ByteStringBuffer.prototype.truncate = function(count) { - var len = Math.max(0, this.length() - count); - this.data = this.data.substr(this.read, len); - this.read = 0; - return this; - }; - - /** - * Converts this buffer to a hexadecimal string. - * - * @return a hexadecimal string. - */ - util.ByteStringBuffer.prototype.toHex = function() { - var rval = ''; - for(var i = this.read; i < this.data.length; ++i) { - var b = this.data.charCodeAt(i); - if(b < 16) { - rval += '0'; - } - rval += b.toString(16); - } - return rval; - }; - - /** - * Converts this buffer to a UTF-16 string (standard JavaScript string). - * - * @return a UTF-16 string. - */ - util.ByteStringBuffer.prototype.toString = function() { - return util.decodeUtf8(this.bytes()); - }; - - /** End Buffer w/BinaryString backing */ - - /** Buffer w/UInt8Array backing */ - - /** - * FIXME: Experimental. Do not use yet. - * - * Constructor for an ArrayBuffer-backed byte buffer. - * - * The buffer may be constructed from a string, an ArrayBuffer, DataView, or a - * TypedArray. - * - * If a string is given, its encoding should be provided as an option, - * otherwise it will default to 'binary'. A 'binary' string is encoded such - * that each character is one byte in length and size. - * - * If an ArrayBuffer, DataView, or TypedArray is given, it will be used - * *directly* without any copying. Note that, if a write to the buffer requires - * more space, the buffer will allocate a new backing ArrayBuffer to - * accommodate. The starting read and write offsets for the buffer may be - * given as options. - * - * @param [b] the initial bytes for this buffer. - * @param options the options to use: - * [readOffset] the starting read offset to use (default: 0). - * [writeOffset] the starting write offset to use (default: the - * length of the first parameter). - * [growSize] the minimum amount, in bytes, to grow the buffer by to - * accommodate writes (default: 1024). - * [encoding] the encoding ('binary', 'utf8', 'utf16', 'hex') for the - * first parameter, if it is a string (default: 'binary'). - */ - function DataBuffer(b, options) { - // default options - options = options || {}; - - // pointers for read from/write to buffer - this.read = options.readOffset || 0; - this.growSize = options.growSize || 1024; - - var isArrayBuffer = util.isArrayBuffer(b); - var isArrayBufferView = util.isArrayBufferView(b); - if(isArrayBuffer || isArrayBufferView) { - // use ArrayBuffer directly - if(isArrayBuffer) { - this.data = new DataView(b); - } else { - // TODO: adjust read/write offset based on the type of view - // or specify that this must be done in the options ... that the - // offsets are byte-based - this.data = new DataView(b.buffer, b.byteOffset, b.byteLength); - } - this.write = ('writeOffset' in options ? - options.writeOffset : this.data.byteLength); - return; - } - - // initialize to empty array buffer and add any given bytes using putBytes - this.data = new DataView(new ArrayBuffer(0)); - this.write = 0; - - if(b !== null && b !== undefined) { - this.putBytes(b); - } - - if('writeOffset' in options) { - this.write = options.writeOffset; - } - } - util.DataBuffer = DataBuffer; - - /** - * Gets the number of bytes in this buffer. - * - * @return the number of bytes in this buffer. - */ - util.DataBuffer.prototype.length = function() { - return this.write - this.read; - }; - - /** - * Gets whether or not this buffer is empty. - * - * @return true if this buffer is empty, false if not. - */ - util.DataBuffer.prototype.isEmpty = function() { - return this.length() <= 0; - }; - - /** - * Ensures this buffer has enough empty space to accommodate the given number - * of bytes. An optional parameter may be given that indicates a minimum - * amount to grow the buffer if necessary. If the parameter is not given, - * the buffer will be grown by some previously-specified default amount - * or heuristic. - * - * @param amount the number of bytes to accommodate. - * @param [growSize] the minimum amount, in bytes, to grow the buffer by if - * necessary. - */ - util.DataBuffer.prototype.accommodate = function(amount, growSize) { - if(this.length() >= amount) { - return this; - } - growSize = Math.max(growSize || this.growSize, amount); - - // grow buffer - var src = new Uint8Array( - this.data.buffer, this.data.byteOffset, this.data.byteLength); - var dst = new Uint8Array(this.length() + growSize); - dst.set(src); - this.data = new DataView(dst.buffer); - - return this; - }; - - /** - * Puts a byte in this buffer. - * - * @param b the byte to put. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putByte = function(b) { - this.accommodate(1); - this.data.setUint8(this.write++, b); - return this; - }; - - /** - * Puts a byte in this buffer N times. - * - * @param b the byte to put. - * @param n the number of bytes of value b to put. - * - * @return this buffer. - */ - util.DataBuffer.prototype.fillWithByte = function(b, n) { - this.accommodate(n); - for(var i = 0; i < n; ++i) { - this.data.setUint8(b); - } - return this; - }; - - /** - * Puts bytes in this buffer. The bytes may be given as a string, an - * ArrayBuffer, a DataView, or a TypedArray. - * - * @param bytes the bytes to put. - * @param [encoding] the encoding for the first parameter ('binary', 'utf8', - * 'utf16', 'hex'), if it is a string (default: 'binary'). - * - * @return this buffer. - */ - util.DataBuffer.prototype.putBytes = function(bytes, encoding) { - if(util.isArrayBufferView(bytes)) { - var src = new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength); - var len = src.byteLength - src.byteOffset; - this.accommodate(len); - var dst = new Uint8Array(this.data.buffer, this.write); - dst.set(src); - this.write += len; - return this; - } - - if(util.isArrayBuffer(bytes)) { - var src = new Uint8Array(bytes); - this.accommodate(src.byteLength); - var dst = new Uint8Array(this.data.buffer); - dst.set(src, this.write); - this.write += src.byteLength; - return this; - } - - // bytes is a util.DataBuffer or equivalent - if(bytes instanceof util.DataBuffer || - (typeof bytes === 'object' && - typeof bytes.read === 'number' && typeof bytes.write === 'number' && - util.isArrayBufferView(bytes.data))) { - var src = new Uint8Array(bytes.data.byteLength, bytes.read, bytes.length()); - this.accommodate(src.byteLength); - var dst = new Uint8Array(bytes.data.byteLength, this.write); - dst.set(src); - this.write += src.byteLength; - return this; - } - - if(bytes instanceof util.ByteStringBuffer) { - // copy binary string and process as the same as a string parameter below - bytes = bytes.data; - encoding = 'binary'; - } - - // string conversion - encoding = encoding || 'binary'; - if(typeof bytes === 'string') { - var view; - - // decode from string - if(encoding === 'hex') { - this.accommodate(Math.ceil(bytes.length / 2)); - view = new Uint8Array(this.data.buffer, this.write); - this.write += util.binary.hex.decode(bytes, view, this.write); - return this; - } - if(encoding === 'base64') { - this.accommodate(Math.ceil(bytes.length / 4) * 3); - view = new Uint8Array(this.data.buffer, this.write); - this.write += util.binary.base64.decode(bytes, view, this.write); - return this; - } - - // encode text as UTF-8 bytes - if(encoding === 'utf8') { - // encode as UTF-8 then decode string as raw binary - bytes = util.encodeUtf8(bytes); - encoding = 'binary'; - } - - // decode string as raw binary - if(encoding === 'binary' || encoding === 'raw') { - // one byte per character - this.accommodate(bytes.length); - view = new Uint8Array(this.data.buffer, this.write); - this.write += util.binary.raw.decode(view); - return this; - } - - // encode text as UTF-16 bytes - if(encoding === 'utf16') { - // two bytes per character - this.accommodate(bytes.length * 2); - view = new Uint16Array(this.data.buffer, this.write); - this.write += util.text.utf16.encode(view); - return this; - } - - throw new Error('Invalid encoding: ' + encoding); - } - - throw Error('Invalid parameter: ' + bytes); - }; - - /** - * Puts the given buffer into this buffer. - * - * @param buffer the buffer to put into this one. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putBuffer = function(buffer) { - this.putBytes(buffer); - buffer.clear(); - return this; - }; - - /** - * Puts a string into this buffer. - * - * @param str the string to put. - * @param [encoding] the encoding for the string (default: 'utf16'). - * - * @return this buffer. - */ - util.DataBuffer.prototype.putString = function(str) { - return this.putBytes(str, 'utf16'); - }; - - /** - * Puts a 16-bit integer in this buffer in big-endian order. - * - * @param i the 16-bit integer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putInt16 = function(i) { - this.accommodate(2); - this.data.setInt16(this.write, i); - this.write += 2; - return this; - }; - - /** - * Puts a 24-bit integer in this buffer in big-endian order. - * - * @param i the 24-bit integer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putInt24 = function(i) { - this.accommodate(3); - this.data.setInt16(this.write, i >> 8 & 0xFFFF); - this.data.setInt8(this.write, i >> 16 & 0xFF); - this.write += 3; - return this; - }; - - /** - * Puts a 32-bit integer in this buffer in big-endian order. - * - * @param i the 32-bit integer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putInt32 = function(i) { - this.accommodate(4); - this.data.setInt32(this.write, i); - this.write += 4; - return this; - }; - - /** - * Puts a 16-bit integer in this buffer in little-endian order. - * - * @param i the 16-bit integer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putInt16Le = function(i) { - this.accommodate(2); - this.data.setInt16(this.write, i, true); - this.write += 2; - return this; - }; - - /** - * Puts a 24-bit integer in this buffer in little-endian order. - * - * @param i the 24-bit integer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putInt24Le = function(i) { - this.accommodate(3); - this.data.setInt8(this.write, i >> 16 & 0xFF); - this.data.setInt16(this.write, i >> 8 & 0xFFFF, true); - this.write += 3; - return this; - }; - - /** - * Puts a 32-bit integer in this buffer in little-endian order. - * - * @param i the 32-bit integer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putInt32Le = function(i) { - this.accommodate(4); - this.data.setInt32(this.write, i, true); - this.write += 4; - return this; - }; - - /** - * Puts an n-bit integer in this buffer in big-endian order. - * - * @param i the n-bit integer. - * @param n the number of bits in the integer (8, 16, 24, or 32). - * - * @return this buffer. - */ - util.DataBuffer.prototype.putInt = function(i, n) { - _checkBitsParam(n); - this.accommodate(n / 8); - do { - n -= 8; - this.data.setInt8(this.write++, (i >> n) & 0xFF); - } while(n > 0); - return this; - }; - - /** - * Puts a signed n-bit integer in this buffer in big-endian order. Two's - * complement representation is used. - * - * @param i the n-bit integer. - * @param n the number of bits in the integer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.putSignedInt = function(i, n) { - _checkBitsParam(n); - this.accommodate(n / 8); - if(i < 0) { - i += 2 << (n - 1); - } - return this.putInt(i, n); - }; - - /** - * Gets a byte from this buffer and advances the read pointer by 1. - * - * @return the byte. - */ - util.DataBuffer.prototype.getByte = function() { - return this.data.getInt8(this.read++); - }; - - /** - * Gets a uint16 from this buffer in big-endian order and advances the read - * pointer by 2. - * - * @return the uint16. - */ - util.DataBuffer.prototype.getInt16 = function() { - var rval = this.data.getInt16(this.read); - this.read += 2; - return rval; - }; - - /** - * Gets a uint24 from this buffer in big-endian order and advances the read - * pointer by 3. - * - * @return the uint24. - */ - util.DataBuffer.prototype.getInt24 = function() { - var rval = ( - this.data.getInt16(this.read) << 8 ^ - this.data.getInt8(this.read + 2)); - this.read += 3; - return rval; - }; - - /** - * Gets a uint32 from this buffer in big-endian order and advances the read - * pointer by 4. - * - * @return the word. - */ - util.DataBuffer.prototype.getInt32 = function() { - var rval = this.data.getInt32(this.read); - this.read += 4; - return rval; - }; - - /** - * Gets a uint16 from this buffer in little-endian order and advances the read - * pointer by 2. - * - * @return the uint16. - */ - util.DataBuffer.prototype.getInt16Le = function() { - var rval = this.data.getInt16(this.read, true); - this.read += 2; - return rval; - }; - - /** - * Gets a uint24 from this buffer in little-endian order and advances the read - * pointer by 3. - * - * @return the uint24. - */ - util.DataBuffer.prototype.getInt24Le = function() { - var rval = ( - this.data.getInt8(this.read) ^ - this.data.getInt16(this.read + 1, true) << 8); - this.read += 3; - return rval; - }; - - /** - * Gets a uint32 from this buffer in little-endian order and advances the read - * pointer by 4. - * - * @return the word. - */ - util.DataBuffer.prototype.getInt32Le = function() { - var rval = this.data.getInt32(this.read, true); - this.read += 4; - return rval; - }; - - /** - * Gets an n-bit integer from this buffer in big-endian order and advances the - * read pointer by n/8. - * - * @param n the number of bits in the integer (8, 16, 24, or 32). - * - * @return the integer. - */ - util.DataBuffer.prototype.getInt = function(n) { - _checkBitsParam(n); - var rval = 0; - do { - // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits. - rval = (rval << 8) + this.data.getInt8(this.read++); - n -= 8; - } while(n > 0); - return rval; - }; - - /** - * Gets a signed n-bit integer from this buffer in big-endian order, using - * two's complement, and advances the read pointer by n/8. - * - * @param n the number of bits in the integer (8, 16, 24, or 32). - * - * @return the integer. - */ - util.DataBuffer.prototype.getSignedInt = function(n) { - // getInt checks n - var x = this.getInt(n); - var max = 2 << (n - 2); - if(x >= max) { - x -= max << 1; - } - return x; - }; - - /** - * Reads bytes out as a binary encoded string and clears them from the - * buffer. - * - * @param count the number of bytes to read, undefined or null for all. - * - * @return a binary encoded string of bytes. - */ - util.DataBuffer.prototype.getBytes = function(count) { - // TODO: deprecate this method, it is poorly named and - // this.toString('binary') replaces it - // add a toTypedArray()/toArrayBuffer() function - var rval; - if(count) { - // read count bytes - count = Math.min(this.length(), count); - rval = this.data.slice(this.read, this.read + count); - this.read += count; - } else if(count === 0) { - rval = ''; - } else { - // read all bytes, optimize to only copy when needed - rval = (this.read === 0) ? this.data : this.data.slice(this.read); - this.clear(); - } - return rval; - }; - - /** - * Gets a binary encoded string of the bytes from this buffer without - * modifying the read pointer. - * - * @param count the number of bytes to get, omit to get all. - * - * @return a string full of binary encoded characters. - */ - util.DataBuffer.prototype.bytes = function(count) { - // TODO: deprecate this method, it is poorly named, add "getString()" - return (typeof(count) === 'undefined' ? - this.data.slice(this.read) : - this.data.slice(this.read, this.read + count)); - }; - - /** - * Gets a byte at the given index without modifying the read pointer. - * - * @param i the byte index. - * - * @return the byte. - */ - util.DataBuffer.prototype.at = function(i) { - return this.data.getUint8(this.read + i); - }; - - /** - * Puts a byte at the given index without modifying the read pointer. - * - * @param i the byte index. - * @param b the byte to put. - * - * @return this buffer. - */ - util.DataBuffer.prototype.setAt = function(i, b) { - this.data.setUint8(i, b); - return this; - }; - - /** - * Gets the last byte without modifying the read pointer. - * - * @return the last byte. - */ - util.DataBuffer.prototype.last = function() { - return this.data.getUint8(this.write - 1); - }; - - /** - * Creates a copy of this buffer. - * - * @return the copy. - */ - util.DataBuffer.prototype.copy = function() { - return new util.DataBuffer(this); - }; - - /** - * Compacts this buffer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.compact = function() { - if(this.read > 0) { - var src = new Uint8Array(this.data.buffer, this.read); - var dst = new Uint8Array(src.byteLength); - dst.set(src); - this.data = new DataView(dst); - this.write -= this.read; - this.read = 0; - } - return this; - }; - - /** - * Clears this buffer. - * - * @return this buffer. - */ - util.DataBuffer.prototype.clear = function() { - this.data = new DataView(new ArrayBuffer(0)); - this.read = this.write = 0; - return this; - }; - - /** - * Shortens this buffer by triming bytes off of the end of this buffer. - * - * @param count the number of bytes to trim off. - * - * @return this buffer. - */ - util.DataBuffer.prototype.truncate = function(count) { - this.write = Math.max(0, this.length() - count); - this.read = Math.min(this.read, this.write); - return this; - }; - - /** - * Converts this buffer to a hexadecimal string. - * - * @return a hexadecimal string. - */ - util.DataBuffer.prototype.toHex = function() { - var rval = ''; - for(var i = this.read; i < this.data.byteLength; ++i) { - var b = this.data.getUint8(i); - if(b < 16) { - rval += '0'; - } - rval += b.toString(16); - } - return rval; - }; - - /** - * Converts this buffer to a string, using the given encoding. If no - * encoding is given, 'utf8' (UTF-8) is used. - * - * @param [encoding] the encoding to use: 'binary', 'utf8', 'utf16', 'hex', - * 'base64' (default: 'utf8'). - * - * @return a string representation of the bytes in this buffer. - */ - util.DataBuffer.prototype.toString = function(encoding) { - var view = new Uint8Array(this.data, this.read, this.length()); - encoding = encoding || 'utf8'; - - // encode to string - if(encoding === 'binary' || encoding === 'raw') { - return util.binary.raw.encode(view); - } - if(encoding === 'hex') { - return util.binary.hex.encode(view); - } - if(encoding === 'base64') { - return util.binary.base64.encode(view); - } - - // decode to text - if(encoding === 'utf8') { - return util.text.utf8.decode(view); - } - if(encoding === 'utf16') { - return util.text.utf16.decode(view); - } - - throw new Error('Invalid encoding: ' + encoding); - }; - - /** End Buffer w/UInt8Array backing */ - - /** - * Creates a buffer that stores bytes. A value may be given to populate the - * buffer with data. This value can either be string of encoded bytes or a - * regular string of characters. When passing a string of binary encoded - * bytes, the encoding `raw` should be given. This is also the default. When - * passing a string of characters, the encoding `utf8` should be given. - * - * @param [input] a string with encoded bytes to store in the buffer. - * @param [encoding] (default: 'raw', other: 'utf8'). - */ - util.createBuffer = function(input, encoding) { - // TODO: deprecate, use new ByteBuffer() instead - encoding = encoding || 'raw'; - if(input !== undefined && encoding === 'utf8') { - input = util.encodeUtf8(input); - } - return new util.ByteBuffer(input); - }; - - /** - * Fills a string with a particular value. If you want the string to be a byte - * string, pass in String.fromCharCode(theByte). - * - * @param c the character to fill the string with, use String.fromCharCode - * to fill the string with a byte value. - * @param n the number of characters of value c to fill with. - * - * @return the filled string. - */ - util.fillString = function(c, n) { - var s = ''; - while(n > 0) { - if(n & 1) { - s += c; - } - n >>>= 1; - if(n > 0) { - c += c; - } - } - return s; - }; - - /** - * Performs a per byte XOR between two byte strings and returns the result as a - * string of bytes. - * - * @param s1 first string of bytes. - * @param s2 second string of bytes. - * @param n the number of bytes to XOR. - * - * @return the XOR'd result. - */ - util.xorBytes = function(s1, s2, n) { - var s3 = ''; - var b = ''; - var t = ''; - var i = 0; - var c = 0; - for(; n > 0; --n, ++i) { - b = s1.charCodeAt(i) ^ s2.charCodeAt(i); - if(c >= 10) { - s3 += t; - t = ''; - c = 0; - } - t += String.fromCharCode(b); - ++c; - } - s3 += t; - return s3; - }; - - /** - * Converts a hex string into a 'binary' encoded string of bytes. - * - * @param hex the hexadecimal string to convert. - * - * @return the binary-encoded string of bytes. - */ - util.hexToBytes = function(hex) { - // TODO: deprecate: "Deprecated. Use util.binary.hex.decode instead." - var rval = ''; - var i = 0; - if(hex.length & 1 == 1) { - // odd number of characters, convert first character alone - i = 1; - rval += String.fromCharCode(parseInt(hex[0], 16)); - } - // convert 2 characters (1 byte) at a time - for(; i < hex.length; i += 2) { - rval += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); - } - return rval; - }; - - /** - * Converts a 'binary' encoded string of bytes to hex. - * - * @param bytes the byte string to convert. - * - * @return the string of hexadecimal characters. - */ - util.bytesToHex = function(bytes) { - // TODO: deprecate: "Deprecated. Use util.binary.hex.encode instead." - return util.createBuffer(bytes).toHex(); - }; - - /** - * Converts an 32-bit integer to 4-big-endian byte string. - * - * @param i the integer. - * - * @return the byte string. - */ - util.int32ToBytes = function(i) { - return ( - String.fromCharCode(i >> 24 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF)); - }; - - // base64 characters, reverse mapping - var _base64 = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - var _base64Idx = [ - /*43 -43 = 0*/ - /*'+', 1, 2, 3,'/' */ - 62, -1, -1, -1, 63, - - /*'0','1','2','3','4','5','6','7','8','9' */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - - /*15, 16, 17,'=', 19, 20, 21 */ - -1, -1, -1, 64, -1, -1, -1, - - /*65 - 43 = 22*/ - /*'A','B','C','D','E','F','G','H','I','J','K','L','M', */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - - /*'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' */ - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - - /*91 - 43 = 48 */ - /*48, 49, 50, 51, 52, 53 */ - -1, -1, -1, -1, -1, -1, - - /*97 - 43 = 54*/ - /*'a','b','c','d','e','f','g','h','i','j','k','l','m' */ - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - - /*'n','o','p','q','r','s','t','u','v','w','x','y','z' */ - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - ]; - - // base58 characters (Bitcoin alphabet) - var _base58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; - - /** - * Base64 encodes a 'binary' encoded string of bytes. - * - * @param input the binary encoded string of bytes to base64-encode. - * @param maxline the maximum number of encoded characters per line to use, - * defaults to none. - * - * @return the base64-encoded output. - */ - util.encode64 = function(input, maxline) { - // TODO: deprecate: "Deprecated. Use util.binary.base64.encode instead." - var line = ''; - var output = ''; - var chr1, chr2, chr3; - var i = 0; - while(i < input.length) { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - // encode 4 character group - line += _base64.charAt(chr1 >> 2); - line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4)); - if(isNaN(chr2)) { - line += '=='; - } else { - line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6)); - line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63); - } - - if(maxline && line.length > maxline) { - output += line.substr(0, maxline) + '\r\n'; - line = line.substr(maxline); - } - } - output += line; - return output; - }; - - /** - * Base64 decodes a string into a 'binary' encoded string of bytes. - * - * @param input the base64-encoded input. - * - * @return the binary encoded string. - */ - util.decode64 = function(input) { - // TODO: deprecate: "Deprecated. Use util.binary.base64.decode instead." - - // remove all non-base64 characters - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); - - var output = ''; - var enc1, enc2, enc3, enc4; - var i = 0; - - while(i < input.length) { - enc1 = _base64Idx[input.charCodeAt(i++) - 43]; - enc2 = _base64Idx[input.charCodeAt(i++) - 43]; - enc3 = _base64Idx[input.charCodeAt(i++) - 43]; - enc4 = _base64Idx[input.charCodeAt(i++) - 43]; - - output += String.fromCharCode((enc1 << 2) | (enc2 >> 4)); - if(enc3 !== 64) { - // decoded at least 2 bytes - output += String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2)); - if(enc4 !== 64) { - // decoded 3 bytes - output += String.fromCharCode(((enc3 & 3) << 6) | enc4); - } - } - } - - return output; - }; - - /** - * Encodes the given string of characters (a standard JavaScript - * string) as a binary encoded string where the bytes represent - * a UTF-8 encoded string of characters. Non-ASCII characters will be - * encoded as multiple bytes according to UTF-8. - * - * @param str a standard string of characters to encode. - * - * @return the binary encoded string. - */ - util.encodeUtf8 = function(str) { - return unescape(encodeURIComponent(str)); - }; - - /** - * Decodes a binary encoded string that contains bytes that - * represent a UTF-8 encoded string of characters -- into a - * string of characters (a standard JavaScript string). - * - * @param str the binary encoded string to decode. - * - * @return the resulting standard string of characters. - */ - util.decodeUtf8 = function(str) { - return decodeURIComponent(escape(str)); - }; - - // binary encoding/decoding tools - // FIXME: Experimental. Do not use yet. - util.binary = { - raw: {}, - hex: {}, - base64: {}, - base58: {}, - baseN : { - encode: baseN.encode, - decode: baseN.decode - } - }; - - /** - * Encodes a Uint8Array as a binary-encoded string. This encoding uses - * a value between 0 and 255 for each character. - * - * @param bytes the Uint8Array to encode. - * - * @return the binary-encoded string. - */ - util.binary.raw.encode = function(bytes) { - return String.fromCharCode.apply(null, bytes); - }; - - /** - * Decodes a binary-encoded string to a Uint8Array. This encoding uses - * a value between 0 and 255 for each character. - * - * @param str the binary-encoded string to decode. - * @param [output] an optional Uint8Array to write the output to; if it - * is too small, an exception will be thrown. - * @param [offset] the start offset for writing to the output (default: 0). - * - * @return the Uint8Array or the number of bytes written if output was given. - */ - util.binary.raw.decode = function(str, output, offset) { - var out = output; - if(!out) { - out = new Uint8Array(str.length); - } - offset = offset || 0; - var j = offset; - for(var i = 0; i < str.length; ++i) { - out[j++] = str.charCodeAt(i); - } - return output ? (j - offset) : out; - }; - - /** - * Encodes a 'binary' string, ArrayBuffer, DataView, TypedArray, or - * ByteBuffer as a string of hexadecimal characters. - * - * @param bytes the bytes to convert. - * - * @return the string of hexadecimal characters. - */ - util.binary.hex.encode = util.bytesToHex; - - /** - * Decodes a hex-encoded string to a Uint8Array. - * - * @param hex the hexadecimal string to convert. - * @param [output] an optional Uint8Array to write the output to; if it - * is too small, an exception will be thrown. - * @param [offset] the start offset for writing to the output (default: 0). - * - * @return the Uint8Array or the number of bytes written if output was given. - */ - util.binary.hex.decode = function(hex, output, offset) { - var out = output; - if(!out) { - out = new Uint8Array(Math.ceil(hex.length / 2)); - } - offset = offset || 0; - var i = 0, j = offset; - if(hex.length & 1) { - // odd number of characters, convert first character alone - i = 1; - out[j++] = parseInt(hex[0], 16); - } - // convert 2 characters (1 byte) at a time - for(; i < hex.length; i += 2) { - out[j++] = parseInt(hex.substr(i, 2), 16); - } - return output ? (j - offset) : out; - }; - - /** - * Base64-encodes a Uint8Array. - * - * @param input the Uint8Array to encode. - * @param maxline the maximum number of encoded characters per line to use, - * defaults to none. - * - * @return the base64-encoded output string. - */ - util.binary.base64.encode = function(input, maxline) { - var line = ''; - var output = ''; - var chr1, chr2, chr3; - var i = 0; - while(i < input.byteLength) { - chr1 = input[i++]; - chr2 = input[i++]; - chr3 = input[i++]; - - // encode 4 character group - line += _base64.charAt(chr1 >> 2); - line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4)); - if(isNaN(chr2)) { - line += '=='; - } else { - line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6)); - line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63); - } - - if(maxline && line.length > maxline) { - output += line.substr(0, maxline) + '\r\n'; - line = line.substr(maxline); - } - } - output += line; - return output; - }; - - /** - * Decodes a base64-encoded string to a Uint8Array. - * - * @param input the base64-encoded input string. - * @param [output] an optional Uint8Array to write the output to; if it - * is too small, an exception will be thrown. - * @param [offset] the start offset for writing to the output (default: 0). - * - * @return the Uint8Array or the number of bytes written if output was given. - */ - util.binary.base64.decode = function(input, output, offset) { - var out = output; - if(!out) { - out = new Uint8Array(Math.ceil(input.length / 4) * 3); - } - - // remove all non-base64 characters - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); - - offset = offset || 0; - var enc1, enc2, enc3, enc4; - var i = 0, j = offset; - - while(i < input.length) { - enc1 = _base64Idx[input.charCodeAt(i++) - 43]; - enc2 = _base64Idx[input.charCodeAt(i++) - 43]; - enc3 = _base64Idx[input.charCodeAt(i++) - 43]; - enc4 = _base64Idx[input.charCodeAt(i++) - 43]; - - out[j++] = (enc1 << 2) | (enc2 >> 4); - if(enc3 !== 64) { - // decoded at least 2 bytes - out[j++] = ((enc2 & 15) << 4) | (enc3 >> 2); - if(enc4 !== 64) { - // decoded 3 bytes - out[j++] = ((enc3 & 3) << 6) | enc4; - } - } - } - - // make sure result is the exact decoded length - return output ? (j - offset) : out.subarray(0, j); - }; - - // add support for base58 encoding/decoding with Bitcoin alphabet - util.binary.base58.encode = function(input, maxline) { - return util.binary.baseN.encode(input, _base58, maxline); - }; - util.binary.base58.decode = function(input, maxline) { - return util.binary.baseN.decode(input, _base58, maxline); - }; - - // text encoding/decoding tools - // FIXME: Experimental. Do not use yet. - util.text = { - utf8: {}, - utf16: {} - }; - - /** - * Encodes the given string as UTF-8 in a Uint8Array. - * - * @param str the string to encode. - * @param [output] an optional Uint8Array to write the output to; if it - * is too small, an exception will be thrown. - * @param [offset] the start offset for writing to the output (default: 0). - * - * @return the Uint8Array or the number of bytes written if output was given. - */ - util.text.utf8.encode = function(str, output, offset) { - str = util.encodeUtf8(str); - var out = output; - if(!out) { - out = new Uint8Array(str.length); - } - offset = offset || 0; - var j = offset; - for(var i = 0; i < str.length; ++i) { - out[j++] = str.charCodeAt(i); - } - return output ? (j - offset) : out; - }; - - /** - * Decodes the UTF-8 contents from a Uint8Array. - * - * @param bytes the Uint8Array to decode. - * - * @return the resulting string. - */ - util.text.utf8.decode = function(bytes) { - return util.decodeUtf8(String.fromCharCode.apply(null, bytes)); - }; - - /** - * Encodes the given string as UTF-16 in a Uint8Array. - * - * @param str the string to encode. - * @param [output] an optional Uint8Array to write the output to; if it - * is too small, an exception will be thrown. - * @param [offset] the start offset for writing to the output (default: 0). - * - * @return the Uint8Array or the number of bytes written if output was given. - */ - util.text.utf16.encode = function(str, output, offset) { - var out = output; - if(!out) { - out = new Uint8Array(str.length * 2); - } - var view = new Uint16Array(out.buffer); - offset = offset || 0; - var j = offset; - var k = offset; - for(var i = 0; i < str.length; ++i) { - view[k++] = str.charCodeAt(i); - j += 2; - } - return output ? (j - offset) : out; - }; - - /** - * Decodes the UTF-16 contents from a Uint8Array. - * - * @param bytes the Uint8Array to decode. - * - * @return the resulting string. - */ - util.text.utf16.decode = function(bytes) { - return String.fromCharCode.apply(null, new Uint16Array(bytes.buffer)); - }; - - /** - * Deflates the given data using a flash interface. - * - * @param api the flash interface. - * @param bytes the data. - * @param raw true to return only raw deflate data, false to include zlib - * header and trailer. - * - * @return the deflated data as a string. - */ - util.deflate = function(api, bytes, raw) { - bytes = util.decode64(api.deflate(util.encode64(bytes)).rval); - - // strip zlib header and trailer if necessary - if(raw) { - // zlib header is 2 bytes (CMF,FLG) where FLG indicates that - // there is a 4-byte DICT (alder-32) block before the data if - // its 5th bit is set - var start = 2; - var flg = bytes.charCodeAt(1); - if(flg & 0x20) { - start = 6; - } - // zlib trailer is 4 bytes of adler-32 - bytes = bytes.substring(start, bytes.length - 4); - } - - return bytes; - }; - - /** - * Inflates the given data using a flash interface. - * - * @param api the flash interface. - * @param bytes the data. - * @param raw true if the incoming data has no zlib header or trailer and is - * raw DEFLATE data. - * - * @return the inflated data as a string, null on error. - */ - util.inflate = function(api, bytes, raw) { - // TODO: add zlib header and trailer if necessary/possible - var rval = api.inflate(util.encode64(bytes)).rval; - return (rval === null) ? null : util.decode64(rval); - }; - - /** - * Sets a storage object. - * - * @param api the storage interface. - * @param id the storage ID to use. - * @param obj the storage object, null to remove. - */ - var _setStorageObject = function(api, id, obj) { - if(!api) { - throw new Error('WebStorage not available.'); - } - - var rval; - if(obj === null) { - rval = api.removeItem(id); - } else { - // json-encode and base64-encode object - obj = util.encode64(JSON.stringify(obj)); - rval = api.setItem(id, obj); - } - - // handle potential flash error - if(typeof(rval) !== 'undefined' && rval.rval !== true) { - var error = new Error(rval.error.message); - error.id = rval.error.id; - error.name = rval.error.name; - throw error; - } - }; - - /** - * Gets a storage object. - * - * @param api the storage interface. - * @param id the storage ID to use. - * - * @return the storage object entry or null if none exists. - */ - var _getStorageObject = function(api, id) { - if(!api) { - throw new Error('WebStorage not available.'); - } - - // get the existing entry - var rval = api.getItem(id); - - /* Note: We check api.init because we can't do (api == localStorage) - on IE because of "Class doesn't support Automation" exception. Only - the flash api has an init method so this works too, but we need a - better solution in the future. */ - - // flash returns item wrapped in an object, handle special case - if(api.init) { - if(rval.rval === null) { - if(rval.error) { - var error = new Error(rval.error.message); - error.id = rval.error.id; - error.name = rval.error.name; - throw error; - } - // no error, but also no item - rval = null; - } else { - rval = rval.rval; - } - } - - // handle decoding - if(rval !== null) { - // base64-decode and json-decode data - rval = JSON.parse(util.decode64(rval)); - } - - return rval; - }; - - /** - * Stores an item in local storage. - * - * @param api the storage interface. - * @param id the storage ID to use. - * @param key the key for the item. - * @param data the data for the item (any javascript object/primitive). - */ - var _setItem = function(api, id, key, data) { - // get storage object - var obj = _getStorageObject(api, id); - if(obj === null) { - // create a new storage object - obj = {}; - } - // update key - obj[key] = data; - - // set storage object - _setStorageObject(api, id, obj); - }; - - /** - * Gets an item from local storage. - * - * @param api the storage interface. - * @param id the storage ID to use. - * @param key the key for the item. - * - * @return the item. - */ - var _getItem = function(api, id, key) { - // get storage object - var rval = _getStorageObject(api, id); - if(rval !== null) { - // return data at key - rval = (key in rval) ? rval[key] : null; - } - - return rval; - }; - - /** - * Removes an item from local storage. - * - * @param api the storage interface. - * @param id the storage ID to use. - * @param key the key for the item. - */ - var _removeItem = function(api, id, key) { - // get storage object - var obj = _getStorageObject(api, id); - if(obj !== null && key in obj) { - // remove key - delete obj[key]; - - // see if entry has no keys remaining - var empty = true; - for(var prop in obj) { - empty = false; - break; - } - if(empty) { - // remove entry entirely if no keys are left - obj = null; - } - - // set storage object - _setStorageObject(api, id, obj); - } - }; - - /** - * Clears the local disk storage identified by the given ID. - * - * @param api the storage interface. - * @param id the storage ID to use. - */ - var _clearItems = function(api, id) { - _setStorageObject(api, id, null); - }; - - /** - * Calls a storage function. - * - * @param func the function to call. - * @param args the arguments for the function. - * @param location the location argument. - * - * @return the return value from the function. - */ - var _callStorageFunction = function(func, args, location) { - var rval = null; - - // default storage types - if(typeof(location) === 'undefined') { - location = ['web', 'flash']; - } - - // apply storage types in order of preference - var type; - var done = false; - var exception = null; - for(var idx in location) { - type = location[idx]; - try { - if(type === 'flash' || type === 'both') { - if(args[0] === null) { - throw new Error('Flash local storage not available.'); - } - rval = func.apply(this, args); - done = (type === 'flash'); - } - if(type === 'web' || type === 'both') { - args[0] = localStorage; - rval = func.apply(this, args); - done = true; - } - } catch(ex) { - exception = ex; - } - if(done) { - break; - } - } - - if(!done) { - throw exception; - } - - return rval; - }; - - /** - * Stores an item on local disk. - * - * The available types of local storage include 'flash', 'web', and 'both'. - * - * The type 'flash' refers to flash local storage (SharedObject). In order - * to use flash local storage, the 'api' parameter must be valid. The type - * 'web' refers to WebStorage, if supported by the browser. The type 'both' - * refers to storing using both 'flash' and 'web', not just one or the - * other. - * - * The location array should list the storage types to use in order of - * preference: - * - * ['flash']: flash only storage - * ['web']: web only storage - * ['both']: try to store in both - * ['flash','web']: store in flash first, but if not available, 'web' - * ['web','flash']: store in web first, but if not available, 'flash' - * - * The location array defaults to: ['web', 'flash'] - * - * @param api the flash interface, null to use only WebStorage. - * @param id the storage ID to use. - * @param key the key for the item. - * @param data the data for the item (any javascript object/primitive). - * @param location an array with the preferred types of storage to use. - */ - util.setItem = function(api, id, key, data, location) { - _callStorageFunction(_setItem, arguments, location); - }; - - /** - * Gets an item on local disk. - * - * Set setItem() for details on storage types. - * - * @param api the flash interface, null to use only WebStorage. - * @param id the storage ID to use. - * @param key the key for the item. - * @param location an array with the preferred types of storage to use. - * - * @return the item. - */ - util.getItem = function(api, id, key, location) { - return _callStorageFunction(_getItem, arguments, location); - }; - - /** - * Removes an item on local disk. - * - * Set setItem() for details on storage types. - * - * @param api the flash interface. - * @param id the storage ID to use. - * @param key the key for the item. - * @param location an array with the preferred types of storage to use. - */ - util.removeItem = function(api, id, key, location) { - _callStorageFunction(_removeItem, arguments, location); - }; - - /** - * Clears the local disk storage identified by the given ID. - * - * Set setItem() for details on storage types. - * - * @param api the flash interface if flash is available. - * @param id the storage ID to use. - * @param location an array with the preferred types of storage to use. - */ - util.clearItems = function(api, id, location) { - _callStorageFunction(_clearItems, arguments, location); - }; - - /** - * Parses the scheme, host, and port from an http(s) url. - * - * @param str the url string. - * - * @return the parsed url object or null if the url is invalid. - */ - util.parseUrl = function(str) { - // FIXME: this regex looks a bit broken - var regex = /^(https?):\/\/([^:&^\/]*):?(\d*)(.*)$/g; - regex.lastIndex = 0; - var m = regex.exec(str); - var url = (m === null) ? null : { - full: str, - scheme: m[1], - host: m[2], - port: m[3], - path: m[4] - }; - if(url) { - url.fullHost = url.host; - if(url.port) { - if(url.port !== 80 && url.scheme === 'http') { - url.fullHost += ':' + url.port; - } else if(url.port !== 443 && url.scheme === 'https') { - url.fullHost += ':' + url.port; - } - } else if(url.scheme === 'http') { - url.port = 80; - } else if(url.scheme === 'https') { - url.port = 443; - } - url.full = url.scheme + '://' + url.fullHost; - } - return url; - }; - - /* Storage for query variables */ - var _queryVariables = null; - - /** - * Returns the window location query variables. Query is parsed on the first - * call and the same object is returned on subsequent calls. The mapping - * is from keys to an array of values. Parameters without values will have - * an object key set but no value added to the value array. Values are - * unescaped. - * - * ...?k1=v1&k2=v2: - * { - * "k1": ["v1"], - * "k2": ["v2"] - * } - * - * ...?k1=v1&k1=v2: - * { - * "k1": ["v1", "v2"] - * } - * - * ...?k1=v1&k2: - * { - * "k1": ["v1"], - * "k2": [] - * } - * - * ...?k1=v1&k1: - * { - * "k1": ["v1"] - * } - * - * ...?k1&k1: - * { - * "k1": [] - * } - * - * @param query the query string to parse (optional, default to cached - * results from parsing window location search query). - * - * @return object mapping keys to variables. - */ - util.getQueryVariables = function(query) { - var parse = function(q) { - var rval = {}; - var kvpairs = q.split('&'); - for(var i = 0; i < kvpairs.length; i++) { - var pos = kvpairs[i].indexOf('='); - var key; - var val; - if(pos > 0) { - key = kvpairs[i].substring(0, pos); - val = kvpairs[i].substring(pos + 1); - } else { - key = kvpairs[i]; - val = null; - } - if(!(key in rval)) { - rval[key] = []; - } - // disallow overriding object prototype keys - if(!(key in Object.prototype) && val !== null) { - rval[key].push(unescape(val)); - } - } - return rval; - }; - - var rval; - if(typeof(query) === 'undefined') { - // set cached variables if needed - if(_queryVariables === null) { - if(typeof(window) !== 'undefined' && window.location && window.location.search) { - // parse window search query - _queryVariables = parse(window.location.search.substring(1)); - } else { - // no query variables available - _queryVariables = {}; - } - } - rval = _queryVariables; - } else { - // parse given query - rval = parse(query); - } - return rval; - }; - - /** - * Parses a fragment into a path and query. This method will take a URI - * fragment and break it up as if it were the main URI. For example: - * /bar/baz?a=1&b=2 - * results in: - * { - * path: ["bar", "baz"], - * query: {"k1": ["v1"], "k2": ["v2"]} - * } - * - * @return object with a path array and query object. - */ - util.parseFragment = function(fragment) { - // default to whole fragment - var fp = fragment; - var fq = ''; - // split into path and query if possible at the first '?' - var pos = fragment.indexOf('?'); - if(pos > 0) { - fp = fragment.substring(0, pos); - fq = fragment.substring(pos + 1); - } - // split path based on '/' and ignore first element if empty - var path = fp.split('/'); - if(path.length > 0 && path[0] === '') { - path.shift(); - } - // convert query into object - var query = (fq === '') ? {} : util.getQueryVariables(fq); - - return { - pathString: fp, - queryString: fq, - path: path, - query: query - }; - }; - - /** - * Makes a request out of a URI-like request string. This is intended to - * be used where a fragment id (after a URI '#') is parsed as a URI with - * path and query parts. The string should have a path beginning and - * delimited by '/' and optional query parameters following a '?'. The - * query should be a standard URL set of key value pairs delimited by - * '&'. For backwards compatibility the initial '/' on the path is not - * required. The request object has the following API, (fully described - * in the method code): - * { - * path: . - * query: , - * getPath(i): get part or all of the split path array, - * getQuery(k, i): get part or all of a query key array, - * getQueryLast(k, _default): get last element of a query key array. - * } - * - * @return object with request parameters. - */ - util.makeRequest = function(reqString) { - var frag = util.parseFragment(reqString); - var req = { - // full path string - path: frag.pathString, - // full query string - query: frag.queryString, - /** - * Get path or element in path. - * - * @param i optional path index. - * - * @return path or part of path if i provided. - */ - getPath: function(i) { - return (typeof(i) === 'undefined') ? frag.path : frag.path[i]; - }, - /** - * Get query, values for a key, or value for a key index. - * - * @param k optional query key. - * @param i optional query key index. - * - * @return query, values for a key, or value for a key index. - */ - getQuery: function(k, i) { - var rval; - if(typeof(k) === 'undefined') { - rval = frag.query; - } else { - rval = frag.query[k]; - if(rval && typeof(i) !== 'undefined') { - rval = rval[i]; - } - } - return rval; - }, - getQueryLast: function(k, _default) { - var rval; - var vals = req.getQuery(k); - if(vals) { - rval = vals[vals.length - 1]; - } else { - rval = _default; - } - return rval; - } - }; - return req; - }; - - /** - * Makes a URI out of a path, an object with query parameters, and a - * fragment. Uses jQuery.param() internally for query string creation. - * If the path is an array, it will be joined with '/'. - * - * @param path string path or array of strings. - * @param query object with query parameters. (optional) - * @param fragment fragment string. (optional) - * - * @return string object with request parameters. - */ - util.makeLink = function(path, query, fragment) { - // join path parts if needed - path = jQuery.isArray(path) ? path.join('/') : path; - - var qstr = jQuery.param(query || {}); - fragment = fragment || ''; - return path + - ((qstr.length > 0) ? ('?' + qstr) : '') + - ((fragment.length > 0) ? ('#' + fragment) : ''); - }; - - /** - * Follows a path of keys deep into an object hierarchy and set a value. - * If a key does not exist or it's value is not an object, create an - * object in it's place. This can be destructive to a object tree if - * leaf nodes are given as non-final path keys. - * Used to avoid exceptions from missing parts of the path. - * - * @param object the starting object. - * @param keys an array of string keys. - * @param value the value to set. - */ - util.setPath = function(object, keys, value) { - // need to start at an object - if(typeof(object) === 'object' && object !== null) { - var i = 0; - var len = keys.length; - while(i < len) { - var next = keys[i++]; - if(i == len) { - // last - object[next] = value; - } else { - // more - var hasNext = (next in object); - if(!hasNext || - (hasNext && typeof(object[next]) !== 'object') || - (hasNext && object[next] === null)) { - object[next] = {}; - } - object = object[next]; - } - } - } - }; - - /** - * Follows a path of keys deep into an object hierarchy and return a value. - * If a key does not exist, create an object in it's place. - * Used to avoid exceptions from missing parts of the path. - * - * @param object the starting object. - * @param keys an array of string keys. - * @param _default value to return if path not found. - * - * @return the value at the path if found, else default if given, else - * undefined. - */ - util.getPath = function(object, keys, _default) { - var i = 0; - var len = keys.length; - var hasNext = true; - while(hasNext && i < len && - typeof(object) === 'object' && object !== null) { - var next = keys[i++]; - hasNext = next in object; - if(hasNext) { - object = object[next]; - } - } - return (hasNext ? object : _default); - }; - - /** - * Follow a path of keys deep into an object hierarchy and delete the - * last one. If a key does not exist, do nothing. - * Used to avoid exceptions from missing parts of the path. - * - * @param object the starting object. - * @param keys an array of string keys. - */ - util.deletePath = function(object, keys) { - // need to start at an object - if(typeof(object) === 'object' && object !== null) { - var i = 0; - var len = keys.length; - while(i < len) { - var next = keys[i++]; - if(i == len) { - // last - delete object[next]; - } else { - // more - if(!(next in object) || - (typeof(object[next]) !== 'object') || - (object[next] === null)) { - break; - } - object = object[next]; - } - } - } - }; - - /** - * Check if an object is empty. - * - * Taken from: - * http://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object-from-json/679937#679937 - * - * @param object the object to check. - */ - util.isEmpty = function(obj) { - for(var prop in obj) { - if(obj.hasOwnProperty(prop)) { - return false; - } - } - return true; - }; - - /** - * Format with simple printf-style interpolation. - * - * %%: literal '%' - * %s,%o: convert next argument into a string. - * - * @param format the string to format. - * @param ... arguments to interpolate into the format string. - */ - util.format = function(format) { - var re = /%./g; - // current match - var match; - // current part - var part; - // current arg index - var argi = 0; - // collected parts to recombine later - var parts = []; - // last index found - var last = 0; - // loop while matches remain - while((match = re.exec(format))) { - part = format.substring(last, re.lastIndex - 2); - // don't add empty strings (ie, parts between %s%s) - if(part.length > 0) { - parts.push(part); - } - last = re.lastIndex; - // switch on % code - var code = match[0][1]; - switch(code) { - case 's': - case 'o': - // check if enough arguments were given - if(argi < arguments.length) { - parts.push(arguments[argi++ + 1]); - } else { - parts.push(''); - } - break; - // FIXME: do proper formating for numbers, etc - //case 'f': - //case 'd': - case '%': - parts.push('%'); - break; - default: - parts.push('<%' + code + '?>'); - } - } - // add trailing part of format string - parts.push(format.substring(last)); - return parts.join(''); - }; - - /** - * Formats a number. - * - * http://snipplr.com/view/5945/javascript-numberformat--ported-from-php/ - */ - util.formatNumber = function(number, decimals, dec_point, thousands_sep) { - // http://kevin.vanzonneveld.net - // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) - // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // + bugfix by: Michael White (http://crestidg.com) - // + bugfix by: Benjamin Lupton - // + bugfix by: Allan Jensen (http://www.winternet.no) - // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) - // * example 1: number_format(1234.5678, 2, '.', ''); - // * returns 1: 1234.57 - - var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals; - var d = dec_point === undefined ? ',' : dec_point; - var t = thousands_sep === undefined ? - '.' : thousands_sep, s = n < 0 ? '-' : ''; - var i = parseInt((n = Math.abs(+n || 0).toFixed(c)), 10) + ''; - var j = (i.length > 3) ? i.length % 3 : 0; - return s + (j ? i.substr(0, j) + t : '') + - i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + t) + - (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ''); - }; - - /** - * Formats a byte size. - * - * http://snipplr.com/view/5949/format-humanize-file-byte-size-presentation-in-javascript/ - */ - util.formatSize = function(size) { - if(size >= 1073741824) { - size = util.formatNumber(size / 1073741824, 2, '.', '') + ' GiB'; - } else if(size >= 1048576) { - size = util.formatNumber(size / 1048576, 2, '.', '') + ' MiB'; - } else if(size >= 1024) { - size = util.formatNumber(size / 1024, 0) + ' KiB'; - } else { - size = util.formatNumber(size, 0) + ' bytes'; - } - return size; - }; - - /** - * Converts an IPv4 or IPv6 string representation into bytes (in network order). - * - * @param ip the IPv4 or IPv6 address to convert. - * - * @return the 4-byte IPv6 or 16-byte IPv6 address or null if the address can't - * be parsed. - */ - util.bytesFromIP = function(ip) { - if(ip.indexOf('.') !== -1) { - return util.bytesFromIPv4(ip); - } - if(ip.indexOf(':') !== -1) { - return util.bytesFromIPv6(ip); - } - return null; - }; - - /** - * Converts an IPv4 string representation into bytes (in network order). - * - * @param ip the IPv4 address to convert. - * - * @return the 4-byte address or null if the address can't be parsed. - */ - util.bytesFromIPv4 = function(ip) { - ip = ip.split('.'); - if(ip.length !== 4) { - return null; - } - var b = util.createBuffer(); - for(var i = 0; i < ip.length; ++i) { - var num = parseInt(ip[i], 10); - if(isNaN(num)) { - return null; - } - b.putByte(num); - } - return b.getBytes(); - }; - - /** - * Converts an IPv6 string representation into bytes (in network order). - * - * @param ip the IPv6 address to convert. - * - * @return the 16-byte address or null if the address can't be parsed. - */ - util.bytesFromIPv6 = function(ip) { - var blanks = 0; - ip = ip.split(':').filter(function(e) { - if(e.length === 0) ++blanks; - return true; - }); - var zeros = (8 - ip.length + blanks) * 2; - var b = util.createBuffer(); - for(var i = 0; i < 8; ++i) { - if(!ip[i] || ip[i].length === 0) { - b.fillWithByte(0, zeros); - zeros = 0; - continue; - } - var bytes = util.hexToBytes(ip[i]); - if(bytes.length < 2) { - b.putByte(0); - } - b.putBytes(bytes); - } - return b.getBytes(); - }; - - /** - * Converts 4-bytes into an IPv4 string representation or 16-bytes into - * an IPv6 string representation. The bytes must be in network order. - * - * @param bytes the bytes to convert. - * - * @return the IPv4 or IPv6 string representation if 4 or 16 bytes, - * respectively, are given, otherwise null. - */ - util.bytesToIP = function(bytes) { - if(bytes.length === 4) { - return util.bytesToIPv4(bytes); - } - if(bytes.length === 16) { - return util.bytesToIPv6(bytes); - } - return null; - }; - - /** - * Converts 4-bytes into an IPv4 string representation. The bytes must be - * in network order. - * - * @param bytes the bytes to convert. - * - * @return the IPv4 string representation or null for an invalid # of bytes. - */ - util.bytesToIPv4 = function(bytes) { - if(bytes.length !== 4) { - return null; - } - var ip = []; - for(var i = 0; i < bytes.length; ++i) { - ip.push(bytes.charCodeAt(i)); - } - return ip.join('.'); - }; - - /** - * Converts 16-bytes into an IPv16 string representation. The bytes must be - * in network order. - * - * @param bytes the bytes to convert. - * - * @return the IPv16 string representation or null for an invalid # of bytes. - */ - util.bytesToIPv6 = function(bytes) { - if(bytes.length !== 16) { - return null; - } - var ip = []; - var zeroGroups = []; - var zeroMaxGroup = 0; - for(var i = 0; i < bytes.length; i += 2) { - var hex = util.bytesToHex(bytes[i] + bytes[i + 1]); - // canonicalize zero representation - while(hex[0] === '0' && hex !== '0') { - hex = hex.substr(1); - } - if(hex === '0') { - var last = zeroGroups[zeroGroups.length - 1]; - var idx = ip.length; - if(!last || idx !== last.end + 1) { - zeroGroups.push({start: idx, end: idx}); - } else { - last.end = idx; - if((last.end - last.start) > - (zeroGroups[zeroMaxGroup].end - zeroGroups[zeroMaxGroup].start)) { - zeroMaxGroup = zeroGroups.length - 1; - } - } - } - ip.push(hex); - } - if(zeroGroups.length > 0) { - var group = zeroGroups[zeroMaxGroup]; - // only shorten group of length > 0 - if(group.end - group.start > 0) { - ip.splice(group.start, group.end - group.start + 1, ''); - if(group.start === 0) { - ip.unshift(''); - } - if(group.end === 7) { - ip.push(''); - } - } - } - return ip.join(':'); - }; - - /** - * Estimates the number of processes that can be run concurrently. If - * creating Web Workers, keep in mind that the main JavaScript process needs - * its own core. - * - * @param options the options to use: - * update true to force an update (not use the cached value). - * @param callback(err, max) called once the operation completes. - */ - util.estimateCores = function(options, callback) { - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; - if('cores' in util && !options.update) { - return callback(null, util.cores); - } - if(typeof navigator !== 'undefined' && - 'hardwareConcurrency' in navigator && - navigator.hardwareConcurrency > 0) { - util.cores = navigator.hardwareConcurrency; - return callback(null, util.cores); - } - if(typeof Worker === 'undefined') { - // workers not available - util.cores = 1; - return callback(null, util.cores); - } - if(typeof Blob === 'undefined') { - // can't estimate, default to 2 - util.cores = 2; - return callback(null, util.cores); - } - - // create worker concurrency estimation code as blob - var blobUrl = URL.createObjectURL(new Blob(['(', - function() { - self.addEventListener('message', function(e) { - // run worker for 4 ms - var st = Date.now(); - var et = st + 4; - self.postMessage({st: st, et: et}); - }); - }.toString(), - ')()'], {type: 'application/javascript'})); - - // take 5 samples using 16 workers - sample([], 5, 16); - - function sample(max, samples, numWorkers) { - if(samples === 0) { - // get overlap average - var avg = Math.floor(max.reduce(function(avg, x) { - return avg + x; - }, 0) / max.length); - util.cores = Math.max(1, avg); - URL.revokeObjectURL(blobUrl); - return callback(null, util.cores); - } - map(numWorkers, function(err, results) { - max.push(reduce(numWorkers, results)); - sample(max, samples - 1, numWorkers); - }); - } - - function map(numWorkers, callback) { - var workers = []; - var results = []; - for(var i = 0; i < numWorkers; ++i) { - var worker = new Worker(blobUrl); - worker.addEventListener('message', function(e) { - results.push(e.data); - if(results.length === numWorkers) { - for(var i = 0; i < numWorkers; ++i) { - workers[i].terminate(); - } - callback(null, results); - } - }); - workers.push(worker); - } - for(var i = 0; i < numWorkers; ++i) { - workers[i].postMessage(i); - } - } - - function reduce(numWorkers, results) { - // find overlapping time windows - var overlaps = []; - for(var n = 0; n < numWorkers; ++n) { - var r1 = results[n]; - var overlap = overlaps[n] = []; - for(var i = 0; i < numWorkers; ++i) { - if(n === i) { - continue; - } - var r2 = results[i]; - if((r1.st > r2.st && r1.st < r2.et) || - (r2.st > r1.st && r2.st < r1.et)) { - overlap.push(i); - } - } - } - // get maximum overlaps ... don't include overlapping worker itself - // as the main JS process was also being scheduled during the work and - // would have to be subtracted from the estimate anyway - return overlaps.reduce(function(max, overlap) { - return Math.max(max, overlap.length); - }, 0); - } - }; - }); - - /** - * Cipher base API. - * - * @author Dave Longley - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - */ - - - - var cipher = forge.cipher = forge.cipher || {}; - - // registered algorithms - forge.cipher.algorithms = forge.cipher.algorithms || {}; - - /** - * Creates a cipher object that can be used to encrypt data using the given - * algorithm and key. The algorithm may be provided as a string value for a - * previously registered algorithm or it may be given as a cipher algorithm - * API object. - * - * @param algorithm the algorithm to use, either a string or an algorithm API - * object. - * @param key the key to use, as a binary-encoded string of bytes or a - * byte buffer. - * - * @return the cipher. - */ - forge.cipher.createCipher = function(algorithm, key) { - var api = algorithm; - if(typeof api === 'string') { - api = forge.cipher.getAlgorithm(api); - if(api) { - api = api(); - } - } - if(!api) { - throw new Error('Unsupported algorithm: ' + algorithm); - } - - // assume block cipher - return new forge.cipher.BlockCipher({ - algorithm: api, - key: key, - decrypt: false - }); - }; - - /** - * Creates a decipher object that can be used to decrypt data using the given - * algorithm and key. The algorithm may be provided as a string value for a - * previously registered algorithm or it may be given as a cipher algorithm - * API object. - * - * @param algorithm the algorithm to use, either a string or an algorithm API - * object. - * @param key the key to use, as a binary-encoded string of bytes or a - * byte buffer. - * - * @return the cipher. - */ - forge.cipher.createDecipher = function(algorithm, key) { - var api = algorithm; - if(typeof api === 'string') { - api = forge.cipher.getAlgorithm(api); - if(api) { - api = api(); - } - } - if(!api) { - throw new Error('Unsupported algorithm: ' + algorithm); - } - - // assume block cipher - return new forge.cipher.BlockCipher({ - algorithm: api, - key: key, - decrypt: true - }); - }; - - /** - * Registers an algorithm by name. If the name was already registered, the - * algorithm API object will be overwritten. - * - * @param name the name of the algorithm. - * @param algorithm the algorithm API object. - */ - forge.cipher.registerAlgorithm = function(name, algorithm) { - name = name.toUpperCase(); - forge.cipher.algorithms[name] = algorithm; - }; - - /** - * Gets a registered algorithm by name. - * - * @param name the name of the algorithm. - * - * @return the algorithm, if found, null if not. - */ - forge.cipher.getAlgorithm = function(name) { - name = name.toUpperCase(); - if(name in forge.cipher.algorithms) { - return forge.cipher.algorithms[name]; - } - return null; - }; - - var BlockCipher = forge.cipher.BlockCipher = function(options) { - this.algorithm = options.algorithm; - this.mode = this.algorithm.mode; - this.blockSize = this.mode.blockSize; - this._finish = false; - this._input = null; - this.output = null; - this._op = options.decrypt ? this.mode.decrypt : this.mode.encrypt; - this._decrypt = options.decrypt; - this.algorithm.initialize(options); - }; - - /** - * Starts or restarts the encryption or decryption process, whichever - * was previously configured. - * - * For non-GCM mode, the IV may be a binary-encoded string of bytes, an array - * of bytes, a byte buffer, or an array of 32-bit integers. If the IV is in - * bytes, then it must be Nb (16) bytes in length. If the IV is given in as - * 32-bit integers, then it must be 4 integers long. - * - * Note: an IV is not required or used in ECB mode. - * - * For GCM-mode, the IV must be given as a binary-encoded string of bytes or - * a byte buffer. The number of bytes should be 12 (96 bits) as recommended - * by NIST SP-800-38D but another length may be given. - * - * @param options the options to use: - * iv the initialization vector to use as a binary-encoded string of - * bytes, null to reuse the last ciphered block from a previous - * update() (this "residue" method is for legacy support only). - * additionalData additional authentication data as a binary-encoded - * string of bytes, for 'GCM' mode, (default: none). - * tagLength desired length of authentication tag, in bits, for - * 'GCM' mode (0-128, default: 128). - * tag the authentication tag to check if decrypting, as a - * binary-encoded string of bytes. - * output the output the buffer to write to, null to create one. - */ - BlockCipher.prototype.start = function(options) { - options = options || {}; - var opts = {}; - for(var key in options) { - opts[key] = options[key]; - } - opts.decrypt = this._decrypt; - this._finish = false; - this._input = forge.util.createBuffer(); - this.output = options.output || forge.util.createBuffer(); - this.mode.start(opts); - }; - - /** - * Updates the next block according to the cipher mode. - * - * @param input the buffer to read from. - */ - BlockCipher.prototype.update = function(input) { - if(input) { - // input given, so empty it into the input buffer - this._input.putBuffer(input); - } - - // do cipher operation until it needs more input and not finished - while(!this._op.call(this.mode, this._input, this.output, this._finish) && - !this._finish) {} - - // free consumed memory from input buffer - this._input.compact(); - }; - - /** - * Finishes encrypting or decrypting. - * - * @param pad a padding function to use in CBC mode, null for default, - * signature(blockSize, buffer, decrypt). - * - * @return true if successful, false on error. - */ - BlockCipher.prototype.finish = function(pad) { - // backwards-compatibility w/deprecated padding API - // Note: will overwrite padding functions even after another start() call - if(pad && (this.mode.name === 'ECB' || this.mode.name === 'CBC')) { - this.mode.pad = function(input) { - return pad(this.blockSize, input, false); - }; - this.mode.unpad = function(output) { - return pad(this.blockSize, output, true); - }; - } - - // build options for padding and afterFinish functions - var options = {}; - options.decrypt = this._decrypt; - - // get # of bytes that won't fill a block - options.overflow = this._input.length() % this.blockSize; - - if(!this._decrypt && this.mode.pad) { - if(!this.mode.pad(this._input, options)) { - return false; - } - } - - // do final update - this._finish = true; - this.update(); - - if(this._decrypt && this.mode.unpad) { - if(!this.mode.unpad(this.output, options)) { - return false; - } - } - - if(this.mode.afterFinish) { - if(!this.mode.afterFinish(this.output, options)) { - return false; - } - } - - return true; - }; - - var cipherModes = createCommonjsModule(function (module) { - /** - * Supported cipher modes. - * - * @author Dave Longley - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - */ - - - - forge.cipher = forge.cipher || {}; - - // supported cipher modes - var modes = module.exports = forge.cipher.modes = forge.cipher.modes || {}; - - /** Electronic codebook (ECB) (Don't use this; it's not secure) **/ - - modes.ecb = function(options) { - options = options || {}; - this.name = 'ECB'; - this.cipher = options.cipher; - this.blockSize = options.blockSize || 16; - this._ints = this.blockSize / 4; - this._inBlock = new Array(this._ints); - this._outBlock = new Array(this._ints); - }; - - modes.ecb.prototype.start = function(options) {}; - - modes.ecb.prototype.encrypt = function(input, output, finish) { - // not enough input to encrypt - if(input.length() < this.blockSize && !(finish && input.length() > 0)) { - return true; - } - - // get next block - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = input.getInt32(); - } - - // encrypt block - this.cipher.encrypt(this._inBlock, this._outBlock); - - // write output - for(var i = 0; i < this._ints; ++i) { - output.putInt32(this._outBlock[i]); - } - }; - - modes.ecb.prototype.decrypt = function(input, output, finish) { - // not enough input to decrypt - if(input.length() < this.blockSize && !(finish && input.length() > 0)) { - return true; - } - - // get next block - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = input.getInt32(); - } - - // decrypt block - this.cipher.decrypt(this._inBlock, this._outBlock); - - // write output - for(var i = 0; i < this._ints; ++i) { - output.putInt32(this._outBlock[i]); - } - }; - - modes.ecb.prototype.pad = function(input, options) { - // add PKCS#7 padding to block (each pad byte is the - // value of the number of pad bytes) - var padding = (input.length() === this.blockSize ? - this.blockSize : (this.blockSize - input.length())); - input.fillWithByte(padding, padding); - return true; - }; - - modes.ecb.prototype.unpad = function(output, options) { - // check for error: input data not a multiple of blockSize - if(options.overflow > 0) { - return false; - } - - // ensure padding byte count is valid - var len = output.length(); - var count = output.at(len - 1); - if(count > (this.blockSize << 2)) { - return false; - } - - // trim off padding bytes - output.truncate(count); - return true; - }; - - /** Cipher-block Chaining (CBC) **/ - - modes.cbc = function(options) { - options = options || {}; - this.name = 'CBC'; - this.cipher = options.cipher; - this.blockSize = options.blockSize || 16; - this._ints = this.blockSize / 4; - this._inBlock = new Array(this._ints); - this._outBlock = new Array(this._ints); - }; - - modes.cbc.prototype.start = function(options) { - // Note: legacy support for using IV residue (has security flaws) - // if IV is null, reuse block from previous processing - if(options.iv === null) { - // must have a previous block - if(!this._prev) { - throw new Error('Invalid IV parameter.'); - } - this._iv = this._prev.slice(0); - } else if(!('iv' in options)) { - throw new Error('Invalid IV parameter.'); - } else { - // save IV as "previous" block - this._iv = transformIV(options.iv, this.blockSize); - this._prev = this._iv.slice(0); - } - }; - - modes.cbc.prototype.encrypt = function(input, output, finish) { - // not enough input to encrypt - if(input.length() < this.blockSize && !(finish && input.length() > 0)) { - return true; - } - - // get next block - // CBC XOR's IV (or previous block) with plaintext - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = this._prev[i] ^ input.getInt32(); - } - - // encrypt block - this.cipher.encrypt(this._inBlock, this._outBlock); - - // write output, save previous block - for(var i = 0; i < this._ints; ++i) { - output.putInt32(this._outBlock[i]); - } - this._prev = this._outBlock; - }; - - modes.cbc.prototype.decrypt = function(input, output, finish) { - // not enough input to decrypt - if(input.length() < this.blockSize && !(finish && input.length() > 0)) { - return true; - } - - // get next block - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = input.getInt32(); - } - - // decrypt block - this.cipher.decrypt(this._inBlock, this._outBlock); - - // write output, save previous ciphered block - // CBC XOR's IV (or previous block) with ciphertext - for(var i = 0; i < this._ints; ++i) { - output.putInt32(this._prev[i] ^ this._outBlock[i]); - } - this._prev = this._inBlock.slice(0); - }; - - modes.cbc.prototype.pad = function(input, options) { - // add PKCS#7 padding to block (each pad byte is the - // value of the number of pad bytes) - var padding = (input.length() === this.blockSize ? - this.blockSize : (this.blockSize - input.length())); - input.fillWithByte(padding, padding); - return true; - }; - - modes.cbc.prototype.unpad = function(output, options) { - // check for error: input data not a multiple of blockSize - if(options.overflow > 0) { - return false; - } - - // ensure padding byte count is valid - var len = output.length(); - var count = output.at(len - 1); - if(count > (this.blockSize << 2)) { - return false; - } - - // trim off padding bytes - output.truncate(count); - return true; - }; - - /** Cipher feedback (CFB) **/ - - modes.cfb = function(options) { - options = options || {}; - this.name = 'CFB'; - this.cipher = options.cipher; - this.blockSize = options.blockSize || 16; - this._ints = this.blockSize / 4; - this._inBlock = null; - this._outBlock = new Array(this._ints); - this._partialBlock = new Array(this._ints); - this._partialOutput = forge.util.createBuffer(); - this._partialBytes = 0; - }; - - modes.cfb.prototype.start = function(options) { - if(!('iv' in options)) { - throw new Error('Invalid IV parameter.'); - } - // use IV as first input - this._iv = transformIV(options.iv, this.blockSize); - this._inBlock = this._iv.slice(0); - this._partialBytes = 0; - }; - - modes.cfb.prototype.encrypt = function(input, output, finish) { - // not enough input to encrypt - var inputLength = input.length(); - if(inputLength === 0) { - return true; - } - - // encrypt block - this.cipher.encrypt(this._inBlock, this._outBlock); - - // handle full block - if(this._partialBytes === 0 && inputLength >= this.blockSize) { - // XOR input with output, write input as output - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = input.getInt32() ^ this._outBlock[i]; - output.putInt32(this._inBlock[i]); - } - return; - } - - // handle partial block - var partialBytes = (this.blockSize - inputLength) % this.blockSize; - if(partialBytes > 0) { - partialBytes = this.blockSize - partialBytes; - } - - // XOR input with output, write input as partial output - this._partialOutput.clear(); - for(var i = 0; i < this._ints; ++i) { - this._partialBlock[i] = input.getInt32() ^ this._outBlock[i]; - this._partialOutput.putInt32(this._partialBlock[i]); - } - - if(partialBytes > 0) { - // block still incomplete, restore input buffer - input.read -= this.blockSize; - } else { - // block complete, update input block - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = this._partialBlock[i]; - } - } - - // skip any previous partial bytes - if(this._partialBytes > 0) { - this._partialOutput.getBytes(this._partialBytes); - } - - if(partialBytes > 0 && !finish) { - output.putBytes(this._partialOutput.getBytes( - partialBytes - this._partialBytes)); - this._partialBytes = partialBytes; - return true; - } - - output.putBytes(this._partialOutput.getBytes( - inputLength - this._partialBytes)); - this._partialBytes = 0; - }; - - modes.cfb.prototype.decrypt = function(input, output, finish) { - // not enough input to decrypt - var inputLength = input.length(); - if(inputLength === 0) { - return true; - } - - // encrypt block (CFB always uses encryption mode) - this.cipher.encrypt(this._inBlock, this._outBlock); - - // handle full block - if(this._partialBytes === 0 && inputLength >= this.blockSize) { - // XOR input with output, write input as output - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = input.getInt32(); - output.putInt32(this._inBlock[i] ^ this._outBlock[i]); - } - return; - } - - // handle partial block - var partialBytes = (this.blockSize - inputLength) % this.blockSize; - if(partialBytes > 0) { - partialBytes = this.blockSize - partialBytes; - } - - // XOR input with output, write input as partial output - this._partialOutput.clear(); - for(var i = 0; i < this._ints; ++i) { - this._partialBlock[i] = input.getInt32(); - this._partialOutput.putInt32(this._partialBlock[i] ^ this._outBlock[i]); - } - - if(partialBytes > 0) { - // block still incomplete, restore input buffer - input.read -= this.blockSize; - } else { - // block complete, update input block - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = this._partialBlock[i]; - } - } - - // skip any previous partial bytes - if(this._partialBytes > 0) { - this._partialOutput.getBytes(this._partialBytes); - } - - if(partialBytes > 0 && !finish) { - output.putBytes(this._partialOutput.getBytes( - partialBytes - this._partialBytes)); - this._partialBytes = partialBytes; - return true; - } - - output.putBytes(this._partialOutput.getBytes( - inputLength - this._partialBytes)); - this._partialBytes = 0; - }; - - /** Output feedback (OFB) **/ - - modes.ofb = function(options) { - options = options || {}; - this.name = 'OFB'; - this.cipher = options.cipher; - this.blockSize = options.blockSize || 16; - this._ints = this.blockSize / 4; - this._inBlock = null; - this._outBlock = new Array(this._ints); - this._partialOutput = forge.util.createBuffer(); - this._partialBytes = 0; - }; - - modes.ofb.prototype.start = function(options) { - if(!('iv' in options)) { - throw new Error('Invalid IV parameter.'); - } - // use IV as first input - this._iv = transformIV(options.iv, this.blockSize); - this._inBlock = this._iv.slice(0); - this._partialBytes = 0; - }; - - modes.ofb.prototype.encrypt = function(input, output, finish) { - // not enough input to encrypt - var inputLength = input.length(); - if(input.length() === 0) { - return true; - } - - // encrypt block (OFB always uses encryption mode) - this.cipher.encrypt(this._inBlock, this._outBlock); - - // handle full block - if(this._partialBytes === 0 && inputLength >= this.blockSize) { - // XOR input with output and update next input - for(var i = 0; i < this._ints; ++i) { - output.putInt32(input.getInt32() ^ this._outBlock[i]); - this._inBlock[i] = this._outBlock[i]; - } - return; - } - - // handle partial block - var partialBytes = (this.blockSize - inputLength) % this.blockSize; - if(partialBytes > 0) { - partialBytes = this.blockSize - partialBytes; - } - - // XOR input with output - this._partialOutput.clear(); - for(var i = 0; i < this._ints; ++i) { - this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); - } - - if(partialBytes > 0) { - // block still incomplete, restore input buffer - input.read -= this.blockSize; - } else { - // block complete, update input block - for(var i = 0; i < this._ints; ++i) { - this._inBlock[i] = this._outBlock[i]; - } - } - - // skip any previous partial bytes - if(this._partialBytes > 0) { - this._partialOutput.getBytes(this._partialBytes); - } - - if(partialBytes > 0 && !finish) { - output.putBytes(this._partialOutput.getBytes( - partialBytes - this._partialBytes)); - this._partialBytes = partialBytes; - return true; - } - - output.putBytes(this._partialOutput.getBytes( - inputLength - this._partialBytes)); - this._partialBytes = 0; - }; - - modes.ofb.prototype.decrypt = modes.ofb.prototype.encrypt; - - /** Counter (CTR) **/ - - modes.ctr = function(options) { - options = options || {}; - this.name = 'CTR'; - this.cipher = options.cipher; - this.blockSize = options.blockSize || 16; - this._ints = this.blockSize / 4; - this._inBlock = null; - this._outBlock = new Array(this._ints); - this._partialOutput = forge.util.createBuffer(); - this._partialBytes = 0; - }; - - modes.ctr.prototype.start = function(options) { - if(!('iv' in options)) { - throw new Error('Invalid IV parameter.'); - } - // use IV as first input - this._iv = transformIV(options.iv, this.blockSize); - this._inBlock = this._iv.slice(0); - this._partialBytes = 0; - }; - - modes.ctr.prototype.encrypt = function(input, output, finish) { - // not enough input to encrypt - var inputLength = input.length(); - if(inputLength === 0) { - return true; - } - - // encrypt block (CTR always uses encryption mode) - this.cipher.encrypt(this._inBlock, this._outBlock); - - // handle full block - if(this._partialBytes === 0 && inputLength >= this.blockSize) { - // XOR input with output - for(var i = 0; i < this._ints; ++i) { - output.putInt32(input.getInt32() ^ this._outBlock[i]); - } - } else { - // handle partial block - var partialBytes = (this.blockSize - inputLength) % this.blockSize; - if(partialBytes > 0) { - partialBytes = this.blockSize - partialBytes; - } - - // XOR input with output - this._partialOutput.clear(); - for(var i = 0; i < this._ints; ++i) { - this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); - } - - if(partialBytes > 0) { - // block still incomplete, restore input buffer - input.read -= this.blockSize; - } - - // skip any previous partial bytes - if(this._partialBytes > 0) { - this._partialOutput.getBytes(this._partialBytes); - } - - if(partialBytes > 0 && !finish) { - output.putBytes(this._partialOutput.getBytes( - partialBytes - this._partialBytes)); - this._partialBytes = partialBytes; - return true; - } - - output.putBytes(this._partialOutput.getBytes( - inputLength - this._partialBytes)); - this._partialBytes = 0; - } - - // block complete, increment counter (input block) - inc32(this._inBlock); - }; - - modes.ctr.prototype.decrypt = modes.ctr.prototype.encrypt; - - /** Galois/Counter Mode (GCM) **/ - - modes.gcm = function(options) { - options = options || {}; - this.name = 'GCM'; - this.cipher = options.cipher; - this.blockSize = options.blockSize || 16; - this._ints = this.blockSize / 4; - this._inBlock = new Array(this._ints); - this._outBlock = new Array(this._ints); - this._partialOutput = forge.util.createBuffer(); - this._partialBytes = 0; - - // R is actually this value concatenated with 120 more zero bits, but - // we only XOR against R so the other zeros have no effect -- we just - // apply this value to the first integer in a block - this._R = 0xE1000000; - }; - - modes.gcm.prototype.start = function(options) { - if(!('iv' in options)) { - throw new Error('Invalid IV parameter.'); - } - // ensure IV is a byte buffer - var iv = forge.util.createBuffer(options.iv); - - // no ciphered data processed yet - this._cipherLength = 0; - - // default additional data is none - var additionalData; - if('additionalData' in options) { - additionalData = forge.util.createBuffer(options.additionalData); - } else { - additionalData = forge.util.createBuffer(); - } - - // default tag length is 128 bits - if('tagLength' in options) { - this._tagLength = options.tagLength; - } else { - this._tagLength = 128; - } - - // if tag is given, ensure tag matches tag length - this._tag = null; - if(options.decrypt) { - // save tag to check later - this._tag = forge.util.createBuffer(options.tag).getBytes(); - if(this._tag.length !== (this._tagLength / 8)) { - throw new Error('Authentication tag does not match tag length.'); - } - } - - // create tmp storage for hash calculation - this._hashBlock = new Array(this._ints); - - // no tag generated yet - this.tag = null; - - // generate hash subkey - // (apply block cipher to "zero" block) - this._hashSubkey = new Array(this._ints); - this.cipher.encrypt([0, 0, 0, 0], this._hashSubkey); - - // generate table M - // use 4-bit tables (32 component decomposition of a 16 byte value) - // 8-bit tables take more space and are known to have security - // vulnerabilities (in native implementations) - this.componentBits = 4; - this._m = this.generateHashTable(this._hashSubkey, this.componentBits); - - // Note: support IV length different from 96 bits? (only supporting - // 96 bits is recommended by NIST SP-800-38D) - // generate J_0 - var ivLength = iv.length(); - if(ivLength === 12) { - // 96-bit IV - this._j0 = [iv.getInt32(), iv.getInt32(), iv.getInt32(), 1]; - } else { - // IV is NOT 96-bits - this._j0 = [0, 0, 0, 0]; - while(iv.length() > 0) { - this._j0 = this.ghash( - this._hashSubkey, this._j0, - [iv.getInt32(), iv.getInt32(), iv.getInt32(), iv.getInt32()]); - } - this._j0 = this.ghash( - this._hashSubkey, this._j0, [0, 0].concat(from64To32(ivLength * 8))); - } - - // generate ICB (initial counter block) - this._inBlock = this._j0.slice(0); - inc32(this._inBlock); - this._partialBytes = 0; - - // consume authentication data - additionalData = forge.util.createBuffer(additionalData); - // save additional data length as a BE 64-bit number - this._aDataLength = from64To32(additionalData.length() * 8); - // pad additional data to 128 bit (16 byte) block size - var overflow = additionalData.length() % this.blockSize; - if(overflow) { - additionalData.fillWithByte(0, this.blockSize - overflow); - } - this._s = [0, 0, 0, 0]; - while(additionalData.length() > 0) { - this._s = this.ghash(this._hashSubkey, this._s, [ - additionalData.getInt32(), - additionalData.getInt32(), - additionalData.getInt32(), - additionalData.getInt32() - ]); - } - }; - - modes.gcm.prototype.encrypt = function(input, output, finish) { - // not enough input to encrypt - var inputLength = input.length(); - if(inputLength === 0) { - return true; - } - - // encrypt block - this.cipher.encrypt(this._inBlock, this._outBlock); - - // handle full block - if(this._partialBytes === 0 && inputLength >= this.blockSize) { - // XOR input with output - for(var i = 0; i < this._ints; ++i) { - output.putInt32(this._outBlock[i] ^= input.getInt32()); - } - this._cipherLength += this.blockSize; - } else { - // handle partial block - var partialBytes = (this.blockSize - inputLength) % this.blockSize; - if(partialBytes > 0) { - partialBytes = this.blockSize - partialBytes; - } - - // XOR input with output - this._partialOutput.clear(); - for(var i = 0; i < this._ints; ++i) { - this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); - } - - if(partialBytes <= 0 || finish) { - // handle overflow prior to hashing - if(finish) { - // get block overflow - var overflow = inputLength % this.blockSize; - this._cipherLength += overflow; - // truncate for hash function - this._partialOutput.truncate(this.blockSize - overflow); - } else { - this._cipherLength += this.blockSize; - } - - // get output block for hashing - for(var i = 0; i < this._ints; ++i) { - this._outBlock[i] = this._partialOutput.getInt32(); - } - this._partialOutput.read -= this.blockSize; - } - - // skip any previous partial bytes - if(this._partialBytes > 0) { - this._partialOutput.getBytes(this._partialBytes); - } - - if(partialBytes > 0 && !finish) { - // block still incomplete, restore input buffer, get partial output, - // and return early - input.read -= this.blockSize; - output.putBytes(this._partialOutput.getBytes( - partialBytes - this._partialBytes)); - this._partialBytes = partialBytes; - return true; - } - - output.putBytes(this._partialOutput.getBytes( - inputLength - this._partialBytes)); - this._partialBytes = 0; - } - - // update hash block S - this._s = this.ghash(this._hashSubkey, this._s, this._outBlock); - - // increment counter (input block) - inc32(this._inBlock); - }; - - modes.gcm.prototype.decrypt = function(input, output, finish) { - // not enough input to decrypt - var inputLength = input.length(); - if(inputLength < this.blockSize && !(finish && inputLength > 0)) { - return true; - } - - // encrypt block (GCM always uses encryption mode) - this.cipher.encrypt(this._inBlock, this._outBlock); - - // increment counter (input block) - inc32(this._inBlock); - - // update hash block S - this._hashBlock[0] = input.getInt32(); - this._hashBlock[1] = input.getInt32(); - this._hashBlock[2] = input.getInt32(); - this._hashBlock[3] = input.getInt32(); - this._s = this.ghash(this._hashSubkey, this._s, this._hashBlock); - - // XOR hash input with output - for(var i = 0; i < this._ints; ++i) { - output.putInt32(this._outBlock[i] ^ this._hashBlock[i]); - } - - // increment cipher data length - if(inputLength < this.blockSize) { - this._cipherLength += inputLength % this.blockSize; - } else { - this._cipherLength += this.blockSize; - } - }; - - modes.gcm.prototype.afterFinish = function(output, options) { - var rval = true; - - // handle overflow - if(options.decrypt && options.overflow) { - output.truncate(this.blockSize - options.overflow); - } - - // handle authentication tag - this.tag = forge.util.createBuffer(); - - // concatenate additional data length with cipher length - var lengths = this._aDataLength.concat(from64To32(this._cipherLength * 8)); - - // include lengths in hash - this._s = this.ghash(this._hashSubkey, this._s, lengths); - - // do GCTR(J_0, S) - var tag = []; - this.cipher.encrypt(this._j0, tag); - for(var i = 0; i < this._ints; ++i) { - this.tag.putInt32(this._s[i] ^ tag[i]); - } - - // trim tag to length - this.tag.truncate(this.tag.length() % (this._tagLength / 8)); - - // check authentication tag - if(options.decrypt && this.tag.bytes() !== this._tag) { - rval = false; - } - - return rval; - }; - - /** - * See NIST SP-800-38D 6.3 (Algorithm 1). This function performs Galois - * field multiplication. The field, GF(2^128), is defined by the polynomial: - * - * x^128 + x^7 + x^2 + x + 1 - * - * Which is represented in little-endian binary form as: 11100001 (0xe1). When - * the value of a coefficient is 1, a bit is set. The value R, is the - * concatenation of this value and 120 zero bits, yielding a 128-bit value - * which matches the block size. - * - * This function will multiply two elements (vectors of bytes), X and Y, in - * the field GF(2^128). The result is initialized to zero. For each bit of - * X (out of 128), x_i, if x_i is set, then the result is multiplied (XOR'd) - * by the current value of Y. For each bit, the value of Y will be raised by - * a power of x (multiplied by the polynomial x). This can be achieved by - * shifting Y once to the right. If the current value of Y, prior to being - * multiplied by x, has 0 as its LSB, then it is a 127th degree polynomial. - * Otherwise, we must divide by R after shifting to find the remainder. - * - * @param x the first block to multiply by the second. - * @param y the second block to multiply by the first. - * - * @return the block result of the multiplication. - */ - modes.gcm.prototype.multiply = function(x, y) { - var z_i = [0, 0, 0, 0]; - var v_i = y.slice(0); - - // calculate Z_128 (block has 128 bits) - for(var i = 0; i < 128; ++i) { - // if x_i is 0, Z_{i+1} = Z_i (unchanged) - // else Z_{i+1} = Z_i ^ V_i - // get x_i by finding 32-bit int position, then left shift 1 by remainder - var x_i = x[(i / 32) | 0] & (1 << (31 - i % 32)); - if(x_i) { - z_i[0] ^= v_i[0]; - z_i[1] ^= v_i[1]; - z_i[2] ^= v_i[2]; - z_i[3] ^= v_i[3]; - } - - // if LSB(V_i) is 1, V_i = V_i >> 1 - // else V_i = (V_i >> 1) ^ R - this.pow(v_i, v_i); - } - - return z_i; - }; - - modes.gcm.prototype.pow = function(x, out) { - // if LSB(x) is 1, x = x >>> 1 - // else x = (x >>> 1) ^ R - var lsb = x[3] & 1; - - // always do x >>> 1: - // starting with the rightmost integer, shift each integer to the right - // one bit, pulling in the bit from the integer to the left as its top - // most bit (do this for the last 3 integers) - for(var i = 3; i > 0; --i) { - out[i] = (x[i] >>> 1) | ((x[i - 1] & 1) << 31); - } - // shift the first integer normally - out[0] = x[0] >>> 1; - - // if lsb was not set, then polynomial had a degree of 127 and doesn't - // need to divided; otherwise, XOR with R to find the remainder; we only - // need to XOR the first integer since R technically ends w/120 zero bits - if(lsb) { - out[0] ^= this._R; - } - }; - - modes.gcm.prototype.tableMultiply = function(x) { - // assumes 4-bit tables are used - var z = [0, 0, 0, 0]; - for(var i = 0; i < 32; ++i) { - var idx = (i / 8) | 0; - var x_i = (x[idx] >>> ((7 - (i % 8)) * 4)) & 0xF; - var ah = this._m[i][x_i]; - z[0] ^= ah[0]; - z[1] ^= ah[1]; - z[2] ^= ah[2]; - z[3] ^= ah[3]; - } - return z; - }; - - /** - * A continuing version of the GHASH algorithm that operates on a single - * block. The hash block, last hash value (Ym) and the new block to hash - * are given. - * - * @param h the hash block. - * @param y the previous value for Ym, use [0, 0, 0, 0] for a new hash. - * @param x the block to hash. - * - * @return the hashed value (Ym). - */ - modes.gcm.prototype.ghash = function(h, y, x) { - y[0] ^= x[0]; - y[1] ^= x[1]; - y[2] ^= x[2]; - y[3] ^= x[3]; - return this.tableMultiply(y); - //return this.multiply(y, h); - }; - - /** - * Precomputes a table for multiplying against the hash subkey. This - * mechanism provides a substantial speed increase over multiplication - * performed without a table. The table-based multiplication this table is - * for solves X * H by multiplying each component of X by H and then - * composing the results together using XOR. - * - * This function can be used to generate tables with different bit sizes - * for the components, however, this implementation assumes there are - * 32 components of X (which is a 16 byte vector), therefore each component - * takes 4-bits (so the table is constructed with bits=4). - * - * @param h the hash subkey. - * @param bits the bit size for a component. - */ - modes.gcm.prototype.generateHashTable = function(h, bits) { - // TODO: There are further optimizations that would use only the - // first table M_0 (or some variant) along with a remainder table; - // this can be explored in the future - var multiplier = 8 / bits; - var perInt = 4 * multiplier; - var size = 16 * multiplier; - var m = new Array(size); - for(var i = 0; i < size; ++i) { - var tmp = [0, 0, 0, 0]; - var idx = (i / perInt) | 0; - var shft = ((perInt - 1 - (i % perInt)) * bits); - tmp[idx] = (1 << (bits - 1)) << shft; - m[i] = this.generateSubHashTable(this.multiply(tmp, h), bits); - } - return m; - }; - - /** - * Generates a table for multiplying against the hash subkey for one - * particular component (out of all possible component values). - * - * @param mid the pre-multiplied value for the middle key of the table. - * @param bits the bit size for a component. - */ - modes.gcm.prototype.generateSubHashTable = function(mid, bits) { - // compute the table quickly by minimizing the number of - // POW operations -- they only need to be performed for powers of 2, - // all other entries can be composed from those powers using XOR - var size = 1 << bits; - var half = size >>> 1; - var m = new Array(size); - m[half] = mid.slice(0); - var i = half >>> 1; - while(i > 0) { - // raise m0[2 * i] and store in m0[i] - this.pow(m[2 * i], m[i] = []); - i >>= 1; - } - i = 2; - while(i < half) { - for(var j = 1; j < i; ++j) { - var m_i = m[i]; - var m_j = m[j]; - m[i + j] = [ - m_i[0] ^ m_j[0], - m_i[1] ^ m_j[1], - m_i[2] ^ m_j[2], - m_i[3] ^ m_j[3] - ]; - } - i *= 2; - } - m[0] = [0, 0, 0, 0]; - /* Note: We could avoid storing these by doing composition during multiply - calculate top half using composition by speed is preferred. */ - for(i = half + 1; i < size; ++i) { - var c = m[i ^ half]; - m[i] = [mid[0] ^ c[0], mid[1] ^ c[1], mid[2] ^ c[2], mid[3] ^ c[3]]; - } - return m; - }; - - /** Utility functions */ - - function transformIV(iv, blockSize) { - if(typeof iv === 'string') { - // convert iv string into byte buffer - iv = forge.util.createBuffer(iv); - } - - if(forge.util.isArray(iv) && iv.length > 4) { - // convert iv byte array into byte buffer - var tmp = iv; - iv = forge.util.createBuffer(); - for(var i = 0; i < tmp.length; ++i) { - iv.putByte(tmp[i]); - } - } - - if(iv.length() < blockSize) { - throw new Error( - 'Invalid IV length; got ' + iv.length() + - ' bytes and expected ' + blockSize + ' bytes.'); - } - - if(!forge.util.isArray(iv)) { - // convert iv byte buffer into 32-bit integer array - var ints = []; - var blocks = blockSize / 4; - for(var i = 0; i < blocks; ++i) { - ints.push(iv.getInt32()); - } - iv = ints; - } - - return iv; - } - - function inc32(block) { - // increment last 32 bits of block only - block[block.length - 1] = (block[block.length - 1] + 1) & 0xFFFFFFFF; - } - - function from64To32(num) { - // convert 64-bit number to two BE Int32s - return [(num / 0x100000000) | 0, num & 0xFFFFFFFF]; - } - }); - - /** - * Advanced Encryption Standard (AES) implementation. - * - * This implementation is based on the public domain library 'jscrypto' which - * was written by: - * - * Emily Stark (estark@stanford.edu) - * Mike Hamburg (mhamburg@stanford.edu) - * Dan Boneh (dabo@cs.stanford.edu) - * - * Parts of this code are based on the OpenSSL implementation of AES: - * http://www.openssl.org - * - * @author Dave Longley - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - */ - - - - - - /* AES API */ - var aes = forge.aes = forge.aes || {}; - - /** - * Deprecated. Instead, use: - * - * var cipher = forge.cipher.createCipher('AES-', key); - * cipher.start({iv: iv}); - * - * Creates an AES cipher object to encrypt data using the given symmetric key. - * The output will be stored in the 'output' member of the returned cipher. - * - * The key and iv may be given as a string of bytes, an array of bytes, - * a byte buffer, or an array of 32-bit words. - * - * @param key the symmetric key to use. - * @param iv the initialization vector to use. - * @param output the buffer to write to, null to create one. - * @param mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - forge.aes.startEncrypting = function(key, iv, output, mode) { - var cipher = _createCipher({ - key: key, - output: output, - decrypt: false, - mode: mode - }); - cipher.start(iv); - return cipher; - }; - - /** - * Deprecated. Instead, use: - * - * var cipher = forge.cipher.createCipher('AES-', key); - * - * Creates an AES cipher object to encrypt data using the given symmetric key. - * - * The key may be given as a string of bytes, an array of bytes, a - * byte buffer, or an array of 32-bit words. - * - * @param key the symmetric key to use. - * @param mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - forge.aes.createEncryptionCipher = function(key, mode) { - return _createCipher({ - key: key, - output: null, - decrypt: false, - mode: mode - }); - }; - - /** - * Deprecated. Instead, use: - * - * var decipher = forge.cipher.createDecipher('AES-', key); - * decipher.start({iv: iv}); - * - * Creates an AES cipher object to decrypt data using the given symmetric key. - * The output will be stored in the 'output' member of the returned cipher. - * - * The key and iv may be given as a string of bytes, an array of bytes, - * a byte buffer, or an array of 32-bit words. - * - * @param key the symmetric key to use. - * @param iv the initialization vector to use. - * @param output the buffer to write to, null to create one. - * @param mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - forge.aes.startDecrypting = function(key, iv, output, mode) { - var cipher = _createCipher({ - key: key, - output: output, - decrypt: true, - mode: mode - }); - cipher.start(iv); - return cipher; - }; - - /** - * Deprecated. Instead, use: - * - * var decipher = forge.cipher.createDecipher('AES-', key); - * - * Creates an AES cipher object to decrypt data using the given symmetric key. - * - * The key may be given as a string of bytes, an array of bytes, a - * byte buffer, or an array of 32-bit words. - * - * @param key the symmetric key to use. - * @param mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - forge.aes.createDecryptionCipher = function(key, mode) { - return _createCipher({ - key: key, - output: null, - decrypt: true, - mode: mode - }); - }; - - /** - * Creates a new AES cipher algorithm object. - * - * @param name the name of the algorithm. - * @param mode the mode factory function. - * - * @return the AES algorithm object. - */ - forge.aes.Algorithm = function(name, mode) { - if(!init) { - initialize(); - } - var self = this; - self.name = name; - self.mode = new mode({ - blockSize: 16, - cipher: { - encrypt: function(inBlock, outBlock) { - return _updateBlock(self._w, inBlock, outBlock, false); - }, - decrypt: function(inBlock, outBlock) { - return _updateBlock(self._w, inBlock, outBlock, true); - } - } - }); - self._init = false; - }; - - /** - * Initializes this AES algorithm by expanding its key. - * - * @param options the options to use. - * key the key to use with this algorithm. - * decrypt true if the algorithm should be initialized for decryption, - * false for encryption. - */ - forge.aes.Algorithm.prototype.initialize = function(options) { - if(this._init) { - return; - } - - var key = options.key; - var tmp; - - /* Note: The key may be a string of bytes, an array of bytes, a byte - buffer, or an array of 32-bit integers. If the key is in bytes, then - it must be 16, 24, or 32 bytes in length. If it is in 32-bit - integers, it must be 4, 6, or 8 integers long. */ - - if(typeof key === 'string' && - (key.length === 16 || key.length === 24 || key.length === 32)) { - // convert key string into byte buffer - key = forge.util.createBuffer(key); - } else if(forge.util.isArray(key) && - (key.length === 16 || key.length === 24 || key.length === 32)) { - // convert key integer array into byte buffer - tmp = key; - key = forge.util.createBuffer(); - for(var i = 0; i < tmp.length; ++i) { - key.putByte(tmp[i]); - } - } - - // convert key byte buffer into 32-bit integer array - if(!forge.util.isArray(key)) { - tmp = key; - key = []; - - // key lengths of 16, 24, 32 bytes allowed - var len = tmp.length(); - if(len === 16 || len === 24 || len === 32) { - len = len >>> 2; - for(var i = 0; i < len; ++i) { - key.push(tmp.getInt32()); - } - } - } - - // key must be an array of 32-bit integers by now - if(!forge.util.isArray(key) || - !(key.length === 4 || key.length === 6 || key.length === 8)) { - throw new Error('Invalid key parameter.'); - } - - // encryption operation is always used for these modes - var mode = this.mode.name; - var encryptOp = (['CFB', 'OFB', 'CTR', 'GCM'].indexOf(mode) !== -1); - - // do key expansion - this._w = _expandKey(key, options.decrypt && !encryptOp); - this._init = true; - }; - - /** - * Expands a key. Typically only used for testing. - * - * @param key the symmetric key to expand, as an array of 32-bit words. - * @param decrypt true to expand for decryption, false for encryption. - * - * @return the expanded key. - */ - forge.aes._expandKey = function(key, decrypt) { - if(!init) { - initialize(); - } - return _expandKey(key, decrypt); - }; - - /** - * Updates a single block. Typically only used for testing. - * - * @param w the expanded key to use. - * @param input an array of block-size 32-bit words. - * @param output an array of block-size 32-bit words. - * @param decrypt true to decrypt, false to encrypt. - */ - forge.aes._updateBlock = _updateBlock; - - /** Register AES algorithms **/ - - registerAlgorithm('AES-ECB', forge.cipher.modes.ecb); - registerAlgorithm('AES-CBC', forge.cipher.modes.cbc); - registerAlgorithm('AES-CFB', forge.cipher.modes.cfb); - registerAlgorithm('AES-OFB', forge.cipher.modes.ofb); - registerAlgorithm('AES-CTR', forge.cipher.modes.ctr); - registerAlgorithm('AES-GCM', forge.cipher.modes.gcm); - - function registerAlgorithm(name, mode) { - var factory = function() { - return new forge.aes.Algorithm(name, mode); - }; - forge.cipher.registerAlgorithm(name, factory); - } - - /** AES implementation **/ - - var init = false; // not yet initialized - var Nb = 4; // number of words comprising the state (AES = 4) - var sbox; // non-linear substitution table used in key expansion - var isbox; // inversion of sbox - var rcon; // round constant word array - var mix; // mix-columns table - var imix; // inverse mix-columns table - - /** - * Performs initialization, ie: precomputes tables to optimize for speed. - * - * One way to understand how AES works is to imagine that 'addition' and - * 'multiplication' are interfaces that require certain mathematical - * properties to hold true (ie: they are associative) but they might have - * different implementations and produce different kinds of results ... - * provided that their mathematical properties remain true. AES defines - * its own methods of addition and multiplication but keeps some important - * properties the same, ie: associativity and distributivity. The - * explanation below tries to shed some light on how AES defines addition - * and multiplication of bytes and 32-bit words in order to perform its - * encryption and decryption algorithms. - * - * The basics: - * - * The AES algorithm views bytes as binary representations of polynomials - * that have either 1 or 0 as the coefficients. It defines the addition - * or subtraction of two bytes as the XOR operation. It also defines the - * multiplication of two bytes as a finite field referred to as GF(2^8) - * (Note: 'GF' means "Galois Field" which is a field that contains a finite - * number of elements so GF(2^8) has 256 elements). - * - * This means that any two bytes can be represented as binary polynomials; - * when they multiplied together and modularly reduced by an irreducible - * polynomial of the 8th degree, the results are the field GF(2^8). The - * specific irreducible polynomial that AES uses in hexadecimal is 0x11b. - * This multiplication is associative with 0x01 as the identity: - * - * (b * 0x01 = GF(b, 0x01) = b). - * - * The operation GF(b, 0x02) can be performed at the byte level by left - * shifting b once and then XOR'ing it (to perform the modular reduction) - * with 0x11b if b is >= 128. Repeated application of the multiplication - * of 0x02 can be used to implement the multiplication of any two bytes. - * - * For instance, multiplying 0x57 and 0x13, denoted as GF(0x57, 0x13), can - * be performed by factoring 0x13 into 0x01, 0x02, and 0x10. Then these - * factors can each be multiplied by 0x57 and then added together. To do - * the multiplication, values for 0x57 multiplied by each of these 3 factors - * can be precomputed and stored in a table. To add them, the values from - * the table are XOR'd together. - * - * AES also defines addition and multiplication of words, that is 4-byte - * numbers represented as polynomials of 3 degrees where the coefficients - * are the values of the bytes. - * - * The word [a0, a1, a2, a3] is a polynomial a3x^3 + a2x^2 + a1x + a0. - * - * Addition is performed by XOR'ing like powers of x. Multiplication - * is performed in two steps, the first is an algebriac expansion as - * you would do normally (where addition is XOR). But the result is - * a polynomial larger than 3 degrees and thus it cannot fit in a word. So - * next the result is modularly reduced by an AES-specific polynomial of - * degree 4 which will always produce a polynomial of less than 4 degrees - * such that it will fit in a word. In AES, this polynomial is x^4 + 1. - * - * The modular product of two polynomials 'a' and 'b' is thus: - * - * d(x) = d3x^3 + d2x^2 + d1x + d0 - * with - * d0 = GF(a0, b0) ^ GF(a3, b1) ^ GF(a2, b2) ^ GF(a1, b3) - * d1 = GF(a1, b0) ^ GF(a0, b1) ^ GF(a3, b2) ^ GF(a2, b3) - * d2 = GF(a2, b0) ^ GF(a1, b1) ^ GF(a0, b2) ^ GF(a3, b3) - * d3 = GF(a3, b0) ^ GF(a2, b1) ^ GF(a1, b2) ^ GF(a0, b3) - * - * As a matrix: - * - * [d0] = [a0 a3 a2 a1][b0] - * [d1] [a1 a0 a3 a2][b1] - * [d2] [a2 a1 a0 a3][b2] - * [d3] [a3 a2 a1 a0][b3] - * - * Special polynomials defined by AES (0x02 == {02}): - * a(x) = {03}x^3 + {01}x^2 + {01}x + {02} - * a^-1(x) = {0b}x^3 + {0d}x^2 + {09}x + {0e}. - * - * These polynomials are used in the MixColumns() and InverseMixColumns() - * operations, respectively, to cause each element in the state to affect - * the output (referred to as diffusing). - * - * RotWord() uses: a0 = a1 = a2 = {00} and a3 = {01}, which is the - * polynomial x3. - * - * The ShiftRows() method modifies the last 3 rows in the state (where - * the state is 4 words with 4 bytes per word) by shifting bytes cyclically. - * The 1st byte in the second row is moved to the end of the row. The 1st - * and 2nd bytes in the third row are moved to the end of the row. The 1st, - * 2nd, and 3rd bytes are moved in the fourth row. - * - * More details on how AES arithmetic works: - * - * In the polynomial representation of binary numbers, XOR performs addition - * and subtraction and multiplication in GF(2^8) denoted as GF(a, b) - * corresponds with the multiplication of polynomials modulo an irreducible - * polynomial of degree 8. In other words, for AES, GF(a, b) will multiply - * polynomial 'a' with polynomial 'b' and then do a modular reduction by - * an AES-specific irreducible polynomial of degree 8. - * - * A polynomial is irreducible if its only divisors are one and itself. For - * the AES algorithm, this irreducible polynomial is: - * - * m(x) = x^8 + x^4 + x^3 + x + 1, - * - * or {01}{1b} in hexadecimal notation, where each coefficient is a bit: - * 100011011 = 283 = 0x11b. - * - * For example, GF(0x57, 0x83) = 0xc1 because - * - * 0x57 = 87 = 01010111 = x^6 + x^4 + x^2 + x + 1 - * 0x85 = 131 = 10000101 = x^7 + x + 1 - * - * (x^6 + x^4 + x^2 + x + 1) * (x^7 + x + 1) - * = x^13 + x^11 + x^9 + x^8 + x^7 + - * x^7 + x^5 + x^3 + x^2 + x + - * x^6 + x^4 + x^2 + x + 1 - * = x^13 + x^11 + x^9 + x^8 + x^6 + x^5 + x^4 + x^3 + 1 = y - * y modulo (x^8 + x^4 + x^3 + x + 1) - * = x^7 + x^6 + 1. - * - * The modular reduction by m(x) guarantees the result will be a binary - * polynomial of less than degree 8, so that it can fit in a byte. - * - * The operation to multiply a binary polynomial b with x (the polynomial - * x in binary representation is 00000010) is: - * - * b_7x^8 + b_6x^7 + b_5x^6 + b_4x^5 + b_3x^4 + b_2x^3 + b_1x^2 + b_0x^1 - * - * To get GF(b, x) we must reduce that by m(x). If b_7 is 0 (that is the - * most significant bit is 0 in b) then the result is already reduced. If - * it is 1, then we can reduce it by subtracting m(x) via an XOR. - * - * It follows that multiplication by x (00000010 or 0x02) can be implemented - * by performing a left shift followed by a conditional bitwise XOR with - * 0x1b. This operation on bytes is denoted by xtime(). Multiplication by - * higher powers of x can be implemented by repeated application of xtime(). - * - * By adding intermediate results, multiplication by any constant can be - * implemented. For instance: - * - * GF(0x57, 0x13) = 0xfe because: - * - * xtime(b) = (b & 128) ? (b << 1 ^ 0x11b) : (b << 1) - * - * Note: We XOR with 0x11b instead of 0x1b because in javascript our - * datatype for b can be larger than 1 byte, so a left shift will not - * automatically eliminate bits that overflow a byte ... by XOR'ing the - * overflow bit with 1 (the extra one from 0x11b) we zero it out. - * - * GF(0x57, 0x02) = xtime(0x57) = 0xae - * GF(0x57, 0x04) = xtime(0xae) = 0x47 - * GF(0x57, 0x08) = xtime(0x47) = 0x8e - * GF(0x57, 0x10) = xtime(0x8e) = 0x07 - * - * GF(0x57, 0x13) = GF(0x57, (0x01 ^ 0x02 ^ 0x10)) - * - * And by the distributive property (since XOR is addition and GF() is - * multiplication): - * - * = GF(0x57, 0x01) ^ GF(0x57, 0x02) ^ GF(0x57, 0x10) - * = 0x57 ^ 0xae ^ 0x07 - * = 0xfe. - */ - function initialize() { - init = true; - - /* Populate the Rcon table. These are the values given by - [x^(i-1),{00},{00},{00}] where x^(i-1) are powers of x (and x = 0x02) - in the field of GF(2^8), where i starts at 1. - - rcon[0] = [0x00, 0x00, 0x00, 0x00] - rcon[1] = [0x01, 0x00, 0x00, 0x00] 2^(1-1) = 2^0 = 1 - rcon[2] = [0x02, 0x00, 0x00, 0x00] 2^(2-1) = 2^1 = 2 - ... - rcon[9] = [0x1B, 0x00, 0x00, 0x00] 2^(9-1) = 2^8 = 0x1B - rcon[10] = [0x36, 0x00, 0x00, 0x00] 2^(10-1) = 2^9 = 0x36 - - We only store the first byte because it is the only one used. - */ - rcon = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]; - - // compute xtime table which maps i onto GF(i, 0x02) - var xtime = new Array(256); - for(var i = 0; i < 128; ++i) { - xtime[i] = i << 1; - xtime[i + 128] = (i + 128) << 1 ^ 0x11B; - } - - // compute all other tables - sbox = new Array(256); - isbox = new Array(256); - mix = new Array(4); - imix = new Array(4); - for(var i = 0; i < 4; ++i) { - mix[i] = new Array(256); - imix[i] = new Array(256); - } - var e = 0, ei = 0, e2, e4, e8, sx, sx2, me, ime; - for(var i = 0; i < 256; ++i) { - /* We need to generate the SubBytes() sbox and isbox tables so that - we can perform byte substitutions. This requires us to traverse - all of the elements in GF, find their multiplicative inverses, - and apply to each the following affine transformation: - - bi' = bi ^ b(i + 4) mod 8 ^ b(i + 5) mod 8 ^ b(i + 6) mod 8 ^ - b(i + 7) mod 8 ^ ci - for 0 <= i < 8, where bi is the ith bit of the byte, and ci is the - ith bit of a byte c with the value {63} or {01100011}. - - It is possible to traverse every possible value in a Galois field - using what is referred to as a 'generator'. There are many - generators (128 out of 256): 3,5,6,9,11,82 to name a few. To fully - traverse GF we iterate 255 times, multiplying by our generator - each time. - - On each iteration we can determine the multiplicative inverse for - the current element. - - Suppose there is an element in GF 'e'. For a given generator 'g', - e = g^x. The multiplicative inverse of e is g^(255 - x). It turns - out that if use the inverse of a generator as another generator - it will produce all of the corresponding multiplicative inverses - at the same time. For this reason, we choose 5 as our inverse - generator because it only requires 2 multiplies and 1 add and its - inverse, 82, requires relatively few operations as well. - - In order to apply the affine transformation, the multiplicative - inverse 'ei' of 'e' can be repeatedly XOR'd (4 times) with a - bit-cycling of 'ei'. To do this 'ei' is first stored in 's' and - 'x'. Then 's' is left shifted and the high bit of 's' is made the - low bit. The resulting value is stored in 's'. Then 'x' is XOR'd - with 's' and stored in 'x'. On each subsequent iteration the same - operation is performed. When 4 iterations are complete, 'x' is - XOR'd with 'c' (0x63) and the transformed value is stored in 'x'. - For example: - - s = 01000001 - x = 01000001 - - iteration 1: s = 10000010, x ^= s - iteration 2: s = 00000101, x ^= s - iteration 3: s = 00001010, x ^= s - iteration 4: s = 00010100, x ^= s - x ^= 0x63 - - This can be done with a loop where s = (s << 1) | (s >> 7). However, - it can also be done by using a single 16-bit (in this case 32-bit) - number 'sx'. Since XOR is an associative operation, we can set 'sx' - to 'ei' and then XOR it with 'sx' left-shifted 1,2,3, and 4 times. - The most significant bits will flow into the high 8 bit positions - and be correctly XOR'd with one another. All that remains will be - to cycle the high 8 bits by XOR'ing them all with the lower 8 bits - afterwards. - - At the same time we're populating sbox and isbox we can precompute - the multiplication we'll need to do to do MixColumns() later. - */ - - // apply affine transformation - sx = ei ^ (ei << 1) ^ (ei << 2) ^ (ei << 3) ^ (ei << 4); - sx = (sx >> 8) ^ (sx & 255) ^ 0x63; - - // update tables - sbox[e] = sx; - isbox[sx] = e; - - /* Mixing columns is done using matrix multiplication. The columns - that are to be mixed are each a single word in the current state. - The state has Nb columns (4 columns). Therefore each column is a - 4 byte word. So to mix the columns in a single column 'c' where - its rows are r0, r1, r2, and r3, we use the following matrix - multiplication: - - [2 3 1 1]*[r0,c]=[r'0,c] - [1 2 3 1] [r1,c] [r'1,c] - [1 1 2 3] [r2,c] [r'2,c] - [3 1 1 2] [r3,c] [r'3,c] - - r0, r1, r2, and r3 are each 1 byte of one of the words in the - state (a column). To do matrix multiplication for each mixed - column c' we multiply the corresponding row from the left matrix - with the corresponding column from the right matrix. In total, we - get 4 equations: - - r0,c' = 2*r0,c + 3*r1,c + 1*r2,c + 1*r3,c - r1,c' = 1*r0,c + 2*r1,c + 3*r2,c + 1*r3,c - r2,c' = 1*r0,c + 1*r1,c + 2*r2,c + 3*r3,c - r3,c' = 3*r0,c + 1*r1,c + 1*r2,c + 2*r3,c - - As usual, the multiplication is as previously defined and the - addition is XOR. In order to optimize mixing columns we can store - the multiplication results in tables. If you think of the whole - column as a word (it might help to visualize by mentally rotating - the equations above by counterclockwise 90 degrees) then you can - see that it would be useful to map the multiplications performed on - each byte (r0, r1, r2, r3) onto a word as well. For instance, we - could map 2*r0,1*r0,1*r0,3*r0 onto a word by storing 2*r0 in the - highest 8 bits and 3*r0 in the lowest 8 bits (with the other two - respectively in the middle). This means that a table can be - constructed that uses r0 as an index to the word. We can do the - same with r1, r2, and r3, creating a total of 4 tables. - - To construct a full c', we can just look up each byte of c in - their respective tables and XOR the results together. - - Also, to build each table we only have to calculate the word - for 2,1,1,3 for every byte ... which we can do on each iteration - of this loop since we will iterate over every byte. After we have - calculated 2,1,1,3 we can get the results for the other tables - by cycling the byte at the end to the beginning. For instance - we can take the result of table 2,1,1,3 and produce table 3,2,1,1 - by moving the right most byte to the left most position just like - how you can imagine the 3 moved out of 2,1,1,3 and to the front - to produce 3,2,1,1. - - There is another optimization in that the same multiples of - the current element we need in order to advance our generator - to the next iteration can be reused in performing the 2,1,1,3 - calculation. We also calculate the inverse mix column tables, - with e,9,d,b being the inverse of 2,1,1,3. - - When we're done, and we need to actually mix columns, the first - byte of each state word should be put through mix[0] (2,1,1,3), - the second through mix[1] (3,2,1,1) and so forth. Then they should - be XOR'd together to produce the fully mixed column. - */ - - // calculate mix and imix table values - sx2 = xtime[sx]; - e2 = xtime[e]; - e4 = xtime[e2]; - e8 = xtime[e4]; - me = - (sx2 << 24) ^ // 2 - (sx << 16) ^ // 1 - (sx << 8) ^ // 1 - (sx ^ sx2); // 3 - ime = - (e2 ^ e4 ^ e8) << 24 ^ // E (14) - (e ^ e8) << 16 ^ // 9 - (e ^ e4 ^ e8) << 8 ^ // D (13) - (e ^ e2 ^ e8); // B (11) - // produce each of the mix tables by rotating the 2,1,1,3 value - for(var n = 0; n < 4; ++n) { - mix[n][e] = me; - imix[n][sx] = ime; - // cycle the right most byte to the left most position - // ie: 2,1,1,3 becomes 3,2,1,1 - me = me << 24 | me >>> 8; - ime = ime << 24 | ime >>> 8; - } - - // get next element and inverse - if(e === 0) { - // 1 is the inverse of 1 - e = ei = 1; - } else { - // e = 2e + 2*2*2*(10e)) = multiply e by 82 (chosen generator) - // ei = ei + 2*2*ei = multiply ei by 5 (inverse generator) - e = e2 ^ xtime[xtime[xtime[e2 ^ e8]]]; - ei ^= xtime[xtime[ei]]; - } - } - } - - /** - * Generates a key schedule using the AES key expansion algorithm. - * - * The AES algorithm takes the Cipher Key, K, and performs a Key Expansion - * routine to generate a key schedule. The Key Expansion generates a total - * of Nb*(Nr + 1) words: the algorithm requires an initial set of Nb words, - * and each of the Nr rounds requires Nb words of key data. The resulting - * key schedule consists of a linear array of 4-byte words, denoted [wi ], - * with i in the range 0 <= i < Nb(Nr + 1). - * - * KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk) - * AES-128 (Nb=4, Nk=4, Nr=10) - * AES-192 (Nb=4, Nk=6, Nr=12) - * AES-256 (Nb=4, Nk=8, Nr=14) - * Note: Nr=Nk+6. - * - * Nb is the number of columns (32-bit words) comprising the State (or - * number of bytes in a block). For AES, Nb=4. - * - * @param key the key to schedule (as an array of 32-bit words). - * @param decrypt true to modify the key schedule to decrypt, false not to. - * - * @return the generated key schedule. - */ - function _expandKey(key, decrypt) { - // copy the key's words to initialize the key schedule - var w = key.slice(0); - - /* RotWord() will rotate a word, moving the first byte to the last - byte's position (shifting the other bytes left). - - We will be getting the value of Rcon at i / Nk. 'i' will iterate - from Nk to (Nb * Nr+1). Nk = 4 (4 byte key), Nb = 4 (4 words in - a block), Nr = Nk + 6 (10). Therefore 'i' will iterate from - 4 to 44 (exclusive). Each time we iterate 4 times, i / Nk will - increase by 1. We use a counter iNk to keep track of this. - */ - - // go through the rounds expanding the key - var temp, iNk = 1; - var Nk = w.length; - var Nr1 = Nk + 6 + 1; - var end = Nb * Nr1; - for(var i = Nk; i < end; ++i) { - temp = w[i - 1]; - if(i % Nk === 0) { - // temp = SubWord(RotWord(temp)) ^ Rcon[i / Nk] - temp = - sbox[temp >>> 16 & 255] << 24 ^ - sbox[temp >>> 8 & 255] << 16 ^ - sbox[temp & 255] << 8 ^ - sbox[temp >>> 24] ^ (rcon[iNk] << 24); - iNk++; - } else if(Nk > 6 && (i % Nk === 4)) { - // temp = SubWord(temp) - temp = - sbox[temp >>> 24] << 24 ^ - sbox[temp >>> 16 & 255] << 16 ^ - sbox[temp >>> 8 & 255] << 8 ^ - sbox[temp & 255]; - } - w[i] = w[i - Nk] ^ temp; - } - - /* When we are updating a cipher block we always use the code path for - encryption whether we are decrypting or not (to shorten code and - simplify the generation of look up tables). However, because there - are differences in the decryption algorithm, other than just swapping - in different look up tables, we must transform our key schedule to - account for these changes: - - 1. The decryption algorithm gets its key rounds in reverse order. - 2. The decryption algorithm adds the round key before mixing columns - instead of afterwards. - - We don't need to modify our key schedule to handle the first case, - we can just traverse the key schedule in reverse order when decrypting. - - The second case requires a little work. - - The tables we built for performing rounds will take an input and then - perform SubBytes() and MixColumns() or, for the decrypt version, - InvSubBytes() and InvMixColumns(). But the decrypt algorithm requires - us to AddRoundKey() before InvMixColumns(). This means we'll need to - apply some transformations to the round key to inverse-mix its columns - so they'll be correct for moving AddRoundKey() to after the state has - had its columns inverse-mixed. - - To inverse-mix the columns of the state when we're decrypting we use a - lookup table that will apply InvSubBytes() and InvMixColumns() at the - same time. However, the round key's bytes are not inverse-substituted - in the decryption algorithm. To get around this problem, we can first - substitute the bytes in the round key so that when we apply the - transformation via the InvSubBytes()+InvMixColumns() table, it will - undo our substitution leaving us with the original value that we - want -- and then inverse-mix that value. - - This change will correctly alter our key schedule so that we can XOR - each round key with our already transformed decryption state. This - allows us to use the same code path as the encryption algorithm. - - We make one more change to the decryption key. Since the decryption - algorithm runs in reverse from the encryption algorithm, we reverse - the order of the round keys to avoid having to iterate over the key - schedule backwards when running the encryption algorithm later in - decryption mode. In addition to reversing the order of the round keys, - we also swap each round key's 2nd and 4th rows. See the comments - section where rounds are performed for more details about why this is - done. These changes are done inline with the other substitution - described above. - */ - if(decrypt) { - var tmp; - var m0 = imix[0]; - var m1 = imix[1]; - var m2 = imix[2]; - var m3 = imix[3]; - var wnew = w.slice(0); - end = w.length; - for(var i = 0, wi = end - Nb; i < end; i += Nb, wi -= Nb) { - // do not sub the first or last round key (round keys are Nb - // words) as no column mixing is performed before they are added, - // but do change the key order - if(i === 0 || i === (end - Nb)) { - wnew[i] = w[wi]; - wnew[i + 1] = w[wi + 3]; - wnew[i + 2] = w[wi + 2]; - wnew[i + 3] = w[wi + 1]; - } else { - // substitute each round key byte because the inverse-mix - // table will inverse-substitute it (effectively cancel the - // substitution because round key bytes aren't sub'd in - // decryption mode) and swap indexes 3 and 1 - for(var n = 0; n < Nb; ++n) { - tmp = w[wi + n]; - wnew[i + (3&-n)] = - m0[sbox[tmp >>> 24]] ^ - m1[sbox[tmp >>> 16 & 255]] ^ - m2[sbox[tmp >>> 8 & 255]] ^ - m3[sbox[tmp & 255]]; - } - } - } - w = wnew; - } - - return w; - } - - /** - * Updates a single block (16 bytes) using AES. The update will either - * encrypt or decrypt the block. - * - * @param w the key schedule. - * @param input the input block (an array of 32-bit words). - * @param output the updated output block. - * @param decrypt true to decrypt the block, false to encrypt it. - */ - function _updateBlock(w, input, output, decrypt) { - /* - Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) - begin - byte state[4,Nb] - state = in - AddRoundKey(state, w[0, Nb-1]) - for round = 1 step 1 to Nr-1 - SubBytes(state) - ShiftRows(state) - MixColumns(state) - AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) - end for - SubBytes(state) - ShiftRows(state) - AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) - out = state - end - - InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) - begin - byte state[4,Nb] - state = in - AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) - for round = Nr-1 step -1 downto 1 - InvShiftRows(state) - InvSubBytes(state) - AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) - InvMixColumns(state) - end for - InvShiftRows(state) - InvSubBytes(state) - AddRoundKey(state, w[0, Nb-1]) - out = state - end - */ - - // Encrypt: AddRoundKey(state, w[0, Nb-1]) - // Decrypt: AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) - var Nr = w.length / 4 - 1; - var m0, m1, m2, m3, sub; - if(decrypt) { - m0 = imix[0]; - m1 = imix[1]; - m2 = imix[2]; - m3 = imix[3]; - sub = isbox; - } else { - m0 = mix[0]; - m1 = mix[1]; - m2 = mix[2]; - m3 = mix[3]; - sub = sbox; - } - var a, b, c, d, a2, b2, c2; - a = input[0] ^ w[0]; - b = input[decrypt ? 3 : 1] ^ w[1]; - c = input[2] ^ w[2]; - d = input[decrypt ? 1 : 3] ^ w[3]; - var i = 3; - - /* In order to share code we follow the encryption algorithm when both - encrypting and decrypting. To account for the changes required in the - decryption algorithm, we use different lookup tables when decrypting - and use a modified key schedule to account for the difference in the - order of transformations applied when performing rounds. We also get - key rounds in reverse order (relative to encryption). */ - for(var round = 1; round < Nr; ++round) { - /* As described above, we'll be using table lookups to perform the - column mixing. Each column is stored as a word in the state (the - array 'input' has one column as a word at each index). In order to - mix a column, we perform these transformations on each row in c, - which is 1 byte in each word. The new column for c0 is c'0: - - m0 m1 m2 m3 - r0,c'0 = 2*r0,c0 + 3*r1,c0 + 1*r2,c0 + 1*r3,c0 - r1,c'0 = 1*r0,c0 + 2*r1,c0 + 3*r2,c0 + 1*r3,c0 - r2,c'0 = 1*r0,c0 + 1*r1,c0 + 2*r2,c0 + 3*r3,c0 - r3,c'0 = 3*r0,c0 + 1*r1,c0 + 1*r2,c0 + 2*r3,c0 - - So using mix tables where c0 is a word with r0 being its upper - 8 bits and r3 being its lower 8 bits: - - m0[c0 >> 24] will yield this word: [2*r0,1*r0,1*r0,3*r0] - ... - m3[c0 & 255] will yield this word: [1*r3,1*r3,3*r3,2*r3] - - Therefore to mix the columns in each word in the state we - do the following (& 255 omitted for brevity): - c'0,r0 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] - c'0,r1 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] - c'0,r2 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] - c'0,r3 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] - - However, before mixing, the algorithm requires us to perform - ShiftRows(). The ShiftRows() transformation cyclically shifts the - last 3 rows of the state over different offsets. The first row - (r = 0) is not shifted. - - s'_r,c = s_r,(c + shift(r, Nb) mod Nb - for 0 < r < 4 and 0 <= c < Nb and - shift(1, 4) = 1 - shift(2, 4) = 2 - shift(3, 4) = 3. - - This causes the first byte in r = 1 to be moved to the end of - the row, the first 2 bytes in r = 2 to be moved to the end of - the row, the first 3 bytes in r = 3 to be moved to the end of - the row: - - r1: [c0 c1 c2 c3] => [c1 c2 c3 c0] - r2: [c0 c1 c2 c3] [c2 c3 c0 c1] - r3: [c0 c1 c2 c3] [c3 c0 c1 c2] - - We can make these substitutions inline with our column mixing to - generate an updated set of equations to produce each word in the - state (note the columns have changed positions): - - c0 c1 c2 c3 => c0 c1 c2 c3 - c0 c1 c2 c3 c1 c2 c3 c0 (cycled 1 byte) - c0 c1 c2 c3 c2 c3 c0 c1 (cycled 2 bytes) - c0 c1 c2 c3 c3 c0 c1 c2 (cycled 3 bytes) - - Therefore: - - c'0 = 2*r0,c0 + 3*r1,c1 + 1*r2,c2 + 1*r3,c3 - c'0 = 1*r0,c0 + 2*r1,c1 + 3*r2,c2 + 1*r3,c3 - c'0 = 1*r0,c0 + 1*r1,c1 + 2*r2,c2 + 3*r3,c3 - c'0 = 3*r0,c0 + 1*r1,c1 + 1*r2,c2 + 2*r3,c3 - - c'1 = 2*r0,c1 + 3*r1,c2 + 1*r2,c3 + 1*r3,c0 - c'1 = 1*r0,c1 + 2*r1,c2 + 3*r2,c3 + 1*r3,c0 - c'1 = 1*r0,c1 + 1*r1,c2 + 2*r2,c3 + 3*r3,c0 - c'1 = 3*r0,c1 + 1*r1,c2 + 1*r2,c3 + 2*r3,c0 - - ... and so forth for c'2 and c'3. The important distinction is - that the columns are cycling, with c0 being used with the m0 - map when calculating c0, but c1 being used with the m0 map when - calculating c1 ... and so forth. - - When performing the inverse we transform the mirror image and - skip the bottom row, instead of the top one, and move upwards: - - c3 c2 c1 c0 => c0 c3 c2 c1 (cycled 3 bytes) *same as encryption - c3 c2 c1 c0 c1 c0 c3 c2 (cycled 2 bytes) - c3 c2 c1 c0 c2 c1 c0 c3 (cycled 1 byte) *same as encryption - c3 c2 c1 c0 c3 c2 c1 c0 - - If you compare the resulting matrices for ShiftRows()+MixColumns() - and for InvShiftRows()+InvMixColumns() the 2nd and 4th columns are - different (in encrypt mode vs. decrypt mode). So in order to use - the same code to handle both encryption and decryption, we will - need to do some mapping. - - If in encryption mode we let a=c0, b=c1, c=c2, d=c3, and r be - a row number in the state, then the resulting matrix in encryption - mode for applying the above transformations would be: - - r1: a b c d - r2: b c d a - r3: c d a b - r4: d a b c - - If we did the same in decryption mode we would get: - - r1: a d c b - r2: b a d c - r3: c b a d - r4: d c b a - - If instead we swap d and b (set b=c3 and d=c1), then we get: - - r1: a b c d - r2: d a b c - r3: c d a b - r4: b c d a - - Now the 1st and 3rd rows are the same as the encryption matrix. All - we need to do then to make the mapping exactly the same is to swap - the 2nd and 4th rows when in decryption mode. To do this without - having to do it on each iteration, we swapped the 2nd and 4th rows - in the decryption key schedule. We also have to do the swap above - when we first pull in the input and when we set the final output. */ - a2 = - m0[a >>> 24] ^ - m1[b >>> 16 & 255] ^ - m2[c >>> 8 & 255] ^ - m3[d & 255] ^ w[++i]; - b2 = - m0[b >>> 24] ^ - m1[c >>> 16 & 255] ^ - m2[d >>> 8 & 255] ^ - m3[a & 255] ^ w[++i]; - c2 = - m0[c >>> 24] ^ - m1[d >>> 16 & 255] ^ - m2[a >>> 8 & 255] ^ - m3[b & 255] ^ w[++i]; - d = - m0[d >>> 24] ^ - m1[a >>> 16 & 255] ^ - m2[b >>> 8 & 255] ^ - m3[c & 255] ^ w[++i]; - a = a2; - b = b2; - c = c2; - } - - /* - Encrypt: - SubBytes(state) - ShiftRows(state) - AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) - - Decrypt: - InvShiftRows(state) - InvSubBytes(state) - AddRoundKey(state, w[0, Nb-1]) - */ - // Note: rows are shifted inline - output[0] = - (sub[a >>> 24] << 24) ^ - (sub[b >>> 16 & 255] << 16) ^ - (sub[c >>> 8 & 255] << 8) ^ - (sub[d & 255]) ^ w[++i]; - output[decrypt ? 3 : 1] = - (sub[b >>> 24] << 24) ^ - (sub[c >>> 16 & 255] << 16) ^ - (sub[d >>> 8 & 255] << 8) ^ - (sub[a & 255]) ^ w[++i]; - output[2] = - (sub[c >>> 24] << 24) ^ - (sub[d >>> 16 & 255] << 16) ^ - (sub[a >>> 8 & 255] << 8) ^ - (sub[b & 255]) ^ w[++i]; - output[decrypt ? 1 : 3] = - (sub[d >>> 24] << 24) ^ - (sub[a >>> 16 & 255] << 16) ^ - (sub[b >>> 8 & 255] << 8) ^ - (sub[c & 255]) ^ w[++i]; - } - - /** - * Deprecated. Instead, use: - * - * forge.cipher.createCipher('AES-', key); - * forge.cipher.createDecipher('AES-', key); - * - * Creates a deprecated AES cipher object. This object's mode will default to - * CBC (cipher-block-chaining). - * - * The key and iv may be given as a string of bytes, an array of bytes, a - * byte buffer, or an array of 32-bit words. - * - * @param options the options to use. - * key the symmetric key to use. - * output the buffer to write to. - * decrypt true for decryption, false for encryption. - * mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - function _createCipher(options) { - options = options || {}; - var mode = (options.mode || 'CBC').toUpperCase(); - var algorithm = 'AES-' + mode; - - var cipher; - if(options.decrypt) { - cipher = forge.cipher.createDecipher(algorithm, options.key); - } else { - cipher = forge.cipher.createCipher(algorithm, options.key); - } - - // backwards compatible start API - var start = cipher.start; - cipher.start = function(iv, options) { - // backwards compatibility: support second arg as output buffer - var output = null; - if(options instanceof forge.util.ByteBuffer) { - output = options; - options = {}; - } - options = options || {}; - options.output = output; - options.iv = iv; - start.call(cipher, options); - }; - - return cipher; - } - - var oids_1 = createCommonjsModule(function (module) { - /** - * Object IDs for ASN.1. - * - * @author Dave Longley - * - * Copyright (c) 2010-2013 Digital Bazaar, Inc. - */ - - - forge.pki = forge.pki || {}; - var oids = module.exports = forge.pki.oids = forge.oids = forge.oids || {}; - - // set id to name mapping and name to id mapping - function _IN(id, name) { - oids[id] = name; - oids[name] = id; - } - // set id to name mapping only - function _I_(id, name) { - oids[id] = name; - } - - // algorithm OIDs - _IN('1.2.840.113549.1.1.1', 'rsaEncryption'); - // Note: md2 & md4 not implemented - //_IN('1.2.840.113549.1.1.2', 'md2WithRSAEncryption'); - //_IN('1.2.840.113549.1.1.3', 'md4WithRSAEncryption'); - _IN('1.2.840.113549.1.1.4', 'md5WithRSAEncryption'); - _IN('1.2.840.113549.1.1.5', 'sha1WithRSAEncryption'); - _IN('1.2.840.113549.1.1.7', 'RSAES-OAEP'); - _IN('1.2.840.113549.1.1.8', 'mgf1'); - _IN('1.2.840.113549.1.1.9', 'pSpecified'); - _IN('1.2.840.113549.1.1.10', 'RSASSA-PSS'); - _IN('1.2.840.113549.1.1.11', 'sha256WithRSAEncryption'); - _IN('1.2.840.113549.1.1.12', 'sha384WithRSAEncryption'); - _IN('1.2.840.113549.1.1.13', 'sha512WithRSAEncryption'); - // Edwards-curve Digital Signature Algorithm (EdDSA) Ed25519 - _IN('1.3.101.112', 'EdDSA25519'); - - _IN('1.2.840.10040.4.3', 'dsa-with-sha1'); - - _IN('1.3.14.3.2.7', 'desCBC'); - - _IN('1.3.14.3.2.26', 'sha1'); - _IN('2.16.840.1.101.3.4.2.1', 'sha256'); - _IN('2.16.840.1.101.3.4.2.2', 'sha384'); - _IN('2.16.840.1.101.3.4.2.3', 'sha512'); - _IN('1.2.840.113549.2.5', 'md5'); - - // pkcs#7 content types - _IN('1.2.840.113549.1.7.1', 'data'); - _IN('1.2.840.113549.1.7.2', 'signedData'); - _IN('1.2.840.113549.1.7.3', 'envelopedData'); - _IN('1.2.840.113549.1.7.4', 'signedAndEnvelopedData'); - _IN('1.2.840.113549.1.7.5', 'digestedData'); - _IN('1.2.840.113549.1.7.6', 'encryptedData'); - - // pkcs#9 oids - _IN('1.2.840.113549.1.9.1', 'emailAddress'); - _IN('1.2.840.113549.1.9.2', 'unstructuredName'); - _IN('1.2.840.113549.1.9.3', 'contentType'); - _IN('1.2.840.113549.1.9.4', 'messageDigest'); - _IN('1.2.840.113549.1.9.5', 'signingTime'); - _IN('1.2.840.113549.1.9.6', 'counterSignature'); - _IN('1.2.840.113549.1.9.7', 'challengePassword'); - _IN('1.2.840.113549.1.9.8', 'unstructuredAddress'); - _IN('1.2.840.113549.1.9.14', 'extensionRequest'); - - _IN('1.2.840.113549.1.9.20', 'friendlyName'); - _IN('1.2.840.113549.1.9.21', 'localKeyId'); - _IN('1.2.840.113549.1.9.22.1', 'x509Certificate'); - - // pkcs#12 safe bags - _IN('1.2.840.113549.1.12.10.1.1', 'keyBag'); - _IN('1.2.840.113549.1.12.10.1.2', 'pkcs8ShroudedKeyBag'); - _IN('1.2.840.113549.1.12.10.1.3', 'certBag'); - _IN('1.2.840.113549.1.12.10.1.4', 'crlBag'); - _IN('1.2.840.113549.1.12.10.1.5', 'secretBag'); - _IN('1.2.840.113549.1.12.10.1.6', 'safeContentsBag'); - - // password-based-encryption for pkcs#12 - _IN('1.2.840.113549.1.5.13', 'pkcs5PBES2'); - _IN('1.2.840.113549.1.5.12', 'pkcs5PBKDF2'); - - _IN('1.2.840.113549.1.12.1.1', 'pbeWithSHAAnd128BitRC4'); - _IN('1.2.840.113549.1.12.1.2', 'pbeWithSHAAnd40BitRC4'); - _IN('1.2.840.113549.1.12.1.3', 'pbeWithSHAAnd3-KeyTripleDES-CBC'); - _IN('1.2.840.113549.1.12.1.4', 'pbeWithSHAAnd2-KeyTripleDES-CBC'); - _IN('1.2.840.113549.1.12.1.5', 'pbeWithSHAAnd128BitRC2-CBC'); - _IN('1.2.840.113549.1.12.1.6', 'pbewithSHAAnd40BitRC2-CBC'); - - // hmac OIDs - _IN('1.2.840.113549.2.7', 'hmacWithSHA1'); - _IN('1.2.840.113549.2.8', 'hmacWithSHA224'); - _IN('1.2.840.113549.2.9', 'hmacWithSHA256'); - _IN('1.2.840.113549.2.10', 'hmacWithSHA384'); - _IN('1.2.840.113549.2.11', 'hmacWithSHA512'); - - // symmetric key algorithm oids - _IN('1.2.840.113549.3.7', 'des-EDE3-CBC'); - _IN('2.16.840.1.101.3.4.1.2', 'aes128-CBC'); - _IN('2.16.840.1.101.3.4.1.22', 'aes192-CBC'); - _IN('2.16.840.1.101.3.4.1.42', 'aes256-CBC'); - - // certificate issuer/subject OIDs - _IN('2.5.4.3', 'commonName'); - _IN('2.5.4.5', 'serialName'); - _IN('2.5.4.6', 'countryName'); - _IN('2.5.4.7', 'localityName'); - _IN('2.5.4.8', 'stateOrProvinceName'); - _IN('2.5.4.9', 'streetAddress'); - _IN('2.5.4.10', 'organizationName'); - _IN('2.5.4.11', 'organizationalUnitName'); - _IN('2.5.4.13', 'description'); - _IN('2.5.4.15', 'businessCategory'); - _IN('2.5.4.17', 'postalCode'); - _IN('1.3.6.1.4.1.311.60.2.1.2', 'jurisdictionOfIncorporationStateOrProvinceName'); - _IN('1.3.6.1.4.1.311.60.2.1.3', 'jurisdictionOfIncorporationCountryName'); - - // X.509 extension OIDs - _IN('2.16.840.1.113730.1.1', 'nsCertType'); - _IN('2.16.840.1.113730.1.13', 'nsComment'); // deprecated in theory; still widely used - _I_('2.5.29.1', 'authorityKeyIdentifier'); // deprecated, use .35 - _I_('2.5.29.2', 'keyAttributes'); // obsolete use .37 or .15 - _I_('2.5.29.3', 'certificatePolicies'); // deprecated, use .32 - _I_('2.5.29.4', 'keyUsageRestriction'); // obsolete use .37 or .15 - _I_('2.5.29.5', 'policyMapping'); // deprecated use .33 - _I_('2.5.29.6', 'subtreesConstraint'); // obsolete use .30 - _I_('2.5.29.7', 'subjectAltName'); // deprecated use .17 - _I_('2.5.29.8', 'issuerAltName'); // deprecated use .18 - _I_('2.5.29.9', 'subjectDirectoryAttributes'); - _I_('2.5.29.10', 'basicConstraints'); // deprecated use .19 - _I_('2.5.29.11', 'nameConstraints'); // deprecated use .30 - _I_('2.5.29.12', 'policyConstraints'); // deprecated use .36 - _I_('2.5.29.13', 'basicConstraints'); // deprecated use .19 - _IN('2.5.29.14', 'subjectKeyIdentifier'); - _IN('2.5.29.15', 'keyUsage'); - _I_('2.5.29.16', 'privateKeyUsagePeriod'); - _IN('2.5.29.17', 'subjectAltName'); - _IN('2.5.29.18', 'issuerAltName'); - _IN('2.5.29.19', 'basicConstraints'); - _I_('2.5.29.20', 'cRLNumber'); - _I_('2.5.29.21', 'cRLReason'); - _I_('2.5.29.22', 'expirationDate'); - _I_('2.5.29.23', 'instructionCode'); - _I_('2.5.29.24', 'invalidityDate'); - _I_('2.5.29.25', 'cRLDistributionPoints'); // deprecated use .31 - _I_('2.5.29.26', 'issuingDistributionPoint'); // deprecated use .28 - _I_('2.5.29.27', 'deltaCRLIndicator'); - _I_('2.5.29.28', 'issuingDistributionPoint'); - _I_('2.5.29.29', 'certificateIssuer'); - _I_('2.5.29.30', 'nameConstraints'); - _IN('2.5.29.31', 'cRLDistributionPoints'); - _IN('2.5.29.32', 'certificatePolicies'); - _I_('2.5.29.33', 'policyMappings'); - _I_('2.5.29.34', 'policyConstraints'); // deprecated use .36 - _IN('2.5.29.35', 'authorityKeyIdentifier'); - _I_('2.5.29.36', 'policyConstraints'); - _IN('2.5.29.37', 'extKeyUsage'); - _I_('2.5.29.46', 'freshestCRL'); - _I_('2.5.29.54', 'inhibitAnyPolicy'); - - // extKeyUsage purposes - _IN('1.3.6.1.4.1.11129.2.4.2', 'timestampList'); - _IN('1.3.6.1.5.5.7.1.1', 'authorityInfoAccess'); - _IN('1.3.6.1.5.5.7.3.1', 'serverAuth'); - _IN('1.3.6.1.5.5.7.3.2', 'clientAuth'); - _IN('1.3.6.1.5.5.7.3.3', 'codeSigning'); - _IN('1.3.6.1.5.5.7.3.4', 'emailProtection'); - _IN('1.3.6.1.5.5.7.3.8', 'timeStamping'); - }); - - var asn1_1 = createCommonjsModule(function (module) { - /** - * Javascript implementation of Abstract Syntax Notation Number One. - * - * @author Dave Longley - * - * Copyright (c) 2010-2015 Digital Bazaar, Inc. - * - * An API for storing data using the Abstract Syntax Notation Number One - * format using DER (Distinguished Encoding Rules) encoding. This encoding is - * commonly used to store data for PKI, i.e. X.509 Certificates, and this - * implementation exists for that purpose. - * - * Abstract Syntax Notation Number One (ASN.1) is used to define the abstract - * syntax of information without restricting the way the information is encoded - * for transmission. It provides a standard that allows for open systems - * communication. ASN.1 defines the syntax of information data and a number of - * simple data types as well as a notation for describing them and specifying - * values for them. - * - * The RSA algorithm creates public and private keys that are often stored in - * X.509 or PKCS#X formats -- which use ASN.1 (encoded in DER format). This - * class provides the most basic functionality required to store and load DSA - * keys that are encoded according to ASN.1. - * - * The most common binary encodings for ASN.1 are BER (Basic Encoding Rules) - * and DER (Distinguished Encoding Rules). DER is just a subset of BER that - * has stricter requirements for how data must be encoded. - * - * Each ASN.1 structure has a tag (a byte identifying the ASN.1 structure type) - * and a byte array for the value of this ASN1 structure which may be data or a - * list of ASN.1 structures. - * - * Each ASN.1 structure using BER is (Tag-Length-Value): - * - * | byte 0 | bytes X | bytes Y | - * |--------|---------|---------- - * | tag | length | value | - * - * ASN.1 allows for tags to be of "High-tag-number form" which allows a tag to - * be two or more octets, but that is not supported by this class. A tag is - * only 1 byte. Bits 1-5 give the tag number (ie the data type within a - * particular 'class'), 6 indicates whether or not the ASN.1 value is - * constructed from other ASN.1 values, and bits 7 and 8 give the 'class'. If - * bits 7 and 8 are both zero, the class is UNIVERSAL. If only bit 7 is set, - * then the class is APPLICATION. If only bit 8 is set, then the class is - * CONTEXT_SPECIFIC. If both bits 7 and 8 are set, then the class is PRIVATE. - * The tag numbers for the data types for the class UNIVERSAL are listed below: - * - * UNIVERSAL 0 Reserved for use by the encoding rules - * UNIVERSAL 1 Boolean type - * UNIVERSAL 2 Integer type - * UNIVERSAL 3 Bitstring type - * UNIVERSAL 4 Octetstring type - * UNIVERSAL 5 Null type - * UNIVERSAL 6 Object identifier type - * UNIVERSAL 7 Object descriptor type - * UNIVERSAL 8 External type and Instance-of type - * UNIVERSAL 9 Real type - * UNIVERSAL 10 Enumerated type - * UNIVERSAL 11 Embedded-pdv type - * UNIVERSAL 12 UTF8String type - * UNIVERSAL 13 Relative object identifier type - * UNIVERSAL 14-15 Reserved for future editions - * UNIVERSAL 16 Sequence and Sequence-of types - * UNIVERSAL 17 Set and Set-of types - * UNIVERSAL 18-22, 25-30 Character string types - * UNIVERSAL 23-24 Time types - * - * The length of an ASN.1 structure is specified after the tag identifier. - * There is a definite form and an indefinite form. The indefinite form may - * be used if the encoding is constructed and not all immediately available. - * The indefinite form is encoded using a length byte with only the 8th bit - * set. The end of the constructed object is marked using end-of-contents - * octets (two zero bytes). - * - * The definite form looks like this: - * - * The length may take up 1 or more bytes, it depends on the length of the - * value of the ASN.1 structure. DER encoding requires that if the ASN.1 - * structure has a value that has a length greater than 127, more than 1 byte - * will be used to store its length, otherwise just one byte will be used. - * This is strict. - * - * In the case that the length of the ASN.1 value is less than 127, 1 octet - * (byte) is used to store the "short form" length. The 8th bit has a value of - * 0 indicating the length is "short form" and not "long form" and bits 7-1 - * give the length of the data. (The 8th bit is the left-most, most significant - * bit: also known as big endian or network format). - * - * In the case that the length of the ASN.1 value is greater than 127, 2 to - * 127 octets (bytes) are used to store the "long form" length. The first - * byte's 8th bit is set to 1 to indicate the length is "long form." Bits 7-1 - * give the number of additional octets. All following octets are in base 256 - * with the most significant digit first (typical big-endian binary unsigned - * integer storage). So, for instance, if the length of a value was 257, the - * first byte would be set to: - * - * 10000010 = 130 = 0x82. - * - * This indicates there are 2 octets (base 256) for the length. The second and - * third bytes (the octets just mentioned) would store the length in base 256: - * - * octet 2: 00000001 = 1 * 256^1 = 256 - * octet 3: 00000001 = 1 * 256^0 = 1 - * total = 257 - * - * The algorithm for converting a js integer value of 257 to base-256 is: - * - * var value = 257; - * var bytes = []; - * bytes[0] = (value >>> 8) & 0xFF; // most significant byte first - * bytes[1] = value & 0xFF; // least significant byte last - * - * On the ASN.1 UNIVERSAL Object Identifier (OID) type: - * - * An OID can be written like: "value1.value2.value3...valueN" - * - * The DER encoding rules: - * - * The first byte has the value 40 * value1 + value2. - * The following bytes, if any, encode the remaining values. Each value is - * encoded in base 128, most significant digit first (big endian), with as - * few digits as possible, and the most significant bit of each byte set - * to 1 except the last in each value's encoding. For example: Given the - * OID "1.2.840.113549", its DER encoding is (remember each byte except the - * last one in each encoding is OR'd with 0x80): - * - * byte 1: 40 * 1 + 2 = 42 = 0x2A. - * bytes 2-3: 128 * 6 + 72 = 840 = 6 72 = 6 72 = 0x0648 = 0x8648 - * bytes 4-6: 16384 * 6 + 128 * 119 + 13 = 6 119 13 = 0x06770D = 0x86F70D - * - * The final value is: 0x2A864886F70D. - * The full OID (including ASN.1 tag and length of 6 bytes) is: - * 0x06062A864886F70D - */ - - - - - /* ASN.1 API */ - var asn1 = module.exports = forge.asn1 = forge.asn1 || {}; - - /** - * ASN.1 classes. - */ - asn1.Class = { - UNIVERSAL: 0x00, - APPLICATION: 0x40, - CONTEXT_SPECIFIC: 0x80, - PRIVATE: 0xC0 - }; - - /** - * ASN.1 types. Not all types are supported by this implementation, only - * those necessary to implement a simple PKI are implemented. - */ - asn1.Type = { - NONE: 0, - BOOLEAN: 1, - INTEGER: 2, - BITSTRING: 3, - OCTETSTRING: 4, - NULL: 5, - OID: 6, - ODESC: 7, - EXTERNAL: 8, - REAL: 9, - ENUMERATED: 10, - EMBEDDED: 11, - UTF8: 12, - ROID: 13, - SEQUENCE: 16, - SET: 17, - PRINTABLESTRING: 19, - IA5STRING: 22, - UTCTIME: 23, - GENERALIZEDTIME: 24, - BMPSTRING: 30 - }; - - /** - * Creates a new asn1 object. - * - * @param tagClass the tag class for the object. - * @param type the data type (tag number) for the object. - * @param constructed true if the asn1 object is in constructed form. - * @param value the value for the object, if it is not constructed. - * @param [options] the options to use: - * [bitStringContents] the plain BIT STRING content including padding - * byte. - * - * @return the asn1 object. - */ - asn1.create = function(tagClass, type, constructed, value, options) { - /* An asn1 object has a tagClass, a type, a constructed flag, and a - value. The value's type depends on the constructed flag. If - constructed, it will contain a list of other asn1 objects. If not, - it will contain the ASN.1 value as an array of bytes formatted - according to the ASN.1 data type. */ - - // remove undefined values - if(forge.util.isArray(value)) { - var tmp = []; - for(var i = 0; i < value.length; ++i) { - if(value[i] !== undefined) { - tmp.push(value[i]); - } - } - value = tmp; - } - - var obj = { - tagClass: tagClass, - type: type, - constructed: constructed, - composed: constructed || forge.util.isArray(value), - value: value - }; - if(options && 'bitStringContents' in options) { - // TODO: copy byte buffer if it's a buffer not a string - obj.bitStringContents = options.bitStringContents; - // TODO: add readonly flag to avoid this overhead - // save copy to detect changes - obj.original = asn1.copy(obj); - } - return obj; - }; - - /** - * Copies an asn1 object. - * - * @param obj the asn1 object. - * @param [options] copy options: - * [excludeBitStringContents] true to not copy bitStringContents - * - * @return the a copy of the asn1 object. - */ - asn1.copy = function(obj, options) { - var copy; - - if(forge.util.isArray(obj)) { - copy = []; - for(var i = 0; i < obj.length; ++i) { - copy.push(asn1.copy(obj[i], options)); - } - return copy; - } - - if(typeof obj === 'string') { - // TODO: copy byte buffer if it's a buffer not a string - return obj; - } - - copy = { - tagClass: obj.tagClass, - type: obj.type, - constructed: obj.constructed, - composed: obj.composed, - value: asn1.copy(obj.value, options) - }; - if(options && !options.excludeBitStringContents) { - // TODO: copy byte buffer if it's a buffer not a string - copy.bitStringContents = obj.bitStringContents; - } - return copy; - }; - - /** - * Compares asn1 objects for equality. - * - * Note this function does not run in constant time. - * - * @param obj1 the first asn1 object. - * @param obj2 the second asn1 object. - * @param [options] compare options: - * [includeBitStringContents] true to compare bitStringContents - * - * @return true if the asn1 objects are equal. - */ - asn1.equals = function(obj1, obj2, options) { - if(forge.util.isArray(obj1)) { - if(!forge.util.isArray(obj2)) { - return false; - } - if(obj1.length !== obj2.length) { - return false; - } - for(var i = 0; i < obj1.length; ++i) { - if(!asn1.equals(obj1[i], obj2[i])) { - return false; - } - } - return true; - } - - if(typeof obj1 !== typeof obj2) { - return false; - } - - if(typeof obj1 === 'string') { - return obj1 === obj2; - } - - var equal = obj1.tagClass === obj2.tagClass && - obj1.type === obj2.type && - obj1.constructed === obj2.constructed && - obj1.composed === obj2.composed && - asn1.equals(obj1.value, obj2.value); - if(options && options.includeBitStringContents) { - equal = equal && (obj1.bitStringContents === obj2.bitStringContents); - } - - return equal; - }; - - /** - * Gets the length of a BER-encoded ASN.1 value. - * - * In case the length is not specified, undefined is returned. - * - * @param b the BER-encoded ASN.1 byte buffer, starting with the first - * length byte. - * - * @return the length of the BER-encoded ASN.1 value or undefined. - */ - asn1.getBerValueLength = function(b) { - // TODO: move this function and related DER/BER functions to a der.js - // file; better abstract ASN.1 away from der/ber. - var b2 = b.getByte(); - if(b2 === 0x80) { - return undefined; - } - - // see if the length is "short form" or "long form" (bit 8 set) - var length; - var longForm = b2 & 0x80; - if(!longForm) { - // length is just the first byte - length = b2; - } else { - // the number of bytes the length is specified in bits 7 through 1 - // and each length byte is in big-endian base-256 - length = b.getInt((b2 & 0x7F) << 3); - } - return length; - }; - - /** - * Check if the byte buffer has enough bytes. Throws an Error if not. - * - * @param bytes the byte buffer to parse from. - * @param remaining the bytes remaining in the current parsing state. - * @param n the number of bytes the buffer must have. - */ - function _checkBufferLength(bytes, remaining, n) { - if(n > remaining) { - var error = new Error('Too few bytes to parse DER.'); - error.available = bytes.length(); - error.remaining = remaining; - error.requested = n; - throw error; - } - } - - /** - * Gets the length of a BER-encoded ASN.1 value. - * - * In case the length is not specified, undefined is returned. - * - * @param bytes the byte buffer to parse from. - * @param remaining the bytes remaining in the current parsing state. - * - * @return the length of the BER-encoded ASN.1 value or undefined. - */ - var _getValueLength = function(bytes, remaining) { - // TODO: move this function and related DER/BER functions to a der.js - // file; better abstract ASN.1 away from der/ber. - // fromDer already checked that this byte exists - var b2 = bytes.getByte(); - remaining--; - if(b2 === 0x80) { - return undefined; - } - - // see if the length is "short form" or "long form" (bit 8 set) - var length; - var longForm = b2 & 0x80; - if(!longForm) { - // length is just the first byte - length = b2; - } else { - // the number of bytes the length is specified in bits 7 through 1 - // and each length byte is in big-endian base-256 - var longFormBytes = b2 & 0x7F; - _checkBufferLength(bytes, remaining, longFormBytes); - length = bytes.getInt(longFormBytes << 3); - } - // FIXME: this will only happen for 32 bit getInt with high bit set - if(length < 0) { - throw new Error('Negative length: ' + length); - } - return length; - }; - - /** - * Parses an asn1 object from a byte buffer in DER format. - * - * @param bytes the byte buffer to parse from. - * @param [strict] true to be strict when checking value lengths, false to - * allow truncated values (default: true). - * @param [options] object with options or boolean strict flag - * [strict] true to be strict when checking value lengths, false to - * allow truncated values (default: true). - * [decodeBitStrings] true to attempt to decode the content of - * BIT STRINGs (not OCTET STRINGs) using strict mode. Note that - * without schema support to understand the data context this can - * erroneously decode values that happen to be valid ASN.1. This - * flag will be deprecated or removed as soon as schema support is - * available. (default: true) - * - * @return the parsed asn1 object. - */ - asn1.fromDer = function(bytes, options) { - if(options === undefined) { - options = { - strict: true, - decodeBitStrings: true - }; - } - if(typeof options === 'boolean') { - options = { - strict: options, - decodeBitStrings: true - }; - } - if(!('strict' in options)) { - options.strict = true; - } - if(!('decodeBitStrings' in options)) { - options.decodeBitStrings = true; - } - - // wrap in buffer if needed - if(typeof bytes === 'string') { - bytes = forge.util.createBuffer(bytes); - } - - return _fromDer(bytes, bytes.length(), 0, options); - }; - - /** - * Internal function to parse an asn1 object from a byte buffer in DER format. - * - * @param bytes the byte buffer to parse from. - * @param remaining the number of bytes remaining for this chunk. - * @param depth the current parsing depth. - * @param options object with same options as fromDer(). - * - * @return the parsed asn1 object. - */ - function _fromDer(bytes, remaining, depth, options) { - // temporary storage for consumption calculations - var start; - - // minimum length for ASN.1 DER structure is 2 - _checkBufferLength(bytes, remaining, 2); - - // get the first byte - var b1 = bytes.getByte(); - // consumed one byte - remaining--; - - // get the tag class - var tagClass = (b1 & 0xC0); - - // get the type (bits 1-5) - var type = b1 & 0x1F; - - // get the variable value length and adjust remaining bytes - start = bytes.length(); - var length = _getValueLength(bytes, remaining); - remaining -= start - bytes.length(); - - // ensure there are enough bytes to get the value - if(length !== undefined && length > remaining) { - if(options.strict) { - var error = new Error('Too few bytes to read ASN.1 value.'); - error.available = bytes.length(); - error.remaining = remaining; - error.requested = length; - throw error; - } - // Note: be lenient with truncated values and use remaining state bytes - length = remaining; - } - - // value storage - var value; - // possible BIT STRING contents storage - var bitStringContents; - - // constructed flag is bit 6 (32 = 0x20) of the first byte - var constructed = ((b1 & 0x20) === 0x20); - if(constructed) { - // parse child asn1 objects from the value - value = []; - if(length === undefined) { - // asn1 object of indefinite length, read until end tag - for(;;) { - _checkBufferLength(bytes, remaining, 2); - if(bytes.bytes(2) === String.fromCharCode(0, 0)) { - bytes.getBytes(2); - remaining -= 2; - break; - } - start = bytes.length(); - value.push(_fromDer(bytes, remaining, depth + 1, options)); - remaining -= start - bytes.length(); - } - } else { - // parsing asn1 object of definite length - while(length > 0) { - start = bytes.length(); - value.push(_fromDer(bytes, length, depth + 1, options)); - remaining -= start - bytes.length(); - length -= start - bytes.length(); - } - } - } - - // if a BIT STRING, save the contents including padding - if(value === undefined && tagClass === asn1.Class.UNIVERSAL && - type === asn1.Type.BITSTRING) { - bitStringContents = bytes.bytes(length); - } - - // determine if a non-constructed value should be decoded as a composed - // value that contains other ASN.1 objects. BIT STRINGs (and OCTET STRINGs) - // can be used this way. - if(value === undefined && options.decodeBitStrings && - tagClass === asn1.Class.UNIVERSAL && - // FIXME: OCTET STRINGs not yet supported here - // .. other parts of forge expect to decode OCTET STRINGs manually - (type === asn1.Type.BITSTRING /*|| type === asn1.Type.OCTETSTRING*/) && - length > 1) { - // save read position - var savedRead = bytes.read; - var savedRemaining = remaining; - var unused = 0; - if(type === asn1.Type.BITSTRING) { - /* The first octet gives the number of bits by which the length of the - bit string is less than the next multiple of eight (this is called - the "number of unused bits"). - - The second and following octets give the value of the bit string - converted to an octet string. */ - _checkBufferLength(bytes, remaining, 1); - unused = bytes.getByte(); - remaining--; - } - // if all bits are used, maybe the BIT/OCTET STRING holds ASN.1 objs - if(unused === 0) { - try { - // attempt to parse child asn1 object from the value - // (stored in array to signal composed value) - start = bytes.length(); - var subOptions = { - // enforce strict mode to avoid parsing ASN.1 from plain data - verbose: options.verbose, - strict: true, - decodeBitStrings: true - }; - var composed = _fromDer(bytes, remaining, depth + 1, subOptions); - var used = start - bytes.length(); - remaining -= used; - if(type == asn1.Type.BITSTRING) { - used++; - } - - // if the data all decoded and the class indicates UNIVERSAL or - // CONTEXT_SPECIFIC then assume we've got an encapsulated ASN.1 object - var tc = composed.tagClass; - if(used === length && - (tc === asn1.Class.UNIVERSAL || tc === asn1.Class.CONTEXT_SPECIFIC)) { - value = [composed]; - } - } catch(ex) { - } - } - if(value === undefined) { - // restore read position - bytes.read = savedRead; - remaining = savedRemaining; - } - } - - if(value === undefined) { - // asn1 not constructed or composed, get raw value - // TODO: do DER to OID conversion and vice-versa in .toDer? - - if(length === undefined) { - if(options.strict) { - throw new Error('Non-constructed ASN.1 object of indefinite length.'); - } - // be lenient and use remaining state bytes - length = remaining; - } - - if(type === asn1.Type.BMPSTRING) { - value = ''; - for(; length > 0; length -= 2) { - _checkBufferLength(bytes, remaining, 2); - value += String.fromCharCode(bytes.getInt16()); - remaining -= 2; - } - } else { - value = bytes.getBytes(length); - } - } - - // add BIT STRING contents if available - var asn1Options = bitStringContents === undefined ? null : { - bitStringContents: bitStringContents - }; - - // create and return asn1 object - return asn1.create(tagClass, type, constructed, value, asn1Options); - } - - /** - * Converts the given asn1 object to a buffer of bytes in DER format. - * - * @param asn1 the asn1 object to convert to bytes. - * - * @return the buffer of bytes. - */ - asn1.toDer = function(obj) { - var bytes = forge.util.createBuffer(); - - // build the first byte - var b1 = obj.tagClass | obj.type; - - // for storing the ASN.1 value - var value = forge.util.createBuffer(); - - // use BIT STRING contents if available and data not changed - var useBitStringContents = false; - if('bitStringContents' in obj) { - useBitStringContents = true; - if(obj.original) { - useBitStringContents = asn1.equals(obj, obj.original); - } - } - - if(useBitStringContents) { - value.putBytes(obj.bitStringContents); - } else if(obj.composed) { - // if composed, use each child asn1 object's DER bytes as value - // turn on 6th bit (0x20 = 32) to indicate asn1 is constructed - // from other asn1 objects - if(obj.constructed) { - b1 |= 0x20; - } else { - // type is a bit string, add unused bits of 0x00 - value.putByte(0x00); - } - - // add all of the child DER bytes together - for(var i = 0; i < obj.value.length; ++i) { - if(obj.value[i] !== undefined) { - value.putBuffer(asn1.toDer(obj.value[i])); - } - } - } else { - // use asn1.value directly - if(obj.type === asn1.Type.BMPSTRING) { - for(var i = 0; i < obj.value.length; ++i) { - value.putInt16(obj.value.charCodeAt(i)); - } - } else { - // ensure integer is minimally-encoded - // TODO: should all leading bytes be stripped vs just one? - // .. ex '00 00 01' => '01'? - if(obj.type === asn1.Type.INTEGER && - obj.value.length > 1 && - // leading 0x00 for positive integer - ((obj.value.charCodeAt(0) === 0 && - (obj.value.charCodeAt(1) & 0x80) === 0) || - // leading 0xFF for negative integer - (obj.value.charCodeAt(0) === 0xFF && - (obj.value.charCodeAt(1) & 0x80) === 0x80))) { - value.putBytes(obj.value.substr(1)); - } else { - value.putBytes(obj.value); - } - } - } - - // add tag byte - bytes.putByte(b1); - - // use "short form" encoding - if(value.length() <= 127) { - // one byte describes the length - // bit 8 = 0 and bits 7-1 = length - bytes.putByte(value.length() & 0x7F); - } else { - // use "long form" encoding - // 2 to 127 bytes describe the length - // first byte: bit 8 = 1 and bits 7-1 = # of additional bytes - // other bytes: length in base 256, big-endian - var len = value.length(); - var lenBytes = ''; - do { - lenBytes += String.fromCharCode(len & 0xFF); - len = len >>> 8; - } while(len > 0); - - // set first byte to # bytes used to store the length and turn on - // bit 8 to indicate long-form length is used - bytes.putByte(lenBytes.length | 0x80); - - // concatenate length bytes in reverse since they were generated - // little endian and we need big endian - for(var i = lenBytes.length - 1; i >= 0; --i) { - bytes.putByte(lenBytes.charCodeAt(i)); - } - } - - // concatenate value bytes - bytes.putBuffer(value); - return bytes; - }; - - /** - * Converts an OID dot-separated string to a byte buffer. The byte buffer - * contains only the DER-encoded value, not any tag or length bytes. - * - * @param oid the OID dot-separated string. - * - * @return the byte buffer. - */ - asn1.oidToDer = function(oid) { - // split OID into individual values - var values = oid.split('.'); - var bytes = forge.util.createBuffer(); - - // first byte is 40 * value1 + value2 - bytes.putByte(40 * parseInt(values[0], 10) + parseInt(values[1], 10)); - // other bytes are each value in base 128 with 8th bit set except for - // the last byte for each value - var last, valueBytes, value, b; - for(var i = 2; i < values.length; ++i) { - // produce value bytes in reverse because we don't know how many - // bytes it will take to store the value - last = true; - valueBytes = []; - value = parseInt(values[i], 10); - do { - b = value & 0x7F; - value = value >>> 7; - // if value is not last, then turn on 8th bit - if(!last) { - b |= 0x80; - } - valueBytes.push(b); - last = false; - } while(value > 0); - - // add value bytes in reverse (needs to be in big endian) - for(var n = valueBytes.length - 1; n >= 0; --n) { - bytes.putByte(valueBytes[n]); - } - } - - return bytes; - }; - - /** - * Converts a DER-encoded byte buffer to an OID dot-separated string. The - * byte buffer should contain only the DER-encoded value, not any tag or - * length bytes. - * - * @param bytes the byte buffer. - * - * @return the OID dot-separated string. - */ - asn1.derToOid = function(bytes) { - var oid; - - // wrap in buffer if needed - if(typeof bytes === 'string') { - bytes = forge.util.createBuffer(bytes); - } - - // first byte is 40 * value1 + value2 - var b = bytes.getByte(); - oid = Math.floor(b / 40) + '.' + (b % 40); - - // other bytes are each value in base 128 with 8th bit set except for - // the last byte for each value - var value = 0; - while(bytes.length() > 0) { - b = bytes.getByte(); - value = value << 7; - // not the last byte for the value - if(b & 0x80) { - value += b & 0x7F; - } else { - // last byte - oid += '.' + (value + b); - value = 0; - } - } - - return oid; - }; - - /** - * Converts a UTCTime value to a date. - * - * Note: GeneralizedTime has 4 digits for the year and is used for X.509 - * dates past 2049. Parsing that structure hasn't been implemented yet. - * - * @param utc the UTCTime value to convert. - * - * @return the date. - */ - asn1.utcTimeToDate = function(utc) { - /* The following formats can be used: - - YYMMDDhhmmZ - YYMMDDhhmm+hh'mm' - YYMMDDhhmm-hh'mm' - YYMMDDhhmmssZ - YYMMDDhhmmss+hh'mm' - YYMMDDhhmmss-hh'mm' - - Where: - - YY is the least significant two digits of the year - MM is the month (01 to 12) - DD is the day (01 to 31) - hh is the hour (00 to 23) - mm are the minutes (00 to 59) - ss are the seconds (00 to 59) - Z indicates that local time is GMT, + indicates that local time is - later than GMT, and - indicates that local time is earlier than GMT - hh' is the absolute value of the offset from GMT in hours - mm' is the absolute value of the offset from GMT in minutes */ - var date = new Date(); - - // if YY >= 50 use 19xx, if YY < 50 use 20xx - var year = parseInt(utc.substr(0, 2), 10); - year = (year >= 50) ? 1900 + year : 2000 + year; - var MM = parseInt(utc.substr(2, 2), 10) - 1; // use 0-11 for month - var DD = parseInt(utc.substr(4, 2), 10); - var hh = parseInt(utc.substr(6, 2), 10); - var mm = parseInt(utc.substr(8, 2), 10); - var ss = 0; - - // not just YYMMDDhhmmZ - if(utc.length > 11) { - // get character after minutes - var c = utc.charAt(10); - var end = 10; - - // see if seconds are present - if(c !== '+' && c !== '-') { - // get seconds - ss = parseInt(utc.substr(10, 2), 10); - end += 2; - } - } - - // update date - date.setUTCFullYear(year, MM, DD); - date.setUTCHours(hh, mm, ss, 0); - - if(end) { - // get +/- after end of time - c = utc.charAt(end); - if(c === '+' || c === '-') { - // get hours+minutes offset - var hhoffset = parseInt(utc.substr(end + 1, 2), 10); - var mmoffset = parseInt(utc.substr(end + 4, 2), 10); - - // calculate offset in milliseconds - var offset = hhoffset * 60 + mmoffset; - offset *= 60000; - - // apply offset - if(c === '+') { - date.setTime(+date - offset); - } else { - date.setTime(+date + offset); - } - } - } - - return date; - }; - - /** - * Converts a GeneralizedTime value to a date. - * - * @param gentime the GeneralizedTime value to convert. - * - * @return the date. - */ - asn1.generalizedTimeToDate = function(gentime) { - /* The following formats can be used: - - YYYYMMDDHHMMSS - YYYYMMDDHHMMSS.fff - YYYYMMDDHHMMSSZ - YYYYMMDDHHMMSS.fffZ - YYYYMMDDHHMMSS+hh'mm' - YYYYMMDDHHMMSS.fff+hh'mm' - YYYYMMDDHHMMSS-hh'mm' - YYYYMMDDHHMMSS.fff-hh'mm' - - Where: - - YYYY is the year - MM is the month (01 to 12) - DD is the day (01 to 31) - hh is the hour (00 to 23) - mm are the minutes (00 to 59) - ss are the seconds (00 to 59) - .fff is the second fraction, accurate to three decimal places - Z indicates that local time is GMT, + indicates that local time is - later than GMT, and - indicates that local time is earlier than GMT - hh' is the absolute value of the offset from GMT in hours - mm' is the absolute value of the offset from GMT in minutes */ - var date = new Date(); - - var YYYY = parseInt(gentime.substr(0, 4), 10); - var MM = parseInt(gentime.substr(4, 2), 10) - 1; // use 0-11 for month - var DD = parseInt(gentime.substr(6, 2), 10); - var hh = parseInt(gentime.substr(8, 2), 10); - var mm = parseInt(gentime.substr(10, 2), 10); - var ss = parseInt(gentime.substr(12, 2), 10); - var fff = 0; - var offset = 0; - var isUTC = false; - - if(gentime.charAt(gentime.length - 1) === 'Z') { - isUTC = true; - } - - var end = gentime.length - 5, c = gentime.charAt(end); - if(c === '+' || c === '-') { - // get hours+minutes offset - var hhoffset = parseInt(gentime.substr(end + 1, 2), 10); - var mmoffset = parseInt(gentime.substr(end + 4, 2), 10); - - // calculate offset in milliseconds - offset = hhoffset * 60 + mmoffset; - offset *= 60000; - - // apply offset - if(c === '+') { - offset *= -1; - } - - isUTC = true; - } - - // check for second fraction - if(gentime.charAt(14) === '.') { - fff = parseFloat(gentime.substr(14), 10) * 1000; - } - - if(isUTC) { - date.setUTCFullYear(YYYY, MM, DD); - date.setUTCHours(hh, mm, ss, fff); - - // apply offset - date.setTime(+date + offset); - } else { - date.setFullYear(YYYY, MM, DD); - date.setHours(hh, mm, ss, fff); - } - - return date; - }; - - /** - * Converts a date to a UTCTime value. - * - * Note: GeneralizedTime has 4 digits for the year and is used for X.509 - * dates past 2049. Converting to a GeneralizedTime hasn't been - * implemented yet. - * - * @param date the date to convert. - * - * @return the UTCTime value. - */ - asn1.dateToUtcTime = function(date) { - // TODO: validate; currently assumes proper format - if(typeof date === 'string') { - return date; - } - - var rval = ''; - - // create format YYMMDDhhmmssZ - var format = []; - format.push(('' + date.getUTCFullYear()).substr(2)); - format.push('' + (date.getUTCMonth() + 1)); - format.push('' + date.getUTCDate()); - format.push('' + date.getUTCHours()); - format.push('' + date.getUTCMinutes()); - format.push('' + date.getUTCSeconds()); - - // ensure 2 digits are used for each format entry - for(var i = 0; i < format.length; ++i) { - if(format[i].length < 2) { - rval += '0'; - } - rval += format[i]; - } - rval += 'Z'; - - return rval; - }; - - /** - * Converts a date to a GeneralizedTime value. - * - * @param date the date to convert. - * - * @return the GeneralizedTime value as a string. - */ - asn1.dateToGeneralizedTime = function(date) { - // TODO: validate; currently assumes proper format - if(typeof date === 'string') { - return date; - } - - var rval = ''; - - // create format YYYYMMDDHHMMSSZ - var format = []; - format.push('' + date.getUTCFullYear()); - format.push('' + (date.getUTCMonth() + 1)); - format.push('' + date.getUTCDate()); - format.push('' + date.getUTCHours()); - format.push('' + date.getUTCMinutes()); - format.push('' + date.getUTCSeconds()); - - // ensure 2 digits are used for each format entry - for(var i = 0; i < format.length; ++i) { - if(format[i].length < 2) { - rval += '0'; - } - rval += format[i]; - } - rval += 'Z'; - - return rval; - }; - - /** - * Converts a javascript integer to a DER-encoded byte buffer to be used - * as the value for an INTEGER type. - * - * @param x the integer. - * - * @return the byte buffer. - */ - asn1.integerToDer = function(x) { - var rval = forge.util.createBuffer(); - if(x >= -0x80 && x < 0x80) { - return rval.putSignedInt(x, 8); - } - if(x >= -0x8000 && x < 0x8000) { - return rval.putSignedInt(x, 16); - } - if(x >= -0x800000 && x < 0x800000) { - return rval.putSignedInt(x, 24); - } - if(x >= -0x80000000 && x < 0x80000000) { - return rval.putSignedInt(x, 32); - } - var error = new Error('Integer too large; max is 32-bits.'); - error.integer = x; - throw error; - }; - - /** - * Converts a DER-encoded byte buffer to a javascript integer. This is - * typically used to decode the value of an INTEGER type. - * - * @param bytes the byte buffer. - * - * @return the integer. - */ - asn1.derToInteger = function(bytes) { - // wrap in buffer if needed - if(typeof bytes === 'string') { - bytes = forge.util.createBuffer(bytes); - } - - var n = bytes.length() * 8; - if(n > 32) { - throw new Error('Integer too large; max is 32-bits.'); - } - return bytes.getSignedInt(n); - }; - - /** - * Validates that the given ASN.1 object is at least a super set of the - * given ASN.1 structure. Only tag classes and types are checked. An - * optional map may also be provided to capture ASN.1 values while the - * structure is checked. - * - * To capture an ASN.1 value, set an object in the validator's 'capture' - * parameter to the key to use in the capture map. To capture the full - * ASN.1 object, specify 'captureAsn1'. To capture BIT STRING bytes, including - * the leading unused bits counter byte, specify 'captureBitStringContents'. - * To capture BIT STRING bytes, without the leading unused bits counter byte, - * specify 'captureBitStringValue'. - * - * Objects in the validator may set a field 'optional' to true to indicate - * that it isn't necessary to pass validation. - * - * @param obj the ASN.1 object to validate. - * @param v the ASN.1 structure validator. - * @param capture an optional map to capture values in. - * @param errors an optional array for storing validation errors. - * - * @return true on success, false on failure. - */ - asn1.validate = function(obj, v, capture, errors) { - var rval = false; - - // ensure tag class and type are the same if specified - if((obj.tagClass === v.tagClass || typeof(v.tagClass) === 'undefined') && - (obj.type === v.type || typeof(v.type) === 'undefined')) { - // ensure constructed flag is the same if specified - if(obj.constructed === v.constructed || - typeof(v.constructed) === 'undefined') { - rval = true; - - // handle sub values - if(v.value && forge.util.isArray(v.value)) { - var j = 0; - for(var i = 0; rval && i < v.value.length; ++i) { - rval = v.value[i].optional || false; - if(obj.value[j]) { - rval = asn1.validate(obj.value[j], v.value[i], capture, errors); - if(rval) { - ++j; - } else if(v.value[i].optional) { - rval = true; - } - } - if(!rval && errors) { - errors.push( - '[' + v.name + '] ' + - 'Tag class "' + v.tagClass + '", type "' + - v.type + '" expected value length "' + - v.value.length + '", got "' + - obj.value.length + '"'); - } - } - } - - if(rval && capture) { - if(v.capture) { - capture[v.capture] = obj.value; - } - if(v.captureAsn1) { - capture[v.captureAsn1] = obj; - } - if(v.captureBitStringContents && 'bitStringContents' in obj) { - capture[v.captureBitStringContents] = obj.bitStringContents; - } - if(v.captureBitStringValue && 'bitStringContents' in obj) { - if(obj.bitStringContents.length < 2) { - capture[v.captureBitStringValue] = ''; - } else { - // FIXME: support unused bits with data shifting - var unused = obj.bitStringContents.charCodeAt(0); - if(unused !== 0) { - throw new Error( - 'captureBitStringValue only supported for zero unused bits'); - } - capture[v.captureBitStringValue] = obj.bitStringContents.slice(1); - } - } - } - } else if(errors) { - errors.push( - '[' + v.name + '] ' + - 'Expected constructed "' + v.constructed + '", got "' + - obj.constructed + '"'); - } - } else if(errors) { - if(obj.tagClass !== v.tagClass) { - errors.push( - '[' + v.name + '] ' + - 'Expected tag class "' + v.tagClass + '", got "' + - obj.tagClass + '"'); - } - if(obj.type !== v.type) { - errors.push( - '[' + v.name + '] ' + - 'Expected type "' + v.type + '", got "' + obj.type + '"'); - } - } - return rval; - }; - - // regex for testing for non-latin characters - var _nonLatinRegex = /[^\\u0000-\\u00ff]/; - - /** - * Pretty prints an ASN.1 object to a string. - * - * @param obj the object to write out. - * @param level the level in the tree. - * @param indentation the indentation to use. - * - * @return the string. - */ - asn1.prettyPrint = function(obj, level, indentation) { - var rval = ''; - - // set default level and indentation - level = level || 0; - indentation = indentation || 2; - - // start new line for deep levels - if(level > 0) { - rval += '\n'; - } - - // create indent - var indent = ''; - for(var i = 0; i < level * indentation; ++i) { - indent += ' '; - } - - // print class:type - rval += indent + 'Tag: '; - switch(obj.tagClass) { - case asn1.Class.UNIVERSAL: - rval += 'Universal:'; - break; - case asn1.Class.APPLICATION: - rval += 'Application:'; - break; - case asn1.Class.CONTEXT_SPECIFIC: - rval += 'Context-Specific:'; - break; - case asn1.Class.PRIVATE: - rval += 'Private:'; - break; - } - - if(obj.tagClass === asn1.Class.UNIVERSAL) { - rval += obj.type; - - // known types - switch(obj.type) { - case asn1.Type.NONE: - rval += ' (None)'; - break; - case asn1.Type.BOOLEAN: - rval += ' (Boolean)'; - break; - case asn1.Type.INTEGER: - rval += ' (Integer)'; - break; - case asn1.Type.BITSTRING: - rval += ' (Bit string)'; - break; - case asn1.Type.OCTETSTRING: - rval += ' (Octet string)'; - break; - case asn1.Type.NULL: - rval += ' (Null)'; - break; - case asn1.Type.OID: - rval += ' (Object Identifier)'; - break; - case asn1.Type.ODESC: - rval += ' (Object Descriptor)'; - break; - case asn1.Type.EXTERNAL: - rval += ' (External or Instance of)'; - break; - case asn1.Type.REAL: - rval += ' (Real)'; - break; - case asn1.Type.ENUMERATED: - rval += ' (Enumerated)'; - break; - case asn1.Type.EMBEDDED: - rval += ' (Embedded PDV)'; - break; - case asn1.Type.UTF8: - rval += ' (UTF8)'; - break; - case asn1.Type.ROID: - rval += ' (Relative Object Identifier)'; - break; - case asn1.Type.SEQUENCE: - rval += ' (Sequence)'; - break; - case asn1.Type.SET: - rval += ' (Set)'; - break; - case asn1.Type.PRINTABLESTRING: - rval += ' (Printable String)'; - break; - case asn1.Type.IA5String: - rval += ' (IA5String (ASCII))'; - break; - case asn1.Type.UTCTIME: - rval += ' (UTC time)'; - break; - case asn1.Type.GENERALIZEDTIME: - rval += ' (Generalized time)'; - break; - case asn1.Type.BMPSTRING: - rval += ' (BMP String)'; - break; - } - } else { - rval += obj.type; - } - - rval += '\n'; - rval += indent + 'Constructed: ' + obj.constructed + '\n'; - - if(obj.composed) { - var subvalues = 0; - var sub = ''; - for(var i = 0; i < obj.value.length; ++i) { - if(obj.value[i] !== undefined) { - subvalues += 1; - sub += asn1.prettyPrint(obj.value[i], level + 1, indentation); - if((i + 1) < obj.value.length) { - sub += ','; - } - } - } - rval += indent + 'Sub values: ' + subvalues + sub; - } else { - rval += indent + 'Value: '; - if(obj.type === asn1.Type.OID) { - var oid = asn1.derToOid(obj.value); - rval += oid; - if(forge.pki && forge.pki.oids) { - if(oid in forge.pki.oids) { - rval += ' (' + forge.pki.oids[oid] + ') '; - } - } - } - if(obj.type === asn1.Type.INTEGER) { - try { - rval += asn1.derToInteger(obj.value); - } catch(ex) { - rval += '0x' + forge.util.bytesToHex(obj.value); - } - } else if(obj.type === asn1.Type.BITSTRING) { - // TODO: shift bits as needed to display without padding - if(obj.value.length > 1) { - // remove unused bits field - rval += '0x' + forge.util.bytesToHex(obj.value.slice(1)); - } else { - rval += '(none)'; - } - // show unused bit count - if(obj.value.length > 0) { - var unused = obj.value.charCodeAt(0); - if(unused == 1) { - rval += ' (1 unused bit shown)'; - } else if(unused > 1) { - rval += ' (' + unused + ' unused bits shown)'; - } - } - } else if(obj.type === asn1.Type.OCTETSTRING) { - if(!_nonLatinRegex.test(obj.value)) { - rval += '(' + obj.value + ') '; - } - rval += '0x' + forge.util.bytesToHex(obj.value); - } else if(obj.type === asn1.Type.UTF8) { - rval += forge.util.decodeUtf8(obj.value); - } else if(obj.type === asn1.Type.PRINTABLESTRING || - obj.type === asn1.Type.IA5String) { - rval += obj.value; - } else if(_nonLatinRegex.test(obj.value)) { - rval += '0x' + forge.util.bytesToHex(obj.value); - } else if(obj.value.length === 0) { - rval += '[null]'; - } else { - rval += obj.value; - } - } - - return rval; - }; - }); - - /** - * Node.js module for Forge message digests. - * - * @author Dave Longley - * - * Copyright 2011-2017 Digital Bazaar, Inc. - */ - - - var md = forge.md = forge.md || {}; - forge.md.algorithms = forge.md.algorithms || {}; - - var hmac_1 = createCommonjsModule(function (module) { - /** - * Hash-based Message Authentication Code implementation. Requires a message - * digest object that can be obtained, for example, from forge.md.sha1 or - * forge.md.md5. - * - * @author Dave Longley - * - * Copyright (c) 2010-2012 Digital Bazaar, Inc. All rights reserved. - */ - - - - - /* HMAC API */ - var hmac = module.exports = forge.hmac = forge.hmac || {}; - - /** - * Creates an HMAC object that uses the given message digest object. - * - * @return an HMAC object. - */ - hmac.create = function() { - // the hmac key to use - var _key = null; - - // the message digest to use - var _md = null; - - // the inner padding - var _ipadding = null; - - // the outer padding - var _opadding = null; - - // hmac context - var ctx = {}; - - /** - * Starts or restarts the HMAC with the given key and message digest. - * - * @param md the message digest to use, null to reuse the previous one, - * a string to use builtin 'sha1', 'md5', 'sha256'. - * @param key the key to use as a string, array of bytes, byte buffer, - * or null to reuse the previous key. - */ - ctx.start = function(md, key) { - if(md !== null) { - if(typeof md === 'string') { - // create builtin message digest - md = md.toLowerCase(); - if(md in forge.md.algorithms) { - _md = forge.md.algorithms[md].create(); - } else { - throw new Error('Unknown hash algorithm "' + md + '"'); - } - } else { - // store message digest - _md = md; - } - } - - if(key === null) { - // reuse previous key - key = _key; - } else { - if(typeof key === 'string') { - // convert string into byte buffer - key = forge.util.createBuffer(key); - } else if(forge.util.isArray(key)) { - // convert byte array into byte buffer - var tmp = key; - key = forge.util.createBuffer(); - for(var i = 0; i < tmp.length; ++i) { - key.putByte(tmp[i]); - } - } - - // if key is longer than blocksize, hash it - var keylen = key.length(); - if(keylen > _md.blockLength) { - _md.start(); - _md.update(key.bytes()); - key = _md.digest(); - } - - // mix key into inner and outer padding - // ipadding = [0x36 * blocksize] ^ key - // opadding = [0x5C * blocksize] ^ key - _ipadding = forge.util.createBuffer(); - _opadding = forge.util.createBuffer(); - keylen = key.length(); - for(var i = 0; i < keylen; ++i) { - var tmp = key.at(i); - _ipadding.putByte(0x36 ^ tmp); - _opadding.putByte(0x5C ^ tmp); - } - - // if key is shorter than blocksize, add additional padding - if(keylen < _md.blockLength) { - var tmp = _md.blockLength - keylen; - for(var i = 0; i < tmp; ++i) { - _ipadding.putByte(0x36); - _opadding.putByte(0x5C); - } - } - _key = key; - _ipadding = _ipadding.bytes(); - _opadding = _opadding.bytes(); - } - - // digest is done like so: hash(opadding | hash(ipadding | message)) - - // prepare to do inner hash - // hash(ipadding | message) - _md.start(); - _md.update(_ipadding); - }; - - /** - * Updates the HMAC with the given message bytes. - * - * @param bytes the bytes to update with. - */ - ctx.update = function(bytes) { - _md.update(bytes); - }; - - /** - * Produces the Message Authentication Code (MAC). - * - * @return a byte buffer containing the digest value. - */ - ctx.getMac = function() { - // digest is done like so: hash(opadding | hash(ipadding | message)) - // here we do the outer hashing - var inner = _md.digest().bytes(); - _md.start(); - _md.update(_opadding); - _md.update(inner); - return _md.digest(); - }; - // alias for getMac - ctx.digest = ctx.getMac; - - return ctx; - }; - }); - - var md5_1 = createCommonjsModule(function (module) { - /** - * Message Digest Algorithm 5 with 128-bit digest (MD5) implementation. - * - * @author Dave Longley - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - */ - - - - - var md5 = module.exports = forge.md5 = forge.md5 || {}; - forge.md.md5 = forge.md.algorithms.md5 = md5; - - /** - * Creates an MD5 message digest object. - * - * @return a message digest object. - */ - md5.create = function() { - // do initialization as necessary - if(!_initialized) { - _init(); - } - - // MD5 state contains four 32-bit integers - var _state = null; - - // input buffer - var _input = forge.util.createBuffer(); - - // used for word storage - var _w = new Array(16); - - // message digest object - var md = { - algorithm: 'md5', - blockLength: 64, - digestLength: 16, - // 56-bit length of message so far (does not including padding) - messageLength: 0, - // true message length - fullMessageLength: null, - // size of message length in bytes - messageLengthSize: 8 - }; - - /** - * Starts the digest. - * - * @return this digest object. - */ - md.start = function() { - // up to 56-bit message length for convenience - md.messageLength = 0; - - // full message length (set md.messageLength64 for backwards-compatibility) - md.fullMessageLength = md.messageLength64 = []; - var int32s = md.messageLengthSize / 4; - for(var i = 0; i < int32s; ++i) { - md.fullMessageLength.push(0); - } - _input = forge.util.createBuffer(); - _state = { - h0: 0x67452301, - h1: 0xEFCDAB89, - h2: 0x98BADCFE, - h3: 0x10325476 - }; - return md; - }; - // start digest automatically for first time - md.start(); - - /** - * Updates the digest with the given message input. The given input can - * treated as raw input (no encoding will be applied) or an encoding of - * 'utf8' maybe given to encode the input using UTF-8. - * - * @param msg the message input to update with. - * @param encoding the encoding to use (default: 'raw', other: 'utf8'). - * - * @return this digest object. - */ - md.update = function(msg, encoding) { - if(encoding === 'utf8') { - msg = forge.util.encodeUtf8(msg); - } - - // update message length - var len = msg.length; - md.messageLength += len; - len = [(len / 0x100000000) >>> 0, len >>> 0]; - for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { - md.fullMessageLength[i] += len[1]; - len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); - md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; - len[0] = (len[1] / 0x100000000) >>> 0; - } - - // add bytes to input buffer - _input.putBytes(msg); - - // process bytes - _update(_state, _w, _input); - - // compact input buffer every 2K or if empty - if(_input.read > 2048 || _input.length() === 0) { - _input.compact(); - } - - return md; - }; - - /** - * Produces the digest. - * - * @return a byte buffer containing the digest value. - */ - md.digest = function() { - /* Note: Here we copy the remaining bytes in the input buffer and - add the appropriate MD5 padding. Then we do the final update - on a copy of the state so that if the user wants to get - intermediate digests they can do so. */ - - /* Determine the number of bytes that must be added to the message - to ensure its length is congruent to 448 mod 512. In other words, - the data to be digested must be a multiple of 512 bits (or 128 bytes). - This data includes the message, some padding, and the length of the - message. Since the length of the message will be encoded as 8 bytes (64 - bits), that means that the last segment of the data must have 56 bytes - (448 bits) of message and padding. Therefore, the length of the message - plus the padding must be congruent to 448 mod 512 because - 512 - 128 = 448. - - In order to fill up the message length it must be filled with - padding that begins with 1 bit followed by all 0 bits. Padding - must *always* be present, so if the message length is already - congruent to 448 mod 512, then 512 padding bits must be added. */ - - var finalBlock = forge.util.createBuffer(); - finalBlock.putBytes(_input.bytes()); - - // compute remaining size to be digested (include message length size) - var remaining = ( - md.fullMessageLength[md.fullMessageLength.length - 1] + - md.messageLengthSize); - - // add padding for overflow blockSize - overflow - // _padding starts with 1 byte with first bit is set (byte value 128), then - // there may be up to (blockSize - 1) other pad bytes - var overflow = remaining & (md.blockLength - 1); - finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); - - // serialize message length in bits in little-endian order; since length - // is stored in bytes we multiply by 8 and add carry - var bits, carry = 0; - for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { - bits = md.fullMessageLength[i] * 8 + carry; - carry = (bits / 0x100000000) >>> 0; - finalBlock.putInt32Le(bits >>> 0); - } - - var s2 = { - h0: _state.h0, - h1: _state.h1, - h2: _state.h2, - h3: _state.h3 - }; - _update(s2, _w, finalBlock); - var rval = forge.util.createBuffer(); - rval.putInt32Le(s2.h0); - rval.putInt32Le(s2.h1); - rval.putInt32Le(s2.h2); - rval.putInt32Le(s2.h3); - return rval; - }; - - return md; - }; - - // padding, constant tables for calculating md5 - var _padding = null; - var _g = null; - var _r = null; - var _k = null; - var _initialized = false; - - /** - * Initializes the constant tables. - */ - function _init() { - // create padding - _padding = String.fromCharCode(128); - _padding += forge.util.fillString(String.fromCharCode(0x00), 64); - - // g values - _g = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, - 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, - 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9]; - - // rounds table - _r = [ - 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]; - - // get the result of abs(sin(i + 1)) as a 32-bit integer - _k = new Array(64); - for(var i = 0; i < 64; ++i) { - _k[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 0x100000000); - } - - // now initialized - _initialized = true; - } - - /** - * Updates an MD5 state with the given byte buffer. - * - * @param s the MD5 state to update. - * @param w the array to use to store words. - * @param bytes the byte buffer to update with. - */ - function _update(s, w, bytes) { - // consume 512 bit (64 byte) chunks - var t, a, b, c, d, f, r, i; - var len = bytes.length(); - while(len >= 64) { - // initialize hash value for this chunk - a = s.h0; - b = s.h1; - c = s.h2; - d = s.h3; - - // round 1 - for(i = 0; i < 16; ++i) { - w[i] = bytes.getInt32Le(); - f = d ^ (b & (c ^ d)); - t = (a + f + _k[i] + w[i]); - r = _r[i]; - a = d; - d = c; - c = b; - b += (t << r) | (t >>> (32 - r)); - } - // round 2 - for(; i < 32; ++i) { - f = c ^ (d & (b ^ c)); - t = (a + f + _k[i] + w[_g[i]]); - r = _r[i]; - a = d; - d = c; - c = b; - b += (t << r) | (t >>> (32 - r)); - } - // round 3 - for(; i < 48; ++i) { - f = b ^ c ^ d; - t = (a + f + _k[i] + w[_g[i]]); - r = _r[i]; - a = d; - d = c; - c = b; - b += (t << r) | (t >>> (32 - r)); - } - // round 4 - for(; i < 64; ++i) { - f = c ^ (b | ~d); - t = (a + f + _k[i] + w[_g[i]]); - r = _r[i]; - a = d; - d = c; - c = b; - b += (t << r) | (t >>> (32 - r)); - } - - // update hash state - s.h0 = (s.h0 + a) | 0; - s.h1 = (s.h1 + b) | 0; - s.h2 = (s.h2 + c) | 0; - s.h3 = (s.h3 + d) | 0; - - len -= 64; - } - } - }); - - var pem_1 = createCommonjsModule(function (module) { - /** - * Javascript implementation of basic PEM (Privacy Enhanced Mail) algorithms. - * - * See: RFC 1421. - * - * @author Dave Longley - * - * Copyright (c) 2013-2014 Digital Bazaar, Inc. - * - * A Forge PEM object has the following fields: - * - * type: identifies the type of message (eg: "RSA PRIVATE KEY"). - * - * procType: identifies the type of processing performed on the message, - * it has two subfields: version and type, eg: 4,ENCRYPTED. - * - * contentDomain: identifies the type of content in the message, typically - * only uses the value: "RFC822". - * - * dekInfo: identifies the message encryption algorithm and mode and includes - * any parameters for the algorithm, it has two subfields: algorithm and - * parameters, eg: DES-CBC,F8143EDE5960C597. - * - * headers: contains all other PEM encapsulated headers -- where order is - * significant (for pairing data like recipient ID + key info). - * - * body: the binary-encoded body. - */ - - - - // shortcut for pem API - var pem = module.exports = forge.pem = forge.pem || {}; - - /** - * Encodes (serializes) the given PEM object. - * - * @param msg the PEM message object to encode. - * @param options the options to use: - * maxline the maximum characters per line for the body, (default: 64). - * - * @return the PEM-formatted string. - */ - pem.encode = function(msg, options) { - options = options || {}; - var rval = '-----BEGIN ' + msg.type + '-----\r\n'; - - // encode special headers - var header; - if(msg.procType) { - header = { - name: 'Proc-Type', - values: [String(msg.procType.version), msg.procType.type] - }; - rval += foldHeader(header); - } - if(msg.contentDomain) { - header = {name: 'Content-Domain', values: [msg.contentDomain]}; - rval += foldHeader(header); - } - if(msg.dekInfo) { - header = {name: 'DEK-Info', values: [msg.dekInfo.algorithm]}; - if(msg.dekInfo.parameters) { - header.values.push(msg.dekInfo.parameters); - } - rval += foldHeader(header); - } - - if(msg.headers) { - // encode all other headers - for(var i = 0; i < msg.headers.length; ++i) { - rval += foldHeader(msg.headers[i]); - } - } - - // terminate header - if(msg.procType) { - rval += '\r\n'; - } - - // add body - rval += forge.util.encode64(msg.body, options.maxline || 64) + '\r\n'; - - rval += '-----END ' + msg.type + '-----\r\n'; - return rval; - }; - - /** - * Decodes (deserializes) all PEM messages found in the given string. - * - * @param str the PEM-formatted string to decode. - * - * @return the PEM message objects in an array. - */ - pem.decode = function(str) { - var rval = []; - - // split string into PEM messages (be lenient w/EOF on BEGIN line) - var rMessage = /\s*-----BEGIN ([A-Z0-9- ]+)-----\r?\n?([\x21-\x7e\s]+?(?:\r?\n\r?\n))?([:A-Za-z0-9+\/=\s]+?)-----END \1-----/g; - var rHeader = /([\x21-\x7e]+):\s*([\x21-\x7e\s^:]+)/; - var rCRLF = /\r?\n/; - var match; - while(true) { - match = rMessage.exec(str); - if(!match) { - break; - } - - var msg = { - type: match[1], - procType: null, - contentDomain: null, - dekInfo: null, - headers: [], - body: forge.util.decode64(match[3]) - }; - rval.push(msg); - - // no headers - if(!match[2]) { - continue; - } - - // parse headers - var lines = match[2].split(rCRLF); - var li = 0; - while(match && li < lines.length) { - // get line, trim any rhs whitespace - var line = lines[li].replace(/\s+$/, ''); - - // RFC2822 unfold any following folded lines - for(var nl = li + 1; nl < lines.length; ++nl) { - var next = lines[nl]; - if(!/\s/.test(next[0])) { - break; - } - line += next; - li = nl; - } - - // parse header - match = line.match(rHeader); - if(match) { - var header = {name: match[1], values: []}; - var values = match[2].split(','); - for(var vi = 0; vi < values.length; ++vi) { - header.values.push(ltrim(values[vi])); - } - - // Proc-Type must be the first header - if(!msg.procType) { - if(header.name !== 'Proc-Type') { - throw new Error('Invalid PEM formatted message. The first ' + - 'encapsulated header must be "Proc-Type".'); - } else if(header.values.length !== 2) { - throw new Error('Invalid PEM formatted message. The "Proc-Type" ' + - 'header must have two subfields.'); - } - msg.procType = {version: values[0], type: values[1]}; - } else if(!msg.contentDomain && header.name === 'Content-Domain') { - // special-case Content-Domain - msg.contentDomain = values[0] || ''; - } else if(!msg.dekInfo && header.name === 'DEK-Info') { - // special-case DEK-Info - if(header.values.length === 0) { - throw new Error('Invalid PEM formatted message. The "DEK-Info" ' + - 'header must have at least one subfield.'); - } - msg.dekInfo = {algorithm: values[0], parameters: values[1] || null}; - } else { - msg.headers.push(header); - } - } - - ++li; - } - - if(msg.procType === 'ENCRYPTED' && !msg.dekInfo) { - throw new Error('Invalid PEM formatted message. The "DEK-Info" ' + - 'header must be present if "Proc-Type" is "ENCRYPTED".'); - } - } - - if(rval.length === 0) { - throw new Error('Invalid PEM formatted message.'); - } - - return rval; - }; - - function foldHeader(header) { - var rval = header.name + ': '; - - // ensure values with CRLF are folded - var values = []; - var insertSpace = function(match, $1) { - return ' ' + $1; - }; - for(var i = 0; i < header.values.length; ++i) { - values.push(header.values[i].replace(/^(\S+\r\n)/, insertSpace)); - } - rval += values.join(',') + '\r\n'; - - // do folding - var length = 0; - var candidate = -1; - for(var i = 0; i < rval.length; ++i, ++length) { - if(length > 65 && candidate !== -1) { - var insert = rval[candidate]; - if(insert === ',') { - ++candidate; - rval = rval.substr(0, candidate) + '\r\n ' + rval.substr(candidate); - } else { - rval = rval.substr(0, candidate) + - '\r\n' + insert + rval.substr(candidate + 1); - } - length = (i - candidate - 1); - candidate = -1; - ++i; - } else if(rval[i] === ' ' || rval[i] === '\t' || rval[i] === ',') { - candidate = i; - } - } - - return rval; - } - - function ltrim(str) { - return str.replace(/^\s+/, ''); - } - }); - - /** - * DES (Data Encryption Standard) implementation. - * - * This implementation supports DES as well as 3DES-EDE in ECB and CBC mode. - * It is based on the BSD-licensed implementation by Paul Tero: - * - * Paul Tero, July 2001 - * http://www.tero.co.uk/des/ - * - * Optimised for performance with large blocks by - * Michael Hayworth, November 2001 - * http://www.netdealing.com - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @author Stefan Siegl - * @author Dave Longley - * - * Copyright (c) 2012 Stefan Siegl - * Copyright (c) 2012-2014 Digital Bazaar, Inc. - */ - - - - - - /* DES API */ - var des = forge.des = forge.des || {}; - - /** - * Deprecated. Instead, use: - * - * var cipher = forge.cipher.createCipher('DES-', key); - * cipher.start({iv: iv}); - * - * Creates an DES cipher object to encrypt data using the given symmetric key. - * The output will be stored in the 'output' member of the returned cipher. - * - * The key and iv may be given as binary-encoded strings of bytes or - * byte buffers. - * - * @param key the symmetric key to use (64 or 192 bits). - * @param iv the initialization vector to use. - * @param output the buffer to write to, null to create one. - * @param mode the cipher mode to use (default: 'CBC' if IV is - * given, 'ECB' if null). - * - * @return the cipher. - */ - forge.des.startEncrypting = function(key, iv, output, mode) { - var cipher = _createCipher$1({ - key: key, - output: output, - decrypt: false, - mode: mode || (iv === null ? 'ECB' : 'CBC') - }); - cipher.start(iv); - return cipher; - }; - - /** - * Deprecated. Instead, use: - * - * var cipher = forge.cipher.createCipher('DES-', key); - * - * Creates an DES cipher object to encrypt data using the given symmetric key. - * - * The key may be given as a binary-encoded string of bytes or a byte buffer. - * - * @param key the symmetric key to use (64 or 192 bits). - * @param mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - forge.des.createEncryptionCipher = function(key, mode) { - return _createCipher$1({ - key: key, - output: null, - decrypt: false, - mode: mode - }); - }; - - /** - * Deprecated. Instead, use: - * - * var decipher = forge.cipher.createDecipher('DES-', key); - * decipher.start({iv: iv}); - * - * Creates an DES cipher object to decrypt data using the given symmetric key. - * The output will be stored in the 'output' member of the returned cipher. - * - * The key and iv may be given as binary-encoded strings of bytes or - * byte buffers. - * - * @param key the symmetric key to use (64 or 192 bits). - * @param iv the initialization vector to use. - * @param output the buffer to write to, null to create one. - * @param mode the cipher mode to use (default: 'CBC' if IV is - * given, 'ECB' if null). - * - * @return the cipher. - */ - forge.des.startDecrypting = function(key, iv, output, mode) { - var cipher = _createCipher$1({ - key: key, - output: output, - decrypt: true, - mode: mode || (iv === null ? 'ECB' : 'CBC') - }); - cipher.start(iv); - return cipher; - }; - - /** - * Deprecated. Instead, use: - * - * var decipher = forge.cipher.createDecipher('DES-', key); - * - * Creates an DES cipher object to decrypt data using the given symmetric key. - * - * The key may be given as a binary-encoded string of bytes or a byte buffer. - * - * @param key the symmetric key to use (64 or 192 bits). - * @param mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - forge.des.createDecryptionCipher = function(key, mode) { - return _createCipher$1({ - key: key, - output: null, - decrypt: true, - mode: mode - }); - }; - - /** - * Creates a new DES cipher algorithm object. - * - * @param name the name of the algorithm. - * @param mode the mode factory function. - * - * @return the DES algorithm object. - */ - forge.des.Algorithm = function(name, mode) { - var self = this; - self.name = name; - self.mode = new mode({ - blockSize: 8, - cipher: { - encrypt: function(inBlock, outBlock) { - return _updateBlock$1(self._keys, inBlock, outBlock, false); - }, - decrypt: function(inBlock, outBlock) { - return _updateBlock$1(self._keys, inBlock, outBlock, true); - } - } - }); - self._init = false; - }; - - /** - * Initializes this DES algorithm by expanding its key. - * - * @param options the options to use. - * key the key to use with this algorithm. - * decrypt true if the algorithm should be initialized for decryption, - * false for encryption. - */ - forge.des.Algorithm.prototype.initialize = function(options) { - if(this._init) { - return; - } - - var key = forge.util.createBuffer(options.key); - if(this.name.indexOf('3DES') === 0) { - if(key.length() !== 24) { - throw new Error('Invalid Triple-DES key size: ' + key.length() * 8); - } - } - - // do key expansion to 16 or 48 subkeys (single or triple DES) - this._keys = _createKeys(key); - this._init = true; - }; - - /** Register DES algorithms **/ - - registerAlgorithm$1('DES-ECB', forge.cipher.modes.ecb); - registerAlgorithm$1('DES-CBC', forge.cipher.modes.cbc); - registerAlgorithm$1('DES-CFB', forge.cipher.modes.cfb); - registerAlgorithm$1('DES-OFB', forge.cipher.modes.ofb); - registerAlgorithm$1('DES-CTR', forge.cipher.modes.ctr); - - registerAlgorithm$1('3DES-ECB', forge.cipher.modes.ecb); - registerAlgorithm$1('3DES-CBC', forge.cipher.modes.cbc); - registerAlgorithm$1('3DES-CFB', forge.cipher.modes.cfb); - registerAlgorithm$1('3DES-OFB', forge.cipher.modes.ofb); - registerAlgorithm$1('3DES-CTR', forge.cipher.modes.ctr); - - function registerAlgorithm$1(name, mode) { - var factory = function() { - return new forge.des.Algorithm(name, mode); - }; - forge.cipher.registerAlgorithm(name, factory); - } - - /** DES implementation **/ - - var spfunction1 = [0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004]; - var spfunction2 = [-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000]; - var spfunction3 = [0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200]; - var spfunction4 = [0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080]; - var spfunction5 = [0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100]; - var spfunction6 = [0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010]; - var spfunction7 = [0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002]; - var spfunction8 = [0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000]; - - /** - * Create necessary sub keys. - * - * @param key the 64-bit or 192-bit key. - * - * @return the expanded keys. - */ - function _createKeys(key) { - var pc2bytes0 = [0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204], - pc2bytes1 = [0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101], - pc2bytes2 = [0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808], - pc2bytes3 = [0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000], - pc2bytes4 = [0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010], - pc2bytes5 = [0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420], - pc2bytes6 = [0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002], - pc2bytes7 = [0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800], - pc2bytes8 = [0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002], - pc2bytes9 = [0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408], - pc2bytes10 = [0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020], - pc2bytes11 = [0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200], - pc2bytes12 = [0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010], - pc2bytes13 = [0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105]; - - // how many iterations (1 for des, 3 for triple des) - // changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys - var iterations = key.length() > 8 ? 3 : 1; - - // stores the return keys - var keys = []; - - // now define the left shifts which need to be done - var shifts = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]; - - var n = 0, tmp; - for(var j = 0; j < iterations; j++) { - var left = key.getInt32(); - var right = key.getInt32(); - - tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; - right ^= tmp; - left ^= (tmp << 4); - - tmp = ((right >>> -16) ^ left) & 0x0000ffff; - left ^= tmp; - right ^= (tmp << -16); - - tmp = ((left >>> 2) ^ right) & 0x33333333; - right ^= tmp; - left ^= (tmp << 2); - - tmp = ((right >>> -16) ^ left) & 0x0000ffff; - left ^= tmp; - right ^= (tmp << -16); - - tmp = ((left >>> 1) ^ right) & 0x55555555; - right ^= tmp; - left ^= (tmp << 1); - - tmp = ((right >>> 8) ^ left) & 0x00ff00ff; - left ^= tmp; - right ^= (tmp << 8); - - tmp = ((left >>> 1) ^ right) & 0x55555555; - right ^= tmp; - left ^= (tmp << 1); - - // right needs to be shifted and OR'd with last four bits of left - tmp = (left << 8) | ((right >>> 20) & 0x000000f0); - - // left needs to be put upside down - left = ((right << 24) | ((right << 8) & 0xff0000) | - ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0)); - right = tmp; - - // now go through and perform these shifts on the left and right keys - for(var i = 0; i < shifts.length; ++i) { - //shift the keys either one or two bits to the left - if(shifts[i]) { - left = (left << 2) | (left >>> 26); - right = (right << 2) | (right >>> 26); - } else { - left = (left << 1) | (left >>> 27); - right = (right << 1) | (right >>> 27); - } - left &= -0xf; - right &= -0xf; - - // now apply PC-2, in such a way that E is easier when encrypting or - // decrypting this conversion will look like PC-2 except only the last 6 - // bits of each byte are used rather than 48 consecutive bits and the - // order of lines will be according to how the S selection functions will - // be applied: S2, S4, S6, S8, S1, S3, S5, S7 - var lefttmp = ( - pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | - pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf] | - pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | - pc2bytes6[(left >>> 4) & 0xf]); - var righttmp = ( - pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | - pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf] | - pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] | - pc2bytes13[(right >>> 4) & 0xf]); - tmp = ((righttmp >>> 16) ^ lefttmp) & 0x0000ffff; - keys[n++] = lefttmp ^ tmp; - keys[n++] = righttmp ^ (tmp << 16); - } - } - - return keys; - } - - /** - * Updates a single block (1 byte) using DES. The update will either - * encrypt or decrypt the block. - * - * @param keys the expanded keys. - * @param input the input block (an array of 32-bit words). - * @param output the updated output block. - * @param decrypt true to decrypt the block, false to encrypt it. - */ - function _updateBlock$1(keys, input, output, decrypt) { - // set up loops for single or triple DES - var iterations = keys.length === 32 ? 3 : 9; - var looping; - if(iterations === 3) { - looping = decrypt ? [30, -2, -2] : [0, 32, 2]; - } else { - looping = (decrypt ? - [94, 62, -2, 32, 64, 2, 30, -2, -2] : - [0, 32, 2, 62, 30, -2, 64, 96, 2]); - } - - var tmp; - - var left = input[0]; - var right = input[1]; - - // first each 64 bit chunk of the message must be permuted according to IP - tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; - right ^= tmp; - left ^= (tmp << 4); - - tmp = ((left >>> 16) ^ right) & 0x0000ffff; - right ^= tmp; - left ^= (tmp << 16); - - tmp = ((right >>> 2) ^ left) & 0x33333333; - left ^= tmp; - right ^= (tmp << 2); - - tmp = ((right >>> 8) ^ left) & 0x00ff00ff; - left ^= tmp; - right ^= (tmp << 8); - - tmp = ((left >>> 1) ^ right) & 0x55555555; - right ^= tmp; - left ^= (tmp << 1); - - // rotate left 1 bit - left = ((left << 1) | (left >>> 31)); - right = ((right << 1) | (right >>> 31)); - - for(var j = 0; j < iterations; j += 3) { - var endloop = looping[j + 1]; - var loopinc = looping[j + 2]; - - // now go through and perform the encryption or decryption - for(var i = looping[j]; i != endloop; i += loopinc) { - var right1 = right ^ keys[i]; - var right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1]; - - // passing these bytes through the S selection functions - tmp = left; - left = right; - right = tmp ^ ( - spfunction2[(right1 >>> 24) & 0x3f] | - spfunction4[(right1 >>> 16) & 0x3f] | - spfunction6[(right1 >>> 8) & 0x3f] | - spfunction8[right1 & 0x3f] | - spfunction1[(right2 >>> 24) & 0x3f] | - spfunction3[(right2 >>> 16) & 0x3f] | - spfunction5[(right2 >>> 8) & 0x3f] | - spfunction7[right2 & 0x3f]); - } - // unreverse left and right - tmp = left; - left = right; - right = tmp; - } - - // rotate right 1 bit - left = ((left >>> 1) | (left << 31)); - right = ((right >>> 1) | (right << 31)); - - // now perform IP-1, which is IP in the opposite direction - tmp = ((left >>> 1) ^ right) & 0x55555555; - right ^= tmp; - left ^= (tmp << 1); - - tmp = ((right >>> 8) ^ left) & 0x00ff00ff; - left ^= tmp; - right ^= (tmp << 8); - - tmp = ((right >>> 2) ^ left) & 0x33333333; - left ^= tmp; - right ^= (tmp << 2); - - tmp = ((left >>> 16) ^ right) & 0x0000ffff; - right ^= tmp; - left ^= (tmp << 16); - - tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; - right ^= tmp; - left ^= (tmp << 4); - - output[0] = left; - output[1] = right; - } - - /** - * Deprecated. Instead, use: - * - * forge.cipher.createCipher('DES-', key); - * forge.cipher.createDecipher('DES-', key); - * - * Creates a deprecated DES cipher object. This object's mode will default to - * CBC (cipher-block-chaining). - * - * The key may be given as a binary-encoded string of bytes or a byte buffer. - * - * @param options the options to use. - * key the symmetric key to use (64 or 192 bits). - * output the buffer to write to. - * decrypt true for decryption, false for encryption. - * mode the cipher mode to use (default: 'CBC'). - * - * @return the cipher. - */ - function _createCipher$1(options) { - options = options || {}; - var mode = (options.mode || 'CBC').toUpperCase(); - var algorithm = 'DES-' + mode; - - var cipher; - if(options.decrypt) { - cipher = forge.cipher.createDecipher(algorithm, options.key); - } else { - cipher = forge.cipher.createCipher(algorithm, options.key); - } - - // backwards compatible start API - var start = cipher.start; - cipher.start = function(iv, options) { - // backwards compatibility: support second arg as output buffer - var output = null; - if(options instanceof forge.util.ByteBuffer) { - output = options; - options = {}; - } - options = options || {}; - options.output = output; - options.iv = iv; - start.call(cipher, options); - }; - - return cipher; - } - - /** - * Password-Based Key-Derivation Function #2 implementation. - * - * See RFC 2898 for details. - * - * @author Dave Longley - * - * Copyright (c) 2010-2013 Digital Bazaar, Inc. - */ - - - - - - var pkcs5 = forge.pkcs5 = forge.pkcs5 || {}; - - var crypto; - if(forge.util.isNodejs && !forge.options.usePureJavaScript) { - crypto = require$$7; - } - - /** - * Derives a key from a password. - * - * @param p the password as a binary-encoded string of bytes. - * @param s the salt as a binary-encoded string of bytes. - * @param c the iteration count, a positive integer. - * @param dkLen the intended length, in bytes, of the derived key, - * (max: 2^32 - 1) * hash length of the PRF. - * @param [md] the message digest (or algorithm identifier as a string) to use - * in the PRF, defaults to SHA-1. - * @param [callback(err, key)] presence triggers asynchronous version, called - * once the operation completes. - * - * @return the derived key, as a binary-encoded string of bytes, for the - * synchronous version (if no callback is specified). - */ - var pbkdf2 = forge.pbkdf2 = pkcs5.pbkdf2 = function( - p, s, c, dkLen, md, callback) { - if(typeof md === 'function') { - callback = md; - md = null; - } - - // use native implementation if possible and not disabled, note that - // some node versions only support SHA-1, others allow digest to be changed - if(forge.util.isNodejs && !forge.options.usePureJavaScript && - crypto.pbkdf2 && (md === null || typeof md !== 'object') && - (crypto.pbkdf2Sync.length > 4 || (!md || md === 'sha1'))) { - if(typeof md !== 'string') { - // default prf to SHA-1 - md = 'sha1'; - } - p = Buffer.from(p, 'binary'); - s = Buffer.from(s, 'binary'); - if(!callback) { - if(crypto.pbkdf2Sync.length === 4) { - return crypto.pbkdf2Sync(p, s, c, dkLen).toString('binary'); - } - return crypto.pbkdf2Sync(p, s, c, dkLen, md).toString('binary'); - } - if(crypto.pbkdf2Sync.length === 4) { - return crypto.pbkdf2(p, s, c, dkLen, function(err, key) { - if(err) { - return callback(err); - } - callback(null, key.toString('binary')); - }); - } - return crypto.pbkdf2(p, s, c, dkLen, md, function(err, key) { - if(err) { - return callback(err); - } - callback(null, key.toString('binary')); - }); - } - - if(typeof md === 'undefined' || md === null) { - // default prf to SHA-1 - md = 'sha1'; - } - if(typeof md === 'string') { - if(!(md in forge.md.algorithms)) { - throw new Error('Unknown hash algorithm: ' + md); - } - md = forge.md[md].create(); - } - - var hLen = md.digestLength; - - /* 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and - stop. */ - if(dkLen > (0xFFFFFFFF * hLen)) { - var err = new Error('Derived key is too long.'); - if(callback) { - return callback(err); - } - throw err; - } - - /* 2. Let len be the number of hLen-octet blocks in the derived key, - rounding up, and let r be the number of octets in the last - block: - - len = CEIL(dkLen / hLen), - r = dkLen - (len - 1) * hLen. */ - var len = Math.ceil(dkLen / hLen); - var r = dkLen - (len - 1) * hLen; - - /* 3. For each block of the derived key apply the function F defined - below to the password P, the salt S, the iteration count c, and - the block index to compute the block: - - T_1 = F(P, S, c, 1), - T_2 = F(P, S, c, 2), - ... - T_len = F(P, S, c, len), - - where the function F is defined as the exclusive-or sum of the - first c iterates of the underlying pseudorandom function PRF - applied to the password P and the concatenation of the salt S - and the block index i: - - F(P, S, c, i) = u_1 XOR u_2 XOR ... XOR u_c - - where - - u_1 = PRF(P, S || INT(i)), - u_2 = PRF(P, u_1), - ... - u_c = PRF(P, u_{c-1}). - - Here, INT(i) is a four-octet encoding of the integer i, most - significant octet first. */ - var prf = forge.hmac.create(); - prf.start(md, p); - var dk = ''; - var xor, u_c, u_c1; - - // sync version - if(!callback) { - for(var i = 1; i <= len; ++i) { - // PRF(P, S || INT(i)) (first iteration) - prf.start(null, null); - prf.update(s); - prf.update(forge.util.int32ToBytes(i)); - xor = u_c1 = prf.digest().getBytes(); - - // PRF(P, u_{c-1}) (other iterations) - for(var j = 2; j <= c; ++j) { - prf.start(null, null); - prf.update(u_c1); - u_c = prf.digest().getBytes(); - // F(p, s, c, i) - xor = forge.util.xorBytes(xor, u_c, hLen); - u_c1 = u_c; - } - - /* 4. Concatenate the blocks and extract the first dkLen octets to - produce a derived key DK: - - DK = T_1 || T_2 || ... || T_len<0..r-1> */ - dk += (i < len) ? xor : xor.substr(0, r); - } - /* 5. Output the derived key DK. */ - return dk; - } - - // async version - var i = 1, j; - function outer() { - if(i > len) { - // done - return callback(null, dk); - } - - // PRF(P, S || INT(i)) (first iteration) - prf.start(null, null); - prf.update(s); - prf.update(forge.util.int32ToBytes(i)); - xor = u_c1 = prf.digest().getBytes(); - - // PRF(P, u_{c-1}) (other iterations) - j = 2; - inner(); - } - - function inner() { - if(j <= c) { - prf.start(null, null); - prf.update(u_c1); - u_c = prf.digest().getBytes(); - // F(p, s, c, i) - xor = forge.util.xorBytes(xor, u_c, hLen); - u_c1 = u_c; - ++j; - return forge.util.setImmediate(inner); - } - - /* 4. Concatenate the blocks and extract the first dkLen octets to - produce a derived key DK: - - DK = T_1 || T_2 || ... || T_len<0..r-1> */ - dk += (i < len) ? xor : xor.substr(0, r); - - ++i; - outer(); - } - - outer(); - }; - - var sha256_1 = createCommonjsModule(function (module) { - /** - * Secure Hash Algorithm with 256-bit digest (SHA-256) implementation. - * - * See FIPS 180-2 for details. - * - * @author Dave Longley - * - * Copyright (c) 2010-2015 Digital Bazaar, Inc. - */ - - - - - var sha256 = module.exports = forge.sha256 = forge.sha256 || {}; - forge.md.sha256 = forge.md.algorithms.sha256 = sha256; - - /** - * Creates a SHA-256 message digest object. - * - * @return a message digest object. - */ - sha256.create = function() { - // do initialization as necessary - if(!_initialized) { - _init(); - } - - // SHA-256 state contains eight 32-bit integers - var _state = null; - - // input buffer - var _input = forge.util.createBuffer(); - - // used for word storage - var _w = new Array(64); - - // message digest object - var md = { - algorithm: 'sha256', - blockLength: 64, - digestLength: 32, - // 56-bit length of message so far (does not including padding) - messageLength: 0, - // true message length - fullMessageLength: null, - // size of message length in bytes - messageLengthSize: 8 - }; - - /** - * Starts the digest. - * - * @return this digest object. - */ - md.start = function() { - // up to 56-bit message length for convenience - md.messageLength = 0; - - // full message length (set md.messageLength64 for backwards-compatibility) - md.fullMessageLength = md.messageLength64 = []; - var int32s = md.messageLengthSize / 4; - for(var i = 0; i < int32s; ++i) { - md.fullMessageLength.push(0); - } - _input = forge.util.createBuffer(); - _state = { - h0: 0x6A09E667, - h1: 0xBB67AE85, - h2: 0x3C6EF372, - h3: 0xA54FF53A, - h4: 0x510E527F, - h5: 0x9B05688C, - h6: 0x1F83D9AB, - h7: 0x5BE0CD19 - }; - return md; - }; - // start digest automatically for first time - md.start(); - - /** - * Updates the digest with the given message input. The given input can - * treated as raw input (no encoding will be applied) or an encoding of - * 'utf8' maybe given to encode the input using UTF-8. - * - * @param msg the message input to update with. - * @param encoding the encoding to use (default: 'raw', other: 'utf8'). - * - * @return this digest object. - */ - md.update = function(msg, encoding) { - if(encoding === 'utf8') { - msg = forge.util.encodeUtf8(msg); - } - - // update message length - var len = msg.length; - md.messageLength += len; - len = [(len / 0x100000000) >>> 0, len >>> 0]; - for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { - md.fullMessageLength[i] += len[1]; - len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); - md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; - len[0] = ((len[1] / 0x100000000) >>> 0); - } - - // add bytes to input buffer - _input.putBytes(msg); - - // process bytes - _update(_state, _w, _input); - - // compact input buffer every 2K or if empty - if(_input.read > 2048 || _input.length() === 0) { - _input.compact(); - } - - return md; - }; - - /** - * Produces the digest. - * - * @return a byte buffer containing the digest value. - */ - md.digest = function() { - /* Note: Here we copy the remaining bytes in the input buffer and - add the appropriate SHA-256 padding. Then we do the final update - on a copy of the state so that if the user wants to get - intermediate digests they can do so. */ - - /* Determine the number of bytes that must be added to the message - to ensure its length is congruent to 448 mod 512. In other words, - the data to be digested must be a multiple of 512 bits (or 128 bytes). - This data includes the message, some padding, and the length of the - message. Since the length of the message will be encoded as 8 bytes (64 - bits), that means that the last segment of the data must have 56 bytes - (448 bits) of message and padding. Therefore, the length of the message - plus the padding must be congruent to 448 mod 512 because - 512 - 128 = 448. - - In order to fill up the message length it must be filled with - padding that begins with 1 bit followed by all 0 bits. Padding - must *always* be present, so if the message length is already - congruent to 448 mod 512, then 512 padding bits must be added. */ - - var finalBlock = forge.util.createBuffer(); - finalBlock.putBytes(_input.bytes()); - - // compute remaining size to be digested (include message length size) - var remaining = ( - md.fullMessageLength[md.fullMessageLength.length - 1] + - md.messageLengthSize); - - // add padding for overflow blockSize - overflow - // _padding starts with 1 byte with first bit is set (byte value 128), then - // there may be up to (blockSize - 1) other pad bytes - var overflow = remaining & (md.blockLength - 1); - finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); - - // serialize message length in bits in big-endian order; since length - // is stored in bytes we multiply by 8 and add carry from next int - var next, carry; - var bits = md.fullMessageLength[0] * 8; - for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { - next = md.fullMessageLength[i + 1] * 8; - carry = (next / 0x100000000) >>> 0; - bits += carry; - finalBlock.putInt32(bits >>> 0); - bits = next >>> 0; - } - finalBlock.putInt32(bits); - - var s2 = { - h0: _state.h0, - h1: _state.h1, - h2: _state.h2, - h3: _state.h3, - h4: _state.h4, - h5: _state.h5, - h6: _state.h6, - h7: _state.h7 - }; - _update(s2, _w, finalBlock); - var rval = forge.util.createBuffer(); - rval.putInt32(s2.h0); - rval.putInt32(s2.h1); - rval.putInt32(s2.h2); - rval.putInt32(s2.h3); - rval.putInt32(s2.h4); - rval.putInt32(s2.h5); - rval.putInt32(s2.h6); - rval.putInt32(s2.h7); - return rval; - }; - - return md; - }; - - // sha-256 padding bytes not initialized yet - var _padding = null; - var _initialized = false; - - // table of constants - var _k = null; - - /** - * Initializes the constant tables. - */ - function _init() { - // create padding - _padding = String.fromCharCode(128); - _padding += forge.util.fillString(String.fromCharCode(0x00), 64); - - // create K table for SHA-256 - _k = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; - - // now initialized - _initialized = true; - } - - /** - * Updates a SHA-256 state with the given byte buffer. - * - * @param s the SHA-256 state to update. - * @param w the array to use to store words. - * @param bytes the byte buffer to update with. - */ - function _update(s, w, bytes) { - // consume 512 bit (64 byte) chunks - var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h; - var len = bytes.length(); - while(len >= 64) { - // the w array will be populated with sixteen 32-bit big-endian words - // and then extended into 64 32-bit words according to SHA-256 - for(i = 0; i < 16; ++i) { - w[i] = bytes.getInt32(); - } - for(; i < 64; ++i) { - // XOR word 2 words ago rot right 17, rot right 19, shft right 10 - t1 = w[i - 2]; - t1 = - ((t1 >>> 17) | (t1 << 15)) ^ - ((t1 >>> 19) | (t1 << 13)) ^ - (t1 >>> 10); - // XOR word 15 words ago rot right 7, rot right 18, shft right 3 - t2 = w[i - 15]; - t2 = - ((t2 >>> 7) | (t2 << 25)) ^ - ((t2 >>> 18) | (t2 << 14)) ^ - (t2 >>> 3); - // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32 - w[i] = (t1 + w[i - 7] + t2 + w[i - 16]) | 0; - } - - // initialize hash value for this chunk - a = s.h0; - b = s.h1; - c = s.h2; - d = s.h3; - e = s.h4; - f = s.h5; - g = s.h6; - h = s.h7; - - // round function - for(i = 0; i < 64; ++i) { - // Sum1(e) - s1 = - ((e >>> 6) | (e << 26)) ^ - ((e >>> 11) | (e << 21)) ^ - ((e >>> 25) | (e << 7)); - // Ch(e, f, g) (optimized the same way as SHA-1) - ch = g ^ (e & (f ^ g)); - // Sum0(a) - s0 = - ((a >>> 2) | (a << 30)) ^ - ((a >>> 13) | (a << 19)) ^ - ((a >>> 22) | (a << 10)); - // Maj(a, b, c) (optimized the same way as SHA-1) - maj = (a & b) | (c & (a ^ b)); - - // main algorithm - t1 = h + s1 + ch + _k[i] + w[i]; - t2 = s0 + maj; - h = g; - g = f; - f = e; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - // can't truncate with `| 0` - e = (d + t1) >>> 0; - d = c; - c = b; - b = a; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - // can't truncate with `| 0` - a = (t1 + t2) >>> 0; - } - - // update hash state - s.h0 = (s.h0 + a) | 0; - s.h1 = (s.h1 + b) | 0; - s.h2 = (s.h2 + c) | 0; - s.h3 = (s.h3 + d) | 0; - s.h4 = (s.h4 + e) | 0; - s.h5 = (s.h5 + f) | 0; - s.h6 = (s.h6 + g) | 0; - s.h7 = (s.h7 + h) | 0; - len -= 64; - } - } - }); - - var prng_1 = createCommonjsModule(function (module) { - /** - * A javascript implementation of a cryptographically-secure - * Pseudo Random Number Generator (PRNG). The Fortuna algorithm is followed - * here though the use of SHA-256 is not enforced; when generating an - * a PRNG context, the hashing algorithm and block cipher used for - * the generator are specified via a plugin. - * - * @author Dave Longley - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - */ - - - - var _crypto = null; - if(forge.util.isNodejs && !forge.options.usePureJavaScript && - !process.versions['node-webkit']) { - _crypto = require$$7; - } - - /* PRNG API */ - var prng = module.exports = forge.prng = forge.prng || {}; - - /** - * Creates a new PRNG context. - * - * A PRNG plugin must be passed in that will provide: - * - * 1. A function that initializes the key and seed of a PRNG context. It - * will be given a 16 byte key and a 16 byte seed. Any key expansion - * or transformation of the seed from a byte string into an array of - * integers (or similar) should be performed. - * 2. The cryptographic function used by the generator. It takes a key and - * a seed. - * 3. A seed increment function. It takes the seed and returns seed + 1. - * 4. An api to create a message digest. - * - * For an example, see random.js. - * - * @param plugin the PRNG plugin to use. - */ - prng.create = function(plugin) { - var ctx = { - plugin: plugin, - key: null, - seed: null, - time: null, - // number of reseeds so far - reseeds: 0, - // amount of data generated so far - generated: 0, - // no initial key bytes - keyBytes: '' - }; - - // create 32 entropy pools (each is a message digest) - var md = plugin.md; - var pools = new Array(32); - for(var i = 0; i < 32; ++i) { - pools[i] = md.create(); - } - ctx.pools = pools; - - // entropy pools are written to cyclically, starting at index 0 - ctx.pool = 0; - - /** - * Generates random bytes. The bytes may be generated synchronously or - * asynchronously. Web workers must use the asynchronous interface or - * else the behavior is undefined. - * - * @param count the number of random bytes to generate. - * @param [callback(err, bytes)] called once the operation completes. - * - * @return count random bytes as a string. - */ - ctx.generate = function(count, callback) { - // do synchronously - if(!callback) { - return ctx.generateSync(count); - } - - // simple generator using counter-based CBC - var cipher = ctx.plugin.cipher; - var increment = ctx.plugin.increment; - var formatKey = ctx.plugin.formatKey; - var formatSeed = ctx.plugin.formatSeed; - var b = forge.util.createBuffer(); - - // paranoid deviation from Fortuna: - // reset key for every request to protect previously - // generated random bytes should the key be discovered; - // there is no 100ms based reseeding because of this - // forced reseed for every `generate` call - ctx.key = null; - - generate(); - - function generate(err) { - if(err) { - return callback(err); - } - - // sufficient bytes generated - if(b.length() >= count) { - return callback(null, b.getBytes(count)); - } - - // if amount of data generated is greater than 1 MiB, trigger reseed - if(ctx.generated > 0xfffff) { - ctx.key = null; - } - - if(ctx.key === null) { - // prevent stack overflow - return forge.util.nextTick(function() { - _reseed(generate); - }); - } - - // generate the random bytes - var bytes = cipher(ctx.key, ctx.seed); - ctx.generated += bytes.length; - b.putBytes(bytes); - - // generate bytes for a new key and seed - ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed))); - ctx.seed = formatSeed(cipher(ctx.key, ctx.seed)); - - forge.util.setImmediate(generate); - } - }; - - /** - * Generates random bytes synchronously. - * - * @param count the number of random bytes to generate. - * - * @return count random bytes as a string. - */ - ctx.generateSync = function(count) { - // simple generator using counter-based CBC - var cipher = ctx.plugin.cipher; - var increment = ctx.plugin.increment; - var formatKey = ctx.plugin.formatKey; - var formatSeed = ctx.plugin.formatSeed; - - // paranoid deviation from Fortuna: - // reset key for every request to protect previously - // generated random bytes should the key be discovered; - // there is no 100ms based reseeding because of this - // forced reseed for every `generateSync` call - ctx.key = null; - - var b = forge.util.createBuffer(); - while(b.length() < count) { - // if amount of data generated is greater than 1 MiB, trigger reseed - if(ctx.generated > 0xfffff) { - ctx.key = null; - } - - if(ctx.key === null) { - _reseedSync(); - } - - // generate the random bytes - var bytes = cipher(ctx.key, ctx.seed); - ctx.generated += bytes.length; - b.putBytes(bytes); - - // generate bytes for a new key and seed - ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed))); - ctx.seed = formatSeed(cipher(ctx.key, ctx.seed)); - } - - return b.getBytes(count); - }; - - /** - * Private function that asynchronously reseeds a generator. - * - * @param callback(err) called once the operation completes. - */ - function _reseed(callback) { - if(ctx.pools[0].messageLength >= 32) { - _seed(); - return callback(); - } - // not enough seed data... - var needed = (32 - ctx.pools[0].messageLength) << 5; - ctx.seedFile(needed, function(err, bytes) { - if(err) { - return callback(err); - } - ctx.collect(bytes); - _seed(); - callback(); - }); - } - - /** - * Private function that synchronously reseeds a generator. - */ - function _reseedSync() { - if(ctx.pools[0].messageLength >= 32) { - return _seed(); - } - // not enough seed data... - var needed = (32 - ctx.pools[0].messageLength) << 5; - ctx.collect(ctx.seedFileSync(needed)); - _seed(); - } - - /** - * Private function that seeds a generator once enough bytes are available. - */ - function _seed() { - // update reseed count - ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1; - - // goal is to update `key` via: - // key = hash(key + s) - // where 's' is all collected entropy from selected pools, then... - - // create a plugin-based message digest - var md = ctx.plugin.md.create(); - - // consume current key bytes - md.update(ctx.keyBytes); - - // digest the entropy of pools whose index k meet the - // condition 'n mod 2^k == 0' where n is the number of reseeds - var _2powK = 1; - for(var k = 0; k < 32; ++k) { - if(ctx.reseeds % _2powK === 0) { - md.update(ctx.pools[k].digest().getBytes()); - ctx.pools[k].start(); - } - _2powK = _2powK << 1; - } - - // get digest for key bytes - ctx.keyBytes = md.digest().getBytes(); - - // paranoid deviation from Fortuna: - // update `seed` via `seed = hash(key)` - // instead of initializing to zero once and only - // ever incrementing it - md.start(); - md.update(ctx.keyBytes); - var seedBytes = md.digest().getBytes(); - - // update state - ctx.key = ctx.plugin.formatKey(ctx.keyBytes); - ctx.seed = ctx.plugin.formatSeed(seedBytes); - ctx.generated = 0; - } - - /** - * The built-in default seedFile. This seedFile is used when entropy - * is needed immediately. - * - * @param needed the number of bytes that are needed. - * - * @return the random bytes. - */ - function defaultSeedFile(needed) { - // use window.crypto.getRandomValues strong source of entropy if available - var getRandomValues = null; - var globalScope = forge.util.globalScope; - var _crypto = globalScope.crypto || globalScope.msCrypto; - if(_crypto && _crypto.getRandomValues) { - getRandomValues = function(arr) { - return _crypto.getRandomValues(arr); - }; - } - - var b = forge.util.createBuffer(); - if(getRandomValues) { - while(b.length() < needed) { - // max byte length is 65536 before QuotaExceededError is thrown - // http://www.w3.org/TR/WebCryptoAPI/#RandomSource-method-getRandomValues - var count = Math.max(1, Math.min(needed - b.length(), 65536) / 4); - var entropy = new Uint32Array(Math.floor(count)); - try { - getRandomValues(entropy); - for(var i = 0; i < entropy.length; ++i) { - b.putInt32(entropy[i]); - } - } catch(e) { - /* only ignore QuotaExceededError */ - if(!(typeof QuotaExceededError !== 'undefined' && - e instanceof QuotaExceededError)) { - throw e; - } - } - } - } - - // be sad and add some weak random data - if(b.length() < needed) { - /* Draws from Park-Miller "minimal standard" 31 bit PRNG, - implemented with David G. Carta's optimization: with 32 bit math - and without division (Public Domain). */ - var hi, lo, next; - var seed = Math.floor(Math.random() * 0x010000); - while(b.length() < needed) { - lo = 16807 * (seed & 0xFFFF); - hi = 16807 * (seed >> 16); - lo += (hi & 0x7FFF) << 16; - lo += hi >> 15; - lo = (lo & 0x7FFFFFFF) + (lo >> 31); - seed = lo & 0xFFFFFFFF; - - // consume lower 3 bytes of seed - for(var i = 0; i < 3; ++i) { - // throw in more pseudo random - next = seed >>> (i << 3); - next ^= Math.floor(Math.random() * 0x0100); - b.putByte(String.fromCharCode(next & 0xFF)); - } - } - } - - return b.getBytes(needed); - } - // initialize seed file APIs - if(_crypto) { - // use nodejs async API - ctx.seedFile = function(needed, callback) { - _crypto.randomBytes(needed, function(err, bytes) { - if(err) { - return callback(err); - } - callback(null, bytes.toString()); - }); - }; - // use nodejs sync API - ctx.seedFileSync = function(needed) { - return _crypto.randomBytes(needed).toString(); - }; - } else { - ctx.seedFile = function(needed, callback) { - try { - callback(null, defaultSeedFile(needed)); - } catch(e) { - callback(e); - } - }; - ctx.seedFileSync = defaultSeedFile; - } - - /** - * Adds entropy to a prng ctx's accumulator. - * - * @param bytes the bytes of entropy as a string. - */ - ctx.collect = function(bytes) { - // iterate over pools distributing entropy cyclically - var count = bytes.length; - for(var i = 0; i < count; ++i) { - ctx.pools[ctx.pool].update(bytes.substr(i, 1)); - ctx.pool = (ctx.pool === 31) ? 0 : ctx.pool + 1; - } - }; - - /** - * Collects an integer of n bits. - * - * @param i the integer entropy. - * @param n the number of bits in the integer. - */ - ctx.collectInt = function(i, n) { - var bytes = ''; - for(var x = 0; x < n; x += 8) { - bytes += String.fromCharCode((i >> x) & 0xFF); - } - ctx.collect(bytes); - }; - - /** - * Registers a Web Worker to receive immediate entropy from the main thread. - * This method is required until Web Workers can access the native crypto - * API. This method should be called twice for each created worker, once in - * the main thread, and once in the worker itself. - * - * @param worker the worker to register. - */ - ctx.registerWorker = function(worker) { - // worker receives random bytes - if(worker === self) { - ctx.seedFile = function(needed, callback) { - function listener(e) { - var data = e.data; - if(data.forge && data.forge.prng) { - self.removeEventListener('message', listener); - callback(data.forge.prng.err, data.forge.prng.bytes); - } - } - self.addEventListener('message', listener); - self.postMessage({forge: {prng: {needed: needed}}}); - }; - } else { - // main thread sends random bytes upon request - var listener = function(e) { - var data = e.data; - if(data.forge && data.forge.prng) { - ctx.seedFile(data.forge.prng.needed, function(err, bytes) { - worker.postMessage({forge: {prng: {err: err, bytes: bytes}}}); - }); - } - }; - // TODO: do we need to remove the event listener when the worker dies? - worker.addEventListener('message', listener); - } - }; - - return ctx; - }; - }); - - var random = createCommonjsModule(function (module) { - /** - * An API for getting cryptographically-secure random bytes. The bytes are - * generated using the Fortuna algorithm devised by Bruce Schneier and - * Niels Ferguson. - * - * Getting strong random bytes is not yet easy to do in javascript. The only - * truish random entropy that can be collected is from the mouse, keyboard, or - * from timing with respect to page loads, etc. This generator makes a poor - * attempt at providing random bytes when those sources haven't yet provided - * enough entropy to initially seed or to reseed the PRNG. - * - * @author Dave Longley - * - * Copyright (c) 2009-2014 Digital Bazaar, Inc. - */ - - - - - - - (function() { - - // forge.random already defined - if(forge.random && forge.random.getBytes) { - module.exports = forge.random; - return; - } - - (function(jQuery) { - - // the default prng plugin, uses AES-128 - var prng_aes = {}; - var _prng_aes_output = new Array(4); - var _prng_aes_buffer = forge.util.createBuffer(); - prng_aes.formatKey = function(key) { - // convert the key into 32-bit integers - var tmp = forge.util.createBuffer(key); - key = new Array(4); - key[0] = tmp.getInt32(); - key[1] = tmp.getInt32(); - key[2] = tmp.getInt32(); - key[3] = tmp.getInt32(); - - // return the expanded key - return forge.aes._expandKey(key, false); - }; - prng_aes.formatSeed = function(seed) { - // convert seed into 32-bit integers - var tmp = forge.util.createBuffer(seed); - seed = new Array(4); - seed[0] = tmp.getInt32(); - seed[1] = tmp.getInt32(); - seed[2] = tmp.getInt32(); - seed[3] = tmp.getInt32(); - return seed; - }; - prng_aes.cipher = function(key, seed) { - forge.aes._updateBlock(key, seed, _prng_aes_output, false); - _prng_aes_buffer.putInt32(_prng_aes_output[0]); - _prng_aes_buffer.putInt32(_prng_aes_output[1]); - _prng_aes_buffer.putInt32(_prng_aes_output[2]); - _prng_aes_buffer.putInt32(_prng_aes_output[3]); - return _prng_aes_buffer.getBytes(); - }; - prng_aes.increment = function(seed) { - // FIXME: do we care about carry or signed issues? - ++seed[3]; - return seed; - }; - prng_aes.md = forge.md.sha256; - - /** - * Creates a new PRNG. - */ - function spawnPrng() { - var ctx = forge.prng.create(prng_aes); - - /** - * Gets random bytes. If a native secure crypto API is unavailable, this - * method tries to make the bytes more unpredictable by drawing from data that - * can be collected from the user of the browser, eg: mouse movement. - * - * If a callback is given, this method will be called asynchronously. - * - * @param count the number of random bytes to get. - * @param [callback(err, bytes)] called once the operation completes. - * - * @return the random bytes in a string. - */ - ctx.getBytes = function(count, callback) { - return ctx.generate(count, callback); - }; - - /** - * Gets random bytes asynchronously. If a native secure crypto API is - * unavailable, this method tries to make the bytes more unpredictable by - * drawing from data that can be collected from the user of the browser, - * eg: mouse movement. - * - * @param count the number of random bytes to get. - * - * @return the random bytes in a string. - */ - ctx.getBytesSync = function(count) { - return ctx.generate(count); - }; - - return ctx; - } - - // create default prng context - var _ctx = spawnPrng(); - - // add other sources of entropy only if window.crypto.getRandomValues is not - // available -- otherwise this source will be automatically used by the prng - var getRandomValues = null; - var globalScope = forge.util.globalScope; - var _crypto = globalScope.crypto || globalScope.msCrypto; - if(_crypto && _crypto.getRandomValues) { - getRandomValues = function(arr) { - return _crypto.getRandomValues(arr); - }; - } - - if( - (!forge.util.isNodejs && !getRandomValues)) { - - // get load time entropy - _ctx.collectInt(+new Date(), 32); - - // add some entropy from navigator object - if(typeof(navigator) !== 'undefined') { - var _navBytes = ''; - for(var key in navigator) { - try { - if(typeof(navigator[key]) == 'string') { - _navBytes += navigator[key]; - } - } catch(e) { - /* Some navigator keys might not be accessible, e.g. the geolocation - attribute throws an exception if touched in Mozilla chrome:// - context. - - Silently ignore this and just don't use this as a source of - entropy. */ - } - } - _ctx.collect(_navBytes); - _navBytes = null; - } - - // add mouse and keyboard collectors if jquery is available - if(jQuery) { - // set up mouse entropy capture - jQuery().mousemove(function(e) { - // add mouse coords - _ctx.collectInt(e.clientX, 16); - _ctx.collectInt(e.clientY, 16); - }); - - // set up keyboard entropy capture - jQuery().keypress(function(e) { - _ctx.collectInt(e.charCode, 8); - }); - } - } - - /* Random API */ - if(!forge.random) { - forge.random = _ctx; - } else { - // extend forge.random with _ctx - for(var key in _ctx) { - forge.random[key] = _ctx[key]; - } - } - - // expose spawn PRNG - forge.random.createInstance = spawnPrng; - - module.exports = forge.random; - - })(typeof(jQuery) !== 'undefined' ? jQuery : null); - - })(); - }); - - /** - * RC2 implementation. - * - * @author Stefan Siegl - * - * Copyright (c) 2012 Stefan Siegl - * - * Information on the RC2 cipher is available from RFC #2268, - * http://www.ietf.org/rfc/rfc2268.txt - */ - - - - var piTable = [ - 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, - 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, - 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, - 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, - 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, - 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, - 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, - 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, - 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, - 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, - 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, - 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, - 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, - 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, - 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, - 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad - ]; - - var s = [1, 2, 3, 5]; - - /** - * Rotate a word left by given number of bits. - * - * Bits that are shifted out on the left are put back in on the right - * hand side. - * - * @param word The word to shift left. - * @param bits The number of bits to shift by. - * @return The rotated word. - */ - var rol = function(word, bits) { - return ((word << bits) & 0xffff) | ((word & 0xffff) >> (16 - bits)); - }; - - /** - * Rotate a word right by given number of bits. - * - * Bits that are shifted out on the right are put back in on the left - * hand side. - * - * @param word The word to shift right. - * @param bits The number of bits to shift by. - * @return The rotated word. - */ - var ror = function(word, bits) { - return ((word & 0xffff) >> bits) | ((word << (16 - bits)) & 0xffff); - }; - - /* RC2 API */ - var rc2 = forge.rc2 = forge.rc2 || {}; - - /** - * Perform RC2 key expansion as per RFC #2268, section 2. - * - * @param key variable-length user key (between 1 and 128 bytes) - * @param effKeyBits number of effective key bits (default: 128) - * @return the expanded RC2 key (ByteBuffer of 128 bytes) - */ - forge.rc2.expandKey = function(key, effKeyBits) { - if(typeof key === 'string') { - key = forge.util.createBuffer(key); - } - effKeyBits = effKeyBits || 128; - - /* introduce variables that match the names used in RFC #2268 */ - var L = key; - var T = key.length(); - var T1 = effKeyBits; - var T8 = Math.ceil(T1 / 8); - var TM = 0xff >> (T1 & 0x07); - var i; - - for(i = T; i < 128; i++) { - L.putByte(piTable[(L.at(i - 1) + L.at(i - T)) & 0xff]); - } - - L.setAt(128 - T8, piTable[L.at(128 - T8) & TM]); - - for(i = 127 - T8; i >= 0; i--) { - L.setAt(i, piTable[L.at(i + 1) ^ L.at(i + T8)]); - } - - return L; - }; - - /** - * Creates a RC2 cipher object. - * - * @param key the symmetric key to use (as base for key generation). - * @param bits the number of effective key bits. - * @param encrypt false for decryption, true for encryption. - * - * @return the cipher. - */ - var createCipher = function(key, bits, encrypt) { - var _finish = false, _input = null, _output = null, _iv = null; - var mixRound, mashRound; - var i, j, K = []; - - /* Expand key and fill into K[] Array */ - key = forge.rc2.expandKey(key, bits); - for(i = 0; i < 64; i++) { - K.push(key.getInt16Le()); - } - - if(encrypt) { - /** - * Perform one mixing round "in place". - * - * @param R Array of four words to perform mixing on. - */ - mixRound = function(R) { - for(i = 0; i < 4; i++) { - R[i] += K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) + - ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); - R[i] = rol(R[i], s[i]); - j++; - } - }; - - /** - * Perform one mashing round "in place". - * - * @param R Array of four words to perform mashing on. - */ - mashRound = function(R) { - for(i = 0; i < 4; i++) { - R[i] += K[R[(i + 3) % 4] & 63]; - } - }; - } else { - /** - * Perform one r-mixing round "in place". - * - * @param R Array of four words to perform mixing on. - */ - mixRound = function(R) { - for(i = 3; i >= 0; i--) { - R[i] = ror(R[i], s[i]); - R[i] -= K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) + - ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); - j--; - } - }; - - /** - * Perform one r-mashing round "in place". - * - * @param R Array of four words to perform mashing on. - */ - mashRound = function(R) { - for(i = 3; i >= 0; i--) { - R[i] -= K[R[(i + 3) % 4] & 63]; - } - }; - } - - /** - * Run the specified cipher execution plan. - * - * This function takes four words from the input buffer, applies the IV on - * it (if requested) and runs the provided execution plan. - * - * The plan must be put together in form of a array of arrays. Where the - * outer one is simply a list of steps to perform and the inner one needs - * to have two elements: the first one telling how many rounds to perform, - * the second one telling what to do (i.e. the function to call). - * - * @param {Array} plan The plan to execute. - */ - var runPlan = function(plan) { - var R = []; - - /* Get data from input buffer and fill the four words into R */ - for(i = 0; i < 4; i++) { - var val = _input.getInt16Le(); - - if(_iv !== null) { - if(encrypt) { - /* We're encrypting, apply the IV first. */ - val ^= _iv.getInt16Le(); - } else { - /* We're decryption, keep cipher text for next block. */ - _iv.putInt16Le(val); - } - } - - R.push(val & 0xffff); - } - - /* Reset global "j" variable as per spec. */ - j = encrypt ? 0 : 63; - - /* Run execution plan. */ - for(var ptr = 0; ptr < plan.length; ptr++) { - for(var ctr = 0; ctr < plan[ptr][0]; ctr++) { - plan[ptr][1](R); - } - } - - /* Write back result to output buffer. */ - for(i = 0; i < 4; i++) { - if(_iv !== null) { - if(encrypt) { - /* We're encrypting in CBC-mode, feed back encrypted bytes into - IV buffer to carry it forward to next block. */ - _iv.putInt16Le(R[i]); - } else { - R[i] ^= _iv.getInt16Le(); - } - } - - _output.putInt16Le(R[i]); - } - }; - - /* Create cipher object */ - var cipher = null; - cipher = { - /** - * Starts or restarts the encryption or decryption process, whichever - * was previously configured. - * - * To use the cipher in CBC mode, iv may be given either as a string - * of bytes, or as a byte buffer. For ECB mode, give null as iv. - * - * @param iv the initialization vector to use, null for ECB mode. - * @param output the output the buffer to write to, null to create one. - */ - start: function(iv, output) { - if(iv) { - /* CBC mode */ - if(typeof iv === 'string') { - iv = forge.util.createBuffer(iv); - } - } - - _finish = false; - _input = forge.util.createBuffer(); - _output = output || new forge.util.createBuffer(); - _iv = iv; - - cipher.output = _output; - }, - - /** - * Updates the next block. - * - * @param input the buffer to read from. - */ - update: function(input) { - if(!_finish) { - // not finishing, so fill the input buffer with more input - _input.putBuffer(input); - } - - while(_input.length() >= 8) { - runPlan([ - [ 5, mixRound ], - [ 1, mashRound ], - [ 6, mixRound ], - [ 1, mashRound ], - [ 5, mixRound ] - ]); - } - }, - - /** - * Finishes encrypting or decrypting. - * - * @param pad a padding function to use, null for PKCS#7 padding, - * signature(blockSize, buffer, decrypt). - * - * @return true if successful, false on error. - */ - finish: function(pad) { - var rval = true; - - if(encrypt) { - if(pad) { - rval = pad(8, _input, !encrypt); - } else { - // add PKCS#7 padding to block (each pad byte is the - // value of the number of pad bytes) - var padding = (_input.length() === 8) ? 8 : (8 - _input.length()); - _input.fillWithByte(padding, padding); - } - } - - if(rval) { - // do final update - _finish = true; - cipher.update(); - } - - if(!encrypt) { - // check for error: input data not a multiple of block size - rval = (_input.length() === 0); - if(rval) { - if(pad) { - rval = pad(8, _output, !encrypt); - } else { - // ensure padding byte count is valid - var len = _output.length(); - var count = _output.at(len - 1); - - if(count > len) { - rval = false; - } else { - // trim off padding bytes - _output.truncate(count); - } - } - } - } - - return rval; - } - }; - - return cipher; - }; - - /** - * Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the - * given symmetric key. The output will be stored in the 'output' member - * of the returned cipher. - * - * The key and iv may be given as a string of bytes or a byte buffer. - * The cipher is initialized to use 128 effective key bits. - * - * @param key the symmetric key to use. - * @param iv the initialization vector to use. - * @param output the buffer to write to, null to create one. - * - * @return the cipher. - */ - forge.rc2.startEncrypting = function(key, iv, output) { - var cipher = forge.rc2.createEncryptionCipher(key, 128); - cipher.start(iv, output); - return cipher; - }; - - /** - * Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the - * given symmetric key. - * - * The key may be given as a string of bytes or a byte buffer. - * - * To start encrypting call start() on the cipher with an iv and optional - * output buffer. - * - * @param key the symmetric key to use. - * - * @return the cipher. - */ - forge.rc2.createEncryptionCipher = function(key, bits) { - return createCipher(key, bits, true); - }; - - /** - * Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the - * given symmetric key. The output will be stored in the 'output' member - * of the returned cipher. - * - * The key and iv may be given as a string of bytes or a byte buffer. - * The cipher is initialized to use 128 effective key bits. - * - * @param key the symmetric key to use. - * @param iv the initialization vector to use. - * @param output the buffer to write to, null to create one. - * - * @return the cipher. - */ - forge.rc2.startDecrypting = function(key, iv, output) { - var cipher = forge.rc2.createDecryptionCipher(key, 128); - cipher.start(iv, output); - return cipher; - }; - - /** - * Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the - * given symmetric key. - * - * The key may be given as a string of bytes or a byte buffer. - * - * To start decrypting call start() on the cipher with an iv and optional - * output buffer. - * - * @param key the symmetric key to use. - * - * @return the cipher. - */ - forge.rc2.createDecryptionCipher = function(key, bits) { - return createCipher(key, bits, false); - }; - - // Copyright (c) 2005 Tom Wu - // All Rights Reserved. - // See "LICENSE" for details. - - // Basic JavaScript BN library - subset useful for RSA encryption. - - /* - Licensing (LICENSE) - ------------------- - - This software is covered under the following copyright: - */ - /* - * Copyright (c) 2003-2005 Tom Wu - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * In addition, the following condition applies: - * - * All redistributions must retain an intact copy of this copyright notice - * and disclaimer. - */ - /* - Address all questions regarding this license to: - - Tom Wu - tjw@cs.Stanford.EDU - */ - - - var jsbn = forge.jsbn = forge.jsbn || {}; - - // Bits per digit - var dbits; - - // (public) Constructor - function BigInteger$1(a,b,c) { - this.data = []; - if(a != null) - if("number" == typeof a) this.fromNumber(a,b,c); - else if(b == null && "string" != typeof a) this.fromString(a,256); - else this.fromString(a,b); - } - forge.jsbn.BigInteger = BigInteger$1; - - // return new, unset BigInteger - function nbi() { return new BigInteger$1(null); } - - // am: Compute w_j += (x*this_i), propagate carries, - // c is initial carry, returns final carry. - // c < 3*dvalue, x < 2*dvalue, this_i < dvalue - // We need to select the fastest one that works in this environment. - - // am1: use a single mult and divide to get the high bits, - // max digit bits should be 26 because - // max internal value = 2*dvalue^2-2*dvalue (< 2^53) - function am1(i,x,w,j,c,n) { - while(--n >= 0) { - var v = x*this.data[i++]+w.data[j]+c; - c = Math.floor(v/0x4000000); - w.data[j++] = v&0x3ffffff; - } - return c; - } - // am2 avoids a big mult-and-extract completely. - // Max digit bits should be <= 30 because we do bitwise ops - // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) - function am2(i,x,w,j,c,n) { - var xl = x&0x7fff, xh = x>>15; - while(--n >= 0) { - var l = this.data[i]&0x7fff; - var h = this.data[i++]>>15; - var m = xh*l+h*xl; - l = xl*l+((m&0x7fff)<<15)+w.data[j]+(c&0x3fffffff); - c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); - w.data[j++] = l&0x3fffffff; - } - return c; - } - // Alternately, set max digit bits to 28 since some - // browsers slow down when dealing with 32-bit numbers. - function am3(i,x,w,j,c,n) { - var xl = x&0x3fff, xh = x>>14; - while(--n >= 0) { - var l = this.data[i]&0x3fff; - var h = this.data[i++]>>14; - var m = xh*l+h*xl; - l = xl*l+((m&0x3fff)<<14)+w.data[j]+c; - c = (l>>28)+(m>>14)+xh*h; - w.data[j++] = l&0xfffffff; - } - return c; - } - - // node.js (no browser) - if(typeof(navigator) === 'undefined') - { - BigInteger$1.prototype.am = am3; - dbits = 28; - } else if( (navigator.appName == "Microsoft Internet Explorer")) { - BigInteger$1.prototype.am = am2; - dbits = 30; - } else if( (navigator.appName != "Netscape")) { - BigInteger$1.prototype.am = am1; - dbits = 26; - } else { // Mozilla/Netscape seems to prefer am3 - BigInteger$1.prototype.am = am3; - dbits = 28; - } - - BigInteger$1.prototype.DB = dbits; - BigInteger$1.prototype.DM = ((1<= 0; --i) r.data[i] = this.data[i]; - r.t = this.t; - r.s = this.s; - } - - // (protected) set from integer value x, -DV <= x < DV - function bnpFromInt(x) { - this.t = 1; - this.s = (x<0)?-1:0; - if(x > 0) this.data[0] = x; - else if(x < -1) this.data[0] = x+this.DV; - else this.t = 0; - } - - // return bigint initialized to value - function nbv(i) { var r = nbi(); r.fromInt(i); return r; } - - // (protected) set from string and radix - function bnpFromString(s,b) { - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 256) k = 8; // byte array - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else { this.fromRadix(s,b); return; } - this.t = 0; - this.s = 0; - var i = s.length, mi = false, sh = 0; - while(--i >= 0) { - var x = (k==8)?s[i]&0xff:intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-") mi = true; - continue; - } - mi = false; - if(sh == 0) - this.data[this.t++] = x; - else if(sh+k > this.DB) { - this.data[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); - } else - this.data[this.t-1] |= x<= this.DB) sh -= this.DB; - } - if(k == 8 && (s[0]&0x80) != 0) { - this.s = -1; - if(sh > 0) this.data[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this.data[this.t-1] == c) --this.t; - } - - // (public) return string representation in given radix - function bnToString(b) { - if(this.s < 0) return "-"+this.negate().toString(b); - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else return this.toRadix(b); - var km = (1< 0) { - if(p < this.DB && (d = this.data[i]>>p) > 0) { m = true; r = int2char(d); } - while(i >= 0) { - if(p < k) { - d = (this.data[i]&((1<>(p+=this.DB-k); - } else { - d = (this.data[i]>>(p-=k))&km; - if(p <= 0) { p += this.DB; --i; } - } - if(d > 0) m = true; - if(m) r += int2char(d); - } - } - return m?r:"0"; - } - - // (public) -this - function bnNegate() { var r = nbi(); BigInteger$1.ZERO.subTo(this,r); return r; } - - // (public) |this| - function bnAbs() { return (this.s<0)?this.negate():this; } - - // (public) return + if this > a, - if this < a, 0 if equal - function bnCompareTo(a) { - var r = this.s-a.s; - if(r != 0) return r; - var i = this.t; - r = i-a.t; - if(r != 0) return (this.s<0)?-r:r; - while(--i >= 0) if((r=this.data[i]-a.data[i]) != 0) return r; - return 0; - } - - // returns bit length of the integer x - function nbits(x) { - var r = 1, t; - if((t=x>>>16) != 0) { x = t; r += 16; } - if((t=x>>8) != 0) { x = t; r += 8; } - if((t=x>>4) != 0) { x = t; r += 4; } - if((t=x>>2) != 0) { x = t; r += 2; } - if((t=x>>1) != 0) { x = t; r += 1; } - return r; - } - - // (public) return the number of bits in "this" - function bnBitLength() { - if(this.t <= 0) return 0; - return this.DB*(this.t-1)+nbits(this.data[this.t-1]^(this.s&this.DM)); - } - - // (protected) r = this << n*DB - function bnpDLShiftTo(n,r) { - var i; - for(i = this.t-1; i >= 0; --i) r.data[i+n] = this.data[i]; - for(i = n-1; i >= 0; --i) r.data[i] = 0; - r.t = this.t+n; - r.s = this.s; - } - - // (protected) r = this >> n*DB - function bnpDRShiftTo(n,r) { - for(var i = n; i < this.t; ++i) r.data[i-n] = this.data[i]; - r.t = Math.max(this.t-n,0); - r.s = this.s; - } - - // (protected) r = this << n - function bnpLShiftTo(n,r) { - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<= 0; --i) { - r.data[i+ds+1] = (this.data[i]>>cbs)|c; - c = (this.data[i]&bm)<= 0; --i) r.data[i] = 0; - r.data[ds] = c; - r.t = this.t+ds+1; - r.s = this.s; - r.clamp(); - } - - // (protected) r = this >> n - function bnpRShiftTo(n,r) { - r.s = this.s; - var ds = Math.floor(n/this.DB); - if(ds >= this.t) { r.t = 0; return; } - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<>bs; - for(var i = ds+1; i < this.t; ++i) { - r.data[i-ds-1] |= (this.data[i]&bm)<>bs; - } - if(bs > 0) r.data[this.t-ds-1] |= (this.s&bm)<>= this.DB; - } - if(a.t < this.t) { - c -= a.s; - while(i < this.t) { - c += this.data[i]; - r.data[i++] = c&this.DM; - c >>= this.DB; - } - c += this.s; - } else { - c += this.s; - while(i < a.t) { - c -= a.data[i]; - r.data[i++] = c&this.DM; - c >>= this.DB; - } - c -= a.s; - } - r.s = (c<0)?-1:0; - if(c < -1) r.data[i++] = this.DV+c; - else if(c > 0) r.data[i++] = c; - r.t = i; - r.clamp(); - } - - // (protected) r = this * a, r != this,a (HAC 14.12) - // "this" should be the larger one if appropriate. - function bnpMultiplyTo(a,r) { - var x = this.abs(), y = a.abs(); - var i = x.t; - r.t = i+y.t; - while(--i >= 0) r.data[i] = 0; - for(i = 0; i < y.t; ++i) r.data[i+x.t] = x.am(0,y.data[i],r,i,0,x.t); - r.s = 0; - r.clamp(); - if(this.s != a.s) BigInteger$1.ZERO.subTo(r,r); - } - - // (protected) r = this^2, r != this (HAC 14.16) - function bnpSquareTo(r) { - var x = this.abs(); - var i = r.t = 2*x.t; - while(--i >= 0) r.data[i] = 0; - for(i = 0; i < x.t-1; ++i) { - var c = x.am(i,x.data[i],r,2*i,0,1); - if((r.data[i+x.t]+=x.am(i+1,2*x.data[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { - r.data[i+x.t] -= x.DV; - r.data[i+x.t+1] = 1; - } - } - if(r.t > 0) r.data[r.t-1] += x.am(i,x.data[i],r,2*i,0,1); - r.s = 0; - r.clamp(); - } - - // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) - // r != q, this != m. q or r may be null. - function bnpDivRemTo(m,q,r) { - var pm = m.abs(); - if(pm.t <= 0) return; - var pt = this.abs(); - if(pt.t < pm.t) { - if(q != null) q.fromInt(0); - if(r != null) this.copyTo(r); - return; - } - if(r == null) r = nbi(); - var y = nbi(), ts = this.s, ms = m.s; - var nsh = this.DB-nbits(pm.data[pm.t-1]); // normalize modulus - if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } else { pm.copyTo(y); pt.copyTo(r); } - var ys = y.t; - var y0 = y.data[ys-1]; - if(y0 == 0) return; - var yt = y0*(1<1)?y.data[ys-2]>>this.F2:0); - var d1 = this.FV/yt, d2 = (1<= 0) { - r.data[r.t++] = 1; - r.subTo(t,r); - } - BigInteger$1.ONE.dlShiftTo(ys,t); - t.subTo(y,y); // "negative" y so we can replace sub with am later - while(y.t < ys) y.data[y.t++] = 0; - while(--j >= 0) { - // Estimate quotient digit - var qd = (r.data[--i]==y0)?this.DM:Math.floor(r.data[i]*d1+(r.data[i-1]+e)*d2); - if((r.data[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out - y.dlShiftTo(j,t); - r.subTo(t,r); - while(r.data[i] < --qd) r.subTo(t,r); - } - } - if(q != null) { - r.drShiftTo(ys,q); - if(ts != ms) BigInteger$1.ZERO.subTo(q,q); - } - r.t = ys; - r.clamp(); - if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder - if(ts < 0) BigInteger$1.ZERO.subTo(r,r); - } - - // (public) this mod a - function bnMod(a) { - var r = nbi(); - this.abs().divRemTo(a,null,r); - if(this.s < 0 && r.compareTo(BigInteger$1.ZERO) > 0) a.subTo(r,r); - return r; - } - - // Modular reduction using "classic" algorithm - function Classic(m) { this.m = m; } - function cConvert(x) { - if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); - else return x; - } - function cRevert(x) { return x; } - function cReduce(x) { x.divRemTo(this.m,null,x); } - function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - - Classic.prototype.convert = cConvert; - Classic.prototype.revert = cRevert; - Classic.prototype.reduce = cReduce; - Classic.prototype.mulTo = cMulTo; - Classic.prototype.sqrTo = cSqrTo; - - // (protected) return "-1/this % 2^DB"; useful for Mont. reduction - // justification: - // xy == 1 (mod m) - // xy = 1+km - // xy(2-xy) = (1+km)(1-km) - // x[y(2-xy)] = 1-k^2m^2 - // x[y(2-xy)] == 1 (mod m^2) - // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 - // should reduce x and y(2-xy) by m^2 at each step to keep size bounded. - // JS multiply "overflows" differently from C/C++, so care is needed here. - function bnpInvDigit() { - if(this.t < 1) return 0; - var x = this.data[0]; - if((x&1) == 0) return 0; - var y = x&3; // y == 1/x mod 2^2 - y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 - y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 - y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 - // last step - calculate inverse mod DV directly; - // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints - y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits - // we really want the negative inverse, and -DV < y < DV - return (y>0)?this.DV-y:-y; - } - - // Montgomery reduction - function Montgomery(m) { - this.m = m; - this.mp = m.invDigit(); - this.mpl = this.mp&0x7fff; - this.mph = this.mp>>15; - this.um = (1<<(m.DB-15))-1; - this.mt2 = 2*m.t; - } - - // xR mod m - function montConvert(x) { - var r = nbi(); - x.abs().dlShiftTo(this.m.t,r); - r.divRemTo(this.m,null,r); - if(x.s < 0 && r.compareTo(BigInteger$1.ZERO) > 0) this.m.subTo(r,r); - return r; - } - - // x/R mod m - function montRevert(x) { - var r = nbi(); - x.copyTo(r); - this.reduce(r); - return r; - } - - // x = x/R mod m (HAC 14.32) - function montReduce(x) { - while(x.t <= this.mt2) // pad x so am has enough room later - x.data[x.t++] = 0; - for(var i = 0; i < this.m.t; ++i) { - // faster way of calculating u0 = x.data[i]*mp mod DV - var j = x.data[i]&0x7fff; - var u0 = (j*this.mpl+(((j*this.mph+(x.data[i]>>15)*this.mpl)&this.um)<<15))&x.DM; - // use am to combine the multiply-shift-add into one call - j = i+this.m.t; - x.data[j] += this.m.am(0,u0,x,i,0,this.m.t); - // propagate carry - while(x.data[j] >= x.DV) { x.data[j] -= x.DV; x.data[++j]++; } - } - x.clamp(); - x.drShiftTo(this.m.t,x); - if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); - } - - // r = "x^2/R mod m"; x != r - function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - - // r = "xy/R mod m"; x,y != r - function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - - Montgomery.prototype.convert = montConvert; - Montgomery.prototype.revert = montRevert; - Montgomery.prototype.reduce = montReduce; - Montgomery.prototype.mulTo = montMulTo; - Montgomery.prototype.sqrTo = montSqrTo; - - // (protected) true iff this is even - function bnpIsEven() { return ((this.t>0)?(this.data[0]&1):this.s) == 0; } - - // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) - function bnpExp(e,z) { - if(e > 0xffffffff || e < 1) return BigInteger$1.ONE; - var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; - g.copyTo(r); - while(--i >= 0) { - z.sqrTo(r,r2); - if((e&(1< 0) z.mulTo(r2,g,r); - else { var t = r; r = r2; r2 = t; } - } - return z.revert(r); - } - - // (public) this^e % m, 0 <= e < 2^32 - function bnModPowInt(e,m) { - var z; - if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); - return this.exp(e,z); - } - - // protected - BigInteger$1.prototype.copyTo = bnpCopyTo; - BigInteger$1.prototype.fromInt = bnpFromInt; - BigInteger$1.prototype.fromString = bnpFromString; - BigInteger$1.prototype.clamp = bnpClamp; - BigInteger$1.prototype.dlShiftTo = bnpDLShiftTo; - BigInteger$1.prototype.drShiftTo = bnpDRShiftTo; - BigInteger$1.prototype.lShiftTo = bnpLShiftTo; - BigInteger$1.prototype.rShiftTo = bnpRShiftTo; - BigInteger$1.prototype.subTo = bnpSubTo; - BigInteger$1.prototype.multiplyTo = bnpMultiplyTo; - BigInteger$1.prototype.squareTo = bnpSquareTo; - BigInteger$1.prototype.divRemTo = bnpDivRemTo; - BigInteger$1.prototype.invDigit = bnpInvDigit; - BigInteger$1.prototype.isEven = bnpIsEven; - BigInteger$1.prototype.exp = bnpExp; - - // public - BigInteger$1.prototype.toString = bnToString; - BigInteger$1.prototype.negate = bnNegate; - BigInteger$1.prototype.abs = bnAbs; - BigInteger$1.prototype.compareTo = bnCompareTo; - BigInteger$1.prototype.bitLength = bnBitLength; - BigInteger$1.prototype.mod = bnMod; - BigInteger$1.prototype.modPowInt = bnModPowInt; - - // "constants" - BigInteger$1.ZERO = nbv(0); - BigInteger$1.ONE = nbv(1); - - // jsbn2 lib - - //Copyright (c) 2005-2009 Tom Wu - //All Rights Reserved. - //See "LICENSE" for details (See jsbn.js for LICENSE). - - //Extended JavaScript BN functions, required for RSA private ops. - - //Version 1.1: new BigInteger("0", 10) returns "proper" zero - - //(public) - function bnClone() { var r = nbi(); this.copyTo(r); return r; } - - //(public) return value as integer - function bnIntValue() { - if(this.s < 0) { - if(this.t == 1) return this.data[0]-this.DV; - else if(this.t == 0) return -1; - } else if(this.t == 1) return this.data[0]; - else if(this.t == 0) return 0; - // assumes 16 < DB < 32 - return ((this.data[1]&((1<<(32-this.DB))-1))<>24; } - - //(public) return value as short (assumes DB>=16) - function bnShortValue() { return (this.t==0)?this.s:(this.data[0]<<16)>>16; } - - //(protected) return x s.t. r^x < DV - function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } - - //(public) 0 if this == 0, 1 if this > 0 - function bnSigNum() { - if(this.s < 0) return -1; - else if(this.t <= 0 || (this.t == 1 && this.data[0] <= 0)) return 0; - else return 1; - } - - //(protected) convert to radix string - function bnpToRadix(b) { - if(b == null) b = 10; - if(this.signum() == 0 || b < 2 || b > 36) return "0"; - var cs = this.chunkSize(b); - var a = Math.pow(b,cs); - var d = nbv(a), y = nbi(), z = nbi(), r = ""; - this.divRemTo(d,y,z); - while(y.signum() > 0) { - r = (a+z.intValue()).toString(b).substr(1) + r; - y.divRemTo(d,y,z); - } - return z.intValue().toString(b) + r; - } - - //(protected) convert from radix string - function bnpFromRadix(s,b) { - this.fromInt(0); - if(b == null) b = 10; - var cs = this.chunkSize(b); - var d = Math.pow(b,cs), mi = false, j = 0, w = 0; - for(var i = 0; i < s.length; ++i) { - var x = intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-" && this.signum() == 0) mi = true; - continue; - } - w = b*w+x; - if(++j >= cs) { - this.dMultiply(d); - this.dAddOffset(w,0); - j = 0; - w = 0; - } - } - if(j > 0) { - this.dMultiply(Math.pow(b,j)); - this.dAddOffset(w,0); - } - if(mi) BigInteger$1.ZERO.subTo(this,this); - } - - //(protected) alternate constructor - function bnpFromNumber(a,b,c) { - if("number" == typeof b) { - // new BigInteger(int,int,RNG) - if(a < 2) this.fromInt(1); - else { - this.fromNumber(a,c); - if(!this.testBit(a-1)) // force MSB set - this.bitwiseTo(BigInteger$1.ONE.shiftLeft(a-1),op_or,this); - if(this.isEven()) this.dAddOffset(1,0); // force odd - while(!this.isProbablePrime(b)) { - this.dAddOffset(2,0); - if(this.bitLength() > a) this.subTo(BigInteger$1.ONE.shiftLeft(a-1),this); - } - } - } else { - // new BigInteger(int,RNG) - var x = new Array(), t = a&7; - x.length = (a>>3)+1; - b.nextBytes(x); - if(t > 0) x[0] &= ((1< 0) { - if(p < this.DB && (d = this.data[i]>>p) != (this.s&this.DM)>>p) - r[k++] = d|(this.s<<(this.DB-p)); - while(i >= 0) { - if(p < 8) { - d = (this.data[i]&((1<>(p+=this.DB-8); - } else { - d = (this.data[i]>>(p-=8))&0xff; - if(p <= 0) { p += this.DB; --i; } - } - if((d&0x80) != 0) d |= -256; - if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; - if(k > 0 || d != this.s) r[k++] = d; - } - } - return r; - } - - function bnEquals(a) { return(this.compareTo(a)==0); } - function bnMin(a) { return (this.compareTo(a)<0)?this:a; } - function bnMax(a) { return (this.compareTo(a)>0)?this:a; } - - //(protected) r = this op a (bitwise) - function bnpBitwiseTo(a,op,r) { - var i, f, m = Math.min(a.t,this.t); - for(i = 0; i < m; ++i) r.data[i] = op(this.data[i],a.data[i]); - if(a.t < this.t) { - f = a.s&this.DM; - for(i = m; i < this.t; ++i) r.data[i] = op(this.data[i],f); - r.t = this.t; - } else { - f = this.s&this.DM; - for(i = m; i < a.t; ++i) r.data[i] = op(f,a.data[i]); - r.t = a.t; - } - r.s = op(this.s,a.s); - r.clamp(); - } - - //(public) this & a - function op_and(x,y) { return x&y; } - function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } - - //(public) this | a - function op_or(x,y) { return x|y; } - function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } - - //(public) this ^ a - function op_xor(x,y) { return x^y; } - function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } - - //(public) this & ~a - function op_andnot(x,y) { return x&~y; } - function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } - - //(public) ~this - function bnNot() { - var r = nbi(); - for(var i = 0; i < this.t; ++i) r.data[i] = this.DM&~this.data[i]; - r.t = this.t; - r.s = ~this.s; - return r; - } - - //(public) this << n - function bnShiftLeft(n) { - var r = nbi(); - if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); - return r; - } - - //(public) this >> n - function bnShiftRight(n) { - var r = nbi(); - if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); - return r; - } - - //return index of lowest 1-bit in x, x < 2^31 - function lbit(x) { - if(x == 0) return -1; - var r = 0; - if((x&0xffff) == 0) { x >>= 16; r += 16; } - if((x&0xff) == 0) { x >>= 8; r += 8; } - if((x&0xf) == 0) { x >>= 4; r += 4; } - if((x&3) == 0) { x >>= 2; r += 2; } - if((x&1) == 0) ++r; - return r; - } - - //(public) returns index of lowest 1-bit (or -1 if none) - function bnGetLowestSetBit() { - for(var i = 0; i < this.t; ++i) - if(this.data[i] != 0) return i*this.DB+lbit(this.data[i]); - if(this.s < 0) return this.t*this.DB; - return -1; - } - - //return number of 1 bits in x - function cbit(x) { - var r = 0; - while(x != 0) { x &= x-1; ++r; } - return r; - } - - //(public) return number of set bits - function bnBitCount() { - var r = 0, x = this.s&this.DM; - for(var i = 0; i < this.t; ++i) r += cbit(this.data[i]^x); - return r; - } - - //(public) true iff nth bit is set - function bnTestBit(n) { - var j = Math.floor(n/this.DB); - if(j >= this.t) return(this.s!=0); - return((this.data[j]&(1<<(n%this.DB)))!=0); - } - - //(protected) this op (1<>= this.DB; - } - if(a.t < this.t) { - c += a.s; - while(i < this.t) { - c += this.data[i]; - r.data[i++] = c&this.DM; - c >>= this.DB; - } - c += this.s; - } else { - c += this.s; - while(i < a.t) { - c += a.data[i]; - r.data[i++] = c&this.DM; - c >>= this.DB; - } - c += a.s; - } - r.s = (c<0)?-1:0; - if(c > 0) r.data[i++] = c; - else if(c < -1) r.data[i++] = this.DV+c; - r.t = i; - r.clamp(); - } - - //(public) this + a - function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } - - //(public) this - a - function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } - - //(public) this * a - function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } - - //(public) this / a - function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } - - //(public) this % a - function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } - - //(public) [this/a,this%a] - function bnDivideAndRemainder(a) { - var q = nbi(), r = nbi(); - this.divRemTo(a,q,r); - return new Array(q,r); - } - - //(protected) this *= n, this >= 0, 1 < n < DV - function bnpDMultiply(n) { - this.data[this.t] = this.am(0,n-1,this,0,0,this.t); - ++this.t; - this.clamp(); - } - - //(protected) this += n << w words, this >= 0 - function bnpDAddOffset(n,w) { - if(n == 0) return; - while(this.t <= w) this.data[this.t++] = 0; - this.data[w] += n; - while(this.data[w] >= this.DV) { - this.data[w] -= this.DV; - if(++w >= this.t) this.data[this.t++] = 0; - ++this.data[w]; - } - } - - //A "null" reducer - function NullExp() {} - function nNop(x) { return x; } - function nMulTo(x,y,r) { x.multiplyTo(y,r); } - function nSqrTo(x,r) { x.squareTo(r); } - - NullExp.prototype.convert = nNop; - NullExp.prototype.revert = nNop; - NullExp.prototype.mulTo = nMulTo; - NullExp.prototype.sqrTo = nSqrTo; - - //(public) this^e - function bnPow(e) { return this.exp(e,new NullExp()); } - - //(protected) r = lower n words of "this * a", a.t <= n - //"this" should be the larger one if appropriate. - function bnpMultiplyLowerTo(a,n,r) { - var i = Math.min(this.t+a.t,n); - r.s = 0; // assumes a,this >= 0 - r.t = i; - while(i > 0) r.data[--i] = 0; - var j; - for(j = r.t-this.t; i < j; ++i) r.data[i+this.t] = this.am(0,a.data[i],r,i,0,this.t); - for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a.data[i],r,i,0,n-i); - r.clamp(); - } - - //(protected) r = "this * a" without lower n words, n > 0 - //"this" should be the larger one if appropriate. - function bnpMultiplyUpperTo(a,n,r) { - --n; - var i = r.t = this.t+a.t-n; - r.s = 0; // assumes a,this >= 0 - while(--i >= 0) r.data[i] = 0; - for(i = Math.max(n-this.t,0); i < a.t; ++i) - r.data[this.t+i-n] = this.am(n-i,a.data[i],r,0,0,this.t+i-n); - r.clamp(); - r.drShiftTo(1,r); - } - - //Barrett modular reduction - function Barrett(m) { - // setup Barrett - this.r2 = nbi(); - this.q3 = nbi(); - BigInteger$1.ONE.dlShiftTo(2*m.t,this.r2); - this.mu = this.r2.divide(m); - this.m = m; - } - - function barrettConvert(x) { - if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); - else if(x.compareTo(this.m) < 0) return x; - else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } - } - - function barrettRevert(x) { return x; } - - //x = x mod m (HAC 14.42) - function barrettReduce(x) { - x.drShiftTo(this.m.t-1,this.r2); - if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } - this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); - this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); - while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); - x.subTo(this.r2,x); - while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); - } - - //r = x^2 mod m; x != r - function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - - //r = x*y mod m; x,y != r - function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - - Barrett.prototype.convert = barrettConvert; - Barrett.prototype.revert = barrettRevert; - Barrett.prototype.reduce = barrettReduce; - Barrett.prototype.mulTo = barrettMulTo; - Barrett.prototype.sqrTo = barrettSqrTo; - - //(public) this^e % m (HAC 14.85) - function bnModPow(e,m) { - var i = e.bitLength(), k, r = nbv(1), z; - if(i <= 0) return r; - else if(i < 18) k = 1; - else if(i < 48) k = 3; - else if(i < 144) k = 4; - else if(i < 768) k = 5; - else k = 6; - if(i < 8) - z = new Classic(m); - else if(m.isEven()) - z = new Barrett(m); - else - z = new Montgomery(m); - - // precomputation - var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { - var g2 = nbi(); - z.sqrTo(g[1],g2); - while(n <= km) { - g[n] = nbi(); - z.mulTo(g2,g[n-2],g[n]); - n += 2; - } - } - - var j = e.t-1, w, is1 = true, r2 = nbi(), t; - i = nbits(e.data[j])-1; - while(j >= 0) { - if(i >= k1) w = (e.data[j]>>(i-k1))&km; - else { - w = (e.data[j]&((1<<(i+1))-1))<<(k1-i); - if(j > 0) w |= e.data[j-1]>>(this.DB+i-k1); - } - - n = k; - while((w&1) == 0) { w >>= 1; --n; } - if((i -= n) < 0) { i += this.DB; --j; } - if(is1) { // ret == 1, don't bother squaring or multiplying it - g[w].copyTo(r); - is1 = false; - } else { - while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } - if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } - z.mulTo(r2,g[w],r); - } - - while(j >= 0 && (e.data[j]&(1< 0) { - x.rShiftTo(g,x); - y.rShiftTo(g,y); - } - while(x.signum() > 0) { - if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); - if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); - if(x.compareTo(y) >= 0) { - x.subTo(y,x); - x.rShiftTo(1,x); - } else { - y.subTo(x,y); - y.rShiftTo(1,y); - } - } - if(g > 0) y.lShiftTo(g,y); - return y; - } - - //(protected) this % n, n < 2^26 - function bnpModInt(n) { - if(n <= 0) return 0; - var d = this.DV%n, r = (this.s<0)?n-1:0; - if(this.t > 0) - if(d == 0) r = this.data[0]%n; - else for(var i = this.t-1; i >= 0; --i) r = (d*r+this.data[i])%n; - return r; - } - - //(public) 1/this % m (HAC 14.61) - function bnModInverse(m) { - var ac = m.isEven(); - if((this.isEven() && ac) || m.signum() == 0) return BigInteger$1.ZERO; - var u = m.clone(), v = this.clone(); - var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); - while(u.signum() != 0) { - while(u.isEven()) { - u.rShiftTo(1,u); - if(ac) { - if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } - a.rShiftTo(1,a); - } else if(!b.isEven()) b.subTo(m,b); - b.rShiftTo(1,b); - } - while(v.isEven()) { - v.rShiftTo(1,v); - if(ac) { - if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } - c.rShiftTo(1,c); - } else if(!d.isEven()) d.subTo(m,d); - d.rShiftTo(1,d); - } - if(u.compareTo(v) >= 0) { - u.subTo(v,u); - if(ac) a.subTo(c,a); - b.subTo(d,b); - } else { - v.subTo(u,v); - if(ac) c.subTo(a,c); - d.subTo(b,d); - } - } - if(v.compareTo(BigInteger$1.ONE) != 0) return BigInteger$1.ZERO; - if(d.compareTo(m) >= 0) return d.subtract(m); - if(d.signum() < 0) d.addTo(m,d); else return d; - if(d.signum() < 0) return d.add(m); else return d; - } - - var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509]; - var lplim = (1<<26)/lowprimes[lowprimes.length-1]; - - //(public) test primality with certainty >= 1-.5^t - function bnIsProbablePrime(t) { - var i, x = this.abs(); - if(x.t == 1 && x.data[0] <= lowprimes[lowprimes.length-1]) { - for(i = 0; i < lowprimes.length; ++i) - if(x.data[0] == lowprimes[i]) return true; - return false; - } - if(x.isEven()) return false; - i = 1; - while(i < lowprimes.length) { - var m = lowprimes[i], j = i+1; - while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; - m = x.modInt(m); - while(i < j) if(m%lowprimes[i++] == 0) return false; - } - return x.millerRabin(t); - } - - //(protected) true if probably prime (HAC 4.24, Miller-Rabin) - function bnpMillerRabin(t) { - var n1 = this.subtract(BigInteger$1.ONE); - var k = n1.getLowestSetBit(); - if(k <= 0) return false; - var r = n1.shiftRight(k); - var prng = bnGetPrng(); - var a; - for(var i = 0; i < t; ++i) { - // select witness 'a' at random from between 1 and n1 - do { - a = new BigInteger$1(this.bitLength(), prng); - } - while(a.compareTo(BigInteger$1.ONE) <= 0 || a.compareTo(n1) >= 0); - var y = a.modPow(r,this); - if(y.compareTo(BigInteger$1.ONE) != 0 && y.compareTo(n1) != 0) { - var j = 1; - while(j++ < k && y.compareTo(n1) != 0) { - y = y.modPowInt(2,this); - if(y.compareTo(BigInteger$1.ONE) == 0) return false; - } - if(y.compareTo(n1) != 0) return false; - } - } - return true; - } - - // get pseudo random number generator - function bnGetPrng() { - // create prng with api that matches BigInteger secure random - return { - // x is an array to fill with bytes - nextBytes: function(x) { - for(var i = 0; i < x.length; ++i) { - x[i] = Math.floor(Math.random() * 0x0100); - } - } - }; - } - - //protected - BigInteger$1.prototype.chunkSize = bnpChunkSize; - BigInteger$1.prototype.toRadix = bnpToRadix; - BigInteger$1.prototype.fromRadix = bnpFromRadix; - BigInteger$1.prototype.fromNumber = bnpFromNumber; - BigInteger$1.prototype.bitwiseTo = bnpBitwiseTo; - BigInteger$1.prototype.changeBit = bnpChangeBit; - BigInteger$1.prototype.addTo = bnpAddTo; - BigInteger$1.prototype.dMultiply = bnpDMultiply; - BigInteger$1.prototype.dAddOffset = bnpDAddOffset; - BigInteger$1.prototype.multiplyLowerTo = bnpMultiplyLowerTo; - BigInteger$1.prototype.multiplyUpperTo = bnpMultiplyUpperTo; - BigInteger$1.prototype.modInt = bnpModInt; - BigInteger$1.prototype.millerRabin = bnpMillerRabin; - - //public - BigInteger$1.prototype.clone = bnClone; - BigInteger$1.prototype.intValue = bnIntValue; - BigInteger$1.prototype.byteValue = bnByteValue; - BigInteger$1.prototype.shortValue = bnShortValue; - BigInteger$1.prototype.signum = bnSigNum; - BigInteger$1.prototype.toByteArray = bnToByteArray; - BigInteger$1.prototype.equals = bnEquals; - BigInteger$1.prototype.min = bnMin; - BigInteger$1.prototype.max = bnMax; - BigInteger$1.prototype.and = bnAnd; - BigInteger$1.prototype.or = bnOr; - BigInteger$1.prototype.xor = bnXor; - BigInteger$1.prototype.andNot = bnAndNot; - BigInteger$1.prototype.not = bnNot; - BigInteger$1.prototype.shiftLeft = bnShiftLeft; - BigInteger$1.prototype.shiftRight = bnShiftRight; - BigInteger$1.prototype.getLowestSetBit = bnGetLowestSetBit; - BigInteger$1.prototype.bitCount = bnBitCount; - BigInteger$1.prototype.testBit = bnTestBit; - BigInteger$1.prototype.setBit = bnSetBit; - BigInteger$1.prototype.clearBit = bnClearBit; - BigInteger$1.prototype.flipBit = bnFlipBit; - BigInteger$1.prototype.add = bnAdd; - BigInteger$1.prototype.subtract = bnSubtract; - BigInteger$1.prototype.multiply = bnMultiply; - BigInteger$1.prototype.divide = bnDivide; - BigInteger$1.prototype.remainder = bnRemainder; - BigInteger$1.prototype.divideAndRemainder = bnDivideAndRemainder; - BigInteger$1.prototype.modPow = bnModPow; - BigInteger$1.prototype.modInverse = bnModInverse; - BigInteger$1.prototype.pow = bnPow; - BigInteger$1.prototype.gcd = bnGCD; - BigInteger$1.prototype.isProbablePrime = bnIsProbablePrime; - - var sha1_1 = createCommonjsModule(function (module) { - /** - * Secure Hash Algorithm with 160-bit digest (SHA-1) implementation. - * - * @author Dave Longley - * - * Copyright (c) 2010-2015 Digital Bazaar, Inc. - */ - - - - - var sha1 = module.exports = forge.sha1 = forge.sha1 || {}; - forge.md.sha1 = forge.md.algorithms.sha1 = sha1; - - /** - * Creates a SHA-1 message digest object. - * - * @return a message digest object. - */ - sha1.create = function() { - // do initialization as necessary - if(!_initialized) { - _init(); - } - - // SHA-1 state contains five 32-bit integers - var _state = null; - - // input buffer - var _input = forge.util.createBuffer(); - - // used for word storage - var _w = new Array(80); - - // message digest object - var md = { - algorithm: 'sha1', - blockLength: 64, - digestLength: 20, - // 56-bit length of message so far (does not including padding) - messageLength: 0, - // true message length - fullMessageLength: null, - // size of message length in bytes - messageLengthSize: 8 - }; - - /** - * Starts the digest. - * - * @return this digest object. - */ - md.start = function() { - // up to 56-bit message length for convenience - md.messageLength = 0; - - // full message length (set md.messageLength64 for backwards-compatibility) - md.fullMessageLength = md.messageLength64 = []; - var int32s = md.messageLengthSize / 4; - for(var i = 0; i < int32s; ++i) { - md.fullMessageLength.push(0); - } - _input = forge.util.createBuffer(); - _state = { - h0: 0x67452301, - h1: 0xEFCDAB89, - h2: 0x98BADCFE, - h3: 0x10325476, - h4: 0xC3D2E1F0 - }; - return md; - }; - // start digest automatically for first time - md.start(); - - /** - * Updates the digest with the given message input. The given input can - * treated as raw input (no encoding will be applied) or an encoding of - * 'utf8' maybe given to encode the input using UTF-8. - * - * @param msg the message input to update with. - * @param encoding the encoding to use (default: 'raw', other: 'utf8'). - * - * @return this digest object. - */ - md.update = function(msg, encoding) { - if(encoding === 'utf8') { - msg = forge.util.encodeUtf8(msg); - } - - // update message length - var len = msg.length; - md.messageLength += len; - len = [(len / 0x100000000) >>> 0, len >>> 0]; - for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { - md.fullMessageLength[i] += len[1]; - len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); - md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; - len[0] = ((len[1] / 0x100000000) >>> 0); - } - - // add bytes to input buffer - _input.putBytes(msg); - - // process bytes - _update(_state, _w, _input); - - // compact input buffer every 2K or if empty - if(_input.read > 2048 || _input.length() === 0) { - _input.compact(); - } - - return md; - }; - - /** - * Produces the digest. - * - * @return a byte buffer containing the digest value. - */ - md.digest = function() { - /* Note: Here we copy the remaining bytes in the input buffer and - add the appropriate SHA-1 padding. Then we do the final update - on a copy of the state so that if the user wants to get - intermediate digests they can do so. */ - - /* Determine the number of bytes that must be added to the message - to ensure its length is congruent to 448 mod 512. In other words, - the data to be digested must be a multiple of 512 bits (or 128 bytes). - This data includes the message, some padding, and the length of the - message. Since the length of the message will be encoded as 8 bytes (64 - bits), that means that the last segment of the data must have 56 bytes - (448 bits) of message and padding. Therefore, the length of the message - plus the padding must be congruent to 448 mod 512 because - 512 - 128 = 448. - - In order to fill up the message length it must be filled with - padding that begins with 1 bit followed by all 0 bits. Padding - must *always* be present, so if the message length is already - congruent to 448 mod 512, then 512 padding bits must be added. */ - - var finalBlock = forge.util.createBuffer(); - finalBlock.putBytes(_input.bytes()); - - // compute remaining size to be digested (include message length size) - var remaining = ( - md.fullMessageLength[md.fullMessageLength.length - 1] + - md.messageLengthSize); - - // add padding for overflow blockSize - overflow - // _padding starts with 1 byte with first bit is set (byte value 128), then - // there may be up to (blockSize - 1) other pad bytes - var overflow = remaining & (md.blockLength - 1); - finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); - - // serialize message length in bits in big-endian order; since length - // is stored in bytes we multiply by 8 and add carry from next int - var next, carry; - var bits = md.fullMessageLength[0] * 8; - for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { - next = md.fullMessageLength[i + 1] * 8; - carry = (next / 0x100000000) >>> 0; - bits += carry; - finalBlock.putInt32(bits >>> 0); - bits = next >>> 0; - } - finalBlock.putInt32(bits); - - var s2 = { - h0: _state.h0, - h1: _state.h1, - h2: _state.h2, - h3: _state.h3, - h4: _state.h4 - }; - _update(s2, _w, finalBlock); - var rval = forge.util.createBuffer(); - rval.putInt32(s2.h0); - rval.putInt32(s2.h1); - rval.putInt32(s2.h2); - rval.putInt32(s2.h3); - rval.putInt32(s2.h4); - return rval; - }; - - return md; - }; - - // sha-1 padding bytes not initialized yet - var _padding = null; - var _initialized = false; - - /** - * Initializes the constant tables. - */ - function _init() { - // create padding - _padding = String.fromCharCode(128); - _padding += forge.util.fillString(String.fromCharCode(0x00), 64); - - // now initialized - _initialized = true; - } - - /** - * Updates a SHA-1 state with the given byte buffer. - * - * @param s the SHA-1 state to update. - * @param w the array to use to store words. - * @param bytes the byte buffer to update with. - */ - function _update(s, w, bytes) { - // consume 512 bit (64 byte) chunks - var t, a, b, c, d, e, f, i; - var len = bytes.length(); - while(len >= 64) { - // the w array will be populated with sixteen 32-bit big-endian words - // and then extended into 80 32-bit words according to SHA-1 algorithm - // and for 32-79 using Max Locktyukhin's optimization - - // initialize hash value for this chunk - a = s.h0; - b = s.h1; - c = s.h2; - d = s.h3; - e = s.h4; - - // round 1 - for(i = 0; i < 16; ++i) { - t = bytes.getInt32(); - w[i] = t; - f = d ^ (b & (c ^ d)); - t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; - e = d; - d = c; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - c = ((b << 30) | (b >>> 2)) >>> 0; - b = a; - a = t; - } - for(; i < 20; ++i) { - t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]); - t = (t << 1) | (t >>> 31); - w[i] = t; - f = d ^ (b & (c ^ d)); - t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; - e = d; - d = c; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - c = ((b << 30) | (b >>> 2)) >>> 0; - b = a; - a = t; - } - // round 2 - for(; i < 32; ++i) { - t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]); - t = (t << 1) | (t >>> 31); - w[i] = t; - f = b ^ c ^ d; - t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; - e = d; - d = c; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - c = ((b << 30) | (b >>> 2)) >>> 0; - b = a; - a = t; - } - for(; i < 40; ++i) { - t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); - t = (t << 2) | (t >>> 30); - w[i] = t; - f = b ^ c ^ d; - t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; - e = d; - d = c; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - c = ((b << 30) | (b >>> 2)) >>> 0; - b = a; - a = t; - } - // round 3 - for(; i < 60; ++i) { - t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); - t = (t << 2) | (t >>> 30); - w[i] = t; - f = (b & c) | (d & (b ^ c)); - t = ((a << 5) | (a >>> 27)) + f + e + 0x8F1BBCDC + t; - e = d; - d = c; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - c = ((b << 30) | (b >>> 2)) >>> 0; - b = a; - a = t; - } - // round 4 - for(; i < 80; ++i) { - t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); - t = (t << 2) | (t >>> 30); - w[i] = t; - f = b ^ c ^ d; - t = ((a << 5) | (a >>> 27)) + f + e + 0xCA62C1D6 + t; - e = d; - d = c; - // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug - c = ((b << 30) | (b >>> 2)) >>> 0; - b = a; - a = t; - } - - // update hash state - s.h0 = (s.h0 + a) | 0; - s.h1 = (s.h1 + b) | 0; - s.h2 = (s.h2 + c) | 0; - s.h3 = (s.h3 + d) | 0; - s.h4 = (s.h4 + e) | 0; - - len -= 64; - } - } - }); - - var pkcs1_1 = createCommonjsModule(function (module) { - /** - * Partial implementation of PKCS#1 v2.2: RSA-OEAP - * - * Modified but based on the following MIT and BSD licensed code: - * - * https://github.com/kjur/jsjws/blob/master/rsa.js: - * - * The 'jsjws'(JSON Web Signature JavaScript Library) License - * - * Copyright (c) 2012 Kenji Urushima - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * http://webrsa.cvs.sourceforge.net/viewvc/webrsa/Client/RSAES-OAEP.js?content-type=text%2Fplain: - * - * RSAES-OAEP.js - * $Id: RSAES-OAEP.js,v 1.1.1.1 2003/03/19 15:37:20 ellispritchard Exp $ - * JavaScript Implementation of PKCS #1 v2.1 RSA CRYPTOGRAPHY STANDARD (RSA Laboratories, June 14, 2002) - * Copyright (C) Ellis Pritchard, Guardian Unlimited 2003. - * Contact: ellis@nukinetics.com - * Distributed under the BSD License. - * - * Official documentation: http://www.rsa.com/rsalabs/node.asp?id=2125 - * - * @author Evan Jones (http://evanjones.ca/) - * @author Dave Longley - * - * Copyright (c) 2013-2014 Digital Bazaar, Inc. - */ - - - - - - // shortcut for PKCS#1 API - var pkcs1 = module.exports = forge.pkcs1 = forge.pkcs1 || {}; - - /** - * Encode the given RSAES-OAEP message (M) using key, with optional label (L) - * and seed. - * - * This method does not perform RSA encryption, it only encodes the message - * using RSAES-OAEP. - * - * @param key the RSA key to use. - * @param message the message to encode. - * @param options the options to use: - * label an optional label to use. - * seed the seed to use. - * md the message digest object to use, undefined for SHA-1. - * mgf1 optional mgf1 parameters: - * md the message digest object to use for MGF1. - * - * @return the encoded message bytes. - */ - pkcs1.encode_rsa_oaep = function(key, message, options) { - // parse arguments - var label; - var seed; - var md; - var mgf1Md; - // legacy args (label, seed, md) - if(typeof options === 'string') { - label = options; - seed = arguments[3] || undefined; - md = arguments[4] || undefined; - } else if(options) { - label = options.label || undefined; - seed = options.seed || undefined; - md = options.md || undefined; - if(options.mgf1 && options.mgf1.md) { - mgf1Md = options.mgf1.md; - } - } - - // default OAEP to SHA-1 message digest - if(!md) { - md = forge.md.sha1.create(); - } else { - md.start(); - } - - // default MGF-1 to same as OAEP - if(!mgf1Md) { - mgf1Md = md; - } - - // compute length in bytes and check output - var keyLength = Math.ceil(key.n.bitLength() / 8); - var maxLength = keyLength - 2 * md.digestLength - 2; - if(message.length > maxLength) { - var error = new Error('RSAES-OAEP input message length is too long.'); - error.length = message.length; - error.maxLength = maxLength; - throw error; - } - - if(!label) { - label = ''; - } - md.update(label, 'raw'); - var lHash = md.digest(); - - var PS = ''; - var PS_length = maxLength - message.length; - for(var i = 0; i < PS_length; i++) { - PS += '\x00'; - } - - var DB = lHash.getBytes() + PS + '\x01' + message; - - if(!seed) { - seed = forge.random.getBytes(md.digestLength); - } else if(seed.length !== md.digestLength) { - var error = new Error('Invalid RSAES-OAEP seed. The seed length must ' + - 'match the digest length.'); - error.seedLength = seed.length; - error.digestLength = md.digestLength; - throw error; - } - - var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md); - var maskedDB = forge.util.xorBytes(DB, dbMask, DB.length); - - var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md); - var maskedSeed = forge.util.xorBytes(seed, seedMask, seed.length); - - // return encoded message - return '\x00' + maskedSeed + maskedDB; - }; - - /** - * Decode the given RSAES-OAEP encoded message (EM) using key, with optional - * label (L). - * - * This method does not perform RSA decryption, it only decodes the message - * using RSAES-OAEP. - * - * @param key the RSA key to use. - * @param em the encoded message to decode. - * @param options the options to use: - * label an optional label to use. - * md the message digest object to use for OAEP, undefined for SHA-1. - * mgf1 optional mgf1 parameters: - * md the message digest object to use for MGF1. - * - * @return the decoded message bytes. - */ - pkcs1.decode_rsa_oaep = function(key, em, options) { - // parse args - var label; - var md; - var mgf1Md; - // legacy args - if(typeof options === 'string') { - label = options; - md = arguments[3] || undefined; - } else if(options) { - label = options.label || undefined; - md = options.md || undefined; - if(options.mgf1 && options.mgf1.md) { - mgf1Md = options.mgf1.md; - } - } - - // compute length in bytes - var keyLength = Math.ceil(key.n.bitLength() / 8); - - if(em.length !== keyLength) { - var error = new Error('RSAES-OAEP encoded message length is invalid.'); - error.length = em.length; - error.expectedLength = keyLength; - throw error; - } - - // default OAEP to SHA-1 message digest - if(md === undefined) { - md = forge.md.sha1.create(); - } else { - md.start(); - } - - // default MGF-1 to same as OAEP - if(!mgf1Md) { - mgf1Md = md; - } - - if(keyLength < 2 * md.digestLength + 2) { - throw new Error('RSAES-OAEP key is too short for the hash function.'); - } - - if(!label) { - label = ''; - } - md.update(label, 'raw'); - var lHash = md.digest().getBytes(); - - // split the message into its parts - var y = em.charAt(0); - var maskedSeed = em.substring(1, md.digestLength + 1); - var maskedDB = em.substring(1 + md.digestLength); - - var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md); - var seed = forge.util.xorBytes(maskedSeed, seedMask, maskedSeed.length); - - var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md); - var db = forge.util.xorBytes(maskedDB, dbMask, maskedDB.length); - - var lHashPrime = db.substring(0, md.digestLength); - - // constant time check that all values match what is expected - var error = (y !== '\x00'); - - // constant time check lHash vs lHashPrime - for(var i = 0; i < md.digestLength; ++i) { - error |= (lHash.charAt(i) !== lHashPrime.charAt(i)); - } - - // "constant time" find the 0x1 byte separating the padding (zeros) from the - // message - // TODO: It must be possible to do this in a better/smarter way? - var in_ps = 1; - var index = md.digestLength; - for(var j = md.digestLength; j < db.length; j++) { - var code = db.charCodeAt(j); - - var is_0 = (code & 0x1) ^ 0x1; - - // non-zero if not 0 or 1 in the ps section - var error_mask = in_ps ? 0xfffe : 0x0000; - error |= (code & error_mask); - - // latch in_ps to zero after we find 0x1 - in_ps = in_ps & is_0; - index += in_ps; - } - - if(error || db.charCodeAt(index) !== 0x1) { - throw new Error('Invalid RSAES-OAEP padding.'); - } - - return db.substring(index + 1); - }; - - function rsa_mgf1(seed, maskLength, hash) { - // default to SHA-1 message digest - if(!hash) { - hash = forge.md.sha1.create(); - } - var t = ''; - var count = Math.ceil(maskLength / hash.digestLength); - for(var i = 0; i < count; ++i) { - var c = String.fromCharCode( - (i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF); - hash.start(); - hash.update(seed + c); - t += hash.digest().getBytes(); - } - return t.substring(0, maskLength); - } - }); - - var prime = createCommonjsModule(function (module) { - /** - * Prime number generation API. - * - * @author Dave Longley - * - * Copyright (c) 2014 Digital Bazaar, Inc. - */ - - - - - - (function() { - - // forge.prime already defined - if(forge.prime) { - module.exports = forge.prime; - return; - } - - /* PRIME API */ - var prime = module.exports = forge.prime = forge.prime || {}; - - var BigInteger = forge.jsbn.BigInteger; - - // primes are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29 - var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2]; - var THIRTY = new BigInteger(null); - THIRTY.fromInt(30); - var op_or = function(x, y) {return x|y;}; - - /** - * Generates a random probable prime with the given number of bits. - * - * Alternative algorithms can be specified by name as a string or as an - * object with custom options like so: - * - * { - * name: 'PRIMEINC', - * options: { - * maxBlockTime: , - * millerRabinTests: , - * workerScript: , - * workers: . - * workLoad: the size of the work load, ie: number of possible prime - * numbers for each web worker to check per work assignment, - * (default: 100). - * } - * } - * - * @param bits the number of bits for the prime number. - * @param options the options to use. - * [algorithm] the algorithm to use (default: 'PRIMEINC'). - * [prng] a custom crypto-secure pseudo-random number generator to use, - * that must define "getBytesSync". - * - * @return callback(err, num) called once the operation completes. - */ - prime.generateProbablePrime = function(bits, options, callback) { - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; - - // default to PRIMEINC algorithm - var algorithm = options.algorithm || 'PRIMEINC'; - if(typeof algorithm === 'string') { - algorithm = {name: algorithm}; - } - algorithm.options = algorithm.options || {}; - - // create prng with api that matches BigInteger secure random - var prng = options.prng || forge.random; - var rng = { - // x is an array to fill with bytes - nextBytes: function(x) { - var b = prng.getBytesSync(x.length); - for(var i = 0; i < x.length; ++i) { - x[i] = b.charCodeAt(i); - } - } - }; - - if(algorithm.name === 'PRIMEINC') { - return primeincFindPrime(bits, rng, algorithm.options, callback); - } - - throw new Error('Invalid prime generation algorithm: ' + algorithm.name); - }; - - function primeincFindPrime(bits, rng, options, callback) { - if('workers' in options) { - return primeincFindPrimeWithWorkers(bits, rng, options, callback); - } - return primeincFindPrimeWithoutWorkers(bits, rng, options, callback); - } - - function primeincFindPrimeWithoutWorkers(bits, rng, options, callback) { - // initialize random number - var num = generateRandom(bits, rng); - - /* Note: All primes are of the form 30k+i for i < 30 and gcd(30, i)=1. The - number we are given is always aligned at 30k + 1. Each time the number is - determined not to be prime we add to get to the next 'i', eg: if the number - was at 30k + 1 we add 6. */ - var deltaIdx = 0; - - // get required number of MR tests - var mrTests = getMillerRabinTests(num.bitLength()); - if('millerRabinTests' in options) { - mrTests = options.millerRabinTests; - } - - // find prime nearest to 'num' for maxBlockTime ms - // 10 ms gives 5ms of leeway for other calculations before dropping - // below 60fps (1000/60 == 16.67), but in reality, the number will - // likely be higher due to an 'atomic' big int modPow - var maxBlockTime = 10; - if('maxBlockTime' in options) { - maxBlockTime = options.maxBlockTime; - } - - _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback); - } - - function _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback) { - var start = +new Date(); - do { - // overflow, regenerate random number - if(num.bitLength() > bits) { - num = generateRandom(bits, rng); - } - // do primality test - if(num.isProbablePrime(mrTests)) { - return callback(null, num); - } - // get next potential prime - num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0); - } while(maxBlockTime < 0 || (+new Date() - start < maxBlockTime)); - - // keep trying later - forge.util.setImmediate(function() { - _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback); - }); - } - - // NOTE: This algorithm is indeterminate in nature because workers - // run in parallel looking at different segments of numbers. Even if this - // algorithm is run twice with the same input from a predictable RNG, it - // may produce different outputs. - function primeincFindPrimeWithWorkers(bits, rng, options, callback) { - // web workers unavailable - if(typeof Worker === 'undefined') { - return primeincFindPrimeWithoutWorkers(bits, rng, options, callback); - } - - // initialize random number - var num = generateRandom(bits, rng); - - // use web workers to generate keys - var numWorkers = options.workers; - var workLoad = options.workLoad || 100; - var range = workLoad * 30 / 8; - var workerScript = options.workerScript || 'forge/prime.worker.js'; - if(numWorkers === -1) { - return forge.util.estimateCores(function(err, cores) { - if(err) { - // default to 2 - cores = 2; - } - numWorkers = cores - 1; - generate(); - }); - } - generate(); - - function generate() { - // require at least 1 worker - numWorkers = Math.max(1, numWorkers); - - // TODO: consider optimizing by starting workers outside getPrime() ... - // note that in order to clean up they will have to be made internally - // asynchronous which may actually be slower - - // start workers immediately - var workers = []; - for(var i = 0; i < numWorkers; ++i) { - // FIXME: fix path or use blob URLs - workers[i] = new Worker(workerScript); - } - - // listen for requests from workers and assign ranges to find prime - for(var i = 0; i < numWorkers; ++i) { - workers[i].addEventListener('message', workerMessage); - } - - /* Note: The distribution of random numbers is unknown. Therefore, each - web worker is continuously allocated a range of numbers to check for a - random number until one is found. - - Every 30 numbers will be checked just 8 times, because prime numbers - have the form: - - 30k+i, for i < 30 and gcd(30, i)=1 (there are 8 values of i for this) - - Therefore, if we want a web worker to run N checks before asking for - a new range of numbers, each range must contain N*30/8 numbers. - - For 100 checks (workLoad), this is a range of 375. */ - - var found = false; - function workerMessage(e) { - // ignore message, prime already found - if(found) { - return; - } - var data = e.data; - if(data.found) { - // terminate all workers - for(var i = 0; i < workers.length; ++i) { - workers[i].terminate(); - } - found = true; - return callback(null, new BigInteger(data.prime, 16)); - } - - // overflow, regenerate random number - if(num.bitLength() > bits) { - num = generateRandom(bits, rng); - } - - // assign new range to check - var hex = num.toString(16); - - // start prime search - e.target.postMessage({ - hex: hex, - workLoad: workLoad - }); - - num.dAddOffset(range, 0); - } - } - } - - /** - * Generates a random number using the given number of bits and RNG. - * - * @param bits the number of bits for the number. - * @param rng the random number generator to use. - * - * @return the random number. - */ - function generateRandom(bits, rng) { - var num = new BigInteger(bits, rng); - // force MSB set - var bits1 = bits - 1; - if(!num.testBit(bits1)) { - num.bitwiseTo(BigInteger.ONE.shiftLeft(bits1), op_or, num); - } - // align number on 30k+1 boundary - num.dAddOffset(31 - num.mod(THIRTY).byteValue(), 0); - return num; - } - - /** - * Returns the required number of Miller-Rabin tests to generate a - * prime with an error probability of (1/2)^80. - * - * See Handbook of Applied Cryptography Chapter 4, Table 4.4. - * - * @param bits the bit size. - * - * @return the required number of iterations. - */ - function getMillerRabinTests(bits) { - if(bits <= 100) return 27; - if(bits <= 150) return 18; - if(bits <= 200) return 15; - if(bits <= 250) return 12; - if(bits <= 300) return 9; - if(bits <= 350) return 8; - if(bits <= 400) return 7; - if(bits <= 500) return 6; - if(bits <= 600) return 5; - if(bits <= 800) return 4; - if(bits <= 1250) return 3; - return 2; - } - - })(); - }); - - /** - * Javascript implementation of basic RSA algorithms. - * - * @author Dave Longley - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - * - * The only algorithm currently supported for PKI is RSA. - * - * An RSA key is often stored in ASN.1 DER format. The SubjectPublicKeyInfo - * ASN.1 structure is composed of an algorithm of type AlgorithmIdentifier - * and a subjectPublicKey of type bit string. - * - * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters - * for the algorithm, if any. In the case of RSA, there aren't any. - * - * SubjectPublicKeyInfo ::= SEQUENCE { - * algorithm AlgorithmIdentifier, - * subjectPublicKey BIT STRING - * } - * - * AlgorithmIdentifer ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - * - * For an RSA public key, the subjectPublicKey is: - * - * RSAPublicKey ::= SEQUENCE { - * modulus INTEGER, -- n - * publicExponent INTEGER -- e - * } - * - * PrivateKeyInfo ::= SEQUENCE { - * version Version, - * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - * privateKey PrivateKey, - * attributes [0] IMPLICIT Attributes OPTIONAL - * } - * - * Version ::= INTEGER - * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier - * PrivateKey ::= OCTET STRING - * Attributes ::= SET OF Attribute - * - * An RSA private key as the following structure: - * - * RSAPrivateKey ::= SEQUENCE { - * version Version, - * modulus INTEGER, -- n - * publicExponent INTEGER, -- e - * privateExponent INTEGER, -- d - * prime1 INTEGER, -- p - * prime2 INTEGER, -- q - * exponent1 INTEGER, -- d mod (p-1) - * exponent2 INTEGER, -- d mod (q-1) - * coefficient INTEGER -- (inverse of q) mod p - * } - * - * Version ::= INTEGER - * - * The OID for the RSA key algorithm is: 1.2.840.113549.1.1.1 - */ - - - - - - - - - - if(typeof BigInteger$2 === 'undefined') { - var BigInteger$2 = forge.jsbn.BigInteger; - } - - var _crypto = forge.util.isNodejs ? require$$7 : null; - - // shortcut for asn.1 API - var asn1 = forge.asn1; - - // shortcut for util API - var util = forge.util; - - /* - * RSA encryption and decryption, see RFC 2313. - */ - forge.pki = forge.pki || {}; - var rsa = forge.pki.rsa = forge.rsa = forge.rsa || {}; - var pki = forge.pki; - - // for finding primes, which are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29 - var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2]; - - // validator for a PrivateKeyInfo structure - var privateKeyValidator = { - // PrivateKeyInfo - name: 'PrivateKeyInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - // Version (INTEGER) - name: 'PrivateKeyInfo.version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyVersion' - }, { - // privateKeyAlgorithm - name: 'PrivateKeyInfo.privateKeyAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'AlgorithmIdentifier.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'privateKeyOid' - }] - }, { - // PrivateKey - name: 'PrivateKeyInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OCTETSTRING, - constructed: false, - capture: 'privateKey' - }] - }; - - // validator for an RSA private key - var rsaPrivateKeyValidator = { - // RSAPrivateKey - name: 'RSAPrivateKey', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - // Version (INTEGER) - name: 'RSAPrivateKey.version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyVersion' - }, { - // modulus (n) - name: 'RSAPrivateKey.modulus', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyModulus' - }, { - // publicExponent (e) - name: 'RSAPrivateKey.publicExponent', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyPublicExponent' - }, { - // privateExponent (d) - name: 'RSAPrivateKey.privateExponent', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyPrivateExponent' - }, { - // prime1 (p) - name: 'RSAPrivateKey.prime1', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyPrime1' - }, { - // prime2 (q) - name: 'RSAPrivateKey.prime2', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyPrime2' - }, { - // exponent1 (d mod (p-1)) - name: 'RSAPrivateKey.exponent1', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyExponent1' - }, { - // exponent2 (d mod (q-1)) - name: 'RSAPrivateKey.exponent2', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyExponent2' - }, { - // coefficient ((inverse of q) mod p) - name: 'RSAPrivateKey.coefficient', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'privateKeyCoefficient' - }] - }; - - // validator for an RSA public key - var rsaPublicKeyValidator = { - // RSAPublicKey - name: 'RSAPublicKey', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - // modulus (n) - name: 'RSAPublicKey.modulus', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'publicKeyModulus' - }, { - // publicExponent (e) - name: 'RSAPublicKey.exponent', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'publicKeyExponent' - }] - }; - - // validator for an SubjectPublicKeyInfo structure - // Note: Currently only works with an RSA public key - var publicKeyValidator = forge.pki.rsa.publicKeyValidator = { - name: 'SubjectPublicKeyInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'subjectPublicKeyInfo', - value: [{ - name: 'SubjectPublicKeyInfo.AlgorithmIdentifier', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'AlgorithmIdentifier.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'publicKeyOid' - }] - }, { - // subjectPublicKey - name: 'SubjectPublicKeyInfo.subjectPublicKey', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.BITSTRING, - constructed: false, - value: [{ - // RSAPublicKey - name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - optional: true, - captureAsn1: 'rsaPublicKey' - }] - }] - }; - - /** - * Wrap digest in DigestInfo object. - * - * This function implements EMSA-PKCS1-v1_5-ENCODE as per RFC 3447. - * - * DigestInfo ::= SEQUENCE { - * digestAlgorithm DigestAlgorithmIdentifier, - * digest Digest - * } - * - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * Digest ::= OCTET STRING - * - * @param md the message digest object with the hash to sign. - * - * @return the encoded message (ready for RSA encrytion) - */ - var emsaPkcs1v15encode = function(md) { - // get the oid for the algorithm - var oid; - if(md.algorithm in pki.oids) { - oid = pki.oids[md.algorithm]; - } else { - var error = new Error('Unknown message digest algorithm.'); - error.algorithm = md.algorithm; - throw error; - } - var oidBytes = asn1.oidToDer(oid).getBytes(); - - // create the digest info - var digestInfo = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - var digestAlgorithm = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - digestAlgorithm.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OID, false, oidBytes)); - digestAlgorithm.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')); - var digest = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, - false, md.digest().getBytes()); - digestInfo.value.push(digestAlgorithm); - digestInfo.value.push(digest); - - // encode digest info - return asn1.toDer(digestInfo).getBytes(); - }; - - /** - * Performs x^c mod n (RSA encryption or decryption operation). - * - * @param x the number to raise and mod. - * @param key the key to use. - * @param pub true if the key is public, false if private. - * - * @return the result of x^c mod n. - */ - var _modPow = function(x, key, pub) { - if(pub) { - return x.modPow(key.e, key.n); - } - - if(!key.p || !key.q) { - // allow calculation without CRT params (slow) - return x.modPow(key.d, key.n); - } - - // pre-compute dP, dQ, and qInv if necessary - if(!key.dP) { - key.dP = key.d.mod(key.p.subtract(BigInteger$2.ONE)); - } - if(!key.dQ) { - key.dQ = key.d.mod(key.q.subtract(BigInteger$2.ONE)); - } - if(!key.qInv) { - key.qInv = key.q.modInverse(key.p); - } - - /* Chinese remainder theorem (CRT) states: - - Suppose n1, n2, ..., nk are positive integers which are pairwise - coprime (n1 and n2 have no common factors other than 1). For any - integers x1, x2, ..., xk there exists an integer x solving the - system of simultaneous congruences (where ~= means modularly - congruent so a ~= b mod n means a mod n = b mod n): - - x ~= x1 mod n1 - x ~= x2 mod n2 - ... - x ~= xk mod nk - - This system of congruences has a single simultaneous solution x - between 0 and n - 1. Furthermore, each xk solution and x itself - is congruent modulo the product n = n1*n2*...*nk. - So x1 mod n = x2 mod n = xk mod n = x mod n. - - The single simultaneous solution x can be solved with the following - equation: - - x = sum(xi*ri*si) mod n where ri = n/ni and si = ri^-1 mod ni. - - Where x is less than n, xi = x mod ni. - - For RSA we are only concerned with k = 2. The modulus n = pq, where - p and q are coprime. The RSA decryption algorithm is: - - y = x^d mod n - - Given the above: - - x1 = x^d mod p - r1 = n/p = q - s1 = q^-1 mod p - x2 = x^d mod q - r2 = n/q = p - s2 = p^-1 mod q - - So y = (x1r1s1 + x2r2s2) mod n - = ((x^d mod p)q(q^-1 mod p) + (x^d mod q)p(p^-1 mod q)) mod n - - According to Fermat's Little Theorem, if the modulus P is prime, - for any integer A not evenly divisible by P, A^(P-1) ~= 1 mod P. - Since A is not divisible by P it follows that if: - N ~= M mod (P - 1), then A^N mod P = A^M mod P. Therefore: - - A^N mod P = A^(M mod (P - 1)) mod P. (The latter takes less effort - to calculate). In order to calculate x^d mod p more quickly the - exponent d mod (p - 1) is stored in the RSA private key (the same - is done for x^d mod q). These values are referred to as dP and dQ - respectively. Therefore we now have: - - y = ((x^dP mod p)q(q^-1 mod p) + (x^dQ mod q)p(p^-1 mod q)) mod n - - Since we'll be reducing x^dP by modulo p (same for q) we can also - reduce x by p (and q respectively) before hand. Therefore, let - - xp = ((x mod p)^dP mod p), and - xq = ((x mod q)^dQ mod q), yielding: - - y = (xp*q*(q^-1 mod p) + xq*p*(p^-1 mod q)) mod n - - This can be further reduced to a simple algorithm that only - requires 1 inverse (the q inverse is used) to be used and stored. - The algorithm is called Garner's algorithm. If qInv is the - inverse of q, we simply calculate: - - y = (qInv*(xp - xq) mod p) * q + xq - - However, there are two further complications. First, we need to - ensure that xp > xq to prevent signed BigIntegers from being used - so we add p until this is true (since we will be mod'ing with - p anyway). Then, there is a known timing attack on algorithms - using the CRT. To mitigate this risk, "cryptographic blinding" - should be used. This requires simply generating a random number r - between 0 and n-1 and its inverse and multiplying x by r^e before - calculating y and then multiplying y by r^-1 afterwards. Note that - r must be coprime with n (gcd(r, n) === 1) in order to have an - inverse. - */ - - // cryptographic blinding - var r; - do { - r = new BigInteger$2( - forge.util.bytesToHex(forge.random.getBytes(key.n.bitLength() / 8)), - 16); - } while(r.compareTo(key.n) >= 0 || !r.gcd(key.n).equals(BigInteger$2.ONE)); - x = x.multiply(r.modPow(key.e, key.n)).mod(key.n); - - // calculate xp and xq - var xp = x.mod(key.p).modPow(key.dP, key.p); - var xq = x.mod(key.q).modPow(key.dQ, key.q); - - // xp must be larger than xq to avoid signed bit usage - while(xp.compareTo(xq) < 0) { - xp = xp.add(key.p); - } - - // do last step - var y = xp.subtract(xq) - .multiply(key.qInv).mod(key.p) - .multiply(key.q).add(xq); - - // remove effect of random for cryptographic blinding - y = y.multiply(r.modInverse(key.n)).mod(key.n); - - return y; - }; - - /** - * NOTE: THIS METHOD IS DEPRECATED, use 'sign' on a private key object or - * 'encrypt' on a public key object instead. - * - * Performs RSA encryption. - * - * The parameter bt controls whether to put padding bytes before the - * message passed in. Set bt to either true or false to disable padding - * completely (in order to handle e.g. EMSA-PSS encoding seperately before), - * signaling whether the encryption operation is a public key operation - * (i.e. encrypting data) or not, i.e. private key operation (data signing). - * - * For PKCS#1 v1.5 padding pass in the block type to use, i.e. either 0x01 - * (for signing) or 0x02 (for encryption). The key operation mode (private - * or public) is derived from this flag in that case). - * - * @param m the message to encrypt as a byte string. - * @param key the RSA key to use. - * @param bt for PKCS#1 v1.5 padding, the block type to use - * (0x01 for private key, 0x02 for public), - * to disable padding: true = public key, false = private key. - * - * @return the encrypted bytes as a string. - */ - pki.rsa.encrypt = function(m, key, bt) { - var pub = bt; - var eb; - - // get the length of the modulus in bytes - var k = Math.ceil(key.n.bitLength() / 8); - - if(bt !== false && bt !== true) { - // legacy, default to PKCS#1 v1.5 padding - pub = (bt === 0x02); - eb = _encodePkcs1_v1_5(m, key, bt); - } else { - eb = forge.util.createBuffer(); - eb.putBytes(m); - } - - // load encryption block as big integer 'x' - // FIXME: hex conversion inefficient, get BigInteger w/byte strings - var x = new BigInteger$2(eb.toHex(), 16); - - // do RSA encryption - var y = _modPow(x, key, pub); - - // convert y into the encrypted data byte string, if y is shorter in - // bytes than k, then prepend zero bytes to fill up ed - // FIXME: hex conversion inefficient, get BigInteger w/byte strings - var yhex = y.toString(16); - var ed = forge.util.createBuffer(); - var zeros = k - Math.ceil(yhex.length / 2); - while(zeros > 0) { - ed.putByte(0x00); - --zeros; - } - ed.putBytes(forge.util.hexToBytes(yhex)); - return ed.getBytes(); - }; - - /** - * NOTE: THIS METHOD IS DEPRECATED, use 'decrypt' on a private key object or - * 'verify' on a public key object instead. - * - * Performs RSA decryption. - * - * The parameter ml controls whether to apply PKCS#1 v1.5 padding - * or not. Set ml = false to disable padding removal completely - * (in order to handle e.g. EMSA-PSS later on) and simply pass back - * the RSA encryption block. - * - * @param ed the encrypted data to decrypt in as a byte string. - * @param key the RSA key to use. - * @param pub true for a public key operation, false for private. - * @param ml the message length, if known, false to disable padding. - * - * @return the decrypted message as a byte string. - */ - pki.rsa.decrypt = function(ed, key, pub, ml) { - // get the length of the modulus in bytes - var k = Math.ceil(key.n.bitLength() / 8); - - // error if the length of the encrypted data ED is not k - if(ed.length !== k) { - var error = new Error('Encrypted message length is invalid.'); - error.length = ed.length; - error.expected = k; - throw error; - } - - // convert encrypted data into a big integer - // FIXME: hex conversion inefficient, get BigInteger w/byte strings - var y = new BigInteger$2(forge.util.createBuffer(ed).toHex(), 16); - - // y must be less than the modulus or it wasn't the result of - // a previous mod operation (encryption) using that modulus - if(y.compareTo(key.n) >= 0) { - throw new Error('Encrypted message is invalid.'); - } - - // do RSA decryption - var x = _modPow(y, key, pub); - - // create the encryption block, if x is shorter in bytes than k, then - // prepend zero bytes to fill up eb - // FIXME: hex conversion inefficient, get BigInteger w/byte strings - var xhex = x.toString(16); - var eb = forge.util.createBuffer(); - var zeros = k - Math.ceil(xhex.length / 2); - while(zeros > 0) { - eb.putByte(0x00); - --zeros; - } - eb.putBytes(forge.util.hexToBytes(xhex)); - - if(ml !== false) { - // legacy, default to PKCS#1 v1.5 padding - return _decodePkcs1_v1_5(eb.getBytes(), key, pub); - } - - // return message - return eb.getBytes(); - }; - - /** - * Creates an RSA key-pair generation state object. It is used to allow - * key-generation to be performed in steps. It also allows for a UI to - * display progress updates. - * - * @param bits the size for the private key in bits, defaults to 2048. - * @param e the public exponent to use, defaults to 65537 (0x10001). - * @param [options] the options to use. - * prng a custom crypto-secure pseudo-random number generator to use, - * that must define "getBytesSync". - * algorithm the algorithm to use (default: 'PRIMEINC'). - * - * @return the state object to use to generate the key-pair. - */ - pki.rsa.createKeyPairGenerationState = function(bits, e, options) { - // TODO: migrate step-based prime generation code to forge.prime - - // set default bits - if(typeof(bits) === 'string') { - bits = parseInt(bits, 10); - } - bits = bits || 2048; - - // create prng with api that matches BigInteger secure random - options = options || {}; - var prng = options.prng || forge.random; - var rng = { - // x is an array to fill with bytes - nextBytes: function(x) { - var b = prng.getBytesSync(x.length); - for(var i = 0; i < x.length; ++i) { - x[i] = b.charCodeAt(i); - } - } - }; - - var algorithm = options.algorithm || 'PRIMEINC'; - - // create PRIMEINC algorithm state - var rval; - if(algorithm === 'PRIMEINC') { - rval = { - algorithm: algorithm, - state: 0, - bits: bits, - rng: rng, - eInt: e || 65537, - e: new BigInteger$2(null), - p: null, - q: null, - qBits: bits >> 1, - pBits: bits - (bits >> 1), - pqState: 0, - num: null, - keys: null - }; - rval.e.fromInt(rval.eInt); - } else { - throw new Error('Invalid key generation algorithm: ' + algorithm); - } - - return rval; - }; - - /** - * Attempts to runs the key-generation algorithm for at most n seconds - * (approximately) using the given state. When key-generation has completed, - * the keys will be stored in state.keys. - * - * To use this function to update a UI while generating a key or to prevent - * causing browser lockups/warnings, set "n" to a value other than 0. A - * simple pattern for generating a key and showing a progress indicator is: - * - * var state = pki.rsa.createKeyPairGenerationState(2048); - * var step = function() { - * // step key-generation, run algorithm for 100 ms, repeat - * if(!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) { - * setTimeout(step, 1); - * } else { - * // key-generation complete - * // TODO: turn off progress indicator here - * // TODO: use the generated key-pair in "state.keys" - * } - * }; - * // TODO: turn on progress indicator here - * setTimeout(step, 0); - * - * @param state the state to use. - * @param n the maximum number of milliseconds to run the algorithm for, 0 - * to run the algorithm to completion. - * - * @return true if the key-generation completed, false if not. - */ - pki.rsa.stepKeyPairGenerationState = function(state, n) { - // set default algorithm if not set - if(!('algorithm' in state)) { - state.algorithm = 'PRIMEINC'; - } - - // TODO: migrate step-based prime generation code to forge.prime - // TODO: abstract as PRIMEINC algorithm - - // do key generation (based on Tom Wu's rsa.js, see jsbn.js license) - // with some minor optimizations and designed to run in steps - - // local state vars - var THIRTY = new BigInteger$2(null); - THIRTY.fromInt(30); - var deltaIdx = 0; - var op_or = function(x, y) {return x | y;}; - - // keep stepping until time limit is reached or done - var t1 = +new Date(); - var t2; - var total = 0; - while(state.keys === null && (n <= 0 || total < n)) { - // generate p or q - if(state.state === 0) { - /* Note: All primes are of the form: - - 30k+i, for i < 30 and gcd(30, i)=1, where there are 8 values for i - - When we generate a random number, we always align it at 30k + 1. Each - time the number is determined not to be prime we add to get to the - next 'i', eg: if the number was at 30k + 1 we add 6. */ - var bits = (state.p === null) ? state.pBits : state.qBits; - var bits1 = bits - 1; - - // get a random number - if(state.pqState === 0) { - state.num = new BigInteger$2(bits, state.rng); - // force MSB set - if(!state.num.testBit(bits1)) { - state.num.bitwiseTo( - BigInteger$2.ONE.shiftLeft(bits1), op_or, state.num); - } - // align number on 30k+1 boundary - state.num.dAddOffset(31 - state.num.mod(THIRTY).byteValue(), 0); - deltaIdx = 0; - - ++state.pqState; - } else if(state.pqState === 1) { - // try to make the number a prime - if(state.num.bitLength() > bits) { - // overflow, try again - state.pqState = 0; - // do primality test - } else if(state.num.isProbablePrime( - _getMillerRabinTests(state.num.bitLength()))) { - ++state.pqState; - } else { - // get next potential prime - state.num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0); - } - } else if(state.pqState === 2) { - // ensure number is coprime with e - state.pqState = - (state.num.subtract(BigInteger$2.ONE).gcd(state.e) - .compareTo(BigInteger$2.ONE) === 0) ? 3 : 0; - } else if(state.pqState === 3) { - // store p or q - state.pqState = 0; - if(state.p === null) { - state.p = state.num; - } else { - state.q = state.num; - } - - // advance state if both p and q are ready - if(state.p !== null && state.q !== null) { - ++state.state; - } - state.num = null; - } - } else if(state.state === 1) { - // ensure p is larger than q (swap them if not) - if(state.p.compareTo(state.q) < 0) { - state.num = state.p; - state.p = state.q; - state.q = state.num; - } - ++state.state; - } else if(state.state === 2) { - // compute phi: (p - 1)(q - 1) (Euler's totient function) - state.p1 = state.p.subtract(BigInteger$2.ONE); - state.q1 = state.q.subtract(BigInteger$2.ONE); - state.phi = state.p1.multiply(state.q1); - ++state.state; - } else if(state.state === 3) { - // ensure e and phi are coprime - if(state.phi.gcd(state.e).compareTo(BigInteger$2.ONE) === 0) { - // phi and e are coprime, advance - ++state.state; - } else { - // phi and e aren't coprime, so generate a new p and q - state.p = null; - state.q = null; - state.state = 0; - } - } else if(state.state === 4) { - // create n, ensure n is has the right number of bits - state.n = state.p.multiply(state.q); - - // ensure n is right number of bits - if(state.n.bitLength() === state.bits) { - // success, advance - ++state.state; - } else { - // failed, get new q - state.q = null; - state.state = 0; - } - } else if(state.state === 5) { - // set keys - var d = state.e.modInverse(state.phi); - state.keys = { - privateKey: pki.rsa.setPrivateKey( - state.n, state.e, d, state.p, state.q, - d.mod(state.p1), d.mod(state.q1), - state.q.modInverse(state.p)), - publicKey: pki.rsa.setPublicKey(state.n, state.e) - }; - } - - // update timing - t2 = +new Date(); - total += t2 - t1; - t1 = t2; - } - - return state.keys !== null; - }; - - /** - * Generates an RSA public-private key pair in a single call. - * - * To generate a key-pair in steps (to allow for progress updates and to - * prevent blocking or warnings in slow browsers) then use the key-pair - * generation state functions. - * - * To generate a key-pair asynchronously (either through web-workers, if - * available, or by breaking up the work on the main thread), pass a - * callback function. - * - * @param [bits] the size for the private key in bits, defaults to 2048. - * @param [e] the public exponent to use, defaults to 65537. - * @param [options] options for key-pair generation, if given then 'bits' - * and 'e' must *not* be given: - * bits the size for the private key in bits, (default: 2048). - * e the public exponent to use, (default: 65537 (0x10001)). - * workerScript the worker script URL. - * workers the number of web workers (if supported) to use, - * (default: 2). - * workLoad the size of the work load, ie: number of possible prime - * numbers for each web worker to check per work assignment, - * (default: 100). - * prng a custom crypto-secure pseudo-random number generator to use, - * that must define "getBytesSync". Disables use of native APIs. - * algorithm the algorithm to use (default: 'PRIMEINC'). - * @param [callback(err, keypair)] called once the operation completes. - * - * @return an object with privateKey and publicKey properties. - */ - pki.rsa.generateKeyPair = function(bits, e, options, callback) { - // (bits), (options), (callback) - if(arguments.length === 1) { - if(typeof bits === 'object') { - options = bits; - bits = undefined; - } else if(typeof bits === 'function') { - callback = bits; - bits = undefined; - } - } else if(arguments.length === 2) { - // (bits, e), (bits, options), (bits, callback), (options, callback) - if(typeof bits === 'number') { - if(typeof e === 'function') { - callback = e; - e = undefined; - } else if(typeof e !== 'number') { - options = e; - e = undefined; - } - } else { - options = bits; - callback = e; - bits = undefined; - e = undefined; - } - } else if(arguments.length === 3) { - // (bits, e, options), (bits, e, callback), (bits, options, callback) - if(typeof e === 'number') { - if(typeof options === 'function') { - callback = options; - options = undefined; - } - } else { - callback = options; - options = e; - e = undefined; - } - } - options = options || {}; - if(bits === undefined) { - bits = options.bits || 2048; - } - if(e === undefined) { - e = options.e || 0x10001; - } - - // use native code if permitted, available, and parameters are acceptable - if( !options.prng && - bits >= 256 && bits <= 16384 && (e === 0x10001 || e === 3)) { - if(callback) { - // try native async - if(_detectNodeCrypto('generateKeyPair')) { - return _crypto.generateKeyPair('rsa', { - modulusLength: bits, - publicExponent: e, - publicKeyEncoding: { - type: 'spki', - format: 'pem' - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem' - } - }, function(err, pub, priv) { - if(err) { - return callback(err); - } - callback(null, { - privateKey: pki.privateKeyFromPem(priv), - publicKey: pki.publicKeyFromPem(pub) - }); - }); - } - if(_detectSubtleCrypto('generateKey') && - _detectSubtleCrypto('exportKey')) { - // use standard native generateKey - return util.globalScope.crypto.subtle.generateKey({ - name: 'RSASSA-PKCS1-v1_5', - modulusLength: bits, - publicExponent: _intToUint8Array(e), - hash: {name: 'SHA-256'} - }, true /* key can be exported*/, ['sign', 'verify']) - .then(function(pair) { - return util.globalScope.crypto.subtle.exportKey( - 'pkcs8', pair.privateKey); - // avoiding catch(function(err) {...}) to support IE <= 8 - }).then(undefined, function(err) { - callback(err); - }).then(function(pkcs8) { - if(pkcs8) { - var privateKey = pki.privateKeyFromAsn1( - asn1.fromDer(forge.util.createBuffer(pkcs8))); - callback(null, { - privateKey: privateKey, - publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e) - }); - } - }); - } - if(_detectSubtleMsCrypto('generateKey') && - _detectSubtleMsCrypto('exportKey')) { - var genOp = util.globalScope.msCrypto.subtle.generateKey({ - name: 'RSASSA-PKCS1-v1_5', - modulusLength: bits, - publicExponent: _intToUint8Array(e), - hash: {name: 'SHA-256'} - }, true /* key can be exported*/, ['sign', 'verify']); - genOp.oncomplete = function(e) { - var pair = e.target.result; - var exportOp = util.globalScope.msCrypto.subtle.exportKey( - 'pkcs8', pair.privateKey); - exportOp.oncomplete = function(e) { - var pkcs8 = e.target.result; - var privateKey = pki.privateKeyFromAsn1( - asn1.fromDer(forge.util.createBuffer(pkcs8))); - callback(null, { - privateKey: privateKey, - publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e) - }); - }; - exportOp.onerror = function(err) { - callback(err); - }; - }; - genOp.onerror = function(err) { - callback(err); - }; - return; - } - } else { - // try native sync - if(_detectNodeCrypto('generateKeyPairSync')) { - var keypair = _crypto.generateKeyPairSync('rsa', { - modulusLength: bits, - publicExponent: e, - publicKeyEncoding: { - type: 'spki', - format: 'pem' - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem' - } - }); - return { - privateKey: pki.privateKeyFromPem(keypair.privateKey), - publicKey: pki.publicKeyFromPem(keypair.publicKey) - }; - } - } - } - - // use JavaScript implementation - var state = pki.rsa.createKeyPairGenerationState(bits, e, options); - if(!callback) { - pki.rsa.stepKeyPairGenerationState(state, 0); - return state.keys; - } - _generateKeyPair(state, options, callback); - }; - - /** - * Sets an RSA public key from BigIntegers modulus and exponent. - * - * @param n the modulus. - * @param e the exponent. - * - * @return the public key. - */ - pki.setRsaPublicKey = pki.rsa.setPublicKey = function(n, e) { - var key = { - n: n, - e: e - }; - - /** - * Encrypts the given data with this public key. Newer applications - * should use the 'RSA-OAEP' decryption scheme, 'RSAES-PKCS1-V1_5' is for - * legacy applications. - * - * @param data the byte string to encrypt. - * @param scheme the encryption scheme to use: - * 'RSAES-PKCS1-V1_5' (default), - * 'RSA-OAEP', - * 'RAW', 'NONE', or null to perform raw RSA encryption, - * an object with an 'encode' property set to a function - * with the signature 'function(data, key)' that returns - * a binary-encoded string representing the encoded data. - * @param schemeOptions any scheme-specific options. - * - * @return the encrypted byte string. - */ - key.encrypt = function(data, scheme, schemeOptions) { - if(typeof scheme === 'string') { - scheme = scheme.toUpperCase(); - } else if(scheme === undefined) { - scheme = 'RSAES-PKCS1-V1_5'; - } - - if(scheme === 'RSAES-PKCS1-V1_5') { - scheme = { - encode: function(m, key, pub) { - return _encodePkcs1_v1_5(m, key, 0x02).getBytes(); - } - }; - } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') { - scheme = { - encode: function(m, key) { - return forge.pkcs1.encode_rsa_oaep(key, m, schemeOptions); - } - }; - } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) { - scheme = {encode: function(e) {return e;}}; - } else if(typeof scheme === 'string') { - throw new Error('Unsupported encryption scheme: "' + scheme + '".'); - } - - // do scheme-based encoding then rsa encryption - var e = scheme.encode(data, key, true); - return pki.rsa.encrypt(e, key, true); - }; - - /** - * Verifies the given signature against the given digest. - * - * PKCS#1 supports multiple (currently two) signature schemes: - * RSASSA-PKCS1-V1_5 and RSASSA-PSS. - * - * By default this implementation uses the "old scheme", i.e. - * RSASSA-PKCS1-V1_5, in which case once RSA-decrypted, the - * signature is an OCTET STRING that holds a DigestInfo. - * - * DigestInfo ::= SEQUENCE { - * digestAlgorithm DigestAlgorithmIdentifier, - * digest Digest - * } - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * Digest ::= OCTET STRING - * - * To perform PSS signature verification, provide an instance - * of Forge PSS object as the scheme parameter. - * - * @param digest the message digest hash to compare against the signature, - * as a binary-encoded string. - * @param signature the signature to verify, as a binary-encoded string. - * @param scheme signature verification scheme to use: - * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5, - * a Forge PSS object for RSASSA-PSS, - * 'NONE' or null for none, DigestInfo will not be expected, but - * PKCS#1 v1.5 padding will still be used. - * - * @return true if the signature was verified, false if not. - */ - key.verify = function(digest, signature, scheme) { - if(typeof scheme === 'string') { - scheme = scheme.toUpperCase(); - } else if(scheme === undefined) { - scheme = 'RSASSA-PKCS1-V1_5'; - } - - if(scheme === 'RSASSA-PKCS1-V1_5') { - scheme = { - verify: function(digest, d) { - // remove padding - d = _decodePkcs1_v1_5(d, key, true); - // d is ASN.1 BER-encoded DigestInfo - var obj = asn1.fromDer(d); - // compare the given digest to the decrypted one - return digest === obj.value[1].value; - } - }; - } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) { - scheme = { - verify: function(digest, d) { - // remove padding - d = _decodePkcs1_v1_5(d, key, true); - return digest === d; - } - }; - } - - // do rsa decryption w/o any decoding, then verify -- which does decoding - var d = pki.rsa.decrypt(signature, key, true, false); - return scheme.verify(digest, d, key.n.bitLength()); - }; - - return key; - }; - - /** - * Sets an RSA private key from BigIntegers modulus, exponent, primes, - * prime exponents, and modular multiplicative inverse. - * - * @param n the modulus. - * @param e the public exponent. - * @param d the private exponent ((inverse of e) mod n). - * @param p the first prime. - * @param q the second prime. - * @param dP exponent1 (d mod (p-1)). - * @param dQ exponent2 (d mod (q-1)). - * @param qInv ((inverse of q) mod p) - * - * @return the private key. - */ - pki.setRsaPrivateKey = pki.rsa.setPrivateKey = function( - n, e, d, p, q, dP, dQ, qInv) { - var key = { - n: n, - e: e, - d: d, - p: p, - q: q, - dP: dP, - dQ: dQ, - qInv: qInv - }; - - /** - * Decrypts the given data with this private key. The decryption scheme - * must match the one used to encrypt the data. - * - * @param data the byte string to decrypt. - * @param scheme the decryption scheme to use: - * 'RSAES-PKCS1-V1_5' (default), - * 'RSA-OAEP', - * 'RAW', 'NONE', or null to perform raw RSA decryption. - * @param schemeOptions any scheme-specific options. - * - * @return the decrypted byte string. - */ - key.decrypt = function(data, scheme, schemeOptions) { - if(typeof scheme === 'string') { - scheme = scheme.toUpperCase(); - } else if(scheme === undefined) { - scheme = 'RSAES-PKCS1-V1_5'; - } - - // do rsa decryption w/o any decoding - var d = pki.rsa.decrypt(data, key, false, false); - - if(scheme === 'RSAES-PKCS1-V1_5') { - scheme = {decode: _decodePkcs1_v1_5}; - } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') { - scheme = { - decode: function(d, key) { - return forge.pkcs1.decode_rsa_oaep(key, d, schemeOptions); - } - }; - } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) { - scheme = {decode: function(d) {return d;}}; - } else { - throw new Error('Unsupported encryption scheme: "' + scheme + '".'); - } - - // decode according to scheme - return scheme.decode(d, key, false); - }; - - /** - * Signs the given digest, producing a signature. - * - * PKCS#1 supports multiple (currently two) signature schemes: - * RSASSA-PKCS1-V1_5 and RSASSA-PSS. - * - * By default this implementation uses the "old scheme", i.e. - * RSASSA-PKCS1-V1_5. In order to generate a PSS signature, provide - * an instance of Forge PSS object as the scheme parameter. - * - * @param md the message digest object with the hash to sign. - * @param scheme the signature scheme to use: - * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5, - * a Forge PSS object for RSASSA-PSS, - * 'NONE' or null for none, DigestInfo will not be used but - * PKCS#1 v1.5 padding will still be used. - * - * @return the signature as a byte string. - */ - key.sign = function(md, scheme) { - /* Note: The internal implementation of RSA operations is being - transitioned away from a PKCS#1 v1.5 hard-coded scheme. Some legacy - code like the use of an encoding block identifier 'bt' will eventually - be removed. */ - - // private key operation - var bt = false; - - if(typeof scheme === 'string') { - scheme = scheme.toUpperCase(); - } - - if(scheme === undefined || scheme === 'RSASSA-PKCS1-V1_5') { - scheme = {encode: emsaPkcs1v15encode}; - bt = 0x01; - } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) { - scheme = {encode: function() {return md;}}; - bt = 0x01; - } - - // encode and then encrypt - var d = scheme.encode(md, key.n.bitLength()); - return pki.rsa.encrypt(d, key, bt); - }; - - return key; - }; - - /** - * Wraps an RSAPrivateKey ASN.1 object in an ASN.1 PrivateKeyInfo object. - * - * @param rsaKey the ASN.1 RSAPrivateKey. - * - * @return the ASN.1 PrivateKeyInfo. - */ - pki.wrapRsaPrivateKey = function(rsaKey) { - // PrivateKeyInfo - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // version (0) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(0).getBytes()), - // privateKeyAlgorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.rsaEncryption).getBytes()), - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ]), - // PrivateKey - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - asn1.toDer(rsaKey).getBytes()) - ]); - }; - - /** - * Converts a private key from an ASN.1 object. - * - * @param obj the ASN.1 representation of a PrivateKeyInfo containing an - * RSAPrivateKey or an RSAPrivateKey. - * - * @return the private key. - */ - pki.privateKeyFromAsn1 = function(obj) { - // get PrivateKeyInfo - var capture = {}; - var errors = []; - if(asn1.validate(obj, privateKeyValidator, capture, errors)) { - obj = asn1.fromDer(forge.util.createBuffer(capture.privateKey)); - } - - // get RSAPrivateKey - capture = {}; - errors = []; - if(!asn1.validate(obj, rsaPrivateKeyValidator, capture, errors)) { - var error = new Error('Cannot read private key. ' + - 'ASN.1 object does not contain an RSAPrivateKey.'); - error.errors = errors; - throw error; - } - - // Note: Version is currently ignored. - // capture.privateKeyVersion - // FIXME: inefficient, get a BigInteger that uses byte strings - var n, e, d, p, q, dP, dQ, qInv; - n = forge.util.createBuffer(capture.privateKeyModulus).toHex(); - e = forge.util.createBuffer(capture.privateKeyPublicExponent).toHex(); - d = forge.util.createBuffer(capture.privateKeyPrivateExponent).toHex(); - p = forge.util.createBuffer(capture.privateKeyPrime1).toHex(); - q = forge.util.createBuffer(capture.privateKeyPrime2).toHex(); - dP = forge.util.createBuffer(capture.privateKeyExponent1).toHex(); - dQ = forge.util.createBuffer(capture.privateKeyExponent2).toHex(); - qInv = forge.util.createBuffer(capture.privateKeyCoefficient).toHex(); - - // set private key - return pki.setRsaPrivateKey( - new BigInteger$2(n, 16), - new BigInteger$2(e, 16), - new BigInteger$2(d, 16), - new BigInteger$2(p, 16), - new BigInteger$2(q, 16), - new BigInteger$2(dP, 16), - new BigInteger$2(dQ, 16), - new BigInteger$2(qInv, 16)); - }; - - /** - * Converts a private key to an ASN.1 RSAPrivateKey. - * - * @param key the private key. - * - * @return the ASN.1 representation of an RSAPrivateKey. - */ - pki.privateKeyToAsn1 = pki.privateKeyToRSAPrivateKey = function(key) { - // RSAPrivateKey - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // version (0 = only 2 primes, 1 multiple primes) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(0).getBytes()), - // modulus (n) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.n)), - // publicExponent (e) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.e)), - // privateExponent (d) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.d)), - // privateKeyPrime1 (p) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.p)), - // privateKeyPrime2 (q) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.q)), - // privateKeyExponent1 (dP) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.dP)), - // privateKeyExponent2 (dQ) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.dQ)), - // coefficient (qInv) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.qInv)) - ]); - }; - - /** - * Converts a public key from an ASN.1 SubjectPublicKeyInfo or RSAPublicKey. - * - * @param obj the asn1 representation of a SubjectPublicKeyInfo or RSAPublicKey. - * - * @return the public key. - */ - pki.publicKeyFromAsn1 = function(obj) { - // get SubjectPublicKeyInfo - var capture = {}; - var errors = []; - if(asn1.validate(obj, publicKeyValidator, capture, errors)) { - // get oid - var oid = asn1.derToOid(capture.publicKeyOid); - if(oid !== pki.oids.rsaEncryption) { - var error = new Error('Cannot read public key. Unknown OID.'); - error.oid = oid; - throw error; - } - obj = capture.rsaPublicKey; - } - - // get RSA params - errors = []; - if(!asn1.validate(obj, rsaPublicKeyValidator, capture, errors)) { - var error = new Error('Cannot read public key. ' + - 'ASN.1 object does not contain an RSAPublicKey.'); - error.errors = errors; - throw error; - } - - // FIXME: inefficient, get a BigInteger that uses byte strings - var n = forge.util.createBuffer(capture.publicKeyModulus).toHex(); - var e = forge.util.createBuffer(capture.publicKeyExponent).toHex(); - - // set public key - return pki.setRsaPublicKey( - new BigInteger$2(n, 16), - new BigInteger$2(e, 16)); - }; - - /** - * Converts a public key to an ASN.1 SubjectPublicKeyInfo. - * - * @param key the public key. - * - * @return the asn1 representation of a SubjectPublicKeyInfo. - */ - pki.publicKeyToAsn1 = pki.publicKeyToSubjectPublicKeyInfo = function(key) { - // SubjectPublicKeyInfo - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // AlgorithmIdentifier - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.rsaEncryption).getBytes()), - // parameters (null) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ]), - // subjectPublicKey - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [ - pki.publicKeyToRSAPublicKey(key) - ]) - ]); - }; - - /** - * Converts a public key to an ASN.1 RSAPublicKey. - * - * @param key the public key. - * - * @return the asn1 representation of a RSAPublicKey. - */ - pki.publicKeyToRSAPublicKey = function(key) { - // RSAPublicKey - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // modulus (n) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.n)), - // publicExponent (e) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - _bnToBytes(key.e)) - ]); - }; - - /** - * Encodes a message using PKCS#1 v1.5 padding. - * - * @param m the message to encode. - * @param key the RSA key to use. - * @param bt the block type to use, i.e. either 0x01 (for signing) or 0x02 - * (for encryption). - * - * @return the padded byte buffer. - */ - function _encodePkcs1_v1_5(m, key, bt) { - var eb = forge.util.createBuffer(); - - // get the length of the modulus in bytes - var k = Math.ceil(key.n.bitLength() / 8); - - /* use PKCS#1 v1.5 padding */ - if(m.length > (k - 11)) { - var error = new Error('Message is too long for PKCS#1 v1.5 padding.'); - error.length = m.length; - error.max = k - 11; - throw error; - } - - /* A block type BT, a padding string PS, and the data D shall be - formatted into an octet string EB, the encryption block: - - EB = 00 || BT || PS || 00 || D - - The block type BT shall be a single octet indicating the structure of - the encryption block. For this version of the document it shall have - value 00, 01, or 02. For a private-key operation, the block type - shall be 00 or 01. For a public-key operation, it shall be 02. - - The padding string PS shall consist of k-3-||D|| octets. For block - type 00, the octets shall have value 00; for block type 01, they - shall have value FF; and for block type 02, they shall be - pseudorandomly generated and nonzero. This makes the length of the - encryption block EB equal to k. */ - - // build the encryption block - eb.putByte(0x00); - eb.putByte(bt); - - // create the padding - var padNum = k - 3 - m.length; - var padByte; - // private key op - if(bt === 0x00 || bt === 0x01) { - padByte = (bt === 0x00) ? 0x00 : 0xFF; - for(var i = 0; i < padNum; ++i) { - eb.putByte(padByte); - } - } else { - // public key op - // pad with random non-zero values - while(padNum > 0) { - var numZeros = 0; - var padBytes = forge.random.getBytes(padNum); - for(var i = 0; i < padNum; ++i) { - padByte = padBytes.charCodeAt(i); - if(padByte === 0) { - ++numZeros; - } else { - eb.putByte(padByte); - } - } - padNum = numZeros; - } - } - - // zero followed by message - eb.putByte(0x00); - eb.putBytes(m); - - return eb; - } - - /** - * Decodes a message using PKCS#1 v1.5 padding. - * - * @param em the message to decode. - * @param key the RSA key to use. - * @param pub true if the key is a public key, false if it is private. - * @param ml the message length, if specified. - * - * @return the decoded bytes. - */ - function _decodePkcs1_v1_5(em, key, pub, ml) { - // get the length of the modulus in bytes - var k = Math.ceil(key.n.bitLength() / 8); - - /* It is an error if any of the following conditions occurs: - - 1. The encryption block EB cannot be parsed unambiguously. - 2. The padding string PS consists of fewer than eight octets - or is inconsisent with the block type BT. - 3. The decryption process is a public-key operation and the block - type BT is not 00 or 01, or the decryption process is a - private-key operation and the block type is not 02. - */ - - // parse the encryption block - var eb = forge.util.createBuffer(em); - var first = eb.getByte(); - var bt = eb.getByte(); - if(first !== 0x00 || - (pub && bt !== 0x00 && bt !== 0x01) || - (!pub && bt != 0x02) || - (pub && bt === 0x00 && typeof(ml) === 'undefined')) { - throw new Error('Encryption block is invalid.'); - } - - var padNum = 0; - if(bt === 0x00) { - // check all padding bytes for 0x00 - padNum = k - 3 - ml; - for(var i = 0; i < padNum; ++i) { - if(eb.getByte() !== 0x00) { - throw new Error('Encryption block is invalid.'); - } - } - } else if(bt === 0x01) { - // find the first byte that isn't 0xFF, should be after all padding - padNum = 0; - while(eb.length() > 1) { - if(eb.getByte() !== 0xFF) { - --eb.read; - break; - } - ++padNum; - } - } else if(bt === 0x02) { - // look for 0x00 byte - padNum = 0; - while(eb.length() > 1) { - if(eb.getByte() === 0x00) { - --eb.read; - break; - } - ++padNum; - } - } - - // zero must be 0x00 and padNum must be (k - 3 - message length) - var zero = eb.getByte(); - if(zero !== 0x00 || padNum !== (k - 3 - eb.length())) { - throw new Error('Encryption block is invalid.'); - } - - return eb.getBytes(); - } - - /** - * Runs the key-generation algorithm asynchronously, either in the background - * via Web Workers, or using the main thread and setImmediate. - * - * @param state the key-pair generation state. - * @param [options] options for key-pair generation: - * workerScript the worker script URL. - * workers the number of web workers (if supported) to use, - * (default: 2, -1 to use estimated cores minus one). - * workLoad the size of the work load, ie: number of possible prime - * numbers for each web worker to check per work assignment, - * (default: 100). - * @param callback(err, keypair) called once the operation completes. - */ - function _generateKeyPair(state, options, callback) { - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; - - var opts = { - algorithm: { - name: options.algorithm || 'PRIMEINC', - options: { - workers: options.workers || 2, - workLoad: options.workLoad || 100, - workerScript: options.workerScript - } - } - }; - if('prng' in options) { - opts.prng = options.prng; - } - - generate(); - - function generate() { - // find p and then q (done in series to simplify) - getPrime(state.pBits, function(err, num) { - if(err) { - return callback(err); - } - state.p = num; - if(state.q !== null) { - return finish(err, state.q); - } - getPrime(state.qBits, finish); - }); - } - - function getPrime(bits, callback) { - forge.prime.generateProbablePrime(bits, opts, callback); - } - - function finish(err, num) { - if(err) { - return callback(err); - } - - // set q - state.q = num; - - // ensure p is larger than q (swap them if not) - if(state.p.compareTo(state.q) < 0) { - var tmp = state.p; - state.p = state.q; - state.q = tmp; - } - - // ensure p is coprime with e - if(state.p.subtract(BigInteger$2.ONE).gcd(state.e) - .compareTo(BigInteger$2.ONE) !== 0) { - state.p = null; - generate(); - return; - } - - // ensure q is coprime with e - if(state.q.subtract(BigInteger$2.ONE).gcd(state.e) - .compareTo(BigInteger$2.ONE) !== 0) { - state.q = null; - getPrime(state.qBits, finish); - return; - } - - // compute phi: (p - 1)(q - 1) (Euler's totient function) - state.p1 = state.p.subtract(BigInteger$2.ONE); - state.q1 = state.q.subtract(BigInteger$2.ONE); - state.phi = state.p1.multiply(state.q1); - - // ensure e and phi are coprime - if(state.phi.gcd(state.e).compareTo(BigInteger$2.ONE) !== 0) { - // phi and e aren't coprime, so generate a new p and q - state.p = state.q = null; - generate(); - return; - } - - // create n, ensure n is has the right number of bits - state.n = state.p.multiply(state.q); - if(state.n.bitLength() !== state.bits) { - // failed, get new q - state.q = null; - getPrime(state.qBits, finish); - return; - } - - // set keys - var d = state.e.modInverse(state.phi); - state.keys = { - privateKey: pki.rsa.setPrivateKey( - state.n, state.e, d, state.p, state.q, - d.mod(state.p1), d.mod(state.q1), - state.q.modInverse(state.p)), - publicKey: pki.rsa.setPublicKey(state.n, state.e) - }; - - callback(null, state.keys); - } - } - - /** - * Converts a positive BigInteger into 2's-complement big-endian bytes. - * - * @param b the big integer to convert. - * - * @return the bytes. - */ - function _bnToBytes(b) { - // prepend 0x00 if first byte >= 0x80 - var hex = b.toString(16); - if(hex[0] >= '8') { - hex = '00' + hex; - } - var bytes = forge.util.hexToBytes(hex); - - // ensure integer is minimally-encoded - if(bytes.length > 1 && - // leading 0x00 for positive integer - ((bytes.charCodeAt(0) === 0 && - (bytes.charCodeAt(1) & 0x80) === 0) || - // leading 0xFF for negative integer - (bytes.charCodeAt(0) === 0xFF && - (bytes.charCodeAt(1) & 0x80) === 0x80))) { - return bytes.substr(1); - } - return bytes; - } - - /** - * Returns the required number of Miller-Rabin tests to generate a - * prime with an error probability of (1/2)^80. - * - * See Handbook of Applied Cryptography Chapter 4, Table 4.4. - * - * @param bits the bit size. - * - * @return the required number of iterations. - */ - function _getMillerRabinTests(bits) { - if(bits <= 100) return 27; - if(bits <= 150) return 18; - if(bits <= 200) return 15; - if(bits <= 250) return 12; - if(bits <= 300) return 9; - if(bits <= 350) return 8; - if(bits <= 400) return 7; - if(bits <= 500) return 6; - if(bits <= 600) return 5; - if(bits <= 800) return 4; - if(bits <= 1250) return 3; - return 2; - } - - /** - * Performs feature detection on the Node crypto interface. - * - * @param fn the feature (function) to detect. - * - * @return true if detected, false if not. - */ - function _detectNodeCrypto(fn) { - return forge.util.isNodejs && typeof _crypto[fn] === 'function'; - } - - /** - * Performs feature detection on the SubtleCrypto interface. - * - * @param fn the feature (function) to detect. - * - * @return true if detected, false if not. - */ - function _detectSubtleCrypto(fn) { - return (typeof util.globalScope !== 'undefined' && - typeof util.globalScope.crypto === 'object' && - typeof util.globalScope.crypto.subtle === 'object' && - typeof util.globalScope.crypto.subtle[fn] === 'function'); - } - - /** - * Performs feature detection on the deprecated Microsoft Internet Explorer - * outdated SubtleCrypto interface. This function should only be used after - * checking for the modern, standard SubtleCrypto interface. - * - * @param fn the feature (function) to detect. - * - * @return true if detected, false if not. - */ - function _detectSubtleMsCrypto(fn) { - return (typeof util.globalScope !== 'undefined' && - typeof util.globalScope.msCrypto === 'object' && - typeof util.globalScope.msCrypto.subtle === 'object' && - typeof util.globalScope.msCrypto.subtle[fn] === 'function'); - } - - function _intToUint8Array(x) { - var bytes = forge.util.hexToBytes(x.toString(16)); - var buffer = new Uint8Array(bytes.length); - for(var i = 0; i < bytes.length; ++i) { - buffer[i] = bytes.charCodeAt(i); - } - return buffer; - } - - /** - * Password-based encryption functions. - * - * @author Dave Longley - * @author Stefan Siegl - * - * Copyright (c) 2010-2013 Digital Bazaar, Inc. - * Copyright (c) 2012 Stefan Siegl - * - * An EncryptedPrivateKeyInfo: - * - * EncryptedPrivateKeyInfo ::= SEQUENCE { - * encryptionAlgorithm EncryptionAlgorithmIdentifier, - * encryptedData EncryptedData } - * - * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - * - * EncryptedData ::= OCTET STRING - */ - - - - - - - - - - - - - - if(typeof BigInteger$3 === 'undefined') { - var BigInteger$3 = forge.jsbn.BigInteger; - } - - // shortcut for asn.1 API - var asn1$1 = forge.asn1; - - /* Password-based encryption implementation. */ - var pki$1 = forge.pki = forge.pki || {}; - var pbe = pki$1.pbe = forge.pbe = forge.pbe || {}; - var oids = pki$1.oids; - - // validator for an EncryptedPrivateKeyInfo structure - // Note: Currently only works w/algorithm params - var encryptedPrivateKeyValidator = { - name: 'EncryptedPrivateKeyInfo', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'EncryptedPrivateKeyInfo.encryptionAlgorithm', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'AlgorithmIdentifier.algorithm', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OID, - constructed: false, - capture: 'encryptionOid' - }, { - name: 'AlgorithmIdentifier.parameters', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'encryptionParams' - }] - }, { - // encryptedData - name: 'EncryptedPrivateKeyInfo.encryptedData', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OCTETSTRING, - constructed: false, - capture: 'encryptedData' - }] - }; - - // validator for a PBES2Algorithms structure - // Note: Currently only works w/PBKDF2 + AES encryption schemes - var PBES2AlgorithmsValidator = { - name: 'PBES2Algorithms', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'PBES2Algorithms.keyDerivationFunc', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'PBES2Algorithms.keyDerivationFunc.oid', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OID, - constructed: false, - capture: 'kdfOid' - }, { - name: 'PBES2Algorithms.params', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'PBES2Algorithms.params.salt', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OCTETSTRING, - constructed: false, - capture: 'kdfSalt' - }, { - name: 'PBES2Algorithms.params.iterationCount', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.INTEGER, - constructed: false, - capture: 'kdfIterationCount' - }, { - name: 'PBES2Algorithms.params.keyLength', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.INTEGER, - constructed: false, - optional: true, - capture: 'keyLength' - }, { - // prf - name: 'PBES2Algorithms.params.prf', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - optional: true, - value: [{ - name: 'PBES2Algorithms.params.prf.algorithm', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OID, - constructed: false, - capture: 'prfOid' - }] - }] - }] - }, { - name: 'PBES2Algorithms.encryptionScheme', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'PBES2Algorithms.encryptionScheme.oid', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OID, - constructed: false, - capture: 'encOid' - }, { - name: 'PBES2Algorithms.encryptionScheme.iv', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OCTETSTRING, - constructed: false, - capture: 'encIv' - }] - }] - }; - - var pkcs12PbeParamsValidator = { - name: 'pkcs-12PbeParams', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'pkcs-12PbeParams.salt', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.OCTETSTRING, - constructed: false, - capture: 'salt' - }, { - name: 'pkcs-12PbeParams.iterations', - tagClass: asn1$1.Class.UNIVERSAL, - type: asn1$1.Type.INTEGER, - constructed: false, - capture: 'iterations' - }] - }; - - /** - * Encrypts a ASN.1 PrivateKeyInfo object, producing an EncryptedPrivateKeyInfo. - * - * PBES2Algorithms ALGORITHM-IDENTIFIER ::= - * { {PBES2-params IDENTIFIED BY id-PBES2}, ...} - * - * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} - * - * PBES2-params ::= SEQUENCE { - * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, - * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} - * } - * - * PBES2-KDFs ALGORITHM-IDENTIFIER ::= - * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } - * - * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } - * - * PBKDF2-params ::= SEQUENCE { - * salt CHOICE { - * specified OCTET STRING, - * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} - * }, - * iterationCount INTEGER (1..MAX), - * keyLength INTEGER (1..MAX) OPTIONAL, - * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 - * } - * - * @param obj the ASN.1 PrivateKeyInfo object. - * @param password the password to encrypt with. - * @param options: - * algorithm the encryption algorithm to use - * ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'. - * count the iteration count to use. - * saltSize the salt size to use. - * prfAlgorithm the PRF message digest algorithm to use - * ('sha1', 'sha224', 'sha256', 'sha384', 'sha512') - * - * @return the ASN.1 EncryptedPrivateKeyInfo. - */ - pki$1.encryptPrivateKeyInfo = function(obj, password, options) { - // set default options - options = options || {}; - options.saltSize = options.saltSize || 8; - options.count = options.count || 2048; - options.algorithm = options.algorithm || 'aes128'; - options.prfAlgorithm = options.prfAlgorithm || 'sha1'; - - // generate PBE params - var salt = forge.random.getBytesSync(options.saltSize); - var count = options.count; - var countBytes = asn1$1.integerToDer(count); - var dkLen; - var encryptionAlgorithm; - var encryptedData; - if(options.algorithm.indexOf('aes') === 0 || options.algorithm === 'des') { - // do PBES2 - var ivLen, encOid, cipherFn; - switch(options.algorithm) { - case 'aes128': - dkLen = 16; - ivLen = 16; - encOid = oids['aes128-CBC']; - cipherFn = forge.aes.createEncryptionCipher; - break; - case 'aes192': - dkLen = 24; - ivLen = 16; - encOid = oids['aes192-CBC']; - cipherFn = forge.aes.createEncryptionCipher; - break; - case 'aes256': - dkLen = 32; - ivLen = 16; - encOid = oids['aes256-CBC']; - cipherFn = forge.aes.createEncryptionCipher; - break; - case 'des': - dkLen = 8; - ivLen = 8; - encOid = oids['desCBC']; - cipherFn = forge.des.createEncryptionCipher; - break; - default: - var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.'); - error.algorithm = options.algorithm; - throw error; - } - - // get PRF message digest - var prfAlgorithm = 'hmacWith' + options.prfAlgorithm.toUpperCase(); - var md = prfAlgorithmToMessageDigest(prfAlgorithm); - - // encrypt private key using pbe SHA-1 and AES/DES - var dk = forge.pkcs5.pbkdf2(password, salt, count, dkLen, md); - var iv = forge.random.getBytesSync(ivLen); - var cipher = cipherFn(dk); - cipher.start(iv); - cipher.update(asn1$1.toDer(obj)); - cipher.finish(); - encryptedData = cipher.output.getBytes(); - - // get PBKDF2-params - var params = createPbkdf2Params(salt, countBytes, dkLen, prfAlgorithm); - - encryptionAlgorithm = asn1$1.create( - asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, - asn1$1.oidToDer(oids['pkcs5PBES2']).getBytes()), - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - // keyDerivationFunc - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, - asn1$1.oidToDer(oids['pkcs5PBKDF2']).getBytes()), - // PBKDF2-params - params - ]), - // encryptionScheme - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, - asn1$1.oidToDer(encOid).getBytes()), - // iv - asn1$1.create( - asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, iv) - ]) - ]) - ]); - } else if(options.algorithm === '3des') { - // Do PKCS12 PBE - dkLen = 24; - - var saltBytes = new forge.util.ByteBuffer(salt); - var dk = pki$1.pbe.generatePkcs12Key(password, saltBytes, 1, count, dkLen); - var iv = pki$1.pbe.generatePkcs12Key(password, saltBytes, 2, count, dkLen); - var cipher = forge.des.createEncryptionCipher(dk); - cipher.start(iv); - cipher.update(asn1$1.toDer(obj)); - cipher.finish(); - encryptedData = cipher.output.getBytes(); - - encryptionAlgorithm = asn1$1.create( - asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, - asn1$1.oidToDer(oids['pbeWithSHAAnd3-KeyTripleDES-CBC']).getBytes()), - // pkcs-12PbeParams - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - // salt - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, salt), - // iteration count - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.INTEGER, false, - countBytes.getBytes()) - ]) - ]); - } else { - var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.'); - error.algorithm = options.algorithm; - throw error; - } - - // EncryptedPrivateKeyInfo - var rval = asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - // encryptionAlgorithm - encryptionAlgorithm, - // encryptedData - asn1$1.create( - asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, encryptedData) - ]); - return rval; - }; - - /** - * Decrypts a ASN.1 PrivateKeyInfo object. - * - * @param obj the ASN.1 EncryptedPrivateKeyInfo object. - * @param password the password to decrypt with. - * - * @return the ASN.1 PrivateKeyInfo on success, null on failure. - */ - pki$1.decryptPrivateKeyInfo = function(obj, password) { - var rval = null; - - // get PBE params - var capture = {}; - var errors = []; - if(!asn1$1.validate(obj, encryptedPrivateKeyValidator, capture, errors)) { - var error = new Error('Cannot read encrypted private key. ' + - 'ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); - error.errors = errors; - throw error; - } - - // get cipher - var oid = asn1$1.derToOid(capture.encryptionOid); - var cipher = pki$1.pbe.getCipher(oid, capture.encryptionParams, password); - - // get encrypted data - var encrypted = forge.util.createBuffer(capture.encryptedData); - - cipher.update(encrypted); - if(cipher.finish()) { - rval = asn1$1.fromDer(cipher.output); - } - - return rval; - }; - - /** - * Converts a EncryptedPrivateKeyInfo to PEM format. - * - * @param epki the EncryptedPrivateKeyInfo. - * @param maxline the maximum characters per line, defaults to 64. - * - * @return the PEM-formatted encrypted private key. - */ - pki$1.encryptedPrivateKeyToPem = function(epki, maxline) { - // convert to DER, then PEM-encode - var msg = { - type: 'ENCRYPTED PRIVATE KEY', - body: asn1$1.toDer(epki).getBytes() - }; - return forge.pem.encode(msg, {maxline: maxline}); - }; - - /** - * Converts a PEM-encoded EncryptedPrivateKeyInfo to ASN.1 format. Decryption - * is not performed. - * - * @param pem the EncryptedPrivateKeyInfo in PEM-format. - * - * @return the ASN.1 EncryptedPrivateKeyInfo. - */ - pki$1.encryptedPrivateKeyFromPem = function(pem) { - var msg = forge.pem.decode(pem)[0]; - - if(msg.type !== 'ENCRYPTED PRIVATE KEY') { - var error = new Error('Could not convert encrypted private key from PEM; ' + - 'PEM header type is "ENCRYPTED PRIVATE KEY".'); - error.headerType = msg.type; - throw error; - } - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error('Could not convert encrypted private key from PEM; ' + - 'PEM is encrypted.'); - } - - // convert DER to ASN.1 object - return asn1$1.fromDer(msg.body); - }; - - /** - * Encrypts an RSA private key. By default, the key will be wrapped in - * a PrivateKeyInfo and encrypted to produce a PKCS#8 EncryptedPrivateKeyInfo. - * This is the standard, preferred way to encrypt a private key. - * - * To produce a non-standard PEM-encrypted private key that uses encapsulated - * headers to indicate the encryption algorithm (old-style non-PKCS#8 OpenSSL - * private key encryption), set the 'legacy' option to true. Note: Using this - * option will cause the iteration count to be forced to 1. - * - * Note: The 'des' algorithm is supported, but it is not considered to be - * secure because it only uses a single 56-bit key. If possible, it is highly - * recommended that a different algorithm be used. - * - * @param rsaKey the RSA key to encrypt. - * @param password the password to use. - * @param options: - * algorithm: the encryption algorithm to use - * ('aes128', 'aes192', 'aes256', '3des', 'des'). - * count: the iteration count to use. - * saltSize: the salt size to use. - * legacy: output an old non-PKCS#8 PEM-encrypted+encapsulated - * headers (DEK-Info) private key. - * - * @return the PEM-encoded ASN.1 EncryptedPrivateKeyInfo. - */ - pki$1.encryptRsaPrivateKey = function(rsaKey, password, options) { - // standard PKCS#8 - options = options || {}; - if(!options.legacy) { - // encrypt PrivateKeyInfo - var rval = pki$1.wrapRsaPrivateKey(pki$1.privateKeyToAsn1(rsaKey)); - rval = pki$1.encryptPrivateKeyInfo(rval, password, options); - return pki$1.encryptedPrivateKeyToPem(rval); - } - - // legacy non-PKCS#8 - var algorithm; - var iv; - var dkLen; - var cipherFn; - switch(options.algorithm) { - case 'aes128': - algorithm = 'AES-128-CBC'; - dkLen = 16; - iv = forge.random.getBytesSync(16); - cipherFn = forge.aes.createEncryptionCipher; - break; - case 'aes192': - algorithm = 'AES-192-CBC'; - dkLen = 24; - iv = forge.random.getBytesSync(16); - cipherFn = forge.aes.createEncryptionCipher; - break; - case 'aes256': - algorithm = 'AES-256-CBC'; - dkLen = 32; - iv = forge.random.getBytesSync(16); - cipherFn = forge.aes.createEncryptionCipher; - break; - case '3des': - algorithm = 'DES-EDE3-CBC'; - dkLen = 24; - iv = forge.random.getBytesSync(8); - cipherFn = forge.des.createEncryptionCipher; - break; - case 'des': - algorithm = 'DES-CBC'; - dkLen = 8; - iv = forge.random.getBytesSync(8); - cipherFn = forge.des.createEncryptionCipher; - break; - default: - var error = new Error('Could not encrypt RSA private key; unsupported ' + - 'encryption algorithm "' + options.algorithm + '".'); - error.algorithm = options.algorithm; - throw error; - } - - // encrypt private key using OpenSSL legacy key derivation - var dk = forge.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen); - var cipher = cipherFn(dk); - cipher.start(iv); - cipher.update(asn1$1.toDer(pki$1.privateKeyToAsn1(rsaKey))); - cipher.finish(); - - var msg = { - type: 'RSA PRIVATE KEY', - procType: { - version: '4', - type: 'ENCRYPTED' - }, - dekInfo: { - algorithm: algorithm, - parameters: forge.util.bytesToHex(iv).toUpperCase() - }, - body: cipher.output.getBytes() - }; - return forge.pem.encode(msg); - }; - - /** - * Decrypts an RSA private key. - * - * @param pem the PEM-formatted EncryptedPrivateKeyInfo to decrypt. - * @param password the password to use. - * - * @return the RSA key on success, null on failure. - */ - pki$1.decryptRsaPrivateKey = function(pem, password) { - var rval = null; - - var msg = forge.pem.decode(pem)[0]; - - if(msg.type !== 'ENCRYPTED PRIVATE KEY' && - msg.type !== 'PRIVATE KEY' && - msg.type !== 'RSA PRIVATE KEY') { - var error = new Error('Could not convert private key from PEM; PEM header type ' + - 'is not "ENCRYPTED PRIVATE KEY", "PRIVATE KEY", or "RSA PRIVATE KEY".'); - error.headerType = error; - throw error; - } - - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - var dkLen; - var cipherFn; - switch(msg.dekInfo.algorithm) { - case 'DES-CBC': - dkLen = 8; - cipherFn = forge.des.createDecryptionCipher; - break; - case 'DES-EDE3-CBC': - dkLen = 24; - cipherFn = forge.des.createDecryptionCipher; - break; - case 'AES-128-CBC': - dkLen = 16; - cipherFn = forge.aes.createDecryptionCipher; - break; - case 'AES-192-CBC': - dkLen = 24; - cipherFn = forge.aes.createDecryptionCipher; - break; - case 'AES-256-CBC': - dkLen = 32; - cipherFn = forge.aes.createDecryptionCipher; - break; - case 'RC2-40-CBC': - dkLen = 5; - cipherFn = function(key) { - return forge.rc2.createDecryptionCipher(key, 40); - }; - break; - case 'RC2-64-CBC': - dkLen = 8; - cipherFn = function(key) { - return forge.rc2.createDecryptionCipher(key, 64); - }; - break; - case 'RC2-128-CBC': - dkLen = 16; - cipherFn = function(key) { - return forge.rc2.createDecryptionCipher(key, 128); - }; - break; - default: - var error = new Error('Could not decrypt private key; unsupported ' + - 'encryption algorithm "' + msg.dekInfo.algorithm + '".'); - error.algorithm = msg.dekInfo.algorithm; - throw error; - } - - // use OpenSSL legacy key derivation - var iv = forge.util.hexToBytes(msg.dekInfo.parameters); - var dk = forge.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen); - var cipher = cipherFn(dk); - cipher.start(iv); - cipher.update(forge.util.createBuffer(msg.body)); - if(cipher.finish()) { - rval = cipher.output.getBytes(); - } else { - return rval; - } - } else { - rval = msg.body; - } - - if(msg.type === 'ENCRYPTED PRIVATE KEY') { - rval = pki$1.decryptPrivateKeyInfo(asn1$1.fromDer(rval), password); - } else { - // decryption already performed above - rval = asn1$1.fromDer(rval); - } - - if(rval !== null) { - rval = pki$1.privateKeyFromAsn1(rval); - } - - return rval; - }; - - /** - * Derives a PKCS#12 key. - * - * @param password the password to derive the key material from, null or - * undefined for none. - * @param salt the salt, as a ByteBuffer, to use. - * @param id the PKCS#12 ID byte (1 = key material, 2 = IV, 3 = MAC). - * @param iter the iteration count. - * @param n the number of bytes to derive from the password. - * @param md the message digest to use, defaults to SHA-1. - * - * @return a ByteBuffer with the bytes derived from the password. - */ - pki$1.pbe.generatePkcs12Key = function(password, salt, id, iter, n, md) { - var j, l; - - if(typeof md === 'undefined' || md === null) { - if(!('sha1' in forge.md)) { - throw new Error('"sha1" hash algorithm unavailable.'); - } - md = forge.md.sha1.create(); - } - - var u = md.digestLength; - var v = md.blockLength; - var result = new forge.util.ByteBuffer(); - - /* Convert password to Unicode byte buffer + trailing 0-byte. */ - var passBuf = new forge.util.ByteBuffer(); - if(password !== null && password !== undefined) { - for(l = 0; l < password.length; l++) { - passBuf.putInt16(password.charCodeAt(l)); - } - passBuf.putInt16(0); - } - - /* Length of salt and password in BYTES. */ - var p = passBuf.length(); - var s = salt.length(); - - /* 1. Construct a string, D (the "diversifier"), by concatenating - v copies of ID. */ - var D = new forge.util.ByteBuffer(); - D.fillWithByte(id, v); - - /* 2. Concatenate copies of the salt together to create a string S of length - v * ceil(s / v) bytes (the final copy of the salt may be trunacted - to create S). - Note that if the salt is the empty string, then so is S. */ - var Slen = v * Math.ceil(s / v); - var S = new forge.util.ByteBuffer(); - for(l = 0; l < Slen; l++) { - S.putByte(salt.at(l % s)); - } - - /* 3. Concatenate copies of the password together to create a string P of - length v * ceil(p / v) bytes (the final copy of the password may be - truncated to create P). - Note that if the password is the empty string, then so is P. */ - var Plen = v * Math.ceil(p / v); - var P = new forge.util.ByteBuffer(); - for(l = 0; l < Plen; l++) { - P.putByte(passBuf.at(l % p)); - } - - /* 4. Set I=S||P to be the concatenation of S and P. */ - var I = S; - I.putBuffer(P); - - /* 5. Set c=ceil(n / u). */ - var c = Math.ceil(n / u); - - /* 6. For i=1, 2, ..., c, do the following: */ - for(var i = 1; i <= c; i++) { - /* a) Set Ai=H^r(D||I). (l.e. the rth hash of D||I, H(H(H(...H(D||I)))) */ - var buf = new forge.util.ByteBuffer(); - buf.putBytes(D.bytes()); - buf.putBytes(I.bytes()); - for(var round = 0; round < iter; round++) { - md.start(); - md.update(buf.getBytes()); - buf = md.digest(); - } - - /* b) Concatenate copies of Ai to create a string B of length v bytes (the - final copy of Ai may be truncated to create B). */ - var B = new forge.util.ByteBuffer(); - for(l = 0; l < v; l++) { - B.putByte(buf.at(l % u)); - } - - /* c) Treating I as a concatenation I0, I1, ..., Ik-1 of v-byte blocks, - where k=ceil(s / v) + ceil(p / v), modify I by setting - Ij=(Ij+B+1) mod 2v for each j. */ - var k = Math.ceil(s / v) + Math.ceil(p / v); - var Inew = new forge.util.ByteBuffer(); - for(j = 0; j < k; j++) { - var chunk = new forge.util.ByteBuffer(I.getBytes(v)); - var x = 0x1ff; - for(l = B.length() - 1; l >= 0; l--) { - x = x >> 8; - x += B.at(l) + chunk.at(l); - chunk.setAt(l, x & 0xff); - } - Inew.putBuffer(chunk); - } - I = Inew; - - /* Add Ai to A. */ - result.putBuffer(buf); - } - - result.truncate(result.length() - n); - return result; - }; - - /** - * Get new Forge cipher object instance. - * - * @param oid the OID (in string notation). - * @param params the ASN.1 params object. - * @param password the password to decrypt with. - * - * @return new cipher object instance. - */ - pki$1.pbe.getCipher = function(oid, params, password) { - switch(oid) { - case pki$1.oids['pkcs5PBES2']: - return pki$1.pbe.getCipherForPBES2(oid, params, password); - - case pki$1.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']: - case pki$1.oids['pbewithSHAAnd40BitRC2-CBC']: - return pki$1.pbe.getCipherForPKCS12PBE(oid, params, password); - - default: - var error = new Error('Cannot read encrypted PBE data block. Unsupported OID.'); - error.oid = oid; - error.supportedOids = [ - 'pkcs5PBES2', - 'pbeWithSHAAnd3-KeyTripleDES-CBC', - 'pbewithSHAAnd40BitRC2-CBC' - ]; - throw error; - } - }; - - /** - * Get new Forge cipher object instance according to PBES2 params block. - * - * The returned cipher instance is already started using the IV - * from PBES2 parameter block. - * - * @param oid the PKCS#5 PBKDF2 OID (in string notation). - * @param params the ASN.1 PBES2-params object. - * @param password the password to decrypt with. - * - * @return new cipher object instance. - */ - pki$1.pbe.getCipherForPBES2 = function(oid, params, password) { - // get PBE params - var capture = {}; - var errors = []; - if(!asn1$1.validate(params, PBES2AlgorithmsValidator, capture, errors)) { - var error = new Error('Cannot read password-based-encryption algorithm ' + - 'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); - error.errors = errors; - throw error; - } - - // check oids - oid = asn1$1.derToOid(capture.kdfOid); - if(oid !== pki$1.oids['pkcs5PBKDF2']) { - var error = new Error('Cannot read encrypted private key. ' + - 'Unsupported key derivation function OID.'); - error.oid = oid; - error.supportedOids = ['pkcs5PBKDF2']; - throw error; - } - oid = asn1$1.derToOid(capture.encOid); - if(oid !== pki$1.oids['aes128-CBC'] && - oid !== pki$1.oids['aes192-CBC'] && - oid !== pki$1.oids['aes256-CBC'] && - oid !== pki$1.oids['des-EDE3-CBC'] && - oid !== pki$1.oids['desCBC']) { - var error = new Error('Cannot read encrypted private key. ' + - 'Unsupported encryption scheme OID.'); - error.oid = oid; - error.supportedOids = [ - 'aes128-CBC', 'aes192-CBC', 'aes256-CBC', 'des-EDE3-CBC', 'desCBC']; - throw error; - } - - // set PBE params - var salt = capture.kdfSalt; - var count = forge.util.createBuffer(capture.kdfIterationCount); - count = count.getInt(count.length() << 3); - var dkLen; - var cipherFn; - switch(pki$1.oids[oid]) { - case 'aes128-CBC': - dkLen = 16; - cipherFn = forge.aes.createDecryptionCipher; - break; - case 'aes192-CBC': - dkLen = 24; - cipherFn = forge.aes.createDecryptionCipher; - break; - case 'aes256-CBC': - dkLen = 32; - cipherFn = forge.aes.createDecryptionCipher; - break; - case 'des-EDE3-CBC': - dkLen = 24; - cipherFn = forge.des.createDecryptionCipher; - break; - case 'desCBC': - dkLen = 8; - cipherFn = forge.des.createDecryptionCipher; - break; - } - - // get PRF message digest - var md = prfOidToMessageDigest(capture.prfOid); - - // decrypt private key using pbe with chosen PRF and AES/DES - var dk = forge.pkcs5.pbkdf2(password, salt, count, dkLen, md); - var iv = capture.encIv; - var cipher = cipherFn(dk); - cipher.start(iv); - - return cipher; - }; - - /** - * Get new Forge cipher object instance for PKCS#12 PBE. - * - * The returned cipher instance is already started using the key & IV - * derived from the provided password and PKCS#12 PBE salt. - * - * @param oid The PKCS#12 PBE OID (in string notation). - * @param params The ASN.1 PKCS#12 PBE-params object. - * @param password The password to decrypt with. - * - * @return the new cipher object instance. - */ - pki$1.pbe.getCipherForPKCS12PBE = function(oid, params, password) { - // get PBE params - var capture = {}; - var errors = []; - if(!asn1$1.validate(params, pkcs12PbeParamsValidator, capture, errors)) { - var error = new Error('Cannot read password-based-encryption algorithm ' + - 'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); - error.errors = errors; - throw error; - } - - var salt = forge.util.createBuffer(capture.salt); - var count = forge.util.createBuffer(capture.iterations); - count = count.getInt(count.length() << 3); - - var dkLen, dIvLen, cipherFn; - switch(oid) { - case pki$1.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']: - dkLen = 24; - dIvLen = 8; - cipherFn = forge.des.startDecrypting; - break; - - case pki$1.oids['pbewithSHAAnd40BitRC2-CBC']: - dkLen = 5; - dIvLen = 8; - cipherFn = function(key, iv) { - var cipher = forge.rc2.createDecryptionCipher(key, 40); - cipher.start(iv, null); - return cipher; - }; - break; - - default: - var error = new Error('Cannot read PKCS #12 PBE data block. Unsupported OID.'); - error.oid = oid; - throw error; - } - - // get PRF message digest - var md = prfOidToMessageDigest(capture.prfOid); - var key = pki$1.pbe.generatePkcs12Key(password, salt, 1, count, dkLen, md); - md.start(); - var iv = pki$1.pbe.generatePkcs12Key(password, salt, 2, count, dIvLen, md); - - return cipherFn(key, iv); - }; - - /** - * OpenSSL's legacy key derivation function. - * - * See: http://www.openssl.org/docs/crypto/EVP_BytesToKey.html - * - * @param password the password to derive the key from. - * @param salt the salt to use, null for none. - * @param dkLen the number of bytes needed for the derived key. - * @param [options] the options to use: - * [md] an optional message digest object to use. - */ - pki$1.pbe.opensslDeriveBytes = function(password, salt, dkLen, md) { - if(typeof md === 'undefined' || md === null) { - if(!('md5' in forge.md)) { - throw new Error('"md5" hash algorithm unavailable.'); - } - md = forge.md.md5.create(); - } - if(salt === null) { - salt = ''; - } - var digests = [hash(md, password + salt)]; - for(var length = 16, i = 1; length < dkLen; ++i, length += 16) { - digests.push(hash(md, digests[i - 1] + password + salt)); - } - return digests.join('').substr(0, dkLen); - }; - - function hash(md, bytes) { - return md.start().update(bytes).digest().getBytes(); - } - - function prfOidToMessageDigest(prfOid) { - // get PRF algorithm, default to SHA-1 - var prfAlgorithm; - if(!prfOid) { - prfAlgorithm = 'hmacWithSHA1'; - } else { - prfAlgorithm = pki$1.oids[asn1$1.derToOid(prfOid)]; - if(!prfAlgorithm) { - var error = new Error('Unsupported PRF OID.'); - error.oid = prfOid; - error.supported = [ - 'hmacWithSHA1', 'hmacWithSHA224', 'hmacWithSHA256', 'hmacWithSHA384', - 'hmacWithSHA512']; - throw error; - } - } - return prfAlgorithmToMessageDigest(prfAlgorithm); - } - - function prfAlgorithmToMessageDigest(prfAlgorithm) { - var factory = forge.md; - switch(prfAlgorithm) { - case 'hmacWithSHA224': - factory = forge.md.sha512; - case 'hmacWithSHA1': - case 'hmacWithSHA256': - case 'hmacWithSHA384': - case 'hmacWithSHA512': - prfAlgorithm = prfAlgorithm.substr(8).toLowerCase(); - break; - default: - var error = new Error('Unsupported PRF algorithm.'); - error.algorithm = prfAlgorithm; - error.supported = [ - 'hmacWithSHA1', 'hmacWithSHA224', 'hmacWithSHA256', 'hmacWithSHA384', - 'hmacWithSHA512']; - throw error; - } - if(!factory || !(prfAlgorithm in factory)) { - throw new Error('Unknown hash algorithm: ' + prfAlgorithm); - } - return factory[prfAlgorithm].create(); - } - - function createPbkdf2Params(salt, countBytes, dkLen, prfAlgorithm) { - var params = asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - // salt - asn1$1.create( - asn1$1.Class.UNIVERSAL, asn1$1.Type.OCTETSTRING, false, salt), - // iteration count - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.INTEGER, false, - countBytes.getBytes()) - ]); - // when PRF algorithm is not SHA-1 default, add key length and PRF algorithm - if(prfAlgorithm !== 'hmacWithSHA1') { - params.value.push( - // key length - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.INTEGER, false, - forge.util.hexToBytes(dkLen.toString(16))), - // AlgorithmIdentifier - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.SEQUENCE, true, [ - // algorithm - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.OID, false, - asn1$1.oidToDer(pki$1.oids[prfAlgorithm]).getBytes()), - // parameters (null) - asn1$1.create(asn1$1.Class.UNIVERSAL, asn1$1.Type.NULL, false, '') - ])); - } - return params; - } - - var pkcs7asn1 = createCommonjsModule(function (module) { - /** - * Javascript implementation of ASN.1 validators for PKCS#7 v1.5. - * - * @author Dave Longley - * @author Stefan Siegl - * - * Copyright (c) 2012-2015 Digital Bazaar, Inc. - * Copyright (c) 2012 Stefan Siegl - * - * The ASN.1 representation of PKCS#7 is as follows - * (see RFC #2315 for details, http://www.ietf.org/rfc/rfc2315.txt): - * - * A PKCS#7 message consists of a ContentInfo on root level, which may - * contain any number of further ContentInfo nested into it. - * - * ContentInfo ::= SEQUENCE { - * contentType ContentType, - * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL - * } - * - * ContentType ::= OBJECT IDENTIFIER - * - * EnvelopedData ::= SEQUENCE { - * version Version, - * recipientInfos RecipientInfos, - * encryptedContentInfo EncryptedContentInfo - * } - * - * EncryptedData ::= SEQUENCE { - * version Version, - * encryptedContentInfo EncryptedContentInfo - * } - * - * id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) - * us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 } - * - * SignedData ::= SEQUENCE { - * version INTEGER, - * digestAlgorithms DigestAlgorithmIdentifiers, - * contentInfo ContentInfo, - * certificates [0] IMPLICIT Certificates OPTIONAL, - * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, - * signerInfos SignerInfos - * } - * - * SignerInfos ::= SET OF SignerInfo - * - * SignerInfo ::= SEQUENCE { - * version Version, - * issuerAndSerialNumber IssuerAndSerialNumber, - * digestAlgorithm DigestAlgorithmIdentifier, - * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, - * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, - * encryptedDigest EncryptedDigest, - * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL - * } - * - * EncryptedDigest ::= OCTET STRING - * - * Attributes ::= SET OF Attribute - * - * Attribute ::= SEQUENCE { - * attrType OBJECT IDENTIFIER, - * attrValues SET OF AttributeValue - * } - * - * AttributeValue ::= ANY - * - * Version ::= INTEGER - * - * RecipientInfos ::= SET OF RecipientInfo - * - * EncryptedContentInfo ::= SEQUENCE { - * contentType ContentType, - * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, - * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL - * } - * - * ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - * - * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters - * for the algorithm, if any. In the case of AES and DES3, there is only one, - * the IV. - * - * AlgorithmIdentifer ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - * - * EncryptedContent ::= OCTET STRING - * - * RecipientInfo ::= SEQUENCE { - * version Version, - * issuerAndSerialNumber IssuerAndSerialNumber, - * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, - * encryptedKey EncryptedKey - * } - * - * IssuerAndSerialNumber ::= SEQUENCE { - * issuer Name, - * serialNumber CertificateSerialNumber - * } - * - * CertificateSerialNumber ::= INTEGER - * - * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - * - * EncryptedKey ::= OCTET STRING - */ - - - - - // shortcut for ASN.1 API - var asn1 = forge.asn1; - - // shortcut for PKCS#7 API - var p7v = module.exports = forge.pkcs7asn1 = forge.pkcs7asn1 || {}; - forge.pkcs7 = forge.pkcs7 || {}; - forge.pkcs7.asn1 = p7v; - - var contentInfoValidator = { - name: 'ContentInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'ContentInfo.ContentType', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'contentType' - }, { - name: 'ContentInfo.content', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 0, - constructed: true, - optional: true, - captureAsn1: 'content' - }] - }; - p7v.contentInfoValidator = contentInfoValidator; - - var encryptedContentInfoValidator = { - name: 'EncryptedContentInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'EncryptedContentInfo.contentType', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'contentType' - }, { - name: 'EncryptedContentInfo.contentEncryptionAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'EncryptedContentInfo.contentEncryptionAlgorithm.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'encAlgorithm' - }, { - name: 'EncryptedContentInfo.contentEncryptionAlgorithm.parameter', - tagClass: asn1.Class.UNIVERSAL, - captureAsn1: 'encParameter' - }] - }, { - name: 'EncryptedContentInfo.encryptedContent', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 0, - /* The PKCS#7 structure output by OpenSSL somewhat differs from what - * other implementations do generate. - * - * OpenSSL generates a structure like this: - * SEQUENCE { - * ... - * [0] - * 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38 - * C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45 - * ... - * } - * - * Whereas other implementations (and this PKCS#7 module) generate: - * SEQUENCE { - * ... - * [0] { - * OCTET STRING - * 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38 - * C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45 - * ... - * } - * } - * - * In order to support both, we just capture the context specific - * field here. The OCTET STRING bit is removed below. - */ - capture: 'encryptedContent', - captureAsn1: 'encryptedContentAsn1' - }] - }; - - p7v.envelopedDataValidator = { - name: 'EnvelopedData', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'EnvelopedData.Version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'version' - }, { - name: 'EnvelopedData.RecipientInfos', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SET, - constructed: true, - captureAsn1: 'recipientInfos' - }].concat(encryptedContentInfoValidator) - }; - - p7v.encryptedDataValidator = { - name: 'EncryptedData', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'EncryptedData.Version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'version' - }].concat(encryptedContentInfoValidator) - }; - - var signerValidator = { - name: 'SignerInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'SignerInfo.version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false - }, { - name: 'SignerInfo.issuerAndSerialNumber', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'SignerInfo.issuerAndSerialNumber.issuer', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'issuer' - }, { - name: 'SignerInfo.issuerAndSerialNumber.serialNumber', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'serial' - }] - }, { - name: 'SignerInfo.digestAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'SignerInfo.digestAlgorithm.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'digestAlgorithm' - }, { - name: 'SignerInfo.digestAlgorithm.parameter', - tagClass: asn1.Class.UNIVERSAL, - constructed: false, - captureAsn1: 'digestParameter', - optional: true - }] - }, { - name: 'SignerInfo.authenticatedAttributes', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 0, - constructed: true, - optional: true, - capture: 'authenticatedAttributes' - }, { - name: 'SignerInfo.digestEncryptionAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - capture: 'signatureAlgorithm' - }, { - name: 'SignerInfo.encryptedDigest', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OCTETSTRING, - constructed: false, - capture: 'signature' - }, { - name: 'SignerInfo.unauthenticatedAttributes', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 1, - constructed: true, - optional: true, - capture: 'unauthenticatedAttributes' - }] - }; - - p7v.signedDataValidator = { - name: 'SignedData', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'SignedData.Version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'version' - }, { - name: 'SignedData.DigestAlgorithms', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SET, - constructed: true, - captureAsn1: 'digestAlgorithms' - }, - contentInfoValidator, - { - name: 'SignedData.Certificates', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 0, - optional: true, - captureAsn1: 'certificates' - }, { - name: 'SignedData.CertificateRevocationLists', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 1, - optional: true, - captureAsn1: 'crls' - }, { - name: 'SignedData.SignerInfos', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SET, - capture: 'signerInfos', - optional: true, - value: [signerValidator] - }] - }; - - p7v.recipientInfoValidator = { - name: 'RecipientInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'RecipientInfo.version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'version' - }, { - name: 'RecipientInfo.issuerAndSerial', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'RecipientInfo.issuerAndSerial.issuer', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'issuer' - }, { - name: 'RecipientInfo.issuerAndSerial.serialNumber', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'serial' - }] - }, { - name: 'RecipientInfo.keyEncryptionAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'RecipientInfo.keyEncryptionAlgorithm.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'encAlgorithm' - }, { - name: 'RecipientInfo.keyEncryptionAlgorithm.parameter', - tagClass: asn1.Class.UNIVERSAL, - constructed: false, - captureAsn1: 'encParameter' - }] - }, { - name: 'RecipientInfo.encryptedKey', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OCTETSTRING, - constructed: false, - capture: 'encKey' - }] - }; - }); - - var mgf1_1 = createCommonjsModule(function (module) { - /** - * Javascript implementation of mask generation function MGF1. - * - * @author Stefan Siegl - * @author Dave Longley - * - * Copyright (c) 2012 Stefan Siegl - * Copyright (c) 2014 Digital Bazaar, Inc. - */ - - - - forge.mgf = forge.mgf || {}; - var mgf1 = module.exports = forge.mgf.mgf1 = forge.mgf1 = forge.mgf1 || {}; - - /** - * Creates a MGF1 mask generation function object. - * - * @param md the message digest API to use (eg: forge.md.sha1.create()). - * - * @return a mask generation function object. - */ - mgf1.create = function(md) { - var mgf = { - /** - * Generate mask of specified length. - * - * @param {String} seed The seed for mask generation. - * @param maskLen Number of bytes to generate. - * @return {String} The generated mask. - */ - generate: function(seed, maskLen) { - /* 2. Let T be the empty octet string. */ - var t = new forge.util.ByteBuffer(); - - /* 3. For counter from 0 to ceil(maskLen / hLen), do the following: */ - var len = Math.ceil(maskLen / md.digestLength); - for(var i = 0; i < len; i++) { - /* a. Convert counter to an octet string C of length 4 octets */ - var c = new forge.util.ByteBuffer(); - c.putInt32(i); - - /* b. Concatenate the hash of the seed mgfSeed and C to the octet - * string T: */ - md.start(); - md.update(seed + c.getBytes()); - t.putBuffer(md.digest()); - } - - /* Output the leading maskLen octets of T as the octet string mask. */ - t.truncate(t.length() - maskLen); - return t.getBytes(); - } - }; - - return mgf; - }; - }); - - /** - * Node.js module for Forge mask generation functions. - * - * @author Stefan Siegl - * - * Copyright 2012 Stefan Siegl - */ - - - - var mgf = forge.mgf = forge.mgf || {}; - forge.mgf.mgf1 = forge.mgf1; - - var pss_1 = createCommonjsModule(function (module) { - /** - * Javascript implementation of PKCS#1 PSS signature padding. - * - * @author Stefan Siegl - * - * Copyright (c) 2012 Stefan Siegl - */ - - - - - // shortcut for PSS API - var pss = module.exports = forge.pss = forge.pss || {}; - - /** - * Creates a PSS signature scheme object. - * - * There are several ways to provide a salt for encoding: - * - * 1. Specify the saltLength only and the built-in PRNG will generate it. - * 2. Specify the saltLength and a custom PRNG with 'getBytesSync' defined that - * will be used. - * 3. Specify the salt itself as a forge.util.ByteBuffer. - * - * @param options the options to use: - * md the message digest object to use, a forge md instance. - * mgf the mask generation function to use, a forge mgf instance. - * [saltLength] the length of the salt in octets. - * [prng] the pseudo-random number generator to use to produce a salt. - * [salt] the salt to use when encoding. - * - * @return a signature scheme object. - */ - pss.create = function(options) { - // backwards compatibility w/legacy args: hash, mgf, sLen - if(arguments.length === 3) { - options = { - md: arguments[0], - mgf: arguments[1], - saltLength: arguments[2] - }; - } - - var hash = options.md; - var mgf = options.mgf; - var hLen = hash.digestLength; - - var salt_ = options.salt || null; - if(typeof salt_ === 'string') { - // assume binary-encoded string - salt_ = forge.util.createBuffer(salt_); - } - - var sLen; - if('saltLength' in options) { - sLen = options.saltLength; - } else if(salt_ !== null) { - sLen = salt_.length(); - } else { - throw new Error('Salt length not specified or specific salt not given.'); - } - - if(salt_ !== null && salt_.length() !== sLen) { - throw new Error('Given salt length does not match length of given salt.'); - } - - var prng = options.prng || forge.random; - - var pssobj = {}; - - /** - * Encodes a PSS signature. - * - * This function implements EMSA-PSS-ENCODE as per RFC 3447, section 9.1.1. - * - * @param md the message digest object with the hash to sign. - * @param modsBits the length of the RSA modulus in bits. - * - * @return the encoded message as a binary-encoded string of length - * ceil((modBits - 1) / 8). - */ - pssobj.encode = function(md, modBits) { - var i; - var emBits = modBits - 1; - var emLen = Math.ceil(emBits / 8); - - /* 2. Let mHash = Hash(M), an octet string of length hLen. */ - var mHash = md.digest().getBytes(); - - /* 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. */ - if(emLen < hLen + sLen + 2) { - throw new Error('Message is too long to encrypt.'); - } - - /* 4. Generate a random octet string salt of length sLen; if sLen = 0, - * then salt is the empty string. */ - var salt; - if(salt_ === null) { - salt = prng.getBytesSync(sLen); - } else { - salt = salt_.bytes(); - } - - /* 5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; */ - var m_ = new forge.util.ByteBuffer(); - m_.fillWithByte(0, 8); - m_.putBytes(mHash); - m_.putBytes(salt); - - /* 6. Let H = Hash(M'), an octet string of length hLen. */ - hash.start(); - hash.update(m_.getBytes()); - var h = hash.digest().getBytes(); - - /* 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 - * zero octets. The length of PS may be 0. */ - var ps = new forge.util.ByteBuffer(); - ps.fillWithByte(0, emLen - sLen - hLen - 2); - - /* 8. Let DB = PS || 0x01 || salt; DB is an octet string of length - * emLen - hLen - 1. */ - ps.putByte(0x01); - ps.putBytes(salt); - var db = ps.getBytes(); - - /* 9. Let dbMask = MGF(H, emLen - hLen - 1). */ - var maskLen = emLen - hLen - 1; - var dbMask = mgf.generate(h, maskLen); - - /* 10. Let maskedDB = DB \xor dbMask. */ - var maskedDB = ''; - for(i = 0; i < maskLen; i++) { - maskedDB += String.fromCharCode(db.charCodeAt(i) ^ dbMask.charCodeAt(i)); - } - - /* 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in - * maskedDB to zero. */ - var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF; - maskedDB = String.fromCharCode(maskedDB.charCodeAt(0) & ~mask) + - maskedDB.substr(1); - - /* 12. Let EM = maskedDB || H || 0xbc. - * 13. Output EM. */ - return maskedDB + h + String.fromCharCode(0xbc); - }; - - /** - * Verifies a PSS signature. - * - * This function implements EMSA-PSS-VERIFY as per RFC 3447, section 9.1.2. - * - * @param mHash the message digest hash, as a binary-encoded string, to - * compare against the signature. - * @param em the encoded message, as a binary-encoded string - * (RSA decryption result). - * @param modsBits the length of the RSA modulus in bits. - * - * @return true if the signature was verified, false if not. - */ - pssobj.verify = function(mHash, em, modBits) { - var i; - var emBits = modBits - 1; - var emLen = Math.ceil(emBits / 8); - - /* c. Convert the message representative m to an encoded message EM - * of length emLen = ceil((modBits - 1) / 8) octets, where modBits - * is the length in bits of the RSA modulus n */ - em = em.substr(-emLen); - - /* 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. */ - if(emLen < hLen + sLen + 2) { - throw new Error('Inconsistent parameters to PSS signature verification.'); - } - - /* 4. If the rightmost octet of EM does not have hexadecimal value - * 0xbc, output "inconsistent" and stop. */ - if(em.charCodeAt(emLen - 1) !== 0xbc) { - throw new Error('Encoded message does not end in 0xBC.'); - } - - /* 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and - * let H be the next hLen octets. */ - var maskLen = emLen - hLen - 1; - var maskedDB = em.substr(0, maskLen); - var h = em.substr(maskLen, hLen); - - /* 6. If the leftmost 8emLen - emBits bits of the leftmost octet in - * maskedDB are not all equal to zero, output "inconsistent" and stop. */ - var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF; - if((maskedDB.charCodeAt(0) & mask) !== 0) { - throw new Error('Bits beyond keysize not zero as expected.'); - } - - /* 7. Let dbMask = MGF(H, emLen - hLen - 1). */ - var dbMask = mgf.generate(h, maskLen); - - /* 8. Let DB = maskedDB \xor dbMask. */ - var db = ''; - for(i = 0; i < maskLen; i++) { - db += String.fromCharCode(maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i)); - } - - /* 9. Set the leftmost 8emLen - emBits bits of the leftmost octet - * in DB to zero. */ - db = String.fromCharCode(db.charCodeAt(0) & ~mask) + db.substr(1); - - /* 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero - * or if the octet at position emLen - hLen - sLen - 1 (the leftmost - * position is "position 1") does not have hexadecimal value 0x01, - * output "inconsistent" and stop. */ - var checkLen = emLen - hLen - sLen - 2; - for(i = 0; i < checkLen; i++) { - if(db.charCodeAt(i) !== 0x00) { - throw new Error('Leftmost octets not zero as expected'); - } - } - - if(db.charCodeAt(checkLen) !== 0x01) { - throw new Error('Inconsistent PSS signature, 0x01 marker not found'); - } - - /* 11. Let salt be the last sLen octets of DB. */ - var salt = db.substr(-sLen); - - /* 12. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */ - var m_ = new forge.util.ByteBuffer(); - m_.fillWithByte(0, 8); - m_.putBytes(mHash); - m_.putBytes(salt); - - /* 13. Let H' = Hash(M'), an octet string of length hLen. */ - hash.start(); - hash.update(m_.getBytes()); - var h_ = hash.digest().getBytes(); - - /* 14. If H = H', output "consistent." Otherwise, output "inconsistent." */ - return h === h_; - }; - - return pssobj; - }; - }); - - var x509 = createCommonjsModule(function (module) { - /** - * Javascript implementation of X.509 and related components (such as - * Certification Signing Requests) of a Public Key Infrastructure. - * - * @author Dave Longley - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - * - * The ASN.1 representation of an X.509v3 certificate is as follows - * (see RFC 2459): - * - * Certificate ::= SEQUENCE { - * tbsCertificate TBSCertificate, - * signatureAlgorithm AlgorithmIdentifier, - * signatureValue BIT STRING - * } - * - * TBSCertificate ::= SEQUENCE { - * version [0] EXPLICIT Version DEFAULT v1, - * serialNumber CertificateSerialNumber, - * signature AlgorithmIdentifier, - * issuer Name, - * validity Validity, - * subject Name, - * subjectPublicKeyInfo SubjectPublicKeyInfo, - * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version shall be v2 or v3 - * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version shall be v2 or v3 - * extensions [3] EXPLICIT Extensions OPTIONAL - * -- If present, version shall be v3 - * } - * - * Version ::= INTEGER { v1(0), v2(1), v3(2) } - * - * CertificateSerialNumber ::= INTEGER - * - * Name ::= CHOICE { - * // only one possible choice for now - * RDNSequence - * } - * - * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - * - * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue - * - * AttributeTypeAndValue ::= SEQUENCE { - * type AttributeType, - * value AttributeValue - * } - * AttributeType ::= OBJECT IDENTIFIER - * AttributeValue ::= ANY DEFINED BY AttributeType - * - * Validity ::= SEQUENCE { - * notBefore Time, - * notAfter Time - * } - * - * Time ::= CHOICE { - * utcTime UTCTime, - * generalTime GeneralizedTime - * } - * - * UniqueIdentifier ::= BIT STRING - * - * SubjectPublicKeyInfo ::= SEQUENCE { - * algorithm AlgorithmIdentifier, - * subjectPublicKey BIT STRING - * } - * - * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - * - * Extension ::= SEQUENCE { - * extnID OBJECT IDENTIFIER, - * critical BOOLEAN DEFAULT FALSE, - * extnValue OCTET STRING - * } - * - * The only key algorithm currently supported for PKI is RSA. - * - * RSASSA-PSS signatures are described in RFC 3447 and RFC 4055. - * - * PKCS#10 v1.7 describes certificate signing requests: - * - * CertificationRequestInfo: - * - * CertificationRequestInfo ::= SEQUENCE { - * version INTEGER { v1(0) } (v1,...), - * subject Name, - * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, - * attributes [0] Attributes{{ CRIAttributes }} - * } - * - * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} - * - * CRIAttributes ATTRIBUTE ::= { - * ... -- add any locally defined attributes here -- } - * - * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { - * type ATTRIBUTE.&id({IOSet}), - * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) - * } - * - * CertificationRequest ::= SEQUENCE { - * certificationRequestInfo CertificationRequestInfo, - * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, - * signature BIT STRING - * } - */ - - - - - - - - - - - - - // shortcut for asn.1 API - var asn1 = forge.asn1; - - /* Public Key Infrastructure (PKI) implementation. */ - var pki = module.exports = forge.pki = forge.pki || {}; - var oids = pki.oids; - - // short name OID mappings - var _shortNames = {}; - _shortNames['CN'] = oids['commonName']; - _shortNames['commonName'] = 'CN'; - _shortNames['C'] = oids['countryName']; - _shortNames['countryName'] = 'C'; - _shortNames['L'] = oids['localityName']; - _shortNames['localityName'] = 'L'; - _shortNames['ST'] = oids['stateOrProvinceName']; - _shortNames['stateOrProvinceName'] = 'ST'; - _shortNames['O'] = oids['organizationName']; - _shortNames['organizationName'] = 'O'; - _shortNames['OU'] = oids['organizationalUnitName']; - _shortNames['organizationalUnitName'] = 'OU'; - _shortNames['E'] = oids['emailAddress']; - _shortNames['emailAddress'] = 'E'; - - // validator for an SubjectPublicKeyInfo structure - // Note: Currently only works with an RSA public key - var publicKeyValidator = forge.pki.rsa.publicKeyValidator; - - // validator for an X.509v3 certificate - var x509CertificateValidator = { - name: 'Certificate', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'Certificate.TBSCertificate', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'tbsCertificate', - value: [{ - name: 'Certificate.TBSCertificate.version', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 0, - constructed: true, - optional: true, - value: [{ - name: 'Certificate.TBSCertificate.version.integer', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'certVersion' - }] - }, { - name: 'Certificate.TBSCertificate.serialNumber', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'certSerialNumber' - }, { - name: 'Certificate.TBSCertificate.signature', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'Certificate.TBSCertificate.signature.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'certinfoSignatureOid' - }, { - name: 'Certificate.TBSCertificate.signature.parameters', - tagClass: asn1.Class.UNIVERSAL, - optional: true, - captureAsn1: 'certinfoSignatureParams' - }] - }, { - name: 'Certificate.TBSCertificate.issuer', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'certIssuer' - }, { - name: 'Certificate.TBSCertificate.validity', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - // Note: UTC and generalized times may both appear so the capture - // names are based on their detected order, the names used below - // are only for the common case, which validity time really means - // "notBefore" and which means "notAfter" will be determined by order - value: [{ - // notBefore (Time) (UTC time case) - name: 'Certificate.TBSCertificate.validity.notBefore (utc)', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.UTCTIME, - constructed: false, - optional: true, - capture: 'certValidity1UTCTime' - }, { - // notBefore (Time) (generalized time case) - name: 'Certificate.TBSCertificate.validity.notBefore (generalized)', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.GENERALIZEDTIME, - constructed: false, - optional: true, - capture: 'certValidity2GeneralizedTime' - }, { - // notAfter (Time) (only UTC time is supported) - name: 'Certificate.TBSCertificate.validity.notAfter (utc)', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.UTCTIME, - constructed: false, - optional: true, - capture: 'certValidity3UTCTime' - }, { - // notAfter (Time) (only UTC time is supported) - name: 'Certificate.TBSCertificate.validity.notAfter (generalized)', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.GENERALIZEDTIME, - constructed: false, - optional: true, - capture: 'certValidity4GeneralizedTime' - }] - }, { - // Name (subject) (RDNSequence) - name: 'Certificate.TBSCertificate.subject', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'certSubject' - }, - // SubjectPublicKeyInfo - publicKeyValidator, - { - // issuerUniqueID (optional) - name: 'Certificate.TBSCertificate.issuerUniqueID', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 1, - constructed: true, - optional: true, - value: [{ - name: 'Certificate.TBSCertificate.issuerUniqueID.id', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.BITSTRING, - constructed: false, - // TODO: support arbitrary bit length ids - captureBitStringValue: 'certIssuerUniqueId' - }] - }, { - // subjectUniqueID (optional) - name: 'Certificate.TBSCertificate.subjectUniqueID', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 2, - constructed: true, - optional: true, - value: [{ - name: 'Certificate.TBSCertificate.subjectUniqueID.id', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.BITSTRING, - constructed: false, - // TODO: support arbitrary bit length ids - captureBitStringValue: 'certSubjectUniqueId' - }] - }, { - // Extensions (optional) - name: 'Certificate.TBSCertificate.extensions', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 3, - constructed: true, - captureAsn1: 'certExtensions', - optional: true - }] - }, { - // AlgorithmIdentifier (signature algorithm) - name: 'Certificate.signatureAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - // algorithm - name: 'Certificate.signatureAlgorithm.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'certSignatureOid' - }, { - name: 'Certificate.TBSCertificate.signature.parameters', - tagClass: asn1.Class.UNIVERSAL, - optional: true, - captureAsn1: 'certSignatureParams' - }] - }, { - // SignatureValue - name: 'Certificate.signatureValue', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.BITSTRING, - constructed: false, - captureBitStringValue: 'certSignature' - }] - }; - - var rsassaPssParameterValidator = { - name: 'rsapss', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'rsapss.hashAlgorithm', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 0, - constructed: true, - value: [{ - name: 'rsapss.hashAlgorithm.AlgorithmIdentifier', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Class.SEQUENCE, - constructed: true, - optional: true, - value: [{ - name: 'rsapss.hashAlgorithm.AlgorithmIdentifier.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'hashOid' - /* parameter block omitted, for SHA1 NULL anyhow. */ - }] - }] - }, { - name: 'rsapss.maskGenAlgorithm', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 1, - constructed: true, - value: [{ - name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Class.SEQUENCE, - constructed: true, - optional: true, - value: [{ - name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'maskGenOid' - }, { - name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'maskGenHashOid' - /* parameter block omitted, for SHA1 NULL anyhow. */ - }] - }] - }] - }, { - name: 'rsapss.saltLength', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 2, - optional: true, - value: [{ - name: 'rsapss.saltLength.saltLength', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Class.INTEGER, - constructed: false, - capture: 'saltLength' - }] - }, { - name: 'rsapss.trailerField', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 3, - optional: true, - value: [{ - name: 'rsapss.trailer.trailer', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Class.INTEGER, - constructed: false, - capture: 'trailer' - }] - }] - }; - - // validator for a CertificationRequestInfo structure - var certificationRequestInfoValidator = { - name: 'CertificationRequestInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'certificationRequestInfo', - value: [{ - name: 'CertificationRequestInfo.integer', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'certificationRequestInfoVersion' - }, { - // Name (subject) (RDNSequence) - name: 'CertificationRequestInfo.subject', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'certificationRequestInfoSubject' - }, - // SubjectPublicKeyInfo - publicKeyValidator, - { - name: 'CertificationRequestInfo.attributes', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - type: 0, - constructed: true, - optional: true, - capture: 'certificationRequestInfoAttributes', - value: [{ - name: 'CertificationRequestInfo.attributes', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'CertificationRequestInfo.attributes.type', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false - }, { - name: 'CertificationRequestInfo.attributes.value', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SET, - constructed: true - }] - }] - }] - }; - - // validator for a CertificationRequest structure - var certificationRequestValidator = { - name: 'CertificationRequest', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - captureAsn1: 'csr', - value: [ - certificationRequestInfoValidator, { - // AlgorithmIdentifier (signature algorithm) - name: 'CertificationRequest.signatureAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - // algorithm - name: 'CertificationRequest.signatureAlgorithm.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'csrSignatureOid' - }, { - name: 'CertificationRequest.signatureAlgorithm.parameters', - tagClass: asn1.Class.UNIVERSAL, - optional: true, - captureAsn1: 'csrSignatureParams' - }] - }, { - // signature - name: 'CertificationRequest.signature', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.BITSTRING, - constructed: false, - captureBitStringValue: 'csrSignature' - } - ] - }; - - /** - * Converts an RDNSequence of ASN.1 DER-encoded RelativeDistinguishedName - * sets into an array with objects that have type and value properties. - * - * @param rdn the RDNSequence to convert. - * @param md a message digest to append type and value to if provided. - */ - pki.RDNAttributesAsArray = function(rdn, md) { - var rval = []; - - // each value in 'rdn' in is a SET of RelativeDistinguishedName - var set, attr, obj; - for(var si = 0; si < rdn.value.length; ++si) { - // get the RelativeDistinguishedName set - set = rdn.value[si]; - - // each value in the SET is an AttributeTypeAndValue sequence - // containing first a type (an OID) and second a value (defined by - // the OID) - for(var i = 0; i < set.value.length; ++i) { - obj = {}; - attr = set.value[i]; - obj.type = asn1.derToOid(attr.value[0].value); - obj.value = attr.value[1].value; - obj.valueTagClass = attr.value[1].type; - // if the OID is known, get its name and short name - if(obj.type in oids) { - obj.name = oids[obj.type]; - if(obj.name in _shortNames) { - obj.shortName = _shortNames[obj.name]; - } - } - if(md) { - md.update(obj.type); - md.update(obj.value); - } - rval.push(obj); - } - } - - return rval; - }; - - /** - * Converts ASN.1 CRIAttributes into an array with objects that have type and - * value properties. - * - * @param attributes the CRIAttributes to convert. - */ - pki.CRIAttributesAsArray = function(attributes) { - var rval = []; - - // each value in 'attributes' in is a SEQUENCE with an OID and a SET - for(var si = 0; si < attributes.length; ++si) { - // get the attribute sequence - var seq = attributes[si]; - - // each value in the SEQUENCE containing first a type (an OID) and - // second a set of values (defined by the OID) - var type = asn1.derToOid(seq.value[0].value); - var values = seq.value[1].value; - for(var vi = 0; vi < values.length; ++vi) { - var obj = {}; - obj.type = type; - obj.value = values[vi].value; - obj.valueTagClass = values[vi].type; - // if the OID is known, get its name and short name - if(obj.type in oids) { - obj.name = oids[obj.type]; - if(obj.name in _shortNames) { - obj.shortName = _shortNames[obj.name]; - } - } - // parse extensions - if(obj.type === oids.extensionRequest) { - obj.extensions = []; - for(var ei = 0; ei < obj.value.length; ++ei) { - obj.extensions.push(pki.certificateExtensionFromAsn1(obj.value[ei])); - } - } - rval.push(obj); - } - } - - return rval; - }; - - /** - * Gets an issuer or subject attribute from its name, type, or short name. - * - * @param obj the issuer or subject object. - * @param options a short name string or an object with: - * shortName the short name for the attribute. - * name the name for the attribute. - * type the type for the attribute. - * - * @return the attribute. - */ - function _getAttribute(obj, options) { - if(typeof options === 'string') { - options = {shortName: options}; - } - - var rval = null; - var attr; - for(var i = 0; rval === null && i < obj.attributes.length; ++i) { - attr = obj.attributes[i]; - if(options.type && options.type === attr.type) { - rval = attr; - } else if(options.name && options.name === attr.name) { - rval = attr; - } else if(options.shortName && options.shortName === attr.shortName) { - rval = attr; - } - } - return rval; - } - - /** - * Converts signature parameters from ASN.1 structure. - * - * Currently only RSASSA-PSS supported. The PKCS#1 v1.5 signature scheme had - * no parameters. - * - * RSASSA-PSS-params ::= SEQUENCE { - * hashAlgorithm [0] HashAlgorithm DEFAULT - * sha1Identifier, - * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT - * mgf1SHA1Identifier, - * saltLength [2] INTEGER DEFAULT 20, - * trailerField [3] INTEGER DEFAULT 1 - * } - * - * HashAlgorithm ::= AlgorithmIdentifier - * - * MaskGenAlgorithm ::= AlgorithmIdentifier - * - * AlgorithmIdentifer ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - * - * @param oid The OID specifying the signature algorithm - * @param obj The ASN.1 structure holding the parameters - * @param fillDefaults Whether to use return default values where omitted - * @return signature parameter object - */ - var _readSignatureParameters = function(oid, obj, fillDefaults) { - var params = {}; - - if(oid !== oids['RSASSA-PSS']) { - return params; - } - - if(fillDefaults) { - params = { - hash: { - algorithmOid: oids['sha1'] - }, - mgf: { - algorithmOid: oids['mgf1'], - hash: { - algorithmOid: oids['sha1'] - } - }, - saltLength: 20 - }; - } - - var capture = {}; - var errors = []; - if(!asn1.validate(obj, rsassaPssParameterValidator, capture, errors)) { - var error = new Error('Cannot read RSASSA-PSS parameter block.'); - error.errors = errors; - throw error; - } - - if(capture.hashOid !== undefined) { - params.hash = params.hash || {}; - params.hash.algorithmOid = asn1.derToOid(capture.hashOid); - } - - if(capture.maskGenOid !== undefined) { - params.mgf = params.mgf || {}; - params.mgf.algorithmOid = asn1.derToOid(capture.maskGenOid); - params.mgf.hash = params.mgf.hash || {}; - params.mgf.hash.algorithmOid = asn1.derToOid(capture.maskGenHashOid); - } - - if(capture.saltLength !== undefined) { - params.saltLength = capture.saltLength.charCodeAt(0); - } - - return params; - }; - - /** - * Converts an X.509 certificate from PEM format. - * - * Note: If the certificate is to be verified then compute hash should - * be set to true. This will scan the TBSCertificate part of the ASN.1 - * object while it is converted so it doesn't need to be converted back - * to ASN.1-DER-encoding later. - * - * @param pem the PEM-formatted certificate. - * @param computeHash true to compute the hash for verification. - * @param strict true to be strict when checking ASN.1 value lengths, false to - * allow truncated values (default: true). - * - * @return the certificate. - */ - pki.certificateFromPem = function(pem, computeHash, strict) { - var msg = forge.pem.decode(pem)[0]; - - if(msg.type !== 'CERTIFICATE' && - msg.type !== 'X509 CERTIFICATE' && - msg.type !== 'TRUSTED CERTIFICATE') { - var error = new Error( - 'Could not convert certificate from PEM; PEM header type ' + - 'is not "CERTIFICATE", "X509 CERTIFICATE", or "TRUSTED CERTIFICATE".'); - error.headerType = msg.type; - throw error; - } - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error( - 'Could not convert certificate from PEM; PEM is encrypted.'); - } - - // convert DER to ASN.1 object - var obj = asn1.fromDer(msg.body, strict); - - return pki.certificateFromAsn1(obj, computeHash); - }; - - /** - * Converts an X.509 certificate to PEM format. - * - * @param cert the certificate. - * @param maxline the maximum characters per line, defaults to 64. - * - * @return the PEM-formatted certificate. - */ - pki.certificateToPem = function(cert, maxline) { - // convert to ASN.1, then DER, then PEM-encode - var msg = { - type: 'CERTIFICATE', - body: asn1.toDer(pki.certificateToAsn1(cert)).getBytes() - }; - return forge.pem.encode(msg, {maxline: maxline}); - }; - - /** - * Converts an RSA public key from PEM format. - * - * @param pem the PEM-formatted public key. - * - * @return the public key. - */ - pki.publicKeyFromPem = function(pem) { - var msg = forge.pem.decode(pem)[0]; - - if(msg.type !== 'PUBLIC KEY' && msg.type !== 'RSA PUBLIC KEY') { - var error = new Error('Could not convert public key from PEM; PEM header ' + - 'type is not "PUBLIC KEY" or "RSA PUBLIC KEY".'); - error.headerType = msg.type; - throw error; - } - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error('Could not convert public key from PEM; PEM is encrypted.'); - } - - // convert DER to ASN.1 object - var obj = asn1.fromDer(msg.body); - - return pki.publicKeyFromAsn1(obj); - }; - - /** - * Converts an RSA public key to PEM format (using a SubjectPublicKeyInfo). - * - * @param key the public key. - * @param maxline the maximum characters per line, defaults to 64. - * - * @return the PEM-formatted public key. - */ - pki.publicKeyToPem = function(key, maxline) { - // convert to ASN.1, then DER, then PEM-encode - var msg = { - type: 'PUBLIC KEY', - body: asn1.toDer(pki.publicKeyToAsn1(key)).getBytes() - }; - return forge.pem.encode(msg, {maxline: maxline}); - }; - - /** - * Converts an RSA public key to PEM format (using an RSAPublicKey). - * - * @param key the public key. - * @param maxline the maximum characters per line, defaults to 64. - * - * @return the PEM-formatted public key. - */ - pki.publicKeyToRSAPublicKeyPem = function(key, maxline) { - // convert to ASN.1, then DER, then PEM-encode - var msg = { - type: 'RSA PUBLIC KEY', - body: asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes() - }; - return forge.pem.encode(msg, {maxline: maxline}); - }; - - /** - * Gets a fingerprint for the given public key. - * - * @param options the options to use. - * [md] the message digest object to use (defaults to forge.md.sha1). - * [type] the type of fingerprint, such as 'RSAPublicKey', - * 'SubjectPublicKeyInfo' (defaults to 'RSAPublicKey'). - * [encoding] an alternative output encoding, such as 'hex' - * (defaults to none, outputs a byte buffer). - * [delimiter] the delimiter to use between bytes for 'hex' encoded - * output, eg: ':' (defaults to none). - * - * @return the fingerprint as a byte buffer or other encoding based on options. - */ - pki.getPublicKeyFingerprint = function(key, options) { - options = options || {}; - var md = options.md || forge.md.sha1.create(); - var type = options.type || 'RSAPublicKey'; - - var bytes; - switch(type) { - case 'RSAPublicKey': - bytes = asn1.toDer(pki.publicKeyToRSAPublicKey(key)).getBytes(); - break; - case 'SubjectPublicKeyInfo': - bytes = asn1.toDer(pki.publicKeyToAsn1(key)).getBytes(); - break; - default: - throw new Error('Unknown fingerprint type "' + options.type + '".'); - } - - // hash public key bytes - md.start(); - md.update(bytes); - var digest = md.digest(); - if(options.encoding === 'hex') { - var hex = digest.toHex(); - if(options.delimiter) { - return hex.match(/.{2}/g).join(options.delimiter); - } - return hex; - } else if(options.encoding === 'binary') { - return digest.getBytes(); - } else if(options.encoding) { - throw new Error('Unknown encoding "' + options.encoding + '".'); - } - return digest; - }; - - /** - * Converts a PKCS#10 certification request (CSR) from PEM format. - * - * Note: If the certification request is to be verified then compute hash - * should be set to true. This will scan the CertificationRequestInfo part of - * the ASN.1 object while it is converted so it doesn't need to be converted - * back to ASN.1-DER-encoding later. - * - * @param pem the PEM-formatted certificate. - * @param computeHash true to compute the hash for verification. - * @param strict true to be strict when checking ASN.1 value lengths, false to - * allow truncated values (default: true). - * - * @return the certification request (CSR). - */ - pki.certificationRequestFromPem = function(pem, computeHash, strict) { - var msg = forge.pem.decode(pem)[0]; - - if(msg.type !== 'CERTIFICATE REQUEST') { - var error = new Error('Could not convert certification request from PEM; ' + - 'PEM header type is not "CERTIFICATE REQUEST".'); - error.headerType = msg.type; - throw error; - } - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error('Could not convert certification request from PEM; ' + - 'PEM is encrypted.'); - } - - // convert DER to ASN.1 object - var obj = asn1.fromDer(msg.body, strict); - - return pki.certificationRequestFromAsn1(obj, computeHash); - }; - - /** - * Converts a PKCS#10 certification request (CSR) to PEM format. - * - * @param csr the certification request. - * @param maxline the maximum characters per line, defaults to 64. - * - * @return the PEM-formatted certification request. - */ - pki.certificationRequestToPem = function(csr, maxline) { - // convert to ASN.1, then DER, then PEM-encode - var msg = { - type: 'CERTIFICATE REQUEST', - body: asn1.toDer(pki.certificationRequestToAsn1(csr)).getBytes() - }; - return forge.pem.encode(msg, {maxline: maxline}); - }; - - /** - * Creates an empty X.509v3 RSA certificate. - * - * @return the certificate. - */ - pki.createCertificate = function() { - var cert = {}; - cert.version = 0x02; - cert.serialNumber = '00'; - cert.signatureOid = null; - cert.signature = null; - cert.siginfo = {}; - cert.siginfo.algorithmOid = null; - cert.validity = {}; - cert.validity.notBefore = new Date(); - cert.validity.notAfter = new Date(); - - cert.issuer = {}; - cert.issuer.getField = function(sn) { - return _getAttribute(cert.issuer, sn); - }; - cert.issuer.addField = function(attr) { - _fillMissingFields([attr]); - cert.issuer.attributes.push(attr); - }; - cert.issuer.attributes = []; - cert.issuer.hash = null; - - cert.subject = {}; - cert.subject.getField = function(sn) { - return _getAttribute(cert.subject, sn); - }; - cert.subject.addField = function(attr) { - _fillMissingFields([attr]); - cert.subject.attributes.push(attr); - }; - cert.subject.attributes = []; - cert.subject.hash = null; - - cert.extensions = []; - cert.publicKey = null; - cert.md = null; - - /** - * Sets the subject of this certificate. - * - * @param attrs the array of subject attributes to use. - * @param uniqueId an optional a unique ID to use. - */ - cert.setSubject = function(attrs, uniqueId) { - // set new attributes, clear hash - _fillMissingFields(attrs); - cert.subject.attributes = attrs; - delete cert.subject.uniqueId; - if(uniqueId) { - // TODO: support arbitrary bit length ids - cert.subject.uniqueId = uniqueId; - } - cert.subject.hash = null; - }; - - /** - * Sets the issuer of this certificate. - * - * @param attrs the array of issuer attributes to use. - * @param uniqueId an optional a unique ID to use. - */ - cert.setIssuer = function(attrs, uniqueId) { - // set new attributes, clear hash - _fillMissingFields(attrs); - cert.issuer.attributes = attrs; - delete cert.issuer.uniqueId; - if(uniqueId) { - // TODO: support arbitrary bit length ids - cert.issuer.uniqueId = uniqueId; - } - cert.issuer.hash = null; - }; - - /** - * Sets the extensions of this certificate. - * - * @param exts the array of extensions to use. - */ - cert.setExtensions = function(exts) { - for(var i = 0; i < exts.length; ++i) { - _fillMissingExtensionFields(exts[i], {cert: cert}); - } - // set new extensions - cert.extensions = exts; - }; - - /** - * Gets an extension by its name or id. - * - * @param options the name to use or an object with: - * name the name to use. - * id the id to use. - * - * @return the extension or null if not found. - */ - cert.getExtension = function(options) { - if(typeof options === 'string') { - options = {name: options}; - } - - var rval = null; - var ext; - for(var i = 0; rval === null && i < cert.extensions.length; ++i) { - ext = cert.extensions[i]; - if(options.id && ext.id === options.id) { - rval = ext; - } else if(options.name && ext.name === options.name) { - rval = ext; - } - } - return rval; - }; - - /** - * Signs this certificate using the given private key. - * - * @param key the private key to sign with. - * @param md the message digest object to use (defaults to forge.md.sha1). - */ - cert.sign = function(key, md) { - // TODO: get signature OID from private key - cert.md = md || forge.md.sha1.create(); - var algorithmOid = oids[cert.md.algorithm + 'WithRSAEncryption']; - if(!algorithmOid) { - var error = new Error('Could not compute certificate digest. ' + - 'Unknown message digest algorithm OID.'); - error.algorithm = cert.md.algorithm; - throw error; - } - cert.signatureOid = cert.siginfo.algorithmOid = algorithmOid; - - // get TBSCertificate, convert to DER - cert.tbsCertificate = pki.getTBSCertificate(cert); - var bytes = asn1.toDer(cert.tbsCertificate); - - // digest and sign - cert.md.update(bytes.getBytes()); - cert.signature = key.sign(cert.md); - }; - - /** - * Attempts verify the signature on the passed certificate using this - * certificate's public key. - * - * @param child the certificate to verify. - * - * @return true if verified, false if not. - */ - cert.verify = function(child) { - var rval = false; - - if(!cert.issued(child)) { - var issuer = child.issuer; - var subject = cert.subject; - var error = new Error( - 'The parent certificate did not issue the given child ' + - 'certificate; the child certificate\'s issuer does not match the ' + - 'parent\'s subject.'); - error.expectedIssuer = issuer.attributes; - error.actualIssuer = subject.attributes; - throw error; - } - - var md = child.md; - if(md === null) { - // check signature OID for supported signature types - if(child.signatureOid in oids) { - var oid = oids[child.signatureOid]; - switch(oid) { - case 'sha1WithRSAEncryption': - md = forge.md.sha1.create(); - break; - case 'md5WithRSAEncryption': - md = forge.md.md5.create(); - break; - case 'sha256WithRSAEncryption': - md = forge.md.sha256.create(); - break; - case 'sha384WithRSAEncryption': - md = forge.md.sha384.create(); - break; - case 'sha512WithRSAEncryption': - md = forge.md.sha512.create(); - break; - case 'RSASSA-PSS': - md = forge.md.sha256.create(); - break; - } - } - if(md === null) { - var error = new Error('Could not compute certificate digest. ' + - 'Unknown signature OID.'); - error.signatureOid = child.signatureOid; - throw error; - } - - // produce DER formatted TBSCertificate and digest it - var tbsCertificate = child.tbsCertificate || pki.getTBSCertificate(child); - var bytes = asn1.toDer(tbsCertificate); - md.update(bytes.getBytes()); - } - - if(md !== null) { - var scheme; - - switch(child.signatureOid) { - case oids.sha1WithRSAEncryption: - scheme = undefined; /* use PKCS#1 v1.5 padding scheme */ - break; - case oids['RSASSA-PSS']: - var hash, mgf; - - /* initialize mgf */ - hash = oids[child.signatureParameters.mgf.hash.algorithmOid]; - if(hash === undefined || forge.md[hash] === undefined) { - var error = new Error('Unsupported MGF hash function.'); - error.oid = child.signatureParameters.mgf.hash.algorithmOid; - error.name = hash; - throw error; - } - - mgf = oids[child.signatureParameters.mgf.algorithmOid]; - if(mgf === undefined || forge.mgf[mgf] === undefined) { - var error = new Error('Unsupported MGF function.'); - error.oid = child.signatureParameters.mgf.algorithmOid; - error.name = mgf; - throw error; - } - - mgf = forge.mgf[mgf].create(forge.md[hash].create()); - - /* initialize hash function */ - hash = oids[child.signatureParameters.hash.algorithmOid]; - if(hash === undefined || forge.md[hash] === undefined) { - throw { - message: 'Unsupported RSASSA-PSS hash function.', - oid: child.signatureParameters.hash.algorithmOid, - name: hash - }; - } - - scheme = forge.pss.create(forge.md[hash].create(), mgf, - child.signatureParameters.saltLength); - break; - } - - // verify signature on cert using public key - rval = cert.publicKey.verify( - md.digest().getBytes(), child.signature, scheme); - } - - return rval; - }; - - /** - * Returns true if this certificate's issuer matches the passed - * certificate's subject. Note that no signature check is performed. - * - * @param parent the certificate to check. - * - * @return true if this certificate's issuer matches the passed certificate's - * subject. - */ - cert.isIssuer = function(parent) { - var rval = false; - - var i = cert.issuer; - var s = parent.subject; - - // compare hashes if present - if(i.hash && s.hash) { - rval = (i.hash === s.hash); - } else if(i.attributes.length === s.attributes.length) { - // all attributes are the same so issuer matches subject - rval = true; - var iattr, sattr; - for(var n = 0; rval && n < i.attributes.length; ++n) { - iattr = i.attributes[n]; - sattr = s.attributes[n]; - if(iattr.type !== sattr.type || iattr.value !== sattr.value) { - // attribute mismatch - rval = false; - } - } - } - - return rval; - }; - - /** - * Returns true if this certificate's subject matches the issuer of the - * given certificate). Note that not signature check is performed. - * - * @param child the certificate to check. - * - * @return true if this certificate's subject matches the passed - * certificate's issuer. - */ - cert.issued = function(child) { - return child.isIssuer(cert); - }; - - /** - * Generates the subjectKeyIdentifier for this certificate as byte buffer. - * - * @return the subjectKeyIdentifier for this certificate as byte buffer. - */ - cert.generateSubjectKeyIdentifier = function() { - /* See: 4.2.1.2 section of the the RFC3280, keyIdentifier is either: - - (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the - value of the BIT STRING subjectPublicKey (excluding the tag, - length, and number of unused bits). - - (2) The keyIdentifier is composed of a four bit type field with - the value 0100 followed by the least significant 60 bits of the - SHA-1 hash of the value of the BIT STRING subjectPublicKey - (excluding the tag, length, and number of unused bit string bits). - */ - - // skipping the tag, length, and number of unused bits is the same - // as just using the RSAPublicKey (for RSA keys, which are the - // only ones supported) - return pki.getPublicKeyFingerprint(cert.publicKey, {type: 'RSAPublicKey'}); - }; - - /** - * Verifies the subjectKeyIdentifier extension value for this certificate - * against its public key. If no extension is found, false will be - * returned. - * - * @return true if verified, false if not. - */ - cert.verifySubjectKeyIdentifier = function() { - var oid = oids['subjectKeyIdentifier']; - for(var i = 0; i < cert.extensions.length; ++i) { - var ext = cert.extensions[i]; - if(ext.id === oid) { - var ski = cert.generateSubjectKeyIdentifier().getBytes(); - return (forge.util.hexToBytes(ext.subjectKeyIdentifier) === ski); - } - } - return false; - }; - - return cert; - }; - - /** - * Converts an X.509v3 RSA certificate from an ASN.1 object. - * - * Note: If the certificate is to be verified then compute hash should - * be set to true. There is currently no implementation for converting - * a certificate back to ASN.1 so the TBSCertificate part of the ASN.1 - * object needs to be scanned before the cert object is created. - * - * @param obj the asn1 representation of an X.509v3 RSA certificate. - * @param computeHash true to compute the hash for verification. - * - * @return the certificate. - */ - pki.certificateFromAsn1 = function(obj, computeHash) { - // validate certificate and capture data - var capture = {}; - var errors = []; - if(!asn1.validate(obj, x509CertificateValidator, capture, errors)) { - var error = new Error('Cannot read X.509 certificate. ' + - 'ASN.1 object is not an X509v3 Certificate.'); - error.errors = errors; - throw error; - } - - // get oid - var oid = asn1.derToOid(capture.publicKeyOid); - if(oid !== pki.oids.rsaEncryption) { - throw new Error('Cannot read public key. OID is not RSA.'); - } - - // create certificate - var cert = pki.createCertificate(); - cert.version = capture.certVersion ? - capture.certVersion.charCodeAt(0) : 0; - var serial = forge.util.createBuffer(capture.certSerialNumber); - cert.serialNumber = serial.toHex(); - cert.signatureOid = forge.asn1.derToOid(capture.certSignatureOid); - cert.signatureParameters = _readSignatureParameters( - cert.signatureOid, capture.certSignatureParams, true); - cert.siginfo.algorithmOid = forge.asn1.derToOid(capture.certinfoSignatureOid); - cert.siginfo.parameters = _readSignatureParameters(cert.siginfo.algorithmOid, - capture.certinfoSignatureParams, false); - cert.signature = capture.certSignature; - - var validity = []; - if(capture.certValidity1UTCTime !== undefined) { - validity.push(asn1.utcTimeToDate(capture.certValidity1UTCTime)); - } - if(capture.certValidity2GeneralizedTime !== undefined) { - validity.push(asn1.generalizedTimeToDate( - capture.certValidity2GeneralizedTime)); - } - if(capture.certValidity3UTCTime !== undefined) { - validity.push(asn1.utcTimeToDate(capture.certValidity3UTCTime)); - } - if(capture.certValidity4GeneralizedTime !== undefined) { - validity.push(asn1.generalizedTimeToDate( - capture.certValidity4GeneralizedTime)); - } - if(validity.length > 2) { - throw new Error('Cannot read notBefore/notAfter validity times; more ' + - 'than two times were provided in the certificate.'); - } - if(validity.length < 2) { - throw new Error('Cannot read notBefore/notAfter validity times; they ' + - 'were not provided as either UTCTime or GeneralizedTime.'); - } - cert.validity.notBefore = validity[0]; - cert.validity.notAfter = validity[1]; - - // keep TBSCertificate to preserve signature when exporting - cert.tbsCertificate = capture.tbsCertificate; - - if(computeHash) { - // check signature OID for supported signature types - cert.md = null; - if(cert.signatureOid in oids) { - var oid = oids[cert.signatureOid]; - switch(oid) { - case 'sha1WithRSAEncryption': - cert.md = forge.md.sha1.create(); - break; - case 'md5WithRSAEncryption': - cert.md = forge.md.md5.create(); - break; - case 'sha256WithRSAEncryption': - cert.md = forge.md.sha256.create(); - break; - case 'sha384WithRSAEncryption': - cert.md = forge.md.sha384.create(); - break; - case 'sha512WithRSAEncryption': - cert.md = forge.md.sha512.create(); - break; - case 'RSASSA-PSS': - cert.md = forge.md.sha256.create(); - break; - } - } - if(cert.md === null) { - var error = new Error('Could not compute certificate digest. ' + - 'Unknown signature OID.'); - error.signatureOid = cert.signatureOid; - throw error; - } - - // produce DER formatted TBSCertificate and digest it - var bytes = asn1.toDer(cert.tbsCertificate); - cert.md.update(bytes.getBytes()); - } - - // handle issuer, build issuer message digest - var imd = forge.md.sha1.create(); - cert.issuer.getField = function(sn) { - return _getAttribute(cert.issuer, sn); - }; - cert.issuer.addField = function(attr) { - _fillMissingFields([attr]); - cert.issuer.attributes.push(attr); - }; - cert.issuer.attributes = pki.RDNAttributesAsArray(capture.certIssuer, imd); - if(capture.certIssuerUniqueId) { - cert.issuer.uniqueId = capture.certIssuerUniqueId; - } - cert.issuer.hash = imd.digest().toHex(); - - // handle subject, build subject message digest - var smd = forge.md.sha1.create(); - cert.subject.getField = function(sn) { - return _getAttribute(cert.subject, sn); - }; - cert.subject.addField = function(attr) { - _fillMissingFields([attr]); - cert.subject.attributes.push(attr); - }; - cert.subject.attributes = pki.RDNAttributesAsArray(capture.certSubject, smd); - if(capture.certSubjectUniqueId) { - cert.subject.uniqueId = capture.certSubjectUniqueId; - } - cert.subject.hash = smd.digest().toHex(); - - // handle extensions - if(capture.certExtensions) { - cert.extensions = pki.certificateExtensionsFromAsn1(capture.certExtensions); - } else { - cert.extensions = []; - } - - // convert RSA public key from ASN.1 - cert.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo); - - return cert; - }; - - /** - * Converts an ASN.1 extensions object (with extension sequences as its - * values) into an array of extension objects with types and values. - * - * Supported extensions: - * - * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } - * KeyUsage ::= BIT STRING { - * digitalSignature (0), - * nonRepudiation (1), - * keyEncipherment (2), - * dataEncipherment (3), - * keyAgreement (4), - * keyCertSign (5), - * cRLSign (6), - * encipherOnly (7), - * decipherOnly (8) - * } - * - * id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } - * BasicConstraints ::= SEQUENCE { - * cA BOOLEAN DEFAULT FALSE, - * pathLenConstraint INTEGER (0..MAX) OPTIONAL - * } - * - * subjectAltName EXTENSION ::= { - * SYNTAX GeneralNames - * IDENTIFIED BY id-ce-subjectAltName - * } - * - * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName - * - * GeneralName ::= CHOICE { - * otherName [0] INSTANCE OF OTHER-NAME, - * rfc822Name [1] IA5String, - * dNSName [2] IA5String, - * x400Address [3] ORAddress, - * directoryName [4] Name, - * ediPartyName [5] EDIPartyName, - * uniformResourceIdentifier [6] IA5String, - * IPAddress [7] OCTET STRING, - * registeredID [8] OBJECT IDENTIFIER - * } - * - * OTHER-NAME ::= TYPE-IDENTIFIER - * - * EDIPartyName ::= SEQUENCE { - * nameAssigner [0] DirectoryString {ub-name} OPTIONAL, - * partyName [1] DirectoryString {ub-name} - * } - * - * @param exts the extensions ASN.1 with extension sequences to parse. - * - * @return the array. - */ - pki.certificateExtensionsFromAsn1 = function(exts) { - var rval = []; - for(var i = 0; i < exts.value.length; ++i) { - // get extension sequence - var extseq = exts.value[i]; - for(var ei = 0; ei < extseq.value.length; ++ei) { - rval.push(pki.certificateExtensionFromAsn1(extseq.value[ei])); - } - } - - return rval; - }; - - /** - * Parses a single certificate extension from ASN.1. - * - * @param ext the extension in ASN.1 format. - * - * @return the parsed extension as an object. - */ - pki.certificateExtensionFromAsn1 = function(ext) { - // an extension has: - // [0] extnID OBJECT IDENTIFIER - // [1] critical BOOLEAN DEFAULT FALSE - // [2] extnValue OCTET STRING - var e = {}; - e.id = asn1.derToOid(ext.value[0].value); - e.critical = false; - if(ext.value[1].type === asn1.Type.BOOLEAN) { - e.critical = (ext.value[1].value.charCodeAt(0) !== 0x00); - e.value = ext.value[2].value; - } else { - e.value = ext.value[1].value; - } - // if the oid is known, get its name - if(e.id in oids) { - e.name = oids[e.id]; - - // handle key usage - if(e.name === 'keyUsage') { - // get value as BIT STRING - var ev = asn1.fromDer(e.value); - var b2 = 0x00; - var b3 = 0x00; - if(ev.value.length > 1) { - // skip first byte, just indicates unused bits which - // will be padded with 0s anyway - // get bytes with flag bits - b2 = ev.value.charCodeAt(1); - b3 = ev.value.length > 2 ? ev.value.charCodeAt(2) : 0; - } - // set flags - e.digitalSignature = (b2 & 0x80) === 0x80; - e.nonRepudiation = (b2 & 0x40) === 0x40; - e.keyEncipherment = (b2 & 0x20) === 0x20; - e.dataEncipherment = (b2 & 0x10) === 0x10; - e.keyAgreement = (b2 & 0x08) === 0x08; - e.keyCertSign = (b2 & 0x04) === 0x04; - e.cRLSign = (b2 & 0x02) === 0x02; - e.encipherOnly = (b2 & 0x01) === 0x01; - e.decipherOnly = (b3 & 0x80) === 0x80; - } else if(e.name === 'basicConstraints') { - // handle basic constraints - // get value as SEQUENCE - var ev = asn1.fromDer(e.value); - // get cA BOOLEAN flag (defaults to false) - if(ev.value.length > 0 && ev.value[0].type === asn1.Type.BOOLEAN) { - e.cA = (ev.value[0].value.charCodeAt(0) !== 0x00); - } else { - e.cA = false; - } - // get path length constraint - var value = null; - if(ev.value.length > 0 && ev.value[0].type === asn1.Type.INTEGER) { - value = ev.value[0].value; - } else if(ev.value.length > 1) { - value = ev.value[1].value; - } - if(value !== null) { - e.pathLenConstraint = asn1.derToInteger(value); - } - } else if(e.name === 'extKeyUsage') { - // handle extKeyUsage - // value is a SEQUENCE of OIDs - var ev = asn1.fromDer(e.value); - for(var vi = 0; vi < ev.value.length; ++vi) { - var oid = asn1.derToOid(ev.value[vi].value); - if(oid in oids) { - e[oids[oid]] = true; - } else { - e[oid] = true; - } - } - } else if(e.name === 'nsCertType') { - // handle nsCertType - // get value as BIT STRING - var ev = asn1.fromDer(e.value); - var b2 = 0x00; - if(ev.value.length > 1) { - // skip first byte, just indicates unused bits which - // will be padded with 0s anyway - // get bytes with flag bits - b2 = ev.value.charCodeAt(1); - } - // set flags - e.client = (b2 & 0x80) === 0x80; - e.server = (b2 & 0x40) === 0x40; - e.email = (b2 & 0x20) === 0x20; - e.objsign = (b2 & 0x10) === 0x10; - e.reserved = (b2 & 0x08) === 0x08; - e.sslCA = (b2 & 0x04) === 0x04; - e.emailCA = (b2 & 0x02) === 0x02; - e.objCA = (b2 & 0x01) === 0x01; - } else if( - e.name === 'subjectAltName' || - e.name === 'issuerAltName') { - // handle subjectAltName/issuerAltName - e.altNames = []; - - // ev is a SYNTAX SEQUENCE - var gn; - var ev = asn1.fromDer(e.value); - for(var n = 0; n < ev.value.length; ++n) { - // get GeneralName - gn = ev.value[n]; - - var altName = { - type: gn.type, - value: gn.value - }; - e.altNames.push(altName); - - // Note: Support for types 1,2,6,7,8 - switch(gn.type) { - // rfc822Name - case 1: - // dNSName - case 2: - // uniformResourceIdentifier (URI) - case 6: - break; - // IPAddress - case 7: - // convert to IPv4/IPv6 string representation - altName.ip = forge.util.bytesToIP(gn.value); - break; - // registeredID - case 8: - altName.oid = asn1.derToOid(gn.value); - break; - // unsupported - } - } - } else if(e.name === 'subjectKeyIdentifier') { - // value is an OCTETSTRING w/the hash of the key-type specific - // public key structure (eg: RSAPublicKey) - var ev = asn1.fromDer(e.value); - e.subjectKeyIdentifier = forge.util.bytesToHex(ev.value); - } - } - return e; - }; - - /** - * Converts a PKCS#10 certification request (CSR) from an ASN.1 object. - * - * Note: If the certification request is to be verified then compute hash - * should be set to true. There is currently no implementation for converting - * a certificate back to ASN.1 so the CertificationRequestInfo part of the - * ASN.1 object needs to be scanned before the csr object is created. - * - * @param obj the asn1 representation of a PKCS#10 certification request (CSR). - * @param computeHash true to compute the hash for verification. - * - * @return the certification request (CSR). - */ - pki.certificationRequestFromAsn1 = function(obj, computeHash) { - // validate certification request and capture data - var capture = {}; - var errors = []; - if(!asn1.validate(obj, certificationRequestValidator, capture, errors)) { - var error = new Error('Cannot read PKCS#10 certificate request. ' + - 'ASN.1 object is not a PKCS#10 CertificationRequest.'); - error.errors = errors; - throw error; - } - - // get oid - var oid = asn1.derToOid(capture.publicKeyOid); - if(oid !== pki.oids.rsaEncryption) { - throw new Error('Cannot read public key. OID is not RSA.'); - } - - // create certification request - var csr = pki.createCertificationRequest(); - csr.version = capture.csrVersion ? capture.csrVersion.charCodeAt(0) : 0; - csr.signatureOid = forge.asn1.derToOid(capture.csrSignatureOid); - csr.signatureParameters = _readSignatureParameters( - csr.signatureOid, capture.csrSignatureParams, true); - csr.siginfo.algorithmOid = forge.asn1.derToOid(capture.csrSignatureOid); - csr.siginfo.parameters = _readSignatureParameters( - csr.siginfo.algorithmOid, capture.csrSignatureParams, false); - csr.signature = capture.csrSignature; - - // keep CertificationRequestInfo to preserve signature when exporting - csr.certificationRequestInfo = capture.certificationRequestInfo; - - if(computeHash) { - // check signature OID for supported signature types - csr.md = null; - if(csr.signatureOid in oids) { - var oid = oids[csr.signatureOid]; - switch(oid) { - case 'sha1WithRSAEncryption': - csr.md = forge.md.sha1.create(); - break; - case 'md5WithRSAEncryption': - csr.md = forge.md.md5.create(); - break; - case 'sha256WithRSAEncryption': - csr.md = forge.md.sha256.create(); - break; - case 'sha384WithRSAEncryption': - csr.md = forge.md.sha384.create(); - break; - case 'sha512WithRSAEncryption': - csr.md = forge.md.sha512.create(); - break; - case 'RSASSA-PSS': - csr.md = forge.md.sha256.create(); - break; - } - } - if(csr.md === null) { - var error = new Error('Could not compute certification request digest. ' + - 'Unknown signature OID.'); - error.signatureOid = csr.signatureOid; - throw error; - } - - // produce DER formatted CertificationRequestInfo and digest it - var bytes = asn1.toDer(csr.certificationRequestInfo); - csr.md.update(bytes.getBytes()); - } - - // handle subject, build subject message digest - var smd = forge.md.sha1.create(); - csr.subject.getField = function(sn) { - return _getAttribute(csr.subject, sn); - }; - csr.subject.addField = function(attr) { - _fillMissingFields([attr]); - csr.subject.attributes.push(attr); - }; - csr.subject.attributes = pki.RDNAttributesAsArray( - capture.certificationRequestInfoSubject, smd); - csr.subject.hash = smd.digest().toHex(); - - // convert RSA public key from ASN.1 - csr.publicKey = pki.publicKeyFromAsn1(capture.subjectPublicKeyInfo); - - // convert attributes from ASN.1 - csr.getAttribute = function(sn) { - return _getAttribute(csr, sn); - }; - csr.addAttribute = function(attr) { - _fillMissingFields([attr]); - csr.attributes.push(attr); - }; - csr.attributes = pki.CRIAttributesAsArray( - capture.certificationRequestInfoAttributes || []); - - return csr; - }; - - /** - * Creates an empty certification request (a CSR or certificate signing - * request). Once created, its public key and attributes can be set and then - * it can be signed. - * - * @return the empty certification request. - */ - pki.createCertificationRequest = function() { - var csr = {}; - csr.version = 0x00; - csr.signatureOid = null; - csr.signature = null; - csr.siginfo = {}; - csr.siginfo.algorithmOid = null; - - csr.subject = {}; - csr.subject.getField = function(sn) { - return _getAttribute(csr.subject, sn); - }; - csr.subject.addField = function(attr) { - _fillMissingFields([attr]); - csr.subject.attributes.push(attr); - }; - csr.subject.attributes = []; - csr.subject.hash = null; - - csr.publicKey = null; - csr.attributes = []; - csr.getAttribute = function(sn) { - return _getAttribute(csr, sn); - }; - csr.addAttribute = function(attr) { - _fillMissingFields([attr]); - csr.attributes.push(attr); - }; - csr.md = null; - - /** - * Sets the subject of this certification request. - * - * @param attrs the array of subject attributes to use. - */ - csr.setSubject = function(attrs) { - // set new attributes - _fillMissingFields(attrs); - csr.subject.attributes = attrs; - csr.subject.hash = null; - }; - - /** - * Sets the attributes of this certification request. - * - * @param attrs the array of attributes to use. - */ - csr.setAttributes = function(attrs) { - // set new attributes - _fillMissingFields(attrs); - csr.attributes = attrs; - }; - - /** - * Signs this certification request using the given private key. - * - * @param key the private key to sign with. - * @param md the message digest object to use (defaults to forge.md.sha1). - */ - csr.sign = function(key, md) { - // TODO: get signature OID from private key - csr.md = md || forge.md.sha1.create(); - var algorithmOid = oids[csr.md.algorithm + 'WithRSAEncryption']; - if(!algorithmOid) { - var error = new Error('Could not compute certification request digest. ' + - 'Unknown message digest algorithm OID.'); - error.algorithm = csr.md.algorithm; - throw error; - } - csr.signatureOid = csr.siginfo.algorithmOid = algorithmOid; - - // get CertificationRequestInfo, convert to DER - csr.certificationRequestInfo = pki.getCertificationRequestInfo(csr); - var bytes = asn1.toDer(csr.certificationRequestInfo); - - // digest and sign - csr.md.update(bytes.getBytes()); - csr.signature = key.sign(csr.md); - }; - - /** - * Attempts verify the signature on the passed certification request using - * its public key. - * - * A CSR that has been exported to a file in PEM format can be verified using - * OpenSSL using this command: - * - * openssl req -in -verify -noout -text - * - * @return true if verified, false if not. - */ - csr.verify = function() { - var rval = false; - - var md = csr.md; - if(md === null) { - // check signature OID for supported signature types - if(csr.signatureOid in oids) { - // TODO: create DRY `OID to md` function - var oid = oids[csr.signatureOid]; - switch(oid) { - case 'sha1WithRSAEncryption': - md = forge.md.sha1.create(); - break; - case 'md5WithRSAEncryption': - md = forge.md.md5.create(); - break; - case 'sha256WithRSAEncryption': - md = forge.md.sha256.create(); - break; - case 'sha384WithRSAEncryption': - md = forge.md.sha384.create(); - break; - case 'sha512WithRSAEncryption': - md = forge.md.sha512.create(); - break; - case 'RSASSA-PSS': - md = forge.md.sha256.create(); - break; - } - } - if(md === null) { - var error = new Error( - 'Could not compute certification request digest. ' + - 'Unknown signature OID.'); - error.signatureOid = csr.signatureOid; - throw error; - } - - // produce DER formatted CertificationRequestInfo and digest it - var cri = csr.certificationRequestInfo || - pki.getCertificationRequestInfo(csr); - var bytes = asn1.toDer(cri); - md.update(bytes.getBytes()); - } - - if(md !== null) { - var scheme; - - switch(csr.signatureOid) { - case oids.sha1WithRSAEncryption: - /* use PKCS#1 v1.5 padding scheme */ - break; - case oids['RSASSA-PSS']: - var hash, mgf; - - /* initialize mgf */ - hash = oids[csr.signatureParameters.mgf.hash.algorithmOid]; - if(hash === undefined || forge.md[hash] === undefined) { - var error = new Error('Unsupported MGF hash function.'); - error.oid = csr.signatureParameters.mgf.hash.algorithmOid; - error.name = hash; - throw error; - } - - mgf = oids[csr.signatureParameters.mgf.algorithmOid]; - if(mgf === undefined || forge.mgf[mgf] === undefined) { - var error = new Error('Unsupported MGF function.'); - error.oid = csr.signatureParameters.mgf.algorithmOid; - error.name = mgf; - throw error; - } - - mgf = forge.mgf[mgf].create(forge.md[hash].create()); - - /* initialize hash function */ - hash = oids[csr.signatureParameters.hash.algorithmOid]; - if(hash === undefined || forge.md[hash] === undefined) { - var error = new Error('Unsupported RSASSA-PSS hash function.'); - error.oid = csr.signatureParameters.hash.algorithmOid; - error.name = hash; - throw error; - } - - scheme = forge.pss.create(forge.md[hash].create(), mgf, - csr.signatureParameters.saltLength); - break; - } - - // verify signature on csr using its public key - rval = csr.publicKey.verify( - md.digest().getBytes(), csr.signature, scheme); - } - - return rval; - }; - - return csr; - }; - - /** - * Converts an X.509 subject or issuer to an ASN.1 RDNSequence. - * - * @param obj the subject or issuer (distinguished name). - * - * @return the ASN.1 RDNSequence. - */ - function _dnToAsn1(obj) { - // create an empty RDNSequence - var rval = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - - // iterate over attributes - var attr, set; - var attrs = obj.attributes; - for(var i = 0; i < attrs.length; ++i) { - attr = attrs[i]; - var value = attr.value; - - // reuse tag class for attribute value if available - var valueTagClass = asn1.Type.PRINTABLESTRING; - if('valueTagClass' in attr) { - valueTagClass = attr.valueTagClass; - - if(valueTagClass === asn1.Type.UTF8) { - value = forge.util.encodeUtf8(value); - } - // FIXME: handle more encodings - } - - // create a RelativeDistinguishedName set - // each value in the set is an AttributeTypeAndValue first - // containing the type (an OID) and second the value - set = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // AttributeType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(attr.type).getBytes()), - // AttributeValue - asn1.create(asn1.Class.UNIVERSAL, valueTagClass, false, value) - ]) - ]); - rval.value.push(set); - } - - return rval; - } - - /** - * Fills in missing fields in attributes. - * - * @param attrs the attributes to fill missing fields in. - */ - function _fillMissingFields(attrs) { - var attr; - for(var i = 0; i < attrs.length; ++i) { - attr = attrs[i]; - - // populate missing name - if(typeof attr.name === 'undefined') { - if(attr.type && attr.type in pki.oids) { - attr.name = pki.oids[attr.type]; - } else if(attr.shortName && attr.shortName in _shortNames) { - attr.name = pki.oids[_shortNames[attr.shortName]]; - } - } - - // populate missing type (OID) - if(typeof attr.type === 'undefined') { - if(attr.name && attr.name in pki.oids) { - attr.type = pki.oids[attr.name]; - } else { - var error = new Error('Attribute type not specified.'); - error.attribute = attr; - throw error; - } - } - - // populate missing shortname - if(typeof attr.shortName === 'undefined') { - if(attr.name && attr.name in _shortNames) { - attr.shortName = _shortNames[attr.name]; - } - } - - // convert extensions to value - if(attr.type === oids.extensionRequest) { - attr.valueConstructed = true; - attr.valueTagClass = asn1.Type.SEQUENCE; - if(!attr.value && attr.extensions) { - attr.value = []; - for(var ei = 0; ei < attr.extensions.length; ++ei) { - attr.value.push(pki.certificateExtensionToAsn1( - _fillMissingExtensionFields(attr.extensions[ei]))); - } - } - } - - if(typeof attr.value === 'undefined') { - var error = new Error('Attribute value not specified.'); - error.attribute = attr; - throw error; - } - } - } - - /** - * Fills in missing fields in certificate extensions. - * - * @param e the extension. - * @param [options] the options to use. - * [cert] the certificate the extensions are for. - * - * @return the extension. - */ - function _fillMissingExtensionFields(e, options) { - options = options || {}; - - // populate missing name - if(typeof e.name === 'undefined') { - if(e.id && e.id in pki.oids) { - e.name = pki.oids[e.id]; - } - } - - // populate missing id - if(typeof e.id === 'undefined') { - if(e.name && e.name in pki.oids) { - e.id = pki.oids[e.name]; - } else { - var error = new Error('Extension ID not specified.'); - error.extension = e; - throw error; - } - } - - if(typeof e.value !== 'undefined') { - return e; - } - - // handle missing value: - - // value is a BIT STRING - if(e.name === 'keyUsage') { - // build flags - var unused = 0; - var b2 = 0x00; - var b3 = 0x00; - if(e.digitalSignature) { - b2 |= 0x80; - unused = 7; - } - if(e.nonRepudiation) { - b2 |= 0x40; - unused = 6; - } - if(e.keyEncipherment) { - b2 |= 0x20; - unused = 5; - } - if(e.dataEncipherment) { - b2 |= 0x10; - unused = 4; - } - if(e.keyAgreement) { - b2 |= 0x08; - unused = 3; - } - if(e.keyCertSign) { - b2 |= 0x04; - unused = 2; - } - if(e.cRLSign) { - b2 |= 0x02; - unused = 1; - } - if(e.encipherOnly) { - b2 |= 0x01; - unused = 0; - } - if(e.decipherOnly) { - b3 |= 0x80; - unused = 7; - } - - // create bit string - var value = String.fromCharCode(unused); - if(b3 !== 0) { - value += String.fromCharCode(b2) + String.fromCharCode(b3); - } else if(b2 !== 0) { - value += String.fromCharCode(b2); - } - e.value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value); - } else if(e.name === 'basicConstraints') { - // basicConstraints is a SEQUENCE - e.value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - // cA BOOLEAN flag defaults to false - if(e.cA) { - e.value.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false, - String.fromCharCode(0xFF))); - } - if('pathLenConstraint' in e) { - e.value.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(e.pathLenConstraint).getBytes())); - } - } else if(e.name === 'extKeyUsage') { - // extKeyUsage is a SEQUENCE of OIDs - e.value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - var seq = e.value.value; - for(var key in e) { - if(e[key] !== true) { - continue; - } - // key is name in OID map - if(key in oids) { - seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, - false, asn1.oidToDer(oids[key]).getBytes())); - } else if(key.indexOf('.') !== -1) { - // assume key is an OID - seq.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, - false, asn1.oidToDer(key).getBytes())); - } - } - } else if(e.name === 'nsCertType') { - // nsCertType is a BIT STRING - // build flags - var unused = 0; - var b2 = 0x00; - - if(e.client) { - b2 |= 0x80; - unused = 7; - } - if(e.server) { - b2 |= 0x40; - unused = 6; - } - if(e.email) { - b2 |= 0x20; - unused = 5; - } - if(e.objsign) { - b2 |= 0x10; - unused = 4; - } - if(e.reserved) { - b2 |= 0x08; - unused = 3; - } - if(e.sslCA) { - b2 |= 0x04; - unused = 2; - } - if(e.emailCA) { - b2 |= 0x02; - unused = 1; - } - if(e.objCA) { - b2 |= 0x01; - unused = 0; - } - - // create bit string - var value = String.fromCharCode(unused); - if(b2 !== 0) { - value += String.fromCharCode(b2); - } - e.value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, value); - } else if(e.name === 'subjectAltName' || e.name === 'issuerAltName') { - // SYNTAX SEQUENCE - e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - - var altName; - for(var n = 0; n < e.altNames.length; ++n) { - altName = e.altNames[n]; - var value = altName.value; - // handle IP - if(altName.type === 7 && altName.ip) { - value = forge.util.bytesFromIP(altName.ip); - if(value === null) { - var error = new Error( - 'Extension "ip" value is not a valid IPv4 or IPv6 address.'); - error.extension = e; - throw error; - } - } else if(altName.type === 8) { - // handle OID - if(altName.oid) { - value = asn1.oidToDer(asn1.oidToDer(altName.oid)); - } else { - // deprecated ... convert value to OID - value = asn1.oidToDer(value); - } - } - e.value.value.push(asn1.create( - asn1.Class.CONTEXT_SPECIFIC, altName.type, false, - value)); - } - } else if(e.name === 'nsComment' && options.cert) { - // sanity check value is ASCII (req'd) and not too big - if(!(/^[\x00-\x7F]*$/.test(e.comment)) || - (e.comment.length < 1) || (e.comment.length > 128)) { - throw new Error('Invalid "nsComment" content.'); - } - // IA5STRING opaque comment - e.value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.IA5STRING, false, e.comment); - } else if(e.name === 'subjectKeyIdentifier' && options.cert) { - var ski = options.cert.generateSubjectKeyIdentifier(); - e.subjectKeyIdentifier = ski.toHex(); - // OCTETSTRING w/digest - e.value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, ski.getBytes()); - } else if(e.name === 'authorityKeyIdentifier' && options.cert) { - // SYNTAX SEQUENCE - e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - var seq = e.value.value; - - if(e.keyIdentifier) { - var keyIdentifier = (e.keyIdentifier === true ? - options.cert.generateSubjectKeyIdentifier().getBytes() : - e.keyIdentifier); - seq.push( - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, false, keyIdentifier)); - } - - if(e.authorityCertIssuer) { - var authorityCertIssuer = [ - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 4, true, [ - _dnToAsn1(e.authorityCertIssuer === true ? - options.cert.issuer : e.authorityCertIssuer) - ]) - ]; - seq.push( - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, authorityCertIssuer)); - } - - if(e.serialNumber) { - var serialNumber = forge.util.hexToBytes(e.serialNumber === true ? - options.cert.serialNumber : e.serialNumber); - seq.push( - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, false, serialNumber)); - } - } else if(e.name === 'cRLDistributionPoints') { - e.value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - var seq = e.value.value; - - // Create sub SEQUENCE of DistributionPointName - var subSeq = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - - // Create fullName CHOICE - var fullNameGeneralNames = asn1.create( - asn1.Class.CONTEXT_SPECIFIC, 0, true, []); - var altName; - for(var n = 0; n < e.altNames.length; ++n) { - altName = e.altNames[n]; - var value = altName.value; - // handle IP - if(altName.type === 7 && altName.ip) { - value = forge.util.bytesFromIP(altName.ip); - if(value === null) { - var error = new Error( - 'Extension "ip" value is not a valid IPv4 or IPv6 address.'); - error.extension = e; - throw error; - } - } else if(altName.type === 8) { - // handle OID - if(altName.oid) { - value = asn1.oidToDer(asn1.oidToDer(altName.oid)); - } else { - // deprecated ... convert value to OID - value = asn1.oidToDer(value); - } - } - fullNameGeneralNames.value.push(asn1.create( - asn1.Class.CONTEXT_SPECIFIC, altName.type, false, - value)); - } - - // Add to the parent SEQUENCE - subSeq.value.push(asn1.create( - asn1.Class.CONTEXT_SPECIFIC, 0, true, [fullNameGeneralNames])); - seq.push(subSeq); - } - - // ensure value has been defined by now - if(typeof e.value === 'undefined') { - var error = new Error('Extension value not specified.'); - error.extension = e; - throw error; - } - - return e; - } - - /** - * Convert signature parameters object to ASN.1 - * - * @param {String} oid Signature algorithm OID - * @param params The signature parametrs object - * @return ASN.1 object representing signature parameters - */ - function _signatureParametersToAsn1(oid, params) { - switch(oid) { - case oids['RSASSA-PSS']: - var parts = []; - - if(params.hash.algorithmOid !== undefined) { - parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(params.hash.algorithmOid).getBytes()), - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ]) - ])); - } - - if(params.mgf.algorithmOid !== undefined) { - parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(params.mgf.algorithmOid).getBytes()), - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(params.mgf.hash.algorithmOid).getBytes()), - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ]) - ]) - ])); - } - - if(params.saltLength !== undefined) { - parts.push(asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(params.saltLength).getBytes()) - ])); - } - - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, parts); - - default: - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, ''); - } - } - - /** - * Converts a certification request's attributes to an ASN.1 set of - * CRIAttributes. - * - * @param csr certification request. - * - * @return the ASN.1 set of CRIAttributes. - */ - function _CRIAttributesToAsn1(csr) { - // create an empty context-specific container - var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, []); - - // no attributes, return empty container - if(csr.attributes.length === 0) { - return rval; - } - - // each attribute has a sequence with a type and a set of values - var attrs = csr.attributes; - for(var i = 0; i < attrs.length; ++i) { - var attr = attrs[i]; - var value = attr.value; - - // reuse tag class for attribute value if available - var valueTagClass = asn1.Type.UTF8; - if('valueTagClass' in attr) { - valueTagClass = attr.valueTagClass; - } - if(valueTagClass === asn1.Type.UTF8) { - value = forge.util.encodeUtf8(value); - } - var valueConstructed = false; - if('valueConstructed' in attr) { - valueConstructed = attr.valueConstructed; - } - // FIXME: handle more encodings - - // create a RelativeDistinguishedName set - // each value in the set is an AttributeTypeAndValue first - // containing the type (an OID) and second the value - var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // AttributeType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(attr.type).getBytes()), - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ - // AttributeValue - asn1.create( - asn1.Class.UNIVERSAL, valueTagClass, valueConstructed, value) - ]) - ]); - rval.value.push(seq); - } - - return rval; - } - - var jan_1_1950 = new Date('1950-01-01T00:00:00Z'); - var jan_1_2050 = new Date('2050-01-01T00:00:00Z'); - - /** - * Converts a Date object to ASN.1 - * Handles the different format before and after 1st January 2050 - * - * @param date date object. - * - * @return the ASN.1 object representing the date. - */ - function _dateToAsn1(date) { - if(date >= jan_1_1950 && date < jan_1_2050) { - return asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false, - asn1.dateToUtcTime(date)); - } else { - return asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false, - asn1.dateToGeneralizedTime(date)); - } - } - - /** - * Gets the ASN.1 TBSCertificate part of an X.509v3 certificate. - * - * @param cert the certificate. - * - * @return the asn1 TBSCertificate. - */ - pki.getTBSCertificate = function(cert) { - // TBSCertificate - var notBefore = _dateToAsn1(cert.validity.notBefore); - var notAfter = _dateToAsn1(cert.validity.notAfter); - var tbs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // version - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - // integer - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(cert.version).getBytes()) - ]), - // serialNumber - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - forge.util.hexToBytes(cert.serialNumber)), - // signature - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(cert.siginfo.algorithmOid).getBytes()), - // parameters - _signatureParametersToAsn1( - cert.siginfo.algorithmOid, cert.siginfo.parameters) - ]), - // issuer - _dnToAsn1(cert.issuer), - // validity - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - notBefore, - notAfter - ]), - // subject - _dnToAsn1(cert.subject), - // SubjectPublicKeyInfo - pki.publicKeyToAsn1(cert.publicKey) - ]); - - if(cert.issuer.uniqueId) { - // issuerUniqueID (optional) - tbs.value.push( - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, - // TODO: support arbitrary bit length ids - String.fromCharCode(0x00) + - cert.issuer.uniqueId - ) - ]) - ); - } - if(cert.subject.uniqueId) { - // subjectUniqueID (optional) - tbs.value.push( - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, - // TODO: support arbitrary bit length ids - String.fromCharCode(0x00) + - cert.subject.uniqueId - ) - ]) - ); - } - - if(cert.extensions.length > 0) { - // extensions (optional) - tbs.value.push(pki.certificateExtensionsToAsn1(cert.extensions)); - } - - return tbs; - }; - - /** - * Gets the ASN.1 CertificationRequestInfo part of a - * PKCS#10 CertificationRequest. - * - * @param csr the certification request. - * - * @return the asn1 CertificationRequestInfo. - */ - pki.getCertificationRequestInfo = function(csr) { - // CertificationRequestInfo - var cri = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // version - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(csr.version).getBytes()), - // subject - _dnToAsn1(csr.subject), - // SubjectPublicKeyInfo - pki.publicKeyToAsn1(csr.publicKey), - // attributes - _CRIAttributesToAsn1(csr) - ]); - - return cri; - }; - - /** - * Converts a DistinguishedName (subject or issuer) to an ASN.1 object. - * - * @param dn the DistinguishedName. - * - * @return the asn1 representation of a DistinguishedName. - */ - pki.distinguishedNameToAsn1 = function(dn) { - return _dnToAsn1(dn); - }; - - /** - * Converts an X.509v3 RSA certificate to an ASN.1 object. - * - * @param cert the certificate. - * - * @return the asn1 representation of an X.509v3 RSA certificate. - */ - pki.certificateToAsn1 = function(cert) { - // prefer cached TBSCertificate over generating one - var tbsCertificate = cert.tbsCertificate || pki.getTBSCertificate(cert); - - // Certificate - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // TBSCertificate - tbsCertificate, - // AlgorithmIdentifier (signature algorithm) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(cert.signatureOid).getBytes()), - // parameters - _signatureParametersToAsn1(cert.signatureOid, cert.signatureParameters) - ]), - // SignatureValue - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, - String.fromCharCode(0x00) + cert.signature) - ]); - }; - - /** - * Converts X.509v3 certificate extensions to ASN.1. - * - * @param exts the extensions to convert. - * - * @return the extensions in ASN.1 format. - */ - pki.certificateExtensionsToAsn1 = function(exts) { - // create top-level extension container - var rval = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 3, true, []); - - // create extension sequence (stores a sequence for each extension) - var seq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - rval.value.push(seq); - - for(var i = 0; i < exts.length; ++i) { - seq.value.push(pki.certificateExtensionToAsn1(exts[i])); - } - - return rval; - }; - - /** - * Converts a single certificate extension to ASN.1. - * - * @param ext the extension to convert. - * - * @return the extension in ASN.1 format. - */ - pki.certificateExtensionToAsn1 = function(ext) { - // create a sequence for each extension - var extseq = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []); - - // extnID (OID) - extseq.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(ext.id).getBytes())); - - // critical defaults to false - if(ext.critical) { - // critical BOOLEAN DEFAULT FALSE - extseq.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.BOOLEAN, false, - String.fromCharCode(0xFF))); - } - - var value = ext.value; - if(typeof ext.value !== 'string') { - // value is asn.1 - value = asn1.toDer(value).getBytes(); - } - - // extnValue (OCTET STRING) - extseq.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, value)); - - return extseq; - }; - - /** - * Converts a PKCS#10 certification request to an ASN.1 object. - * - * @param csr the certification request. - * - * @return the asn1 representation of a certification request. - */ - pki.certificationRequestToAsn1 = function(csr) { - // prefer cached CertificationRequestInfo over generating one - var cri = csr.certificationRequestInfo || - pki.getCertificationRequestInfo(csr); - - // Certificate - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // CertificationRequestInfo - cri, - // AlgorithmIdentifier (signature algorithm) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(csr.signatureOid).getBytes()), - // parameters - _signatureParametersToAsn1(csr.signatureOid, csr.signatureParameters) - ]), - // signature - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, - String.fromCharCode(0x00) + csr.signature) - ]); - }; - - /** - * Creates a CA store. - * - * @param certs an optional array of certificate objects or PEM-formatted - * certificate strings to add to the CA store. - * - * @return the CA store. - */ - pki.createCaStore = function(certs) { - // create CA store - var caStore = { - // stored certificates - certs: {} - }; - - /** - * Gets the certificate that issued the passed certificate or its - * 'parent'. - * - * @param cert the certificate to get the parent for. - * - * @return the parent certificate or null if none was found. - */ - caStore.getIssuer = function(cert) { - var rval = getBySubject(cert.issuer); - - // see if there are multiple matches - /*if(forge.util.isArray(rval)) { - // TODO: resolve multiple matches by checking - // authorityKey/subjectKey/issuerUniqueID/other identifiers, etc. - // FIXME: or alternatively do authority key mapping - // if possible (X.509v1 certs can't work?) - throw new Error('Resolving multiple issuer matches not implemented yet.'); - }*/ - - return rval; - }; - - /** - * Adds a trusted certificate to the store. - * - * @param cert the certificate to add as a trusted certificate (either a - * pki.certificate object or a PEM-formatted certificate). - */ - caStore.addCertificate = function(cert) { - // convert from pem if necessary - if(typeof cert === 'string') { - cert = forge.pki.certificateFromPem(cert); - } - - ensureSubjectHasHash(cert.subject); - - if(!caStore.hasCertificate(cert)) { // avoid duplicate certificates in store - if(cert.subject.hash in caStore.certs) { - // subject hash already exists, append to array - var tmp = caStore.certs[cert.subject.hash]; - if(!forge.util.isArray(tmp)) { - tmp = [tmp]; - } - tmp.push(cert); - caStore.certs[cert.subject.hash] = tmp; - } else { - caStore.certs[cert.subject.hash] = cert; - } - } - }; - - /** - * Checks to see if the given certificate is in the store. - * - * @param cert the certificate to check (either a pki.certificate or a - * PEM-formatted certificate). - * - * @return true if the certificate is in the store, false if not. - */ - caStore.hasCertificate = function(cert) { - // convert from pem if necessary - if(typeof cert === 'string') { - cert = forge.pki.certificateFromPem(cert); - } - - var match = getBySubject(cert.subject); - if(!match) { - return false; - } - if(!forge.util.isArray(match)) { - match = [match]; - } - // compare DER-encoding of certificates - var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes(); - for(var i = 0; i < match.length; ++i) { - var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes(); - if(der1 === der2) { - return true; - } - } - return false; - }; - - /** - * Lists all of the certificates kept in the store. - * - * @return an array of all of the pki.certificate objects in the store. - */ - caStore.listAllCertificates = function() { - var certList = []; - - for(var hash in caStore.certs) { - if(caStore.certs.hasOwnProperty(hash)) { - var value = caStore.certs[hash]; - if(!forge.util.isArray(value)) { - certList.push(value); - } else { - for(var i = 0; i < value.length; ++i) { - certList.push(value[i]); - } - } - } - } - - return certList; - }; - - /** - * Removes a certificate from the store. - * - * @param cert the certificate to remove (either a pki.certificate or a - * PEM-formatted certificate). - * - * @return the certificate that was removed or null if the certificate - * wasn't in store. - */ - caStore.removeCertificate = function(cert) { - var result; - - // convert from pem if necessary - if(typeof cert === 'string') { - cert = forge.pki.certificateFromPem(cert); - } - ensureSubjectHasHash(cert.subject); - if(!caStore.hasCertificate(cert)) { - return null; - } - - var match = getBySubject(cert.subject); - - if(!forge.util.isArray(match)) { - result = caStore.certs[cert.subject.hash]; - delete caStore.certs[cert.subject.hash]; - return result; - } - - // compare DER-encoding of certificates - var der1 = asn1.toDer(pki.certificateToAsn1(cert)).getBytes(); - for(var i = 0; i < match.length; ++i) { - var der2 = asn1.toDer(pki.certificateToAsn1(match[i])).getBytes(); - if(der1 === der2) { - result = match[i]; - match.splice(i, 1); - } - } - if(match.length === 0) { - delete caStore.certs[cert.subject.hash]; - } - - return result; - }; - - function getBySubject(subject) { - ensureSubjectHasHash(subject); - return caStore.certs[subject.hash] || null; - } - - function ensureSubjectHasHash(subject) { - // produce subject hash if it doesn't exist - if(!subject.hash) { - var md = forge.md.sha1.create(); - subject.attributes = pki.RDNAttributesAsArray(_dnToAsn1(subject), md); - subject.hash = md.digest().toHex(); - } - } - - // auto-add passed in certs - if(certs) { - // parse PEM-formatted certificates as necessary - for(var i = 0; i < certs.length; ++i) { - var cert = certs[i]; - caStore.addCertificate(cert); - } - } - - return caStore; - }; - - /** - * Certificate verification errors, based on TLS. - */ - pki.certificateError = { - bad_certificate: 'forge.pki.BadCertificate', - unsupported_certificate: 'forge.pki.UnsupportedCertificate', - certificate_revoked: 'forge.pki.CertificateRevoked', - certificate_expired: 'forge.pki.CertificateExpired', - certificate_unknown: 'forge.pki.CertificateUnknown', - unknown_ca: 'forge.pki.UnknownCertificateAuthority' - }; - - /** - * Verifies a certificate chain against the given Certificate Authority store - * with an optional custom verify callback. - * - * @param caStore a certificate store to verify against. - * @param chain the certificate chain to verify, with the root or highest - * authority at the end (an array of certificates). - * @param options a callback to be called for every certificate in the chain or - * an object with: - * verify a callback to be called for every certificate in the - * chain - * validityCheckDate the date against which the certificate - * validity period should be checked. Pass null to not check - * the validity period. By default, the current date is used. - * - * The verify callback has the following signature: - * - * verified - Set to true if certificate was verified, otherwise the - * pki.certificateError for why the certificate failed. - * depth - The current index in the chain, where 0 is the end point's cert. - * certs - The certificate chain, *NOTE* an empty chain indicates an anonymous - * end point. - * - * The function returns true on success and on failure either the appropriate - * pki.certificateError or an object with 'error' set to the appropriate - * pki.certificateError and 'message' set to a custom error message. - * - * @return true if successful, error thrown if not. - */ - pki.verifyCertificateChain = function(caStore, chain, options) { - /* From: RFC3280 - Internet X.509 Public Key Infrastructure Certificate - Section 6: Certification Path Validation - See inline parentheticals related to this particular implementation. - - The primary goal of path validation is to verify the binding between - a subject distinguished name or a subject alternative name and subject - public key, as represented in the end entity certificate, based on the - public key of the trust anchor. This requires obtaining a sequence of - certificates that support that binding. That sequence should be provided - in the passed 'chain'. The trust anchor should be in the given CA - store. The 'end entity' certificate is the certificate provided by the - end point (typically a server) and is the first in the chain. - - To meet this goal, the path validation process verifies, among other - things, that a prospective certification path (a sequence of n - certificates or a 'chain') satisfies the following conditions: - - (a) for all x in {1, ..., n-1}, the subject of certificate x is - the issuer of certificate x+1; - - (b) certificate 1 is issued by the trust anchor; - - (c) certificate n is the certificate to be validated; and - - (d) for all x in {1, ..., n}, the certificate was valid at the - time in question. - - Note that here 'n' is index 0 in the chain and 1 is the last certificate - in the chain and it must be signed by a certificate in the connection's - CA store. - - The path validation process also determines the set of certificate - policies that are valid for this path, based on the certificate policies - extension, policy mapping extension, policy constraints extension, and - inhibit any-policy extension. - - Note: Policy mapping extension not supported (Not Required). - - Note: If the certificate has an unsupported critical extension, then it - must be rejected. - - Note: A certificate is self-issued if the DNs that appear in the subject - and issuer fields are identical and are not empty. - - The path validation algorithm assumes the following seven inputs are - provided to the path processing logic. What this specific implementation - will use is provided parenthetically: - - (a) a prospective certification path of length n (the 'chain') - (b) the current date/time: ('now'). - (c) user-initial-policy-set: A set of certificate policy identifiers - naming the policies that are acceptable to the certificate user. - The user-initial-policy-set contains the special value any-policy - if the user is not concerned about certificate policy - (Not implemented. Any policy is accepted). - (d) trust anchor information, describing a CA that serves as a trust - anchor for the certification path. The trust anchor information - includes: - - (1) the trusted issuer name, - (2) the trusted public key algorithm, - (3) the trusted public key, and - (4) optionally, the trusted public key parameters associated - with the public key. - - (Trust anchors are provided via certificates in the CA store). - - The trust anchor information may be provided to the path processing - procedure in the form of a self-signed certificate. The trusted anchor - information is trusted because it was delivered to the path processing - procedure by some trustworthy out-of-band procedure. If the trusted - public key algorithm requires parameters, then the parameters are - provided along with the trusted public key (No parameters used in this - implementation). - - (e) initial-policy-mapping-inhibit, which indicates if policy mapping is - allowed in the certification path. - (Not implemented, no policy checking) - - (f) initial-explicit-policy, which indicates if the path must be valid - for at least one of the certificate policies in the user-initial- - policy-set. - (Not implemented, no policy checking) - - (g) initial-any-policy-inhibit, which indicates whether the - anyPolicy OID should be processed if it is included in a - certificate. - (Not implemented, so any policy is valid provided that it is - not marked as critical) */ - - /* Basic Path Processing: - - For each certificate in the 'chain', the following is checked: - - 1. The certificate validity period includes the current time. - 2. The certificate was signed by its parent (where the parent is either - the next in the chain or from the CA store). Allow processing to - continue to the next step if no parent is found but the certificate is - in the CA store. - 3. TODO: The certificate has not been revoked. - 4. The certificate issuer name matches the parent's subject name. - 5. TODO: If the certificate is self-issued and not the final certificate - in the chain, skip this step, otherwise verify that the subject name - is within one of the permitted subtrees of X.500 distinguished names - and that each of the alternative names in the subjectAltName extension - (critical or non-critical) is within one of the permitted subtrees for - that name type. - 6. TODO: If the certificate is self-issued and not the final certificate - in the chain, skip this step, otherwise verify that the subject name - is not within one of the excluded subtrees for X.500 distinguished - names and none of the subjectAltName extension names are excluded for - that name type. - 7. The other steps in the algorithm for basic path processing involve - handling the policy extension which is not presently supported in this - implementation. Instead, if a critical policy extension is found, the - certificate is rejected as not supported. - 8. If the certificate is not the first or if its the only certificate in - the chain (having no parent from the CA store or is self-signed) and it - has a critical key usage extension, verify that the keyCertSign bit is - set. If the key usage extension exists, verify that the basic - constraints extension exists. If the basic constraints extension exists, - verify that the cA flag is set. If pathLenConstraint is set, ensure that - the number of certificates that precede in the chain (come earlier - in the chain as implemented below), excluding the very first in the - chain (typically the end-entity one), isn't greater than the - pathLenConstraint. This constraint limits the number of intermediate - CAs that may appear below a CA before only end-entity certificates - may be issued. */ - - // if a verify callback is passed as the third parameter, package it within - // the options object. This is to support a legacy function signature that - // expected the verify callback as the third parameter. - if(typeof options === 'function') { - options = {verify: options}; - } - options = options || {}; - - // copy cert chain references to another array to protect against changes - // in verify callback - chain = chain.slice(0); - var certs = chain.slice(0); - - var validityCheckDate = options.validityCheckDate; - // if no validityCheckDate is specified, default to the current date. Make - // sure to maintain the value null because it indicates that the validity - // period should not be checked. - if(typeof validityCheckDate === 'undefined') { - validityCheckDate = new Date(); - } - - // verify each cert in the chain using its parent, where the parent - // is either the next in the chain or from the CA store - var first = true; - var error = null; - var depth = 0; - do { - var cert = chain.shift(); - var parent = null; - var selfSigned = false; - - if(validityCheckDate) { - // 1. check valid time - if(validityCheckDate < cert.validity.notBefore || - validityCheckDate > cert.validity.notAfter) { - error = { - message: 'Certificate is not valid yet or has expired.', - error: pki.certificateError.certificate_expired, - notBefore: cert.validity.notBefore, - notAfter: cert.validity.notAfter, - // TODO: we might want to reconsider renaming 'now' to - // 'validityCheckDate' should this API be changed in the future. - now: validityCheckDate - }; - } - } - - // 2. verify with parent from chain or CA store - if(error === null) { - parent = chain[0] || caStore.getIssuer(cert); - if(parent === null) { - // check for self-signed cert - if(cert.isIssuer(cert)) { - selfSigned = true; - parent = cert; - } - } - - if(parent) { - // FIXME: current CA store implementation might have multiple - // certificates where the issuer can't be determined from the - // certificate (happens rarely with, eg: old certificates) so normalize - // by always putting parents into an array - // TODO: there's may be an extreme degenerate case currently uncovered - // where an old intermediate certificate seems to have a matching parent - // but none of the parents actually verify ... but the intermediate - // is in the CA and it should pass this check; needs investigation - var parents = parent; - if(!forge.util.isArray(parents)) { - parents = [parents]; - } - - // try to verify with each possible parent (typically only one) - var verified = false; - while(!verified && parents.length > 0) { - parent = parents.shift(); - try { - verified = parent.verify(cert); - } catch(ex) { - // failure to verify, don't care why, try next one - } - } - - if(!verified) { - error = { - message: 'Certificate signature is invalid.', - error: pki.certificateError.bad_certificate - }; - } - } - - if(error === null && (!parent || selfSigned) && - !caStore.hasCertificate(cert)) { - // no parent issuer and certificate itself is not trusted - error = { - message: 'Certificate is not trusted.', - error: pki.certificateError.unknown_ca - }; - } - } - - // TODO: 3. check revoked - - // 4. check for matching issuer/subject - if(error === null && parent && !cert.isIssuer(parent)) { - // parent is not issuer - error = { - message: 'Certificate issuer is invalid.', - error: pki.certificateError.bad_certificate - }; - } - - // 5. TODO: check names with permitted names tree - - // 6. TODO: check names against excluded names tree - - // 7. check for unsupported critical extensions - if(error === null) { - // supported extensions - var se = { - keyUsage: true, - basicConstraints: true - }; - for(var i = 0; error === null && i < cert.extensions.length; ++i) { - var ext = cert.extensions[i]; - if(ext.critical && !(ext.name in se)) { - error = { - message: - 'Certificate has an unsupported critical extension.', - error: pki.certificateError.unsupported_certificate - }; - } - } - } - - // 8. check for CA if cert is not first or is the only certificate - // remaining in chain with no parent or is self-signed - if(error === null && - (!first || (chain.length === 0 && (!parent || selfSigned)))) { - // first check keyUsage extension and then basic constraints - var bcExt = cert.getExtension('basicConstraints'); - var keyUsageExt = cert.getExtension('keyUsage'); - if(keyUsageExt !== null) { - // keyCertSign must be true and there must be a basic - // constraints extension - if(!keyUsageExt.keyCertSign || bcExt === null) { - // bad certificate - error = { - message: - 'Certificate keyUsage or basicConstraints conflict ' + - 'or indicate that the certificate is not a CA. ' + - 'If the certificate is the only one in the chain or ' + - 'isn\'t the first then the certificate must be a ' + - 'valid CA.', - error: pki.certificateError.bad_certificate - }; - } - } - // basic constraints cA flag must be set - if(error === null && bcExt !== null && !bcExt.cA) { - // bad certificate - error = { - message: - 'Certificate basicConstraints indicates the certificate ' + - 'is not a CA.', - error: pki.certificateError.bad_certificate - }; - } - // if error is not null and keyUsage is available, then we know it - // has keyCertSign and there is a basic constraints extension too, - // which means we can check pathLenConstraint (if it exists) - if(error === null && keyUsageExt !== null && - 'pathLenConstraint' in bcExt) { - // pathLen is the maximum # of intermediate CA certs that can be - // found between the current certificate and the end-entity (depth 0) - // certificate; this number does not include the end-entity (depth 0, - // last in the chain) even if it happens to be a CA certificate itself - var pathLen = depth - 1; - if(pathLen > bcExt.pathLenConstraint) { - // pathLenConstraint violated, bad certificate - error = { - message: - 'Certificate basicConstraints pathLenConstraint violated.', - error: pki.certificateError.bad_certificate - }; - } - } - } - - // call application callback - var vfd = (error === null) ? true : error.error; - var ret = options.verify ? options.verify(vfd, depth, certs) : vfd; - if(ret === true) { - // clear any set error - error = null; - } else { - // if passed basic tests, set default message and alert - if(vfd === true) { - error = { - message: 'The application rejected the certificate.', - error: pki.certificateError.bad_certificate - }; - } - - // check for custom error info - if(ret || ret === 0) { - // set custom message and error - if(typeof ret === 'object' && !forge.util.isArray(ret)) { - if(ret.message) { - error.message = ret.message; - } - if(ret.error) { - error.error = ret.error; - } - } else if(typeof ret === 'string') { - // set custom error - error.error = ret; - } - } - - // throw error - throw error; - } - - // no longer first cert in chain - first = false; - ++depth; - } while(chain.length > 0); - - return true; - }; - }); - - var pkcs12 = createCommonjsModule(function (module) { - /** - * Javascript implementation of PKCS#12. - * - * @author Dave Longley - * @author Stefan Siegl - * - * Copyright (c) 2010-2014 Digital Bazaar, Inc. - * Copyright (c) 2012 Stefan Siegl - * - * The ASN.1 representation of PKCS#12 is as follows - * (see ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12-tc1.pdf for details) - * - * PFX ::= SEQUENCE { - * version INTEGER {v3(3)}(v3,...), - * authSafe ContentInfo, - * macData MacData OPTIONAL - * } - * - * MacData ::= SEQUENCE { - * mac DigestInfo, - * macSalt OCTET STRING, - * iterations INTEGER DEFAULT 1 - * } - * Note: The iterations default is for historical reasons and its use is - * deprecated. A higher value, like 1024, is recommended. - * - * DigestInfo is defined in PKCS#7 as follows: - * - * DigestInfo ::= SEQUENCE { - * digestAlgorithm DigestAlgorithmIdentifier, - * digest Digest - * } - * - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * - * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters - * for the algorithm, if any. In the case of SHA1 there is none. - * - * AlgorithmIdentifer ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - * - * Digest ::= OCTET STRING - * - * - * ContentInfo ::= SEQUENCE { - * contentType ContentType, - * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL - * } - * - * ContentType ::= OBJECT IDENTIFIER - * - * AuthenticatedSafe ::= SEQUENCE OF ContentInfo - * -- Data if unencrypted - * -- EncryptedData if password-encrypted - * -- EnvelopedData if public key-encrypted - * - * - * SafeContents ::= SEQUENCE OF SafeBag - * - * SafeBag ::= SEQUENCE { - * bagId BAG-TYPE.&id ({PKCS12BagSet}) - * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), - * bagAttributes SET OF PKCS12Attribute OPTIONAL - * } - * - * PKCS12Attribute ::= SEQUENCE { - * attrId ATTRIBUTE.&id ({PKCS12AttrSet}), - * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId}) - * } -- This type is compatible with the X.500 type 'Attribute' - * - * PKCS12AttrSet ATTRIBUTE ::= { - * friendlyName | -- from PKCS #9 - * localKeyId, -- from PKCS #9 - * ... -- Other attributes are allowed - * } - * - * CertBag ::= SEQUENCE { - * certId BAG-TYPE.&id ({CertTypes}), - * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId}) - * } - * - * x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}} - * -- DER-encoded X.509 certificate stored in OCTET STRING - * - * sdsiCertificate BAG-TYPE ::= {IA5String IDENTIFIED BY {certTypes 2}} - * -- Base64-encoded SDSI certificate stored in IA5String - * - * CertTypes BAG-TYPE ::= { - * x509Certificate | - * sdsiCertificate, - * ... -- For future extensions - * } - */ - - - - - - - - - - - - - // shortcut for asn.1 & PKI API - var asn1 = forge.asn1; - var pki = forge.pki; - - // shortcut for PKCS#12 API - var p12 = module.exports = forge.pkcs12 = forge.pkcs12 || {}; - - var contentInfoValidator = { - name: 'ContentInfo', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, // a ContentInfo - constructed: true, - value: [{ - name: 'ContentInfo.contentType', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'contentType' - }, { - name: 'ContentInfo.content', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - constructed: true, - captureAsn1: 'content' - }] - }; - - var pfxValidator = { - name: 'PFX', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'PFX.version', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - capture: 'version' - }, - contentInfoValidator, { - name: 'PFX.macData', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - optional: true, - captureAsn1: 'mac', - value: [{ - name: 'PFX.macData.mac', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, // DigestInfo - constructed: true, - value: [{ - name: 'PFX.macData.mac.digestAlgorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, // DigestAlgorithmIdentifier - constructed: true, - value: [{ - name: 'PFX.macData.mac.digestAlgorithm.algorithm', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'macAlgorithm' - }, { - name: 'PFX.macData.mac.digestAlgorithm.parameters', - tagClass: asn1.Class.UNIVERSAL, - captureAsn1: 'macAlgorithmParameters' - }] - }, { - name: 'PFX.macData.mac.digest', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OCTETSTRING, - constructed: false, - capture: 'macDigest' - }] - }, { - name: 'PFX.macData.macSalt', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OCTETSTRING, - constructed: false, - capture: 'macSalt' - }, { - name: 'PFX.macData.iterations', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.INTEGER, - constructed: false, - optional: true, - capture: 'macIterations' - }] - }] - }; - - var safeBagValidator = { - name: 'SafeBag', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'SafeBag.bagId', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'bagId' - }, { - name: 'SafeBag.bagValue', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - constructed: true, - captureAsn1: 'bagValue' - }, { - name: 'SafeBag.bagAttributes', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SET, - constructed: true, - optional: true, - capture: 'bagAttributes' - }] - }; - - var attributeValidator = { - name: 'Attribute', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'Attribute.attrId', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'oid' - }, { - name: 'Attribute.attrValues', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SET, - constructed: true, - capture: 'values' - }] - }; - - var certBagValidator = { - name: 'CertBag', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'CertBag.certId', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.OID, - constructed: false, - capture: 'certId' - }, { - name: 'CertBag.certValue', - tagClass: asn1.Class.CONTEXT_SPECIFIC, - constructed: true, - /* So far we only support X.509 certificates (which are wrapped in - an OCTET STRING, hence hard code that here). */ - value: [{ - name: 'CertBag.certValue[0]', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Class.OCTETSTRING, - constructed: false, - capture: 'cert' - }] - }] - }; - - /** - * Search SafeContents structure for bags with matching attributes. - * - * The search can optionally be narrowed by a certain bag type. - * - * @param safeContents the SafeContents structure to search in. - * @param attrName the name of the attribute to compare against. - * @param attrValue the attribute value to search for. - * @param [bagType] bag type to narrow search by. - * - * @return an array of matching bags. - */ - function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) { - var result = []; - - for(var i = 0; i < safeContents.length; i++) { - for(var j = 0; j < safeContents[i].safeBags.length; j++) { - var bag = safeContents[i].safeBags[j]; - if(bagType !== undefined && bag.type !== bagType) { - continue; - } - // only filter by bag type, no attribute specified - if(attrName === null) { - result.push(bag); - continue; - } - if(bag.attributes[attrName] !== undefined && - bag.attributes[attrName].indexOf(attrValue) >= 0) { - result.push(bag); - } - } - } - - return result; - } - - /** - * Converts a PKCS#12 PFX in ASN.1 notation into a PFX object. - * - * @param obj The PKCS#12 PFX in ASN.1 notation. - * @param strict true to use strict DER decoding, false not to (default: true). - * @param {String} password Password to decrypt with (optional). - * - * @return PKCS#12 PFX object. - */ - p12.pkcs12FromAsn1 = function(obj, strict, password) { - // handle args - if(typeof strict === 'string') { - password = strict; - strict = true; - } else if(strict === undefined) { - strict = true; - } - - // validate PFX and capture data - var capture = {}; - var errors = []; - if(!asn1.validate(obj, pfxValidator, capture, errors)) { - var error = new Error('Cannot read PKCS#12 PFX. ' + - 'ASN.1 object is not an PKCS#12 PFX.'); - error.errors = error; - throw error; - } - - var pfx = { - version: capture.version.charCodeAt(0), - safeContents: [], - - /** - * Gets bags with matching attributes. - * - * @param filter the attributes to filter by: - * [localKeyId] the localKeyId to search for. - * [localKeyIdHex] the localKeyId in hex to search for. - * [friendlyName] the friendly name to search for. - * [bagType] bag type to narrow each attribute search by. - * - * @return a map of attribute type to an array of matching bags or, if no - * attribute was given but a bag type, the map key will be the - * bag type. - */ - getBags: function(filter) { - var rval = {}; - - var localKeyId; - if('localKeyId' in filter) { - localKeyId = filter.localKeyId; - } else if('localKeyIdHex' in filter) { - localKeyId = forge.util.hexToBytes(filter.localKeyIdHex); - } - - // filter on bagType only - if(localKeyId === undefined && !('friendlyName' in filter) && - 'bagType' in filter) { - rval[filter.bagType] = _getBagsByAttribute( - pfx.safeContents, null, null, filter.bagType); - } - - if(localKeyId !== undefined) { - rval.localKeyId = _getBagsByAttribute( - pfx.safeContents, 'localKeyId', - localKeyId, filter.bagType); - } - if('friendlyName' in filter) { - rval.friendlyName = _getBagsByAttribute( - pfx.safeContents, 'friendlyName', - filter.friendlyName, filter.bagType); - } - - return rval; - }, - - /** - * DEPRECATED: use getBags() instead. - * - * Get bags with matching friendlyName attribute. - * - * @param friendlyName the friendly name to search for. - * @param [bagType] bag type to narrow search by. - * - * @return an array of bags with matching friendlyName attribute. - */ - getBagsByFriendlyName: function(friendlyName, bagType) { - return _getBagsByAttribute( - pfx.safeContents, 'friendlyName', friendlyName, bagType); - }, - - /** - * DEPRECATED: use getBags() instead. - * - * Get bags with matching localKeyId attribute. - * - * @param localKeyId the localKeyId to search for. - * @param [bagType] bag type to narrow search by. - * - * @return an array of bags with matching localKeyId attribute. - */ - getBagsByLocalKeyId: function(localKeyId, bagType) { - return _getBagsByAttribute( - pfx.safeContents, 'localKeyId', localKeyId, bagType); - } - }; - - if(capture.version.charCodeAt(0) !== 3) { - var error = new Error('PKCS#12 PFX of version other than 3 not supported.'); - error.version = capture.version.charCodeAt(0); - throw error; - } - - if(asn1.derToOid(capture.contentType) !== pki.oids.data) { - var error = new Error('Only PKCS#12 PFX in password integrity mode supported.'); - error.oid = asn1.derToOid(capture.contentType); - throw error; - } - - var data = capture.content.value[0]; - if(data.tagClass !== asn1.Class.UNIVERSAL || - data.type !== asn1.Type.OCTETSTRING) { - throw new Error('PKCS#12 authSafe content data is not an OCTET STRING.'); - } - data = _decodePkcs7Data(data); - - // check for MAC - if(capture.mac) { - var md = null; - var macKeyBytes = 0; - var macAlgorithm = asn1.derToOid(capture.macAlgorithm); - switch(macAlgorithm) { - case pki.oids.sha1: - md = forge.md.sha1.create(); - macKeyBytes = 20; - break; - case pki.oids.sha256: - md = forge.md.sha256.create(); - macKeyBytes = 32; - break; - case pki.oids.sha384: - md = forge.md.sha384.create(); - macKeyBytes = 48; - break; - case pki.oids.sha512: - md = forge.md.sha512.create(); - macKeyBytes = 64; - break; - case pki.oids.md5: - md = forge.md.md5.create(); - macKeyBytes = 16; - break; - } - if(md === null) { - throw new Error('PKCS#12 uses unsupported MAC algorithm: ' + macAlgorithm); - } - - // verify MAC (iterations default to 1) - var macSalt = new forge.util.ByteBuffer(capture.macSalt); - var macIterations = (('macIterations' in capture) ? - parseInt(forge.util.bytesToHex(capture.macIterations), 16) : 1); - var macKey = p12.generateKey( - password, macSalt, 3, macIterations, macKeyBytes, md); - var mac = forge.hmac.create(); - mac.start(md, macKey); - mac.update(data.value); - var macValue = mac.getMac(); - if(macValue.getBytes() !== capture.macDigest) { - throw new Error('PKCS#12 MAC could not be verified. Invalid password?'); - } - } - - _decodeAuthenticatedSafe(pfx, data.value, strict, password); - return pfx; - }; - - /** - * Decodes PKCS#7 Data. PKCS#7 (RFC 2315) defines "Data" as an OCTET STRING, - * but it is sometimes an OCTET STRING that is composed/constructed of chunks, - * each its own OCTET STRING. This is BER-encoding vs. DER-encoding. This - * function transforms this corner-case into the usual simple, - * non-composed/constructed OCTET STRING. - * - * This function may be moved to ASN.1 at some point to better deal with - * more BER-encoding issues, should they arise. - * - * @param data the ASN.1 Data object to transform. - */ - function _decodePkcs7Data(data) { - // handle special case of "chunked" data content: an octet string composed - // of other octet strings - if(data.composed || data.constructed) { - var value = forge.util.createBuffer(); - for(var i = 0; i < data.value.length; ++i) { - value.putBytes(data.value[i].value); - } - data.composed = data.constructed = false; - data.value = value.getBytes(); - } - return data; - } - - /** - * Decode PKCS#12 AuthenticatedSafe (BER encoded) into PFX object. - * - * The AuthenticatedSafe is a BER-encoded SEQUENCE OF ContentInfo. - * - * @param pfx The PKCS#12 PFX object to fill. - * @param {String} authSafe BER-encoded AuthenticatedSafe. - * @param strict true to use strict DER decoding, false not to. - * @param {String} password Password to decrypt with (optional). - */ - function _decodeAuthenticatedSafe(pfx, authSafe, strict, password) { - authSafe = asn1.fromDer(authSafe, strict); /* actually it's BER encoded */ - - if(authSafe.tagClass !== asn1.Class.UNIVERSAL || - authSafe.type !== asn1.Type.SEQUENCE || - authSafe.constructed !== true) { - throw new Error('PKCS#12 AuthenticatedSafe expected to be a ' + - 'SEQUENCE OF ContentInfo'); - } - - for(var i = 0; i < authSafe.value.length; i++) { - var contentInfo = authSafe.value[i]; - - // validate contentInfo and capture data - var capture = {}; - var errors = []; - if(!asn1.validate(contentInfo, contentInfoValidator, capture, errors)) { - var error = new Error('Cannot read ContentInfo.'); - error.errors = errors; - throw error; - } - - var obj = { - encrypted: false - }; - var safeContents = null; - var data = capture.content.value[0]; - switch(asn1.derToOid(capture.contentType)) { - case pki.oids.data: - if(data.tagClass !== asn1.Class.UNIVERSAL || - data.type !== asn1.Type.OCTETSTRING) { - throw new Error('PKCS#12 SafeContents Data is not an OCTET STRING.'); - } - safeContents = _decodePkcs7Data(data).value; - break; - case pki.oids.encryptedData: - safeContents = _decryptSafeContents(data, password); - obj.encrypted = true; - break; - default: - var error = new Error('Unsupported PKCS#12 contentType.'); - error.contentType = asn1.derToOid(capture.contentType); - throw error; - } - - obj.safeBags = _decodeSafeContents(safeContents, strict, password); - pfx.safeContents.push(obj); - } - } - - /** - * Decrypt PKCS#7 EncryptedData structure. - * - * @param data ASN.1 encoded EncryptedContentInfo object. - * @param password The user-provided password. - * - * @return The decrypted SafeContents (ASN.1 object). - */ - function _decryptSafeContents(data, password) { - var capture = {}; - var errors = []; - if(!asn1.validate( - data, forge.pkcs7.asn1.encryptedDataValidator, capture, errors)) { - var error = new Error('Cannot read EncryptedContentInfo.'); - error.errors = errors; - throw error; - } - - var oid = asn1.derToOid(capture.contentType); - if(oid !== pki.oids.data) { - var error = new Error( - 'PKCS#12 EncryptedContentInfo ContentType is not Data.'); - error.oid = oid; - throw error; - } - - // get cipher - oid = asn1.derToOid(capture.encAlgorithm); - var cipher = pki.pbe.getCipher(oid, capture.encParameter, password); - - // get encrypted data - var encryptedContentAsn1 = _decodePkcs7Data(capture.encryptedContentAsn1); - var encrypted = forge.util.createBuffer(encryptedContentAsn1.value); - - cipher.update(encrypted); - if(!cipher.finish()) { - throw new Error('Failed to decrypt PKCS#12 SafeContents.'); - } - - return cipher.output.getBytes(); - } - - /** - * Decode PKCS#12 SafeContents (BER-encoded) into array of Bag objects. - * - * The safeContents is a BER-encoded SEQUENCE OF SafeBag. - * - * @param {String} safeContents BER-encoded safeContents. - * @param strict true to use strict DER decoding, false not to. - * @param {String} password Password to decrypt with (optional). - * - * @return {Array} Array of Bag objects. - */ - function _decodeSafeContents(safeContents, strict, password) { - // if strict and no safe contents, return empty safes - if(!strict && safeContents.length === 0) { - return []; - } - - // actually it's BER-encoded - safeContents = asn1.fromDer(safeContents, strict); - - if(safeContents.tagClass !== asn1.Class.UNIVERSAL || - safeContents.type !== asn1.Type.SEQUENCE || - safeContents.constructed !== true) { - throw new Error( - 'PKCS#12 SafeContents expected to be a SEQUENCE OF SafeBag.'); - } - - var res = []; - for(var i = 0; i < safeContents.value.length; i++) { - var safeBag = safeContents.value[i]; - - // validate SafeBag and capture data - var capture = {}; - var errors = []; - if(!asn1.validate(safeBag, safeBagValidator, capture, errors)) { - var error = new Error('Cannot read SafeBag.'); - error.errors = errors; - throw error; - } - - /* Create bag object and push to result array. */ - var bag = { - type: asn1.derToOid(capture.bagId), - attributes: _decodeBagAttributes(capture.bagAttributes) - }; - res.push(bag); - - var validator, decoder; - var bagAsn1 = capture.bagValue.value[0]; - switch(bag.type) { - case pki.oids.pkcs8ShroudedKeyBag: - /* bagAsn1 has a EncryptedPrivateKeyInfo, which we need to decrypt. - Afterwards we can handle it like a keyBag, - which is a PrivateKeyInfo. */ - bagAsn1 = pki.decryptPrivateKeyInfo(bagAsn1, password); - if(bagAsn1 === null) { - throw new Error( - 'Unable to decrypt PKCS#8 ShroudedKeyBag, wrong password?'); - } - - /* fall through */ - case pki.oids.keyBag: - /* A PKCS#12 keyBag is a simple PrivateKeyInfo as understood by our - PKI module, hence we don't have to do validation/capturing here, - just pass what we already got. */ - try { - bag.key = pki.privateKeyFromAsn1(bagAsn1); - } catch(e) { - // ignore unknown key type, pass asn1 value - bag.key = null; - bag.asn1 = bagAsn1; - } - continue; /* Nothing more to do. */ - - case pki.oids.certBag: - /* A PKCS#12 certBag can wrap both X.509 and sdsi certificates. - Therefore put the SafeBag content through another validator to - capture the fields. Afterwards check & store the results. */ - validator = certBagValidator; - decoder = function() { - if(asn1.derToOid(capture.certId) !== pki.oids.x509Certificate) { - var error = new Error( - 'Unsupported certificate type, only X.509 supported.'); - error.oid = asn1.derToOid(capture.certId); - throw error; - } - - // true=produce cert hash - var certAsn1 = asn1.fromDer(capture.cert, strict); - try { - bag.cert = pki.certificateFromAsn1(certAsn1, true); - } catch(e) { - // ignore unknown cert type, pass asn1 value - bag.cert = null; - bag.asn1 = certAsn1; - } - }; - break; - - default: - var error = new Error('Unsupported PKCS#12 SafeBag type.'); - error.oid = bag.type; - throw error; - } - - /* Validate SafeBag value (i.e. CertBag, etc.) and capture data if needed. */ - if(validator !== undefined && - !asn1.validate(bagAsn1, validator, capture, errors)) { - var error = new Error('Cannot read PKCS#12 ' + validator.name); - error.errors = errors; - throw error; - } - - /* Call decoder function from above to store the results. */ - decoder(); - } - - return res; - } - - /** - * Decode PKCS#12 SET OF PKCS12Attribute into JavaScript object. - * - * @param attributes SET OF PKCS12Attribute (ASN.1 object). - * - * @return the decoded attributes. - */ - function _decodeBagAttributes(attributes) { - var decodedAttrs = {}; - - if(attributes !== undefined) { - for(var i = 0; i < attributes.length; ++i) { - var capture = {}; - var errors = []; - if(!asn1.validate(attributes[i], attributeValidator, capture, errors)) { - var error = new Error('Cannot read PKCS#12 BagAttribute.'); - error.errors = errors; - throw error; - } - - var oid = asn1.derToOid(capture.oid); - if(pki.oids[oid] === undefined) { - // unsupported attribute type, ignore. - continue; - } - - decodedAttrs[pki.oids[oid]] = []; - for(var j = 0; j < capture.values.length; ++j) { - decodedAttrs[pki.oids[oid]].push(capture.values[j].value); - } - } - } - - return decodedAttrs; - } - - /** - * Wraps a private key and certificate in a PKCS#12 PFX wrapper. If a - * password is provided then the private key will be encrypted. - * - * An entire certificate chain may also be included. To do this, pass - * an array for the "cert" parameter where the first certificate is - * the one that is paired with the private key and each subsequent one - * verifies the previous one. The certificates may be in PEM format or - * have been already parsed by Forge. - * - * @todo implement password-based-encryption for the whole package - * - * @param key the private key. - * @param cert the certificate (may be an array of certificates in order - * to specify a certificate chain). - * @param password the password to use, null for none. - * @param options: - * algorithm the encryption algorithm to use - * ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'. - * count the iteration count to use. - * saltSize the salt size to use. - * useMac true to include a MAC, false not to, defaults to true. - * localKeyId the local key ID to use, in hex. - * friendlyName the friendly name to use. - * generateLocalKeyId true to generate a random local key ID, - * false not to, defaults to true. - * - * @return the PKCS#12 PFX ASN.1 object. - */ - p12.toPkcs12Asn1 = function(key, cert, password, options) { - // set default options - options = options || {}; - options.saltSize = options.saltSize || 8; - options.count = options.count || 2048; - options.algorithm = options.algorithm || options.encAlgorithm || 'aes128'; - if(!('useMac' in options)) { - options.useMac = true; - } - if(!('localKeyId' in options)) { - options.localKeyId = null; - } - if(!('generateLocalKeyId' in options)) { - options.generateLocalKeyId = true; - } - - var localKeyId = options.localKeyId; - var bagAttrs; - if(localKeyId !== null) { - localKeyId = forge.util.hexToBytes(localKeyId); - } else if(options.generateLocalKeyId) { - // use SHA-1 of paired cert, if available - if(cert) { - var pairedCert = forge.util.isArray(cert) ? cert[0] : cert; - if(typeof pairedCert === 'string') { - pairedCert = pki.certificateFromPem(pairedCert); - } - var sha1 = forge.md.sha1.create(); - sha1.update(asn1.toDer(pki.certificateToAsn1(pairedCert)).getBytes()); - localKeyId = sha1.digest().getBytes(); - } else { - // FIXME: consider using SHA-1 of public key (which can be generated - // from private key components), see: cert.generateSubjectKeyIdentifier - // generate random bytes - localKeyId = forge.random.getBytes(20); - } - } - - var attrs = []; - if(localKeyId !== null) { - attrs.push( - // localKeyID - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // attrId - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.localKeyId).getBytes()), - // attrValues - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - localKeyId) - ]) - ])); - } - if('friendlyName' in options) { - attrs.push( - // friendlyName - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // attrId - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.friendlyName).getBytes()), - // attrValues - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BMPSTRING, false, - options.friendlyName) - ]) - ])); - } - - if(attrs.length > 0) { - bagAttrs = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, attrs); - } - - // collect contents for AuthenticatedSafe - var contents = []; - - // create safe bag(s) for certificate chain - var chain = []; - if(cert !== null) { - if(forge.util.isArray(cert)) { - chain = cert; - } else { - chain = [cert]; - } - } - - var certSafeBags = []; - for(var i = 0; i < chain.length; ++i) { - // convert cert from PEM as necessary - cert = chain[i]; - if(typeof cert === 'string') { - cert = pki.certificateFromPem(cert); - } - - // SafeBag - var certBagAttrs = (i === 0) ? bagAttrs : undefined; - var certAsn1 = pki.certificateToAsn1(cert); - var certSafeBag = - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // bagId - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.certBag).getBytes()), - // bagValue - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - // CertBag - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // certId - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.x509Certificate).getBytes()), - // certValue (x509Certificate) - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - asn1.toDer(certAsn1).getBytes()) - ])])]), - // bagAttributes (OPTIONAL) - certBagAttrs - ]); - certSafeBags.push(certSafeBag); - } - - if(certSafeBags.length > 0) { - // SafeContents - var certSafeContents = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, certSafeBags); - - // ContentInfo - var certCI = - // PKCS#7 ContentInfo - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // contentType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - // OID for the content type is 'data' - asn1.oidToDer(pki.oids.data).getBytes()), - // content - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - asn1.toDer(certSafeContents).getBytes()) - ]) - ]); - contents.push(certCI); - } - - // create safe contents for private key - var keyBag = null; - if(key !== null) { - // SafeBag - var pkAsn1 = pki.wrapRsaPrivateKey(pki.privateKeyToAsn1(key)); - if(password === null) { - // no encryption - keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // bagId - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.keyBag).getBytes()), - // bagValue - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - // PrivateKeyInfo - pkAsn1 - ]), - // bagAttributes (OPTIONAL) - bagAttrs - ]); - } else { - // encrypted PrivateKeyInfo - keyBag = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // bagId - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.pkcs8ShroudedKeyBag).getBytes()), - // bagValue - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - // EncryptedPrivateKeyInfo - pki.encryptPrivateKeyInfo(pkAsn1, password, options) - ]), - // bagAttributes (OPTIONAL) - bagAttrs - ]); - } - - // SafeContents - var keySafeContents = - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [keyBag]); - - // ContentInfo - var keyCI = - // PKCS#7 ContentInfo - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // contentType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - // OID for the content type is 'data' - asn1.oidToDer(pki.oids.data).getBytes()), - // content - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - asn1.toDer(keySafeContents).getBytes()) - ]) - ]); - contents.push(keyCI); - } - - // create AuthenticatedSafe by stringing together the contents - var safe = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, contents); - - var macData; - if(options.useMac) { - // MacData - var sha1 = forge.md.sha1.create(); - var macSalt = new forge.util.ByteBuffer( - forge.random.getBytes(options.saltSize)); - var count = options.count; - // 160-bit key - var key = p12.generateKey(password, macSalt, 3, count, 20); - var mac = forge.hmac.create(); - mac.start(sha1, key); - mac.update(asn1.toDer(safe).getBytes()); - var macValue = mac.getMac(); - macData = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // mac DigestInfo - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // digestAlgorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm = SHA-1 - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(pki.oids.sha1).getBytes()), - // parameters = Null - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ]), - // digest - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, - false, macValue.getBytes()) - ]), - // macSalt OCTET STRING - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, macSalt.getBytes()), - // iterations INTEGER (XXX: Only support count < 65536) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(count).getBytes() - ) - ]); - } - - // PFX - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // version (3) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(3).getBytes()), - // PKCS#7 ContentInfo - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // contentType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - // OID for the content type is 'data' - asn1.oidToDer(pki.oids.data).getBytes()), - // content - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - asn1.toDer(safe).getBytes()) - ]) - ]), - macData - ]); - }; - - /** - * Derives a PKCS#12 key. - * - * @param password the password to derive the key material from, null or - * undefined for none. - * @param salt the salt, as a ByteBuffer, to use. - * @param id the PKCS#12 ID byte (1 = key material, 2 = IV, 3 = MAC). - * @param iter the iteration count. - * @param n the number of bytes to derive from the password. - * @param md the message digest to use, defaults to SHA-1. - * - * @return a ByteBuffer with the bytes derived from the password. - */ - p12.generateKey = forge.pbe.generatePkcs12Key; - }); - - var pki_1 = createCommonjsModule(function (module) { - /** - * Javascript implementation of a basic Public Key Infrastructure, including - * support for RSA public and private keys. - * - * @author Dave Longley - * - * Copyright (c) 2010-2013 Digital Bazaar, Inc. - */ - - - - - - - - - - - - - // shortcut for asn.1 API - var asn1 = forge.asn1; - - /* Public Key Infrastructure (PKI) implementation. */ - var pki = module.exports = forge.pki = forge.pki || {}; - - /** - * NOTE: THIS METHOD IS DEPRECATED. Use pem.decode() instead. - * - * Converts PEM-formatted data to DER. - * - * @param pem the PEM-formatted data. - * - * @return the DER-formatted data. - */ - pki.pemToDer = function(pem) { - var msg = forge.pem.decode(pem)[0]; - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error('Could not convert PEM to DER; PEM is encrypted.'); - } - return forge.util.createBuffer(msg.body); - }; - - /** - * Converts an RSA private key from PEM format. - * - * @param pem the PEM-formatted private key. - * - * @return the private key. - */ - pki.privateKeyFromPem = function(pem) { - var msg = forge.pem.decode(pem)[0]; - - if(msg.type !== 'PRIVATE KEY' && msg.type !== 'RSA PRIVATE KEY') { - var error = new Error('Could not convert private key from PEM; PEM ' + - 'header type is not "PRIVATE KEY" or "RSA PRIVATE KEY".'); - error.headerType = msg.type; - throw error; - } - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error('Could not convert private key from PEM; PEM is encrypted.'); - } - - // convert DER to ASN.1 object - var obj = asn1.fromDer(msg.body); - - return pki.privateKeyFromAsn1(obj); - }; - - /** - * Converts an RSA private key to PEM format. - * - * @param key the private key. - * @param maxline the maximum characters per line, defaults to 64. - * - * @return the PEM-formatted private key. - */ - pki.privateKeyToPem = function(key, maxline) { - // convert to ASN.1, then DER, then PEM-encode - var msg = { - type: 'RSA PRIVATE KEY', - body: asn1.toDer(pki.privateKeyToAsn1(key)).getBytes() - }; - return forge.pem.encode(msg, {maxline: maxline}); - }; - - /** - * Converts a PrivateKeyInfo to PEM format. - * - * @param pki the PrivateKeyInfo. - * @param maxline the maximum characters per line, defaults to 64. - * - * @return the PEM-formatted private key. - */ - pki.privateKeyInfoToPem = function(pki, maxline) { - // convert to DER, then PEM-encode - var msg = { - type: 'PRIVATE KEY', - body: asn1.toDer(pki).getBytes() - }; - return forge.pem.encode(msg, {maxline: maxline}); - }; - }); - - /** - * A Javascript implementation of Transport Layer Security (TLS). - * - * @author Dave Longley - * - * Copyright (c) 2009-2014 Digital Bazaar, Inc. - * - * The TLS Handshake Protocol involves the following steps: - * - * - Exchange hello messages to agree on algorithms, exchange random values, - * and check for session resumption. - * - * - Exchange the necessary cryptographic parameters to allow the client and - * server to agree on a premaster secret. - * - * - Exchange certificates and cryptographic information to allow the client - * and server to authenticate themselves. - * - * - Generate a master secret from the premaster secret and exchanged random - * values. - * - * - Provide security parameters to the record layer. - * - * - Allow the client and server to verify that their peer has calculated the - * same security parameters and that the handshake occurred without tampering - * by an attacker. - * - * Up to 4 different messages may be sent during a key exchange. The server - * certificate, the server key exchange, the client certificate, and the - * client key exchange. - * - * A typical handshake (from the client's perspective). - * - * 1. Client sends ClientHello. - * 2. Client receives ServerHello. - * 3. Client receives optional Certificate. - * 4. Client receives optional ServerKeyExchange. - * 5. Client receives ServerHelloDone. - * 6. Client sends optional Certificate. - * 7. Client sends ClientKeyExchange. - * 8. Client sends optional CertificateVerify. - * 9. Client sends ChangeCipherSpec. - * 10. Client sends Finished. - * 11. Client receives ChangeCipherSpec. - * 12. Client receives Finished. - * 13. Client sends/receives application data. - * - * To reuse an existing session: - * - * 1. Client sends ClientHello with session ID for reuse. - * 2. Client receives ServerHello with same session ID if reusing. - * 3. Client receives ChangeCipherSpec message if reusing. - * 4. Client receives Finished. - * 5. Client sends ChangeCipherSpec. - * 6. Client sends Finished. - * - * Note: Client ignores HelloRequest if in the middle of a handshake. - * - * Record Layer: - * - * The record layer fragments information blocks into TLSPlaintext records - * carrying data in chunks of 2^14 bytes or less. Client message boundaries are - * not preserved in the record layer (i.e., multiple client messages of the - * same ContentType MAY be coalesced into a single TLSPlaintext record, or a - * single message MAY be fragmented across several records). - * - * struct { - * uint8 major; - * uint8 minor; - * } ProtocolVersion; - * - * struct { - * ContentType type; - * ProtocolVersion version; - * uint16 length; - * opaque fragment[TLSPlaintext.length]; - * } TLSPlaintext; - * - * type: - * The higher-level protocol used to process the enclosed fragment. - * - * version: - * The version of the protocol being employed. TLS Version 1.2 uses version - * {3, 3}. TLS Version 1.0 uses version {3, 1}. Note that a client that - * supports multiple versions of TLS may not know what version will be - * employed before it receives the ServerHello. - * - * length: - * The length (in bytes) of the following TLSPlaintext.fragment. The length - * MUST NOT exceed 2^14 = 16384 bytes. - * - * fragment: - * The application data. This data is transparent and treated as an - * independent block to be dealt with by the higher-level protocol specified - * by the type field. - * - * Implementations MUST NOT send zero-length fragments of Handshake, Alert, or - * ChangeCipherSpec content types. Zero-length fragments of Application data - * MAY be sent as they are potentially useful as a traffic analysis - * countermeasure. - * - * Note: Data of different TLS record layer content types MAY be interleaved. - * Application data is generally of lower precedence for transmission than - * other content types. However, records MUST be delivered to the network in - * the same order as they are protected by the record layer. Recipients MUST - * receive and process interleaved application layer traffic during handshakes - * subsequent to the first one on a connection. - * - * struct { - * ContentType type; // same as TLSPlaintext.type - * ProtocolVersion version;// same as TLSPlaintext.version - * uint16 length; - * opaque fragment[TLSCompressed.length]; - * } TLSCompressed; - * - * length: - * The length (in bytes) of the following TLSCompressed.fragment. - * The length MUST NOT exceed 2^14 + 1024. - * - * fragment: - * The compressed form of TLSPlaintext.fragment. - * - * Note: A CompressionMethod.null operation is an identity operation; no fields - * are altered. In this implementation, since no compression is supported, - * uncompressed records are always the same as compressed records. - * - * Encryption Information: - * - * The encryption and MAC functions translate a TLSCompressed structure into a - * TLSCiphertext. The decryption functions reverse the process. The MAC of the - * record also includes a sequence number so that missing, extra, or repeated - * messages are detectable. - * - * struct { - * ContentType type; - * ProtocolVersion version; - * uint16 length; - * select (SecurityParameters.cipher_type) { - * case stream: GenericStreamCipher; - * case block: GenericBlockCipher; - * case aead: GenericAEADCipher; - * } fragment; - * } TLSCiphertext; - * - * type: - * The type field is identical to TLSCompressed.type. - * - * version: - * The version field is identical to TLSCompressed.version. - * - * length: - * The length (in bytes) of the following TLSCiphertext.fragment. - * The length MUST NOT exceed 2^14 + 2048. - * - * fragment: - * The encrypted form of TLSCompressed.fragment, with the MAC. - * - * Note: Only CBC Block Ciphers are supported by this implementation. - * - * The TLSCompressed.fragment structures are converted to/from block - * TLSCiphertext.fragment structures. - * - * struct { - * opaque IV[SecurityParameters.record_iv_length]; - * block-ciphered struct { - * opaque content[TLSCompressed.length]; - * opaque MAC[SecurityParameters.mac_length]; - * uint8 padding[GenericBlockCipher.padding_length]; - * uint8 padding_length; - * }; - * } GenericBlockCipher; - * - * The MAC is generated as described in Section 6.2.3.1. - * - * IV: - * The Initialization Vector (IV) SHOULD be chosen at random, and MUST be - * unpredictable. Note that in versions of TLS prior to 1.1, there was no - * IV field, and the last ciphertext block of the previous record (the "CBC - * residue") was used as the IV. This was changed to prevent the attacks - * described in [CBCATT]. For block ciphers, the IV length is of length - * SecurityParameters.record_iv_length, which is equal to the - * SecurityParameters.block_size. - * - * padding: - * Padding that is added to force the length of the plaintext to be an - * integral multiple of the block cipher's block length. The padding MAY be - * any length up to 255 bytes, as long as it results in the - * TLSCiphertext.length being an integral multiple of the block length. - * Lengths longer than necessary might be desirable to frustrate attacks on - * a protocol that are based on analysis of the lengths of exchanged - * messages. Each uint8 in the padding data vector MUST be filled with the - * padding length value. The receiver MUST check this padding and MUST use - * the bad_record_mac alert to indicate padding errors. - * - * padding_length: - * The padding length MUST be such that the total size of the - * GenericBlockCipher structure is a multiple of the cipher's block length. - * Legal values range from zero to 255, inclusive. This length specifies the - * length of the padding field exclusive of the padding_length field itself. - * - * The encrypted data length (TLSCiphertext.length) is one more than the sum of - * SecurityParameters.block_length, TLSCompressed.length, - * SecurityParameters.mac_length, and padding_length. - * - * Example: If the block length is 8 bytes, the content length - * (TLSCompressed.length) is 61 bytes, and the MAC length is 20 bytes, then the - * length before padding is 82 bytes (this does not include the IV. Thus, the - * padding length modulo 8 must be equal to 6 in order to make the total length - * an even multiple of 8 bytes (the block length). The padding length can be - * 6, 14, 22, and so on, through 254. If the padding length were the minimum - * necessary, 6, the padding would be 6 bytes, each containing the value 6. - * Thus, the last 8 octets of the GenericBlockCipher before block encryption - * would be xx 06 06 06 06 06 06 06, where xx is the last octet of the MAC. - * - * Note: With block ciphers in CBC mode (Cipher Block Chaining), it is critical - * that the entire plaintext of the record be known before any ciphertext is - * transmitted. Otherwise, it is possible for the attacker to mount the attack - * described in [CBCATT]. - * - * Implementation note: Canvel et al. [CBCTIME] have demonstrated a timing - * attack on CBC padding based on the time required to compute the MAC. In - * order to defend against this attack, implementations MUST ensure that - * record processing time is essentially the same whether or not the padding - * is correct. In general, the best way to do this is to compute the MAC even - * if the padding is incorrect, and only then reject the packet. For instance, - * if the pad appears to be incorrect, the implementation might assume a - * zero-length pad and then compute the MAC. This leaves a small timing - * channel, since MAC performance depends, to some extent, on the size of the - * data fragment, but it is not believed to be large enough to be exploitable, - * due to the large block size of existing MACs and the small size of the - * timing signal. - */ - - - - - - - - - - - /** - * Generates pseudo random bytes by mixing the result of two hash functions, - * MD5 and SHA-1. - * - * prf_TLS1(secret, label, seed) = - * P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed); - * - * Each P_hash function functions as follows: - * - * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + - * HMAC_hash(secret, A(2) + seed) + - * HMAC_hash(secret, A(3) + seed) + ... - * A() is defined as: - * A(0) = seed - * A(i) = HMAC_hash(secret, A(i-1)) - * - * The '+' operator denotes concatenation. - * - * As many iterations A(N) as are needed are performed to generate enough - * pseudo random byte output. If an iteration creates more data than is - * necessary, then it is truncated. - * - * Therefore: - * A(1) = HMAC_hash(secret, A(0)) - * = HMAC_hash(secret, seed) - * A(2) = HMAC_hash(secret, A(1)) - * = HMAC_hash(secret, HMAC_hash(secret, seed)) - * - * Therefore: - * P_hash(secret, seed) = - * HMAC_hash(secret, HMAC_hash(secret, A(0)) + seed) + - * HMAC_hash(secret, HMAC_hash(secret, A(1)) + seed) + - * ... - * - * Therefore: - * P_hash(secret, seed) = - * HMAC_hash(secret, HMAC_hash(secret, seed) + seed) + - * HMAC_hash(secret, HMAC_hash(secret, HMAC_hash(secret, seed)) + seed) + - * ... - * - * @param secret the secret to use. - * @param label the label to use. - * @param seed the seed value to use. - * @param length the number of bytes to generate. - * - * @return the pseudo random bytes in a byte buffer. - */ - var prf_TLS1 = function(secret, label, seed, length) { - var rval = forge.util.createBuffer(); - - /* For TLS 1.0, the secret is split in half, into two secrets of equal - length. If the secret has an odd length then the last byte of the first - half will be the same as the first byte of the second. The length of the - two secrets is half of the secret rounded up. */ - var idx = (secret.length >> 1); - var slen = idx + (secret.length & 1); - var s1 = secret.substr(0, slen); - var s2 = secret.substr(idx, slen); - var ai = forge.util.createBuffer(); - var hmac = forge.hmac.create(); - seed = label + seed; - - // determine the number of iterations that must be performed to generate - // enough output bytes, md5 creates 16 byte hashes, sha1 creates 20 - var md5itr = Math.ceil(length / 16); - var sha1itr = Math.ceil(length / 20); - - // do md5 iterations - hmac.start('MD5', s1); - var md5bytes = forge.util.createBuffer(); - ai.putBytes(seed); - for(var i = 0; i < md5itr; ++i) { - // HMAC_hash(secret, A(i-1)) - hmac.start(null, null); - hmac.update(ai.getBytes()); - ai.putBuffer(hmac.digest()); - - // HMAC_hash(secret, A(i) + seed) - hmac.start(null, null); - hmac.update(ai.bytes() + seed); - md5bytes.putBuffer(hmac.digest()); - } - - // do sha1 iterations - hmac.start('SHA1', s2); - var sha1bytes = forge.util.createBuffer(); - ai.clear(); - ai.putBytes(seed); - for(var i = 0; i < sha1itr; ++i) { - // HMAC_hash(secret, A(i-1)) - hmac.start(null, null); - hmac.update(ai.getBytes()); - ai.putBuffer(hmac.digest()); - - // HMAC_hash(secret, A(i) + seed) - hmac.start(null, null); - hmac.update(ai.bytes() + seed); - sha1bytes.putBuffer(hmac.digest()); - } - - // XOR the md5 bytes with the sha1 bytes - rval.putBytes(forge.util.xorBytes( - md5bytes.getBytes(), sha1bytes.getBytes(), length)); - - return rval; - }; - - /** - * Gets a MAC for a record using the SHA-1 hash algorithm. - * - * @param key the mac key. - * @param state the sequence number (array of two 32-bit integers). - * @param record the record. - * - * @return the sha-1 hash (20 bytes) for the given record. - */ - var hmac_sha1 = function(key, seqNum, record) { - /* MAC is computed like so: - HMAC_hash( - key, seqNum + - TLSCompressed.type + - TLSCompressed.version + - TLSCompressed.length + - TLSCompressed.fragment) - */ - var hmac = forge.hmac.create(); - hmac.start('SHA1', key); - var b = forge.util.createBuffer(); - b.putInt32(seqNum[0]); - b.putInt32(seqNum[1]); - b.putByte(record.type); - b.putByte(record.version.major); - b.putByte(record.version.minor); - b.putInt16(record.length); - b.putBytes(record.fragment.bytes()); - hmac.update(b.getBytes()); - return hmac.digest().getBytes(); - }; - - /** - * Compresses the TLSPlaintext record into a TLSCompressed record using the - * deflate algorithm. - * - * @param c the TLS connection. - * @param record the TLSPlaintext record to compress. - * @param s the ConnectionState to use. - * - * @return true on success, false on failure. - */ - var deflate = function(c, record, s) { - var rval = false; - - try { - var bytes = c.deflate(record.fragment.getBytes()); - record.fragment = forge.util.createBuffer(bytes); - record.length = bytes.length; - rval = true; - } catch(ex) { - // deflate error, fail out - } - - return rval; - }; - - /** - * Decompresses the TLSCompressed record into a TLSPlaintext record using the - * deflate algorithm. - * - * @param c the TLS connection. - * @param record the TLSCompressed record to decompress. - * @param s the ConnectionState to use. - * - * @return true on success, false on failure. - */ - var inflate = function(c, record, s) { - var rval = false; - - try { - var bytes = c.inflate(record.fragment.getBytes()); - record.fragment = forge.util.createBuffer(bytes); - record.length = bytes.length; - rval = true; - } catch(ex) { - // inflate error, fail out - } - - return rval; - }; - - /** - * Reads a TLS variable-length vector from a byte buffer. - * - * Variable-length vectors are defined by specifying a subrange of legal - * lengths, inclusively, using the notation . When these are - * encoded, the actual length precedes the vector's contents in the byte - * stream. The length will be in the form of a number consuming as many bytes - * as required to hold the vector's specified maximum (ceiling) length. A - * variable-length vector with an actual length field of zero is referred to - * as an empty vector. - * - * @param b the byte buffer. - * @param lenBytes the number of bytes required to store the length. - * - * @return the resulting byte buffer. - */ - var readVector = function(b, lenBytes) { - var len = 0; - switch(lenBytes) { - case 1: - len = b.getByte(); - break; - case 2: - len = b.getInt16(); - break; - case 3: - len = b.getInt24(); - break; - case 4: - len = b.getInt32(); - break; - } - - // read vector bytes into a new buffer - return forge.util.createBuffer(b.getBytes(len)); - }; - - /** - * Writes a TLS variable-length vector to a byte buffer. - * - * @param b the byte buffer. - * @param lenBytes the number of bytes required to store the length. - * @param v the byte buffer vector. - */ - var writeVector = function(b, lenBytes, v) { - // encode length at the start of the vector, where the number of bytes for - // the length is the maximum number of bytes it would take to encode the - // vector's ceiling - b.putInt(v.length(), lenBytes << 3); - b.putBuffer(v); - }; - - /** - * The tls implementation. - */ - var tls = {}; - - /** - * Version: TLS 1.2 = 3.3, TLS 1.1 = 3.2, TLS 1.0 = 3.1. Both TLS 1.1 and - * TLS 1.2 were still too new (ie: openSSL didn't implement them) at the time - * of this implementation so TLS 1.0 was implemented instead. - */ - tls.Versions = { - TLS_1_0: {major: 3, minor: 1}, - TLS_1_1: {major: 3, minor: 2}, - TLS_1_2: {major: 3, minor: 3} - }; - tls.SupportedVersions = [ - tls.Versions.TLS_1_1, - tls.Versions.TLS_1_0 - ]; - tls.Version = tls.SupportedVersions[0]; - - /** - * Maximum fragment size. True maximum is 16384, but we fragment before that - * to allow for unusual small increases during compression. - */ - tls.MaxFragment = 16384 - 1024; - - /** - * Whether this entity is considered the "client" or "server". - * enum { server, client } ConnectionEnd; - */ - tls.ConnectionEnd = { - server: 0, - client: 1 - }; - - /** - * Pseudo-random function algorithm used to generate keys from the master - * secret. - * enum { tls_prf_sha256 } PRFAlgorithm; - */ - tls.PRFAlgorithm = { - tls_prf_sha256: 0 - }; - - /** - * Bulk encryption algorithms. - * enum { null, rc4, des3, aes } BulkCipherAlgorithm; - */ - tls.BulkCipherAlgorithm = { - none: null, - rc4: 0, - des3: 1, - aes: 2 - }; - - /** - * Cipher types. - * enum { stream, block, aead } CipherType; - */ - tls.CipherType = { - stream: 0, - block: 1, - aead: 2 - }; - - /** - * MAC (Message Authentication Code) algorithms. - * enum { null, hmac_md5, hmac_sha1, hmac_sha256, - * hmac_sha384, hmac_sha512} MACAlgorithm; - */ - tls.MACAlgorithm = { - none: null, - hmac_md5: 0, - hmac_sha1: 1, - hmac_sha256: 2, - hmac_sha384: 3, - hmac_sha512: 4 - }; - - /** - * Compression algorithms. - * enum { null(0), deflate(1), (255) } CompressionMethod; - */ - tls.CompressionMethod = { - none: 0, - deflate: 1 - }; - - /** - * TLS record content types. - * enum { - * change_cipher_spec(20), alert(21), handshake(22), - * application_data(23), (255) - * } ContentType; - */ - tls.ContentType = { - change_cipher_spec: 20, - alert: 21, - handshake: 22, - application_data: 23, - heartbeat: 24 - }; - - /** - * TLS handshake types. - * enum { - * hello_request(0), client_hello(1), server_hello(2), - * certificate(11), server_key_exchange (12), - * certificate_request(13), server_hello_done(14), - * certificate_verify(15), client_key_exchange(16), - * finished(20), (255) - * } HandshakeType; - */ - tls.HandshakeType = { - hello_request: 0, - client_hello: 1, - server_hello: 2, - certificate: 11, - server_key_exchange: 12, - certificate_request: 13, - server_hello_done: 14, - certificate_verify: 15, - client_key_exchange: 16, - finished: 20 - }; - - /** - * TLS Alert Protocol. - * - * enum { warning(1), fatal(2), (255) } AlertLevel; - * - * enum { - * close_notify(0), - * unexpected_message(10), - * bad_record_mac(20), - * decryption_failed(21), - * record_overflow(22), - * decompression_failure(30), - * handshake_failure(40), - * bad_certificate(42), - * unsupported_certificate(43), - * certificate_revoked(44), - * certificate_expired(45), - * certificate_unknown(46), - * illegal_parameter(47), - * unknown_ca(48), - * access_denied(49), - * decode_error(50), - * decrypt_error(51), - * export_restriction(60), - * protocol_version(70), - * insufficient_security(71), - * internal_error(80), - * user_canceled(90), - * no_renegotiation(100), - * (255) - * } AlertDescription; - * - * struct { - * AlertLevel level; - * AlertDescription description; - * } Alert; - */ - tls.Alert = {}; - tls.Alert.Level = { - warning: 1, - fatal: 2 - }; - tls.Alert.Description = { - close_notify: 0, - unexpected_message: 10, - bad_record_mac: 20, - decryption_failed: 21, - record_overflow: 22, - decompression_failure: 30, - handshake_failure: 40, - bad_certificate: 42, - unsupported_certificate: 43, - certificate_revoked: 44, - certificate_expired: 45, - certificate_unknown: 46, - illegal_parameter: 47, - unknown_ca: 48, - access_denied: 49, - decode_error: 50, - decrypt_error: 51, - export_restriction: 60, - protocol_version: 70, - insufficient_security: 71, - internal_error: 80, - user_canceled: 90, - no_renegotiation: 100 - }; - - /** - * TLS Heartbeat Message types. - * enum { - * heartbeat_request(1), - * heartbeat_response(2), - * (255) - * } HeartbeatMessageType; - */ - tls.HeartbeatMessageType = { - heartbeat_request: 1, - heartbeat_response: 2 - }; - - /** - * Supported cipher suites. - */ - tls.CipherSuites = {}; - - /** - * Gets a supported cipher suite from its 2 byte ID. - * - * @param twoBytes two bytes in a string. - * - * @return the matching supported cipher suite or null. - */ - tls.getCipherSuite = function(twoBytes) { - var rval = null; - for(var key in tls.CipherSuites) { - var cs = tls.CipherSuites[key]; - if(cs.id[0] === twoBytes.charCodeAt(0) && - cs.id[1] === twoBytes.charCodeAt(1)) { - rval = cs; - break; - } - } - return rval; - }; - - /** - * Called when an unexpected record is encountered. - * - * @param c the connection. - * @param record the record. - */ - tls.handleUnexpected = function(c, record) { - // if connection is client and closed, ignore unexpected messages - var ignore = (!c.open && c.entity === tls.ConnectionEnd.client); - if(!ignore) { - c.error(c, { - message: 'Unexpected message. Received TLS record out of order.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.unexpected_message - } - }); - } - }; - - /** - * Called when a client receives a HelloRequest record. - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleHelloRequest = function(c, record, length) { - // ignore renegotiation requests from the server during a handshake, but - // if handshaking, send a warning alert that renegotation is denied - if(!c.handshaking && c.handshakes > 0) { - // send alert warning - tls.queue(c, tls.createAlert(c, { - level: tls.Alert.Level.warning, - description: tls.Alert.Description.no_renegotiation - })); - tls.flush(c); - } - - // continue - c.process(); - }; - - /** - * Parses a hello message from a ClientHello or ServerHello record. - * - * @param record the record to parse. - * - * @return the parsed message. - */ - tls.parseHelloMessage = function(c, record, length) { - var msg = null; - - var client = (c.entity === tls.ConnectionEnd.client); - - // minimum of 38 bytes in message - if(length < 38) { - c.error(c, { - message: client ? - 'Invalid ServerHello message. Message too short.' : - 'Invalid ClientHello message. Message too short.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.illegal_parameter - } - }); - } else { - // use 'remaining' to calculate # of remaining bytes in the message - var b = record.fragment; - var remaining = b.length(); - msg = { - version: { - major: b.getByte(), - minor: b.getByte() - }, - random: forge.util.createBuffer(b.getBytes(32)), - session_id: readVector(b, 1), - extensions: [] - }; - if(client) { - msg.cipher_suite = b.getBytes(2); - msg.compression_method = b.getByte(); - } else { - msg.cipher_suites = readVector(b, 2); - msg.compression_methods = readVector(b, 1); - } - - // read extensions if there are any bytes left in the message - remaining = length - (remaining - b.length()); - if(remaining > 0) { - // parse extensions - var exts = readVector(b, 2); - while(exts.length() > 0) { - msg.extensions.push({ - type: [exts.getByte(), exts.getByte()], - data: readVector(exts, 2) - }); - } - - // TODO: make extension support modular - if(!client) { - for(var i = 0; i < msg.extensions.length; ++i) { - var ext = msg.extensions[i]; - - // support SNI extension - if(ext.type[0] === 0x00 && ext.type[1] === 0x00) { - // get server name list - var snl = readVector(ext.data, 2); - while(snl.length() > 0) { - // read server name type - var snType = snl.getByte(); - - // only HostName type (0x00) is known, break out if - // another type is detected - if(snType !== 0x00) { - break; - } - - // add host name to server name list - c.session.extensions.server_name.serverNameList.push( - readVector(snl, 2).getBytes()); - } - } - } - } - } - - // version already set, do not allow version change - if(c.session.version) { - if(msg.version.major !== c.session.version.major || - msg.version.minor !== c.session.version.minor) { - return c.error(c, { - message: 'TLS version change is disallowed during renegotiation.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.protocol_version - } - }); - } - } - - // get the chosen (ServerHello) cipher suite - if(client) { - // FIXME: should be checking configured acceptable cipher suites - c.session.cipherSuite = tls.getCipherSuite(msg.cipher_suite); - } else { - // get a supported preferred (ClientHello) cipher suite - // choose the first supported cipher suite - var tmp = forge.util.createBuffer(msg.cipher_suites.bytes()); - while(tmp.length() > 0) { - // FIXME: should be checking configured acceptable suites - // cipher suites take up 2 bytes - c.session.cipherSuite = tls.getCipherSuite(tmp.getBytes(2)); - if(c.session.cipherSuite !== null) { - break; - } - } - } - - // cipher suite not supported - if(c.session.cipherSuite === null) { - return c.error(c, { - message: 'No cipher suites in common.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.handshake_failure - }, - cipherSuite: forge.util.bytesToHex(msg.cipher_suite) - }); - } - - // TODO: handle compression methods - if(client) { - c.session.compressionMethod = msg.compression_method; - } else { - // no compression - c.session.compressionMethod = tls.CompressionMethod.none; - } - } - - return msg; - }; - - /** - * Creates security parameters for the given connection based on the given - * hello message. - * - * @param c the TLS connection. - * @param msg the hello message. - */ - tls.createSecurityParameters = function(c, msg) { - /* Note: security params are from TLS 1.2, some values like prf_algorithm - are ignored for TLS 1.0/1.1 and the builtin as specified in the spec is - used. */ - - // TODO: handle other options from server when more supported - - // get client and server randoms - var client = (c.entity === tls.ConnectionEnd.client); - var msgRandom = msg.random.bytes(); - var cRandom = client ? c.session.sp.client_random : msgRandom; - var sRandom = client ? msgRandom : tls.createRandom().getBytes(); - - // create new security parameters - c.session.sp = { - entity: c.entity, - prf_algorithm: tls.PRFAlgorithm.tls_prf_sha256, - bulk_cipher_algorithm: null, - cipher_type: null, - enc_key_length: null, - block_length: null, - fixed_iv_length: null, - record_iv_length: null, - mac_algorithm: null, - mac_length: null, - mac_key_length: null, - compression_algorithm: c.session.compressionMethod, - pre_master_secret: null, - master_secret: null, - client_random: cRandom, - server_random: sRandom - }; - }; - - /** - * Called when a client receives a ServerHello record. - * - * When a ServerHello message will be sent: - * The server will send this message in response to a client hello message - * when it was able to find an acceptable set of algorithms. If it cannot - * find such a match, it will respond with a handshake failure alert. - * - * uint24 length; - * struct { - * ProtocolVersion server_version; - * Random random; - * SessionID session_id; - * CipherSuite cipher_suite; - * CompressionMethod compression_method; - * select(extensions_present) { - * case false: - * struct {}; - * case true: - * Extension extensions<0..2^16-1>; - * }; - * } ServerHello; - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleServerHello = function(c, record, length) { - var msg = tls.parseHelloMessage(c, record, length); - if(c.fail) { - return; - } - - // ensure server version is compatible - if(msg.version.minor <= c.version.minor) { - c.version.minor = msg.version.minor; - } else { - return c.error(c, { - message: 'Incompatible TLS version.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.protocol_version - } - }); - } - - // indicate session version has been set - c.session.version = c.version; - - // get the session ID from the message - var sessionId = msg.session_id.bytes(); - - // if the session ID is not blank and matches the cached one, resume - // the session - if(sessionId.length > 0 && sessionId === c.session.id) { - // resuming session, expect a ChangeCipherSpec next - c.expect = SCC; - c.session.resuming = true; - - // get new server random - c.session.sp.server_random = msg.random.bytes(); - } else { - // not resuming, expect a server Certificate message next - c.expect = SCE; - c.session.resuming = false; - - // create new security parameters - tls.createSecurityParameters(c, msg); - } - - // set new session ID - c.session.id = sessionId; - - // continue - c.process(); - }; - - /** - * Called when a server receives a ClientHello record. - * - * When a ClientHello message will be sent: - * When a client first connects to a server it is required to send the - * client hello as its first message. The client can also send a client - * hello in response to a hello request or on its own initiative in order - * to renegotiate the security parameters in an existing connection. - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleClientHello = function(c, record, length) { - var msg = tls.parseHelloMessage(c, record, length); - if(c.fail) { - return; - } - - // get the session ID from the message - var sessionId = msg.session_id.bytes(); - - // see if the given session ID is in the cache - var session = null; - if(c.sessionCache) { - session = c.sessionCache.getSession(sessionId); - if(session === null) { - // session ID not found - sessionId = ''; - } else if(session.version.major !== msg.version.major || - session.version.minor > msg.version.minor) { - // if session version is incompatible with client version, do not resume - session = null; - sessionId = ''; - } - } - - // no session found to resume, generate a new session ID - if(sessionId.length === 0) { - sessionId = forge.random.getBytes(32); - } - - // update session - c.session.id = sessionId; - c.session.clientHelloVersion = msg.version; - c.session.sp = {}; - if(session) { - // use version and security parameters from resumed session - c.version = c.session.version = session.version; - c.session.sp = session.sp; - } else { - // use highest compatible minor version - var version; - for(var i = 1; i < tls.SupportedVersions.length; ++i) { - version = tls.SupportedVersions[i]; - if(version.minor <= msg.version.minor) { - break; - } - } - c.version = {major: version.major, minor: version.minor}; - c.session.version = c.version; - } - - // if a session is set, resume it - if(session !== null) { - // resuming session, expect a ChangeCipherSpec next - c.expect = CCC; - c.session.resuming = true; - - // get new client random - c.session.sp.client_random = msg.random.bytes(); - } else { - // not resuming, expect a Certificate or ClientKeyExchange - c.expect = (c.verifyClient !== false) ? CCE : CKE; - c.session.resuming = false; - - // create new security parameters - tls.createSecurityParameters(c, msg); - } - - // connection now open - c.open = true; - - // queue server hello - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createServerHello(c) - })); - - if(c.session.resuming) { - // queue change cipher spec message - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.change_cipher_spec, - data: tls.createChangeCipherSpec() - })); - - // create pending state - c.state.pending = tls.createConnectionState(c); - - // change current write state to pending write state - c.state.current.write = c.state.pending.write; - - // queue finished - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createFinished(c) - })); - } else { - // queue server certificate - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createCertificate(c) - })); - - if(!c.fail) { - // queue server key exchange - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createServerKeyExchange(c) - })); - - // request client certificate if set - if(c.verifyClient !== false) { - // queue certificate request - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createCertificateRequest(c) - })); - } - - // queue server hello done - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createServerHelloDone(c) - })); - } - } - - // send records - tls.flush(c); - - // continue - c.process(); - }; - - /** - * Called when a client receives a Certificate record. - * - * When this message will be sent: - * The server must send a certificate whenever the agreed-upon key exchange - * method is not an anonymous one. This message will always immediately - * follow the server hello message. - * - * Meaning of this message: - * The certificate type must be appropriate for the selected cipher suite's - * key exchange algorithm, and is generally an X.509v3 certificate. It must - * contain a key which matches the key exchange method, as follows. Unless - * otherwise specified, the signing algorithm for the certificate must be - * the same as the algorithm for the certificate key. Unless otherwise - * specified, the public key may be of any length. - * - * opaque ASN.1Cert<1..2^24-1>; - * struct { - * ASN.1Cert certificate_list<1..2^24-1>; - * } Certificate; - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleCertificate = function(c, record, length) { - // minimum of 3 bytes in message - if(length < 3) { - return c.error(c, { - message: 'Invalid Certificate message. Message too short.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.illegal_parameter - } - }); - } - - var b = record.fragment; - var msg = { - certificate_list: readVector(b, 3) - }; - - /* The sender's certificate will be first in the list (chain), each - subsequent one that follows will certify the previous one, but root - certificates (self-signed) that specify the certificate authority may - be omitted under the assumption that clients must already possess it. */ - var cert, asn1; - var certs = []; - try { - while(msg.certificate_list.length() > 0) { - // each entry in msg.certificate_list is a vector with 3 len bytes - cert = readVector(msg.certificate_list, 3); - asn1 = forge.asn1.fromDer(cert); - cert = forge.pki.certificateFromAsn1(asn1, true); - certs.push(cert); - } - } catch(ex) { - return c.error(c, { - message: 'Could not parse certificate list.', - cause: ex, - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.bad_certificate - } - }); - } - - // ensure at least 1 certificate was provided if in client-mode - // or if verifyClient was set to true to require a certificate - // (as opposed to 'optional') - var client = (c.entity === tls.ConnectionEnd.client); - if((client || c.verifyClient === true) && certs.length === 0) { - // error, no certificate - c.error(c, { - message: client ? - 'No server certificate provided.' : - 'No client certificate provided.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.illegal_parameter - } - }); - } else if(certs.length === 0) { - // no certs to verify - // expect a ServerKeyExchange or ClientKeyExchange message next - c.expect = client ? SKE : CKE; - } else { - // save certificate in session - if(client) { - c.session.serverCertificate = certs[0]; - } else { - c.session.clientCertificate = certs[0]; - } - - if(tls.verifyCertificateChain(c, certs)) { - // expect a ServerKeyExchange or ClientKeyExchange message next - c.expect = client ? SKE : CKE; - } - } - - // continue - c.process(); - }; - - /** - * Called when a client receives a ServerKeyExchange record. - * - * When this message will be sent: - * This message will be sent immediately after the server certificate - * message (or the server hello message, if this is an anonymous - * negotiation). - * - * The server key exchange message is sent by the server only when the - * server certificate message (if sent) does not contain enough data to - * allow the client to exchange a premaster secret. - * - * Meaning of this message: - * This message conveys cryptographic information to allow the client to - * communicate the premaster secret: either an RSA public key to encrypt - * the premaster secret with, or a Diffie-Hellman public key with which the - * client can complete a key exchange (with the result being the premaster - * secret.) - * - * enum { - * dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa - * } KeyExchangeAlgorithm; - * - * struct { - * opaque dh_p<1..2^16-1>; - * opaque dh_g<1..2^16-1>; - * opaque dh_Ys<1..2^16-1>; - * } ServerDHParams; - * - * struct { - * select(KeyExchangeAlgorithm) { - * case dh_anon: - * ServerDHParams params; - * case dhe_dss: - * case dhe_rsa: - * ServerDHParams params; - * digitally-signed struct { - * opaque client_random[32]; - * opaque server_random[32]; - * ServerDHParams params; - * } signed_params; - * case rsa: - * case dh_dss: - * case dh_rsa: - * struct {}; - * }; - * } ServerKeyExchange; - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleServerKeyExchange = function(c, record, length) { - // this implementation only supports RSA, no Diffie-Hellman support - // so any length > 0 is invalid - if(length > 0) { - return c.error(c, { - message: 'Invalid key parameters. Only RSA is supported.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.unsupported_certificate - } - }); - } - - // expect an optional CertificateRequest message next - c.expect = SCR; - - // continue - c.process(); - }; - - /** - * Called when a client receives a ClientKeyExchange record. - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleClientKeyExchange = function(c, record, length) { - // this implementation only supports RSA, no Diffie-Hellman support - // so any length < 48 is invalid - if(length < 48) { - return c.error(c, { - message: 'Invalid key parameters. Only RSA is supported.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.unsupported_certificate - } - }); - } - - var b = record.fragment; - var msg = { - enc_pre_master_secret: readVector(b, 2).getBytes() - }; - - // do rsa decryption - var privateKey = null; - if(c.getPrivateKey) { - try { - privateKey = c.getPrivateKey(c, c.session.serverCertificate); - privateKey = forge.pki.privateKeyFromPem(privateKey); - } catch(ex) { - c.error(c, { - message: 'Could not get private key.', - cause: ex, - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.internal_error - } - }); - } - } - - if(privateKey === null) { - return c.error(c, { - message: 'No private key set.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.internal_error - } - }); - } - - try { - // decrypt 48-byte pre-master secret - var sp = c.session.sp; - sp.pre_master_secret = privateKey.decrypt(msg.enc_pre_master_secret); - - // ensure client hello version matches first 2 bytes - var version = c.session.clientHelloVersion; - if(version.major !== sp.pre_master_secret.charCodeAt(0) || - version.minor !== sp.pre_master_secret.charCodeAt(1)) { - // error, do not send alert (see BLEI attack below) - throw new Error('TLS version rollback attack detected.'); - } - } catch(ex) { - /* Note: Daniel Bleichenbacher [BLEI] can be used to attack a - TLS server which is using PKCS#1 encoded RSA, so instead of - failing here, we generate 48 random bytes and use that as - the pre-master secret. */ - sp.pre_master_secret = forge.random.getBytes(48); - } - - // expect a CertificateVerify message if a Certificate was received that - // does not have fixed Diffie-Hellman params, otherwise expect - // ChangeCipherSpec - c.expect = CCC; - if(c.session.clientCertificate !== null) { - // only RSA support, so expect CertificateVerify - // TODO: support Diffie-Hellman - c.expect = CCV; - } - - // continue - c.process(); - }; - - /** - * Called when a client receives a CertificateRequest record. - * - * When this message will be sent: - * A non-anonymous server can optionally request a certificate from the - * client, if appropriate for the selected cipher suite. This message, if - * sent, will immediately follow the Server Key Exchange message (if it is - * sent; otherwise, the Server Certificate message). - * - * enum { - * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), - * rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6), - * fortezza_dms_RESERVED(20), (255) - * } ClientCertificateType; - * - * opaque DistinguishedName<1..2^16-1>; - * - * struct { - * ClientCertificateType certificate_types<1..2^8-1>; - * SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>; - * DistinguishedName certificate_authorities<0..2^16-1>; - * } CertificateRequest; - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleCertificateRequest = function(c, record, length) { - // minimum of 3 bytes in message - if(length < 3) { - return c.error(c, { - message: 'Invalid CertificateRequest. Message too short.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.illegal_parameter - } - }); - } - - // TODO: TLS 1.2+ has different format including - // SignatureAndHashAlgorithm after cert types - var b = record.fragment; - var msg = { - certificate_types: readVector(b, 1), - certificate_authorities: readVector(b, 2) - }; - - // save certificate request in session - c.session.certificateRequest = msg; - - // expect a ServerHelloDone message next - c.expect = SHD; - - // continue - c.process(); - }; - - /** - * Called when a server receives a CertificateVerify record. - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleCertificateVerify = function(c, record, length) { - if(length < 2) { - return c.error(c, { - message: 'Invalid CertificateVerify. Message too short.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.illegal_parameter - } - }); - } - - // rewind to get full bytes for message so it can be manually - // digested below (special case for CertificateVerify messages because - // they must be digested *after* handling as opposed to all others) - var b = record.fragment; - b.read -= 4; - var msgBytes = b.bytes(); - b.read += 4; - - var msg = { - signature: readVector(b, 2).getBytes() - }; - - // TODO: add support for DSA - - // generate data to verify - var verify = forge.util.createBuffer(); - verify.putBuffer(c.session.md5.digest()); - verify.putBuffer(c.session.sha1.digest()); - verify = verify.getBytes(); - - try { - var cert = c.session.clientCertificate; - /*b = forge.pki.rsa.decrypt( - msg.signature, cert.publicKey, true, verify.length); - if(b !== verify) {*/ - if(!cert.publicKey.verify(verify, msg.signature, 'NONE')) { - throw new Error('CertificateVerify signature does not match.'); - } - - // digest message now that it has been handled - c.session.md5.update(msgBytes); - c.session.sha1.update(msgBytes); - } catch(ex) { - return c.error(c, { - message: 'Bad signature in CertificateVerify.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.handshake_failure - } - }); - } - - // expect ChangeCipherSpec - c.expect = CCC; - - // continue - c.process(); - }; - - /** - * Called when a client receives a ServerHelloDone record. - * - * When this message will be sent: - * The server hello done message is sent by the server to indicate the end - * of the server hello and associated messages. After sending this message - * the server will wait for a client response. - * - * Meaning of this message: - * This message means that the server is done sending messages to support - * the key exchange, and the client can proceed with its phase of the key - * exchange. - * - * Upon receipt of the server hello done message the client should verify - * that the server provided a valid certificate if required and check that - * the server hello parameters are acceptable. - * - * struct {} ServerHelloDone; - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleServerHelloDone = function(c, record, length) { - // len must be 0 bytes - if(length > 0) { - return c.error(c, { - message: 'Invalid ServerHelloDone message. Invalid length.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.record_overflow - } - }); - } - - if(c.serverCertificate === null) { - // no server certificate was provided - var error = { - message: 'No server certificate provided. Not enough security.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.insufficient_security - } - }; - - // call application callback - var depth = 0; - var ret = c.verify(c, error.alert.description, depth, []); - if(ret !== true) { - // check for custom alert info - if(ret || ret === 0) { - // set custom message and alert description - if(typeof ret === 'object' && !forge.util.isArray(ret)) { - if(ret.message) { - error.message = ret.message; - } - if(ret.alert) { - error.alert.description = ret.alert; - } - } else if(typeof ret === 'number') { - // set custom alert description - error.alert.description = ret; - } - } - - // send error - return c.error(c, error); - } - } - - // create client certificate message if requested - if(c.session.certificateRequest !== null) { - record = tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createCertificate(c) - }); - tls.queue(c, record); - } - - // create client key exchange message - record = tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createClientKeyExchange(c) - }); - tls.queue(c, record); - - // expect no messages until the following callback has been called - c.expect = SER; - - // create callback to handle client signature (for client-certs) - var callback = function(c, signature) { - if(c.session.certificateRequest !== null && - c.session.clientCertificate !== null) { - // create certificate verify message - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createCertificateVerify(c, signature) - })); - } - - // create change cipher spec message - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.change_cipher_spec, - data: tls.createChangeCipherSpec() - })); - - // create pending state - c.state.pending = tls.createConnectionState(c); - - // change current write state to pending write state - c.state.current.write = c.state.pending.write; - - // create finished message - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createFinished(c) - })); - - // expect a server ChangeCipherSpec message next - c.expect = SCC; - - // send records - tls.flush(c); - - // continue - c.process(); - }; - - // if there is no certificate request or no client certificate, do - // callback immediately - if(c.session.certificateRequest === null || - c.session.clientCertificate === null) { - return callback(c, null); - } - - // otherwise get the client signature - tls.getClientSignature(c, callback); - }; - - /** - * Called when a ChangeCipherSpec record is received. - * - * @param c the connection. - * @param record the record. - */ - tls.handleChangeCipherSpec = function(c, record) { - if(record.fragment.getByte() !== 0x01) { - return c.error(c, { - message: 'Invalid ChangeCipherSpec message received.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.illegal_parameter - } - }); - } - - // create pending state if: - // 1. Resuming session in client mode OR - // 2. NOT resuming session in server mode - var client = (c.entity === tls.ConnectionEnd.client); - if((c.session.resuming && client) || (!c.session.resuming && !client)) { - c.state.pending = tls.createConnectionState(c); - } - - // change current read state to pending read state - c.state.current.read = c.state.pending.read; - - // clear pending state if: - // 1. NOT resuming session in client mode OR - // 2. resuming a session in server mode - if((!c.session.resuming && client) || (c.session.resuming && !client)) { - c.state.pending = null; - } - - // expect a Finished record next - c.expect = client ? SFI : CFI; - - // continue - c.process(); - }; - - /** - * Called when a Finished record is received. - * - * When this message will be sent: - * A finished message is always sent immediately after a change - * cipher spec message to verify that the key exchange and - * authentication processes were successful. It is essential that a - * change cipher spec message be received between the other - * handshake messages and the Finished message. - * - * Meaning of this message: - * The finished message is the first protected with the just- - * negotiated algorithms, keys, and secrets. Recipients of finished - * messages must verify that the contents are correct. Once a side - * has sent its Finished message and received and validated the - * Finished message from its peer, it may begin to send and receive - * application data over the connection. - * - * struct { - * opaque verify_data[verify_data_length]; - * } Finished; - * - * verify_data - * PRF(master_secret, finished_label, Hash(handshake_messages)) - * [0..verify_data_length-1]; - * - * finished_label - * For Finished messages sent by the client, the string - * "client finished". For Finished messages sent by the server, the - * string "server finished". - * - * verify_data_length depends on the cipher suite. If it is not specified - * by the cipher suite, then it is 12. Versions of TLS < 1.2 always used - * 12 bytes. - * - * @param c the connection. - * @param record the record. - * @param length the length of the handshake message. - */ - tls.handleFinished = function(c, record, length) { - // rewind to get full bytes for message so it can be manually - // digested below (special case for Finished messages because they - // must be digested *after* handling as opposed to all others) - var b = record.fragment; - b.read -= 4; - var msgBytes = b.bytes(); - b.read += 4; - - // message contains only verify_data - var vd = record.fragment.getBytes(); - - // ensure verify data is correct - b = forge.util.createBuffer(); - b.putBuffer(c.session.md5.digest()); - b.putBuffer(c.session.sha1.digest()); - - // set label based on entity type - var client = (c.entity === tls.ConnectionEnd.client); - var label = client ? 'server finished' : 'client finished'; - - // TODO: determine prf function and verify length for TLS 1.2 - var sp = c.session.sp; - var vdl = 12; - var prf = prf_TLS1; - b = prf(sp.master_secret, label, b.getBytes(), vdl); - if(b.getBytes() !== vd) { - return c.error(c, { - message: 'Invalid verify_data in Finished message.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.decrypt_error - } - }); - } - - // digest finished message now that it has been handled - c.session.md5.update(msgBytes); - c.session.sha1.update(msgBytes); - - // resuming session as client or NOT resuming session as server - if((c.session.resuming && client) || (!c.session.resuming && !client)) { - // create change cipher spec message - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.change_cipher_spec, - data: tls.createChangeCipherSpec() - })); - - // change current write state to pending write state, clear pending - c.state.current.write = c.state.pending.write; - c.state.pending = null; - - // create finished message - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createFinished(c) - })); - } - - // expect application data next - c.expect = client ? SAD : CAD; - - // handshake complete - c.handshaking = false; - ++c.handshakes; - - // save access to peer certificate - c.peerCertificate = client ? - c.session.serverCertificate : c.session.clientCertificate; - - // send records - tls.flush(c); - - // now connected - c.isConnected = true; - c.connected(c); - - // continue - c.process(); - }; - - /** - * Called when an Alert record is received. - * - * @param c the connection. - * @param record the record. - */ - tls.handleAlert = function(c, record) { - // read alert - var b = record.fragment; - var alert = { - level: b.getByte(), - description: b.getByte() - }; - - // TODO: consider using a table? - // get appropriate message - var msg; - switch(alert.description) { - case tls.Alert.Description.close_notify: - msg = 'Connection closed.'; - break; - case tls.Alert.Description.unexpected_message: - msg = 'Unexpected message.'; - break; - case tls.Alert.Description.bad_record_mac: - msg = 'Bad record MAC.'; - break; - case tls.Alert.Description.decryption_failed: - msg = 'Decryption failed.'; - break; - case tls.Alert.Description.record_overflow: - msg = 'Record overflow.'; - break; - case tls.Alert.Description.decompression_failure: - msg = 'Decompression failed.'; - break; - case tls.Alert.Description.handshake_failure: - msg = 'Handshake failure.'; - break; - case tls.Alert.Description.bad_certificate: - msg = 'Bad certificate.'; - break; - case tls.Alert.Description.unsupported_certificate: - msg = 'Unsupported certificate.'; - break; - case tls.Alert.Description.certificate_revoked: - msg = 'Certificate revoked.'; - break; - case tls.Alert.Description.certificate_expired: - msg = 'Certificate expired.'; - break; - case tls.Alert.Description.certificate_unknown: - msg = 'Certificate unknown.'; - break; - case tls.Alert.Description.illegal_parameter: - msg = 'Illegal parameter.'; - break; - case tls.Alert.Description.unknown_ca: - msg = 'Unknown certificate authority.'; - break; - case tls.Alert.Description.access_denied: - msg = 'Access denied.'; - break; - case tls.Alert.Description.decode_error: - msg = 'Decode error.'; - break; - case tls.Alert.Description.decrypt_error: - msg = 'Decrypt error.'; - break; - case tls.Alert.Description.export_restriction: - msg = 'Export restriction.'; - break; - case tls.Alert.Description.protocol_version: - msg = 'Unsupported protocol version.'; - break; - case tls.Alert.Description.insufficient_security: - msg = 'Insufficient security.'; - break; - case tls.Alert.Description.internal_error: - msg = 'Internal error.'; - break; - case tls.Alert.Description.user_canceled: - msg = 'User canceled.'; - break; - case tls.Alert.Description.no_renegotiation: - msg = 'Renegotiation not supported.'; - break; - default: - msg = 'Unknown error.'; - break; - } - - // close connection on close_notify, not an error - if(alert.description === tls.Alert.Description.close_notify) { - return c.close(); - } - - // call error handler - c.error(c, { - message: msg, - send: false, - // origin is the opposite end - origin: (c.entity === tls.ConnectionEnd.client) ? 'server' : 'client', - alert: alert - }); - - // continue - c.process(); - }; - - /** - * Called when a Handshake record is received. - * - * @param c the connection. - * @param record the record. - */ - tls.handleHandshake = function(c, record) { - // get the handshake type and message length - var b = record.fragment; - var type = b.getByte(); - var length = b.getInt24(); - - // see if the record fragment doesn't yet contain the full message - if(length > b.length()) { - // cache the record, clear its fragment, and reset the buffer read - // pointer before the type and length were read - c.fragmented = record; - record.fragment = forge.util.createBuffer(); - b.read -= 4; - - // continue - return c.process(); - } - - // full message now available, clear cache, reset read pointer to - // before type and length - c.fragmented = null; - b.read -= 4; - - // save the handshake bytes for digestion after handler is found - // (include type and length of handshake msg) - var bytes = b.bytes(length + 4); - - // restore read pointer - b.read += 4; - - // handle expected message - if(type in hsTable[c.entity][c.expect]) { - // initialize server session - if(c.entity === tls.ConnectionEnd.server && !c.open && !c.fail) { - c.handshaking = true; - c.session = { - version: null, - extensions: { - server_name: { - serverNameList: [] - } - }, - cipherSuite: null, - compressionMethod: null, - serverCertificate: null, - clientCertificate: null, - md5: forge.md.md5.create(), - sha1: forge.md.sha1.create() - }; - } - - /* Update handshake messages digest. Finished and CertificateVerify - messages are not digested here. They can't be digested as part of - the verify_data that they contain. These messages are manually - digested in their handlers. HelloRequest messages are simply never - included in the handshake message digest according to spec. */ - if(type !== tls.HandshakeType.hello_request && - type !== tls.HandshakeType.certificate_verify && - type !== tls.HandshakeType.finished) { - c.session.md5.update(bytes); - c.session.sha1.update(bytes); - } - - // handle specific handshake type record - hsTable[c.entity][c.expect][type](c, record, length); - } else { - // unexpected record - tls.handleUnexpected(c, record); - } - }; - - /** - * Called when an ApplicationData record is received. - * - * @param c the connection. - * @param record the record. - */ - tls.handleApplicationData = function(c, record) { - // buffer data, notify that its ready - c.data.putBuffer(record.fragment); - c.dataReady(c); - - // continue - c.process(); - }; - - /** - * Called when a Heartbeat record is received. - * - * @param c the connection. - * @param record the record. - */ - tls.handleHeartbeat = function(c, record) { - // get the heartbeat type and payload - var b = record.fragment; - var type = b.getByte(); - var length = b.getInt16(); - var payload = b.getBytes(length); - - if(type === tls.HeartbeatMessageType.heartbeat_request) { - // discard request during handshake or if length is too large - if(c.handshaking || length > payload.length) { - // continue - return c.process(); - } - // retransmit payload - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.heartbeat, - data: tls.createHeartbeat( - tls.HeartbeatMessageType.heartbeat_response, payload) - })); - tls.flush(c); - } else if(type === tls.HeartbeatMessageType.heartbeat_response) { - // check payload against expected payload, discard heartbeat if no match - if(payload !== c.expectedHeartbeatPayload) { - // continue - return c.process(); - } - - // notify that a valid heartbeat was received - if(c.heartbeatReceived) { - c.heartbeatReceived(c, forge.util.createBuffer(payload)); - } - } - - // continue - c.process(); - }; - - /** - * The transistional state tables for receiving TLS records. It maps the - * current TLS engine state and a received record to a function to handle the - * record and update the state. - * - * For instance, if the current state is SHE, then the TLS engine is expecting - * a ServerHello record. Once a record is received, the handler function is - * looked up using the state SHE and the record's content type. - * - * The resulting function will either be an error handler or a record handler. - * The function will take whatever action is appropriate and update the state - * for the next record. - * - * The states are all based on possible server record types. Note that the - * client will never specifically expect to receive a HelloRequest or an alert - * from the server so there is no state that reflects this. These messages may - * occur at any time. - * - * There are two tables for mapping states because there is a second tier of - * types for handshake messages. Once a record with a content type of handshake - * is received, the handshake record handler will look up the handshake type in - * the secondary map to get its appropriate handler. - * - * Valid message orders are as follows: - * - * =======================FULL HANDSHAKE====================== - * Client Server - * - * ClientHello --------> - * ServerHello - * Certificate* - * ServerKeyExchange* - * CertificateRequest* - * <-------- ServerHelloDone - * Certificate* - * ClientKeyExchange - * CertificateVerify* - * [ChangeCipherSpec] - * Finished --------> - * [ChangeCipherSpec] - * <-------- Finished - * Application Data <-------> Application Data - * - * =====================SESSION RESUMPTION===================== - * Client Server - * - * ClientHello --------> - * ServerHello - * [ChangeCipherSpec] - * <-------- Finished - * [ChangeCipherSpec] - * Finished --------> - * Application Data <-------> Application Data - */ - // client expect states (indicate which records are expected to be received) - var SHE = 0; // rcv server hello - var SCE = 1; // rcv server certificate - var SKE = 2; // rcv server key exchange - var SCR = 3; // rcv certificate request - var SHD = 4; // rcv server hello done - var SCC = 5; // rcv change cipher spec - var SFI = 6; // rcv finished - var SAD = 7; // rcv application data - var SER = 8; // not expecting any messages at this point - - // server expect states - var CHE = 0; // rcv client hello - var CCE = 1; // rcv client certificate - var CKE = 2; // rcv client key exchange - var CCV = 3; // rcv certificate verify - var CCC = 4; // rcv change cipher spec - var CFI = 5; // rcv finished - var CAD = 6; // rcv application data - - // map client current expect state and content type to function - var __ = tls.handleUnexpected; - var R0 = tls.handleChangeCipherSpec; - var R1 = tls.handleAlert; - var R2 = tls.handleHandshake; - var R3 = tls.handleApplicationData; - var R4 = tls.handleHeartbeat; - var ctTable = []; - ctTable[tls.ConnectionEnd.client] = [ - // CC,AL,HS,AD,HB - /*SHE*/[__,R1,R2,__,R4], - /*SCE*/[__,R1,R2,__,R4], - /*SKE*/[__,R1,R2,__,R4], - /*SCR*/[__,R1,R2,__,R4], - /*SHD*/[__,R1,R2,__,R4], - /*SCC*/[R0,R1,__,__,R4], - /*SFI*/[__,R1,R2,__,R4], - /*SAD*/[__,R1,R2,R3,R4], - /*SER*/[__,R1,R2,__,R4] - ]; - - // map server current expect state and content type to function - ctTable[tls.ConnectionEnd.server] = [ - // CC,AL,HS,AD - /*CHE*/[__,R1,R2,__,R4], - /*CCE*/[__,R1,R2,__,R4], - /*CKE*/[__,R1,R2,__,R4], - /*CCV*/[__,R1,R2,__,R4], - /*CCC*/[R0,R1,__,__,R4], - /*CFI*/[__,R1,R2,__,R4], - /*CAD*/[__,R1,R2,R3,R4], - /*CER*/[__,R1,R2,__,R4] - ]; - - // map client current expect state and handshake type to function - var H0 = tls.handleHelloRequest; - var H1 = tls.handleServerHello; - var H2 = tls.handleCertificate; - var H3 = tls.handleServerKeyExchange; - var H4 = tls.handleCertificateRequest; - var H5 = tls.handleServerHelloDone; - var H6 = tls.handleFinished; - var hsTable = []; - hsTable[tls.ConnectionEnd.client] = [ - // HR,01,SH,03,04,05,06,07,08,09,10,SC,SK,CR,HD,15,CK,17,18,19,FI - /*SHE*/[__,__,H1,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], - /*SCE*/[H0,__,__,__,__,__,__,__,__,__,__,H2,H3,H4,H5,__,__,__,__,__,__], - /*SKE*/[H0,__,__,__,__,__,__,__,__,__,__,__,H3,H4,H5,__,__,__,__,__,__], - /*SCR*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,H4,H5,__,__,__,__,__,__], - /*SHD*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,H5,__,__,__,__,__,__], - /*SCC*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], - /*SFI*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H6], - /*SAD*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], - /*SER*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__] - ]; - - // map server current expect state and handshake type to function - // Note: CAD[CH] does not map to FB because renegotation is prohibited - var H7 = tls.handleClientHello; - var H8 = tls.handleClientKeyExchange; - var H9 = tls.handleCertificateVerify; - hsTable[tls.ConnectionEnd.server] = [ - // 01,CH,02,03,04,05,06,07,08,09,10,CC,12,13,14,CV,CK,17,18,19,FI - /*CHE*/[__,H7,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], - /*CCE*/[__,__,__,__,__,__,__,__,__,__,__,H2,__,__,__,__,__,__,__,__,__], - /*CKE*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H8,__,__,__,__], - /*CCV*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H9,__,__,__,__,__], - /*CCC*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], - /*CFI*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H6], - /*CAD*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], - /*CER*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__] - ]; - - /** - * Generates the master_secret and keys using the given security parameters. - * - * The security parameters for a TLS connection state are defined as such: - * - * struct { - * ConnectionEnd entity; - * PRFAlgorithm prf_algorithm; - * BulkCipherAlgorithm bulk_cipher_algorithm; - * CipherType cipher_type; - * uint8 enc_key_length; - * uint8 block_length; - * uint8 fixed_iv_length; - * uint8 record_iv_length; - * MACAlgorithm mac_algorithm; - * uint8 mac_length; - * uint8 mac_key_length; - * CompressionMethod compression_algorithm; - * opaque master_secret[48]; - * opaque client_random[32]; - * opaque server_random[32]; - * } SecurityParameters; - * - * Note that this definition is from TLS 1.2. In TLS 1.0 some of these - * parameters are ignored because, for instance, the PRFAlgorithm is a - * builtin-fixed algorithm combining iterations of MD5 and SHA-1 in TLS 1.0. - * - * The Record Protocol requires an algorithm to generate keys required by the - * current connection state. - * - * The master secret is expanded into a sequence of secure bytes, which is then - * split to a client write MAC key, a server write MAC key, a client write - * encryption key, and a server write encryption key. In TLS 1.0 a client write - * IV and server write IV are also generated. Each of these is generated from - * the byte sequence in that order. Unused values are empty. In TLS 1.2, some - * AEAD ciphers may additionally require a client write IV and a server write - * IV (see Section 6.2.3.3). - * - * When keys, MAC keys, and IVs are generated, the master secret is used as an - * entropy source. - * - * To generate the key material, compute: - * - * master_secret = PRF(pre_master_secret, "master secret", - * ClientHello.random + ServerHello.random) - * - * key_block = PRF(SecurityParameters.master_secret, - * "key expansion", - * SecurityParameters.server_random + - * SecurityParameters.client_random); - * - * until enough output has been generated. Then, the key_block is - * partitioned as follows: - * - * client_write_MAC_key[SecurityParameters.mac_key_length] - * server_write_MAC_key[SecurityParameters.mac_key_length] - * client_write_key[SecurityParameters.enc_key_length] - * server_write_key[SecurityParameters.enc_key_length] - * client_write_IV[SecurityParameters.fixed_iv_length] - * server_write_IV[SecurityParameters.fixed_iv_length] - * - * In TLS 1.2, the client_write_IV and server_write_IV are only generated for - * implicit nonce techniques as described in Section 3.2.1 of [AEAD]. This - * implementation uses TLS 1.0 so IVs are generated. - * - * Implementation note: The currently defined cipher suite which requires the - * most material is AES_256_CBC_SHA256. It requires 2 x 32 byte keys and 2 x 32 - * byte MAC keys, for a total 128 bytes of key material. In TLS 1.0 it also - * requires 2 x 16 byte IVs, so it actually takes 160 bytes of key material. - * - * @param c the connection. - * @param sp the security parameters to use. - * - * @return the security keys. - */ - tls.generateKeys = function(c, sp) { - // TLS_RSA_WITH_AES_128_CBC_SHA (required to be compliant with TLS 1.2) & - // TLS_RSA_WITH_AES_256_CBC_SHA are the only cipher suites implemented - // at present - - // TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA is required to be compliant with - // TLS 1.0 but we don't care right now because AES is better and we have - // an implementation for it - - // TODO: TLS 1.2 implementation - /* - // determine the PRF - var prf; - switch(sp.prf_algorithm) { - case tls.PRFAlgorithm.tls_prf_sha256: - prf = prf_sha256; - break; - default: - // should never happen - throw new Error('Invalid PRF'); - } - */ - - // TLS 1.0/1.1 implementation - var prf = prf_TLS1; - - // concatenate server and client random - var random = sp.client_random + sp.server_random; - - // only create master secret if session is new - if(!c.session.resuming) { - // create master secret, clean up pre-master secret - sp.master_secret = prf( - sp.pre_master_secret, 'master secret', random, 48).bytes(); - sp.pre_master_secret = null; - } - - // generate the amount of key material needed - random = sp.server_random + sp.client_random; - var length = 2 * sp.mac_key_length + 2 * sp.enc_key_length; - - // include IV for TLS/1.0 - var tls10 = (c.version.major === tls.Versions.TLS_1_0.major && - c.version.minor === tls.Versions.TLS_1_0.minor); - if(tls10) { - length += 2 * sp.fixed_iv_length; - } - var km = prf(sp.master_secret, 'key expansion', random, length); - - // split the key material into the MAC and encryption keys - var rval = { - client_write_MAC_key: km.getBytes(sp.mac_key_length), - server_write_MAC_key: km.getBytes(sp.mac_key_length), - client_write_key: km.getBytes(sp.enc_key_length), - server_write_key: km.getBytes(sp.enc_key_length) - }; - - // include TLS 1.0 IVs - if(tls10) { - rval.client_write_IV = km.getBytes(sp.fixed_iv_length); - rval.server_write_IV = km.getBytes(sp.fixed_iv_length); - } - - return rval; - }; - - /** - * Creates a new initialized TLS connection state. A connection state has - * a read mode and a write mode. - * - * compression state: - * The current state of the compression algorithm. - * - * cipher state: - * The current state of the encryption algorithm. This will consist of the - * scheduled key for that connection. For stream ciphers, this will also - * contain whatever state information is necessary to allow the stream to - * continue to encrypt or decrypt data. - * - * MAC key: - * The MAC key for the connection. - * - * sequence number: - * Each connection state contains a sequence number, which is maintained - * separately for read and write states. The sequence number MUST be set to - * zero whenever a connection state is made the active state. Sequence - * numbers are of type uint64 and may not exceed 2^64-1. Sequence numbers do - * not wrap. If a TLS implementation would need to wrap a sequence number, - * it must renegotiate instead. A sequence number is incremented after each - * record: specifically, the first record transmitted under a particular - * connection state MUST use sequence number 0. - * - * @param c the connection. - * - * @return the new initialized TLS connection state. - */ - tls.createConnectionState = function(c) { - var client = (c.entity === tls.ConnectionEnd.client); - - var createMode = function() { - var mode = { - // two 32-bit numbers, first is most significant - sequenceNumber: [0, 0], - macKey: null, - macLength: 0, - macFunction: null, - cipherState: null, - cipherFunction: function(record) {return true;}, - compressionState: null, - compressFunction: function(record) {return true;}, - updateSequenceNumber: function() { - if(mode.sequenceNumber[1] === 0xFFFFFFFF) { - mode.sequenceNumber[1] = 0; - ++mode.sequenceNumber[0]; - } else { - ++mode.sequenceNumber[1]; - } - } - }; - return mode; - }; - var state = { - read: createMode(), - write: createMode() - }; - - // update function in read mode will decrypt then decompress a record - state.read.update = function(c, record) { - if(!state.read.cipherFunction(record, state.read)) { - c.error(c, { - message: 'Could not decrypt record or bad MAC.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - // doesn't matter if decryption failed or MAC was - // invalid, return the same error so as not to reveal - // which one occurred - description: tls.Alert.Description.bad_record_mac - } - }); - } else if(!state.read.compressFunction(c, record, state.read)) { - c.error(c, { - message: 'Could not decompress record.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.decompression_failure - } - }); - } - return !c.fail; - }; - - // update function in write mode will compress then encrypt a record - state.write.update = function(c, record) { - if(!state.write.compressFunction(c, record, state.write)) { - // error, but do not send alert since it would require - // compression as well - c.error(c, { - message: 'Could not compress record.', - send: false, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.internal_error - } - }); - } else if(!state.write.cipherFunction(record, state.write)) { - // error, but do not send alert since it would require - // encryption as well - c.error(c, { - message: 'Could not encrypt record.', - send: false, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.internal_error - } - }); - } - return !c.fail; - }; - - // handle security parameters - if(c.session) { - var sp = c.session.sp; - c.session.cipherSuite.initSecurityParameters(sp); - - // generate keys - sp.keys = tls.generateKeys(c, sp); - state.read.macKey = client ? - sp.keys.server_write_MAC_key : sp.keys.client_write_MAC_key; - state.write.macKey = client ? - sp.keys.client_write_MAC_key : sp.keys.server_write_MAC_key; - - // cipher suite setup - c.session.cipherSuite.initConnectionState(state, c, sp); - - // compression setup - switch(sp.compression_algorithm) { - case tls.CompressionMethod.none: - break; - case tls.CompressionMethod.deflate: - state.read.compressFunction = inflate; - state.write.compressFunction = deflate; - break; - default: - throw new Error('Unsupported compression algorithm.'); - } - } - - return state; - }; - - /** - * Creates a Random structure. - * - * struct { - * uint32 gmt_unix_time; - * opaque random_bytes[28]; - * } Random; - * - * gmt_unix_time: - * The current time and date in standard UNIX 32-bit format (seconds since - * the midnight starting Jan 1, 1970, UTC, ignoring leap seconds) according - * to the sender's internal clock. Clocks are not required to be set - * correctly by the basic TLS protocol; higher-level or application - * protocols may define additional requirements. Note that, for historical - * reasons, the data element is named using GMT, the predecessor of the - * current worldwide time base, UTC. - * random_bytes: - * 28 bytes generated by a secure random number generator. - * - * @return the Random structure as a byte array. - */ - tls.createRandom = function() { - // get UTC milliseconds - var d = new Date(); - var utc = +d + d.getTimezoneOffset() * 60000; - var rval = forge.util.createBuffer(); - rval.putInt32(utc); - rval.putBytes(forge.random.getBytes(28)); - return rval; - }; - - /** - * Creates a TLS record with the given type and data. - * - * @param c the connection. - * @param options: - * type: the record type. - * data: the plain text data in a byte buffer. - * - * @return the created record. - */ - tls.createRecord = function(c, options) { - if(!options.data) { - return null; - } - var record = { - type: options.type, - version: { - major: c.version.major, - minor: c.version.minor - }, - length: options.data.length(), - fragment: options.data - }; - return record; - }; - - /** - * Creates a TLS alert record. - * - * @param c the connection. - * @param alert: - * level: the TLS alert level. - * description: the TLS alert description. - * - * @return the created alert record. - */ - tls.createAlert = function(c, alert) { - var b = forge.util.createBuffer(); - b.putByte(alert.level); - b.putByte(alert.description); - return tls.createRecord(c, { - type: tls.ContentType.alert, - data: b - }); - }; - - /* The structure of a TLS handshake message. - * - * struct { - * HandshakeType msg_type; // handshake type - * uint24 length; // bytes in message - * select(HandshakeType) { - * case hello_request: HelloRequest; - * case client_hello: ClientHello; - * case server_hello: ServerHello; - * case certificate: Certificate; - * case server_key_exchange: ServerKeyExchange; - * case certificate_request: CertificateRequest; - * case server_hello_done: ServerHelloDone; - * case certificate_verify: CertificateVerify; - * case client_key_exchange: ClientKeyExchange; - * case finished: Finished; - * } body; - * } Handshake; - */ - - /** - * Creates a ClientHello message. - * - * opaque SessionID<0..32>; - * enum { null(0), deflate(1), (255) } CompressionMethod; - * uint8 CipherSuite[2]; - * - * struct { - * ProtocolVersion client_version; - * Random random; - * SessionID session_id; - * CipherSuite cipher_suites<2..2^16-2>; - * CompressionMethod compression_methods<1..2^8-1>; - * select(extensions_present) { - * case false: - * struct {}; - * case true: - * Extension extensions<0..2^16-1>; - * }; - * } ClientHello; - * - * The extension format for extended client hellos and server hellos is: - * - * struct { - * ExtensionType extension_type; - * opaque extension_data<0..2^16-1>; - * } Extension; - * - * Here: - * - * - "extension_type" identifies the particular extension type. - * - "extension_data" contains information specific to the particular - * extension type. - * - * The extension types defined in this document are: - * - * enum { - * server_name(0), max_fragment_length(1), - * client_certificate_url(2), trusted_ca_keys(3), - * truncated_hmac(4), status_request(5), (65535) - * } ExtensionType; - * - * @param c the connection. - * - * @return the ClientHello byte buffer. - */ - tls.createClientHello = function(c) { - // save hello version - c.session.clientHelloVersion = { - major: c.version.major, - minor: c.version.minor - }; - - // create supported cipher suites - var cipherSuites = forge.util.createBuffer(); - for(var i = 0; i < c.cipherSuites.length; ++i) { - var cs = c.cipherSuites[i]; - cipherSuites.putByte(cs.id[0]); - cipherSuites.putByte(cs.id[1]); - } - var cSuites = cipherSuites.length(); - - // create supported compression methods, null always supported, but - // also support deflate if connection has inflate and deflate methods - var compressionMethods = forge.util.createBuffer(); - compressionMethods.putByte(tls.CompressionMethod.none); - // FIXME: deflate support disabled until issues with raw deflate data - // without zlib headers are resolved - /* - if(c.inflate !== null && c.deflate !== null) { - compressionMethods.putByte(tls.CompressionMethod.deflate); - } - */ - var cMethods = compressionMethods.length(); - - // create TLS SNI (server name indication) extension if virtual host - // has been specified, see RFC 3546 - var extensions = forge.util.createBuffer(); - if(c.virtualHost) { - // create extension struct - var ext = forge.util.createBuffer(); - ext.putByte(0x00); // type server_name (ExtensionType is 2 bytes) - ext.putByte(0x00); - - /* In order to provide the server name, clients MAY include an - * extension of type "server_name" in the (extended) client hello. - * The "extension_data" field of this extension SHALL contain - * "ServerNameList" where: - * - * struct { - * NameType name_type; - * select(name_type) { - * case host_name: HostName; - * } name; - * } ServerName; - * - * enum { - * host_name(0), (255) - * } NameType; - * - * opaque HostName<1..2^16-1>; - * - * struct { - * ServerName server_name_list<1..2^16-1> - * } ServerNameList; - */ - var serverName = forge.util.createBuffer(); - serverName.putByte(0x00); // type host_name - writeVector(serverName, 2, forge.util.createBuffer(c.virtualHost)); - - // ServerNameList is in extension_data - var snList = forge.util.createBuffer(); - writeVector(snList, 2, serverName); - writeVector(ext, 2, snList); - extensions.putBuffer(ext); - } - var extLength = extensions.length(); - if(extLength > 0) { - // add extension vector length - extLength += 2; - } - - // determine length of the handshake message - // cipher suites and compression methods size will need to be - // updated if more get added to the list - var sessionId = c.session.id; - var length = - sessionId.length + 1 + // session ID vector - 2 + // version (major + minor) - 4 + 28 + // random time and random bytes - 2 + cSuites + // cipher suites vector - 1 + cMethods + // compression methods vector - extLength; // extensions vector - - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.client_hello); - rval.putInt24(length); // handshake length - rval.putByte(c.version.major); // major version - rval.putByte(c.version.minor); // minor version - rval.putBytes(c.session.sp.client_random); // random time + bytes - writeVector(rval, 1, forge.util.createBuffer(sessionId)); - writeVector(rval, 2, cipherSuites); - writeVector(rval, 1, compressionMethods); - if(extLength > 0) { - writeVector(rval, 2, extensions); - } - return rval; - }; - - /** - * Creates a ServerHello message. - * - * @param c the connection. - * - * @return the ServerHello byte buffer. - */ - tls.createServerHello = function(c) { - // determine length of the handshake message - var sessionId = c.session.id; - var length = - sessionId.length + 1 + // session ID vector - 2 + // version (major + minor) - 4 + 28 + // random time and random bytes - 2 + // chosen cipher suite - 1; // chosen compression method - - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.server_hello); - rval.putInt24(length); // handshake length - rval.putByte(c.version.major); // major version - rval.putByte(c.version.minor); // minor version - rval.putBytes(c.session.sp.server_random); // random time + bytes - writeVector(rval, 1, forge.util.createBuffer(sessionId)); - rval.putByte(c.session.cipherSuite.id[0]); - rval.putByte(c.session.cipherSuite.id[1]); - rval.putByte(c.session.compressionMethod); - return rval; - }; - - /** - * Creates a Certificate message. - * - * When this message will be sent: - * This is the first message the client can send after receiving a server - * hello done message and the first message the server can send after - * sending a ServerHello. This client message is only sent if the server - * requests a certificate. If no suitable certificate is available, the - * client should send a certificate message containing no certificates. If - * client authentication is required by the server for the handshake to - * continue, it may respond with a fatal handshake failure alert. - * - * opaque ASN.1Cert<1..2^24-1>; - * - * struct { - * ASN.1Cert certificate_list<0..2^24-1>; - * } Certificate; - * - * @param c the connection. - * - * @return the Certificate byte buffer. - */ - tls.createCertificate = function(c) { - // TODO: check certificate request to ensure types are supported - - // get a certificate (a certificate as a PEM string) - var client = (c.entity === tls.ConnectionEnd.client); - var cert = null; - if(c.getCertificate) { - var hint; - if(client) { - hint = c.session.certificateRequest; - } else { - hint = c.session.extensions.server_name.serverNameList; - } - cert = c.getCertificate(c, hint); - } - - // buffer to hold certificate list - var certList = forge.util.createBuffer(); - if(cert !== null) { - try { - // normalize cert to a chain of certificates - if(!forge.util.isArray(cert)) { - cert = [cert]; - } - var asn1 = null; - for(var i = 0; i < cert.length; ++i) { - var msg = forge.pem.decode(cert[i])[0]; - if(msg.type !== 'CERTIFICATE' && - msg.type !== 'X509 CERTIFICATE' && - msg.type !== 'TRUSTED CERTIFICATE') { - var error = new Error('Could not convert certificate from PEM; PEM ' + - 'header type is not "CERTIFICATE", "X509 CERTIFICATE", or ' + - '"TRUSTED CERTIFICATE".'); - error.headerType = msg.type; - throw error; - } - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error('Could not convert certificate from PEM; PEM is encrypted.'); - } - - var der = forge.util.createBuffer(msg.body); - if(asn1 === null) { - asn1 = forge.asn1.fromDer(der.bytes(), false); - } - - // certificate entry is itself a vector with 3 length bytes - var certBuffer = forge.util.createBuffer(); - writeVector(certBuffer, 3, der); - - // add cert vector to cert list vector - certList.putBuffer(certBuffer); - } - - // save certificate - cert = forge.pki.certificateFromAsn1(asn1); - if(client) { - c.session.clientCertificate = cert; - } else { - c.session.serverCertificate = cert; - } - } catch(ex) { - return c.error(c, { - message: 'Could not send certificate list.', - cause: ex, - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.bad_certificate - } - }); - } - } - - // determine length of the handshake message - var length = 3 + certList.length(); // cert list vector - - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.certificate); - rval.putInt24(length); - writeVector(rval, 3, certList); - return rval; - }; - - /** - * Creates a ClientKeyExchange message. - * - * When this message will be sent: - * This message is always sent by the client. It will immediately follow the - * client certificate message, if it is sent. Otherwise it will be the first - * message sent by the client after it receives the server hello done - * message. - * - * Meaning of this message: - * With this message, the premaster secret is set, either though direct - * transmission of the RSA-encrypted secret, or by the transmission of - * Diffie-Hellman parameters which will allow each side to agree upon the - * same premaster secret. When the key exchange method is DH_RSA or DH_DSS, - * client certification has been requested, and the client was able to - * respond with a certificate which contained a Diffie-Hellman public key - * whose parameters (group and generator) matched those specified by the - * server in its certificate, this message will not contain any data. - * - * Meaning of this message: - * If RSA is being used for key agreement and authentication, the client - * generates a 48-byte premaster secret, encrypts it using the public key - * from the server's certificate or the temporary RSA key provided in a - * server key exchange message, and sends the result in an encrypted - * premaster secret message. This structure is a variant of the client - * key exchange message, not a message in itself. - * - * struct { - * select(KeyExchangeAlgorithm) { - * case rsa: EncryptedPreMasterSecret; - * case diffie_hellman: ClientDiffieHellmanPublic; - * } exchange_keys; - * } ClientKeyExchange; - * - * struct { - * ProtocolVersion client_version; - * opaque random[46]; - * } PreMasterSecret; - * - * struct { - * public-key-encrypted PreMasterSecret pre_master_secret; - * } EncryptedPreMasterSecret; - * - * A public-key-encrypted element is encoded as a vector <0..2^16-1>. - * - * @param c the connection. - * - * @return the ClientKeyExchange byte buffer. - */ - tls.createClientKeyExchange = function(c) { - // create buffer to encrypt - var b = forge.util.createBuffer(); - - // add highest client-supported protocol to help server avoid version - // rollback attacks - b.putByte(c.session.clientHelloVersion.major); - b.putByte(c.session.clientHelloVersion.minor); - - // generate and add 46 random bytes - b.putBytes(forge.random.getBytes(46)); - - // save pre-master secret - var sp = c.session.sp; - sp.pre_master_secret = b.getBytes(); - - // RSA-encrypt the pre-master secret - var key = c.session.serverCertificate.publicKey; - b = key.encrypt(sp.pre_master_secret); - - /* Note: The encrypted pre-master secret will be stored in a - public-key-encrypted opaque vector that has the length prefixed using - 2 bytes, so include those 2 bytes in the handshake message length. This - is done as a minor optimization instead of calling writeVector(). */ - - // determine length of the handshake message - var length = b.length + 2; - - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.client_key_exchange); - rval.putInt24(length); - // add vector length bytes - rval.putInt16(b.length); - rval.putBytes(b); - return rval; - }; - - /** - * Creates a ServerKeyExchange message. - * - * @param c the connection. - * - * @return the ServerKeyExchange byte buffer. - */ - tls.createServerKeyExchange = function(c) { - - // build record fragment - var rval = forge.util.createBuffer(); - return rval; - }; - - /** - * Gets the signed data used to verify a client-side certificate. See - * tls.createCertificateVerify() for details. - * - * @param c the connection. - * @param callback the callback to call once the signed data is ready. - */ - tls.getClientSignature = function(c, callback) { - // generate data to RSA encrypt - var b = forge.util.createBuffer(); - b.putBuffer(c.session.md5.digest()); - b.putBuffer(c.session.sha1.digest()); - b = b.getBytes(); - - // create default signing function as necessary - c.getSignature = c.getSignature || function(c, b, callback) { - // do rsa encryption, call callback - var privateKey = null; - if(c.getPrivateKey) { - try { - privateKey = c.getPrivateKey(c, c.session.clientCertificate); - privateKey = forge.pki.privateKeyFromPem(privateKey); - } catch(ex) { - c.error(c, { - message: 'Could not get private key.', - cause: ex, - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.internal_error - } - }); - } - } - if(privateKey === null) { - c.error(c, { - message: 'No private key set.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.internal_error - } - }); - } else { - b = privateKey.sign(b, null); - } - callback(c, b); - }; - - // get client signature - c.getSignature(c, b, callback); - }; - - /** - * Creates a CertificateVerify message. - * - * Meaning of this message: - * This structure conveys the client's Diffie-Hellman public value - * (Yc) if it was not already included in the client's certificate. - * The encoding used for Yc is determined by the enumerated - * PublicValueEncoding. This structure is a variant of the client - * key exchange message, not a message in itself. - * - * When this message will be sent: - * This message is used to provide explicit verification of a client - * certificate. This message is only sent following a client - * certificate that has signing capability (i.e. all certificates - * except those containing fixed Diffie-Hellman parameters). When - * sent, it will immediately follow the client key exchange message. - * - * struct { - * Signature signature; - * } CertificateVerify; - * - * CertificateVerify.signature.md5_hash - * MD5(handshake_messages); - * - * Certificate.signature.sha_hash - * SHA(handshake_messages); - * - * Here handshake_messages refers to all handshake messages sent or - * received starting at client hello up to but not including this - * message, including the type and length fields of the handshake - * messages. - * - * select(SignatureAlgorithm) { - * case anonymous: struct { }; - * case rsa: - * digitally-signed struct { - * opaque md5_hash[16]; - * opaque sha_hash[20]; - * }; - * case dsa: - * digitally-signed struct { - * opaque sha_hash[20]; - * }; - * } Signature; - * - * In digital signing, one-way hash functions are used as input for a - * signing algorithm. A digitally-signed element is encoded as an opaque - * vector <0..2^16-1>, where the length is specified by the signing - * algorithm and key. - * - * In RSA signing, a 36-byte structure of two hashes (one SHA and one - * MD5) is signed (encrypted with the private key). It is encoded with - * PKCS #1 block type 0 or type 1 as described in [PKCS1]. - * - * In DSS, the 20 bytes of the SHA hash are run directly through the - * Digital Signing Algorithm with no additional hashing. - * - * @param c the connection. - * @param signature the signature to include in the message. - * - * @return the CertificateVerify byte buffer. - */ - tls.createCertificateVerify = function(c, signature) { - /* Note: The signature will be stored in a "digitally-signed" opaque - vector that has the length prefixed using 2 bytes, so include those - 2 bytes in the handshake message length. This is done as a minor - optimization instead of calling writeVector(). */ - - // determine length of the handshake message - var length = signature.length + 2; - - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.certificate_verify); - rval.putInt24(length); - // add vector length bytes - rval.putInt16(signature.length); - rval.putBytes(signature); - return rval; - }; - - /** - * Creates a CertificateRequest message. - * - * @param c the connection. - * - * @return the CertificateRequest byte buffer. - */ - tls.createCertificateRequest = function(c) { - // TODO: support other certificate types - var certTypes = forge.util.createBuffer(); - - // common RSA certificate type - certTypes.putByte(0x01); - - // add distinguished names from CA store - var cAs = forge.util.createBuffer(); - for(var key in c.caStore.certs) { - var cert = c.caStore.certs[key]; - var dn = forge.pki.distinguishedNameToAsn1(cert.subject); - var byteBuffer = forge.asn1.toDer(dn); - cAs.putInt16(byteBuffer.length()); - cAs.putBuffer(byteBuffer); - } - - // TODO: TLS 1.2+ has a different format - - // determine length of the handshake message - var length = - 1 + certTypes.length() + - 2 + cAs.length(); - - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.certificate_request); - rval.putInt24(length); - writeVector(rval, 1, certTypes); - writeVector(rval, 2, cAs); - return rval; - }; - - /** - * Creates a ServerHelloDone message. - * - * @param c the connection. - * - * @return the ServerHelloDone byte buffer. - */ - tls.createServerHelloDone = function(c) { - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.server_hello_done); - rval.putInt24(0); - return rval; - }; - - /** - * Creates a ChangeCipherSpec message. - * - * The change cipher spec protocol exists to signal transitions in - * ciphering strategies. The protocol consists of a single message, - * which is encrypted and compressed under the current (not the pending) - * connection state. The message consists of a single byte of value 1. - * - * struct { - * enum { change_cipher_spec(1), (255) } type; - * } ChangeCipherSpec; - * - * @return the ChangeCipherSpec byte buffer. - */ - tls.createChangeCipherSpec = function() { - var rval = forge.util.createBuffer(); - rval.putByte(0x01); - return rval; - }; - - /** - * Creates a Finished message. - * - * struct { - * opaque verify_data[12]; - * } Finished; - * - * verify_data - * PRF(master_secret, finished_label, MD5(handshake_messages) + - * SHA-1(handshake_messages)) [0..11]; - * - * finished_label - * For Finished messages sent by the client, the string "client - * finished". For Finished messages sent by the server, the - * string "server finished". - * - * handshake_messages - * All of the data from all handshake messages up to but not - * including this message. This is only data visible at the - * handshake layer and does not include record layer headers. - * This is the concatenation of all the Handshake structures as - * defined in 7.4 exchanged thus far. - * - * @param c the connection. - * - * @return the Finished byte buffer. - */ - tls.createFinished = function(c) { - // generate verify_data - var b = forge.util.createBuffer(); - b.putBuffer(c.session.md5.digest()); - b.putBuffer(c.session.sha1.digest()); - - // TODO: determine prf function and verify length for TLS 1.2 - var client = (c.entity === tls.ConnectionEnd.client); - var sp = c.session.sp; - var vdl = 12; - var prf = prf_TLS1; - var label = client ? 'client finished' : 'server finished'; - b = prf(sp.master_secret, label, b.getBytes(), vdl); - - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(tls.HandshakeType.finished); - rval.putInt24(b.length()); - rval.putBuffer(b); - return rval; - }; - - /** - * Creates a HeartbeatMessage (See RFC 6520). - * - * struct { - * HeartbeatMessageType type; - * uint16 payload_length; - * opaque payload[HeartbeatMessage.payload_length]; - * opaque padding[padding_length]; - * } HeartbeatMessage; - * - * The total length of a HeartbeatMessage MUST NOT exceed 2^14 or - * max_fragment_length when negotiated as defined in [RFC6066]. - * - * type: The message type, either heartbeat_request or heartbeat_response. - * - * payload_length: The length of the payload. - * - * payload: The payload consists of arbitrary content. - * - * padding: The padding is random content that MUST be ignored by the - * receiver. The length of a HeartbeatMessage is TLSPlaintext.length - * for TLS and DTLSPlaintext.length for DTLS. Furthermore, the - * length of the type field is 1 byte, and the length of the - * payload_length is 2. Therefore, the padding_length is - * TLSPlaintext.length - payload_length - 3 for TLS and - * DTLSPlaintext.length - payload_length - 3 for DTLS. The - * padding_length MUST be at least 16. - * - * The sender of a HeartbeatMessage MUST use a random padding of at - * least 16 bytes. The padding of a received HeartbeatMessage message - * MUST be ignored. - * - * If the payload_length of a received HeartbeatMessage is too large, - * the received HeartbeatMessage MUST be discarded silently. - * - * @param c the connection. - * @param type the tls.HeartbeatMessageType. - * @param payload the heartbeat data to send as the payload. - * @param [payloadLength] the payload length to use, defaults to the - * actual payload length. - * - * @return the HeartbeatRequest byte buffer. - */ - tls.createHeartbeat = function(type, payload, payloadLength) { - if(typeof payloadLength === 'undefined') { - payloadLength = payload.length; - } - // build record fragment - var rval = forge.util.createBuffer(); - rval.putByte(type); // heartbeat message type - rval.putInt16(payloadLength); // payload length - rval.putBytes(payload); // payload - // padding - var plaintextLength = rval.length(); - var paddingLength = Math.max(16, plaintextLength - payloadLength - 3); - rval.putBytes(forge.random.getBytes(paddingLength)); - return rval; - }; - - /** - * Fragments, compresses, encrypts, and queues a record for delivery. - * - * @param c the connection. - * @param record the record to queue. - */ - tls.queue = function(c, record) { - // error during record creation - if(!record) { - return; - } - - if(record.fragment.length() === 0) { - if(record.type === tls.ContentType.handshake || - record.type === tls.ContentType.alert || - record.type === tls.ContentType.change_cipher_spec) { - // Empty handshake, alert of change cipher spec messages are not allowed per the TLS specification and should not be sent. - return; - } - } - - // if the record is a handshake record, update handshake hashes - if(record.type === tls.ContentType.handshake) { - var bytes = record.fragment.bytes(); - c.session.md5.update(bytes); - c.session.sha1.update(bytes); - bytes = null; - } - - // handle record fragmentation - var records; - if(record.fragment.length() <= tls.MaxFragment) { - records = [record]; - } else { - // fragment data as long as it is too long - records = []; - var data = record.fragment.bytes(); - while(data.length > tls.MaxFragment) { - records.push(tls.createRecord(c, { - type: record.type, - data: forge.util.createBuffer(data.slice(0, tls.MaxFragment)) - })); - data = data.slice(tls.MaxFragment); - } - // add last record - if(data.length > 0) { - records.push(tls.createRecord(c, { - type: record.type, - data: forge.util.createBuffer(data) - })); - } - } - - // compress and encrypt all fragmented records - for(var i = 0; i < records.length && !c.fail; ++i) { - // update the record using current write state - var rec = records[i]; - var s = c.state.current.write; - if(s.update(c, rec)) { - // store record - c.records.push(rec); - } - } - }; - - /** - * Flushes all queued records to the output buffer and calls the - * tlsDataReady() handler on the given connection. - * - * @param c the connection. - * - * @return true on success, false on failure. - */ - tls.flush = function(c) { - for(var i = 0; i < c.records.length; ++i) { - var record = c.records[i]; - - // add record header and fragment - c.tlsData.putByte(record.type); - c.tlsData.putByte(record.version.major); - c.tlsData.putByte(record.version.minor); - c.tlsData.putInt16(record.fragment.length()); - c.tlsData.putBuffer(c.records[i].fragment); - } - c.records = []; - return c.tlsDataReady(c); - }; - - /** - * Maps a pki.certificateError to a tls.Alert.Description. - * - * @param error the error to map. - * - * @return the alert description. - */ - var _certErrorToAlertDesc = function(error) { - switch(error) { - case true: - return true; - case forge.pki.certificateError.bad_certificate: - return tls.Alert.Description.bad_certificate; - case forge.pki.certificateError.unsupported_certificate: - return tls.Alert.Description.unsupported_certificate; - case forge.pki.certificateError.certificate_revoked: - return tls.Alert.Description.certificate_revoked; - case forge.pki.certificateError.certificate_expired: - return tls.Alert.Description.certificate_expired; - case forge.pki.certificateError.certificate_unknown: - return tls.Alert.Description.certificate_unknown; - case forge.pki.certificateError.unknown_ca: - return tls.Alert.Description.unknown_ca; - default: - return tls.Alert.Description.bad_certificate; - } - }; - - /** - * Maps a tls.Alert.Description to a pki.certificateError. - * - * @param desc the alert description. - * - * @return the certificate error. - */ - var _alertDescToCertError = function(desc) { - switch(desc) { - case true: - return true; - case tls.Alert.Description.bad_certificate: - return forge.pki.certificateError.bad_certificate; - case tls.Alert.Description.unsupported_certificate: - return forge.pki.certificateError.unsupported_certificate; - case tls.Alert.Description.certificate_revoked: - return forge.pki.certificateError.certificate_revoked; - case tls.Alert.Description.certificate_expired: - return forge.pki.certificateError.certificate_expired; - case tls.Alert.Description.certificate_unknown: - return forge.pki.certificateError.certificate_unknown; - case tls.Alert.Description.unknown_ca: - return forge.pki.certificateError.unknown_ca; - default: - return forge.pki.certificateError.bad_certificate; - } - }; - - /** - * Verifies a certificate chain against the given connection's - * Certificate Authority store. - * - * @param c the TLS connection. - * @param chain the certificate chain to verify, with the root or highest - * authority at the end. - * - * @return true if successful, false if not. - */ - tls.verifyCertificateChain = function(c, chain) { - try { - // Make a copy of c.verifyOptions so that we can modify options.verify - // without modifying c.verifyOptions. - var options = {}; - for (var key in c.verifyOptions) { - options[key] = c.verifyOptions[key]; - } - - options.verify = function(vfd, depth, chain) { - // convert pki.certificateError to tls alert description - var desc = _certErrorToAlertDesc(vfd); - - // call application callback - var ret = c.verify(c, vfd, depth, chain); - if(ret !== true) { - if(typeof ret === 'object' && !forge.util.isArray(ret)) { - // throw custom error - var error = new Error('The application rejected the certificate.'); - error.send = true; - error.alert = { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.bad_certificate - }; - if(ret.message) { - error.message = ret.message; - } - if(ret.alert) { - error.alert.description = ret.alert; - } - throw error; - } - - // convert tls alert description to pki.certificateError - if(ret !== vfd) { - ret = _alertDescToCertError(ret); - } - } - - return ret; - }; - - // verify chain - forge.pki.verifyCertificateChain(c.caStore, chain, options); - } catch(ex) { - // build tls error if not already customized - var err = ex; - if(typeof err !== 'object' || forge.util.isArray(err)) { - err = { - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: _certErrorToAlertDesc(ex) - } - }; - } - if(!('send' in err)) { - err.send = true; - } - if(!('alert' in err)) { - err.alert = { - level: tls.Alert.Level.fatal, - description: _certErrorToAlertDesc(err.error) - }; - } - - // send error - c.error(c, err); - } - - return !c.fail; - }; - - /** - * Creates a new TLS session cache. - * - * @param cache optional map of session ID to cached session. - * @param capacity the maximum size for the cache (default: 100). - * - * @return the new TLS session cache. - */ - tls.createSessionCache = function(cache, capacity) { - var rval = null; - - // assume input is already a session cache object - if(cache && cache.getSession && cache.setSession && cache.order) { - rval = cache; - } else { - // create cache - rval = {}; - rval.cache = cache || {}; - rval.capacity = Math.max(capacity || 100, 1); - rval.order = []; - - // store order for sessions, delete session overflow - for(var key in cache) { - if(rval.order.length <= capacity) { - rval.order.push(key); - } else { - delete cache[key]; - } - } - - // get a session from a session ID (or get any session) - rval.getSession = function(sessionId) { - var session = null; - var key = null; - - // if session ID provided, use it - if(sessionId) { - key = forge.util.bytesToHex(sessionId); - } else if(rval.order.length > 0) { - // get first session from cache - key = rval.order[0]; - } - - if(key !== null && key in rval.cache) { - // get cached session and remove from cache - session = rval.cache[key]; - delete rval.cache[key]; - for(var i in rval.order) { - if(rval.order[i] === key) { - rval.order.splice(i, 1); - break; - } - } - } - - return session; - }; - - // set a session in the cache - rval.setSession = function(sessionId, session) { - // remove session from cache if at capacity - if(rval.order.length === rval.capacity) { - var key = rval.order.shift(); - delete rval.cache[key]; - } - // add session to cache - var key = forge.util.bytesToHex(sessionId); - rval.order.push(key); - rval.cache[key] = session; - }; - } - - return rval; - }; - - /** - * Creates a new TLS connection. - * - * See public createConnection() docs for more details. - * - * @param options the options for this connection. - * - * @return the new TLS connection. - */ - tls.createConnection = function(options) { - var caStore = null; - if(options.caStore) { - // if CA store is an array, convert it to a CA store object - if(forge.util.isArray(options.caStore)) { - caStore = forge.pki.createCaStore(options.caStore); - } else { - caStore = options.caStore; - } - } else { - // create empty CA store - caStore = forge.pki.createCaStore(); - } - - // setup default cipher suites - var cipherSuites = options.cipherSuites || null; - if(cipherSuites === null) { - cipherSuites = []; - for(var key in tls.CipherSuites) { - cipherSuites.push(tls.CipherSuites[key]); - } - } - - // set default entity - var entity = (options.server || false) ? - tls.ConnectionEnd.server : tls.ConnectionEnd.client; - - // create session cache if requested - var sessionCache = options.sessionCache ? - tls.createSessionCache(options.sessionCache) : null; - - // create TLS connection - var c = { - version: {major: tls.Version.major, minor: tls.Version.minor}, - entity: entity, - sessionId: options.sessionId, - caStore: caStore, - sessionCache: sessionCache, - cipherSuites: cipherSuites, - connected: options.connected, - virtualHost: options.virtualHost || null, - verifyClient: options.verifyClient || false, - verify: options.verify || function(cn, vfd, dpth, cts) {return vfd;}, - verifyOptions: options.verifyOptions || {}, - getCertificate: options.getCertificate || null, - getPrivateKey: options.getPrivateKey || null, - getSignature: options.getSignature || null, - input: forge.util.createBuffer(), - tlsData: forge.util.createBuffer(), - data: forge.util.createBuffer(), - tlsDataReady: options.tlsDataReady, - dataReady: options.dataReady, - heartbeatReceived: options.heartbeatReceived, - closed: options.closed, - error: function(c, ex) { - // set origin if not set - ex.origin = ex.origin || - ((c.entity === tls.ConnectionEnd.client) ? 'client' : 'server'); - - // send TLS alert - if(ex.send) { - tls.queue(c, tls.createAlert(c, ex.alert)); - tls.flush(c); - } - - // error is fatal by default - var fatal = (ex.fatal !== false); - if(fatal) { - // set fail flag - c.fail = true; - } - - // call error handler first - options.error(c, ex); - - if(fatal) { - // fatal error, close connection, do not clear fail - c.close(false); - } - }, - deflate: options.deflate || null, - inflate: options.inflate || null - }; - - /** - * Resets a closed TLS connection for reuse. Called in c.close(). - * - * @param clearFail true to clear the fail flag (default: true). - */ - c.reset = function(clearFail) { - c.version = {major: tls.Version.major, minor: tls.Version.minor}; - c.record = null; - c.session = null; - c.peerCertificate = null; - c.state = { - pending: null, - current: null - }; - c.expect = (c.entity === tls.ConnectionEnd.client) ? SHE : CHE; - c.fragmented = null; - c.records = []; - c.open = false; - c.handshakes = 0; - c.handshaking = false; - c.isConnected = false; - c.fail = !(clearFail || typeof(clearFail) === 'undefined'); - c.input.clear(); - c.tlsData.clear(); - c.data.clear(); - c.state.current = tls.createConnectionState(c); - }; - - // do initial reset of connection - c.reset(); - - /** - * Updates the current TLS engine state based on the given record. - * - * @param c the TLS connection. - * @param record the TLS record to act on. - */ - var _update = function(c, record) { - // get record handler (align type in table by subtracting lowest) - var aligned = record.type - tls.ContentType.change_cipher_spec; - var handlers = ctTable[c.entity][c.expect]; - if(aligned in handlers) { - handlers[aligned](c, record); - } else { - // unexpected record - tls.handleUnexpected(c, record); - } - }; - - /** - * Reads the record header and initializes the next record on the given - * connection. - * - * @param c the TLS connection with the next record. - * - * @return 0 if the input data could be processed, otherwise the - * number of bytes required for data to be processed. - */ - var _readRecordHeader = function(c) { - var rval = 0; - - // get input buffer and its length - var b = c.input; - var len = b.length(); - - // need at least 5 bytes to initialize a record - if(len < 5) { - rval = 5 - len; - } else { - // enough bytes for header - // initialize record - c.record = { - type: b.getByte(), - version: { - major: b.getByte(), - minor: b.getByte() - }, - length: b.getInt16(), - fragment: forge.util.createBuffer(), - ready: false - }; - - // check record version - var compatibleVersion = (c.record.version.major === c.version.major); - if(compatibleVersion && c.session && c.session.version) { - // session version already set, require same minor version - compatibleVersion = (c.record.version.minor === c.version.minor); - } - if(!compatibleVersion) { - c.error(c, { - message: 'Incompatible TLS version.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: tls.Alert.Description.protocol_version - } - }); - } - } - - return rval; - }; - - /** - * Reads the next record's contents and appends its message to any - * previously fragmented message. - * - * @param c the TLS connection with the next record. - * - * @return 0 if the input data could be processed, otherwise the - * number of bytes required for data to be processed. - */ - var _readRecord = function(c) { - var rval = 0; - - // ensure there is enough input data to get the entire record - var b = c.input; - var len = b.length(); - if(len < c.record.length) { - // not enough data yet, return how much is required - rval = c.record.length - len; - } else { - // there is enough data to parse the pending record - // fill record fragment and compact input buffer - c.record.fragment.putBytes(b.getBytes(c.record.length)); - b.compact(); - - // update record using current read state - var s = c.state.current.read; - if(s.update(c, c.record)) { - // see if there is a previously fragmented message that the - // new record's message fragment should be appended to - if(c.fragmented !== null) { - // if the record type matches a previously fragmented - // record, append the record fragment to it - if(c.fragmented.type === c.record.type) { - // concatenate record fragments - c.fragmented.fragment.putBuffer(c.record.fragment); - c.record = c.fragmented; - } else { - // error, invalid fragmented record - c.error(c, { - message: 'Invalid fragmented record.', - send: true, - alert: { - level: tls.Alert.Level.fatal, - description: - tls.Alert.Description.unexpected_message - } - }); - } - } - - // record is now ready - c.record.ready = true; - } - } - - return rval; - }; - - /** - * Performs a handshake using the TLS Handshake Protocol, as a client. - * - * This method should only be called if the connection is in client mode. - * - * @param sessionId the session ID to use, null to start a new one. - */ - c.handshake = function(sessionId) { - // error to call this in non-client mode - if(c.entity !== tls.ConnectionEnd.client) { - // not fatal error - c.error(c, { - message: 'Cannot initiate handshake as a server.', - fatal: false - }); - } else if(c.handshaking) { - // handshake is already in progress, fail but not fatal error - c.error(c, { - message: 'Handshake already in progress.', - fatal: false - }); - } else { - // clear fail flag on reuse - if(c.fail && !c.open && c.handshakes === 0) { - c.fail = false; - } - - // now handshaking - c.handshaking = true; - - // default to blank (new session) - sessionId = sessionId || ''; - - // if a session ID was specified, try to find it in the cache - var session = null; - if(sessionId.length > 0) { - if(c.sessionCache) { - session = c.sessionCache.getSession(sessionId); - } - - // matching session not found in cache, clear session ID - if(session === null) { - sessionId = ''; - } - } - - // no session given, grab a session from the cache, if available - if(sessionId.length === 0 && c.sessionCache) { - session = c.sessionCache.getSession(); - if(session !== null) { - sessionId = session.id; - } - } - - // set up session - c.session = { - id: sessionId, - version: null, - cipherSuite: null, - compressionMethod: null, - serverCertificate: null, - certificateRequest: null, - clientCertificate: null, - sp: {}, - md5: forge.md.md5.create(), - sha1: forge.md.sha1.create() - }; - - // use existing session information - if(session) { - // only update version on connection, session version not yet set - c.version = session.version; - c.session.sp = session.sp; - } - - // generate new client random - c.session.sp.client_random = tls.createRandom().getBytes(); - - // connection now open - c.open = true; - - // send hello - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.handshake, - data: tls.createClientHello(c) - })); - tls.flush(c); - } - }; - - /** - * Called when TLS protocol data has been received from somewhere and should - * be processed by the TLS engine. - * - * @param data the TLS protocol data, as a string, to process. - * - * @return 0 if the data could be processed, otherwise the number of bytes - * required for data to be processed. - */ - c.process = function(data) { - var rval = 0; - - // buffer input data - if(data) { - c.input.putBytes(data); - } - - // process next record if no failure, process will be called after - // each record is handled (since handling can be asynchronous) - if(!c.fail) { - // reset record if ready and now empty - if(c.record !== null && - c.record.ready && c.record.fragment.isEmpty()) { - c.record = null; - } - - // if there is no pending record, try to read record header - if(c.record === null) { - rval = _readRecordHeader(c); - } - - // read the next record (if record not yet ready) - if(!c.fail && c.record !== null && !c.record.ready) { - rval = _readRecord(c); - } - - // record ready to be handled, update engine state - if(!c.fail && c.record !== null && c.record.ready) { - _update(c, c.record); - } - } - - return rval; - }; - - /** - * Requests that application data be packaged into a TLS record. The - * tlsDataReady handler will be called when the TLS record(s) have been - * prepared. - * - * @param data the application data, as a raw 'binary' encoded string, to - * be sent; to send utf-16/utf-8 string data, use the return value - * of util.encodeUtf8(str). - * - * @return true on success, false on failure. - */ - c.prepare = function(data) { - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.application_data, - data: forge.util.createBuffer(data) - })); - return tls.flush(c); - }; - - /** - * Requests that a heartbeat request be packaged into a TLS record for - * transmission. The tlsDataReady handler will be called when TLS record(s) - * have been prepared. - * - * When a heartbeat response has been received, the heartbeatReceived - * handler will be called with the matching payload. This handler can - * be used to clear a retransmission timer, etc. - * - * @param payload the heartbeat data to send as the payload in the message. - * @param [payloadLength] the payload length to use, defaults to the - * actual payload length. - * - * @return true on success, false on failure. - */ - c.prepareHeartbeatRequest = function(payload, payloadLength) { - if(payload instanceof forge.util.ByteBuffer) { - payload = payload.bytes(); - } - if(typeof payloadLength === 'undefined') { - payloadLength = payload.length; - } - c.expectedHeartbeatPayload = payload; - tls.queue(c, tls.createRecord(c, { - type: tls.ContentType.heartbeat, - data: tls.createHeartbeat( - tls.HeartbeatMessageType.heartbeat_request, payload, payloadLength) - })); - return tls.flush(c); - }; - - /** - * Closes the connection (sends a close_notify alert). - * - * @param clearFail true to clear the fail flag (default: true). - */ - c.close = function(clearFail) { - // save session if connection didn't fail - if(!c.fail && c.sessionCache && c.session) { - // only need to preserve session ID, version, and security params - var session = { - id: c.session.id, - version: c.session.version, - sp: c.session.sp - }; - session.sp.keys = null; - c.sessionCache.setSession(session.id, session); - } - - if(c.open) { - // connection no longer open, clear input - c.open = false; - c.input.clear(); - - // if connected or handshaking, send an alert - if(c.isConnected || c.handshaking) { - c.isConnected = c.handshaking = false; - - // send close_notify alert - tls.queue(c, tls.createAlert(c, { - level: tls.Alert.Level.warning, - description: tls.Alert.Description.close_notify - })); - tls.flush(c); - } - - // call handler - c.closed(c); - } - - // reset TLS connection, do not clear fail flag - c.reset(clearFail); - }; - - return c; - }; - - /* TLS API */ - var tls_1 = forge.tls = forge.tls || {}; - - // expose non-functions - for(var key in tls) { - if(typeof tls[key] !== 'function') { - forge.tls[key] = tls[key]; - } - } - - // expose prf_tls1 for testing - forge.tls.prf_tls1 = prf_TLS1; - - // expose sha1 hmac method - forge.tls.hmac_sha1 = hmac_sha1; - - // expose session cache creation - forge.tls.createSessionCache = tls.createSessionCache; - - /** - * Creates a new TLS connection. This does not make any assumptions about the - * transport layer that TLS is working on top of, ie: it does not assume there - * is a TCP/IP connection or establish one. A TLS connection is totally - * abstracted away from the layer is runs on top of, it merely establishes a - * secure channel between a client" and a "server". - * - * A TLS connection contains 4 connection states: pending read and write, and - * current read and write. - * - * At initialization, the current read and write states will be null. Only once - * the security parameters have been set and the keys have been generated can - * the pending states be converted into current states. Current states will be - * updated for each record processed. - * - * A custom certificate verify callback may be provided to check information - * like the common name on the server's certificate. It will be called for - * every certificate in the chain. It has the following signature: - * - * variable func(c, certs, index, preVerify) - * Where: - * c The TLS connection - * verified Set to true if certificate was verified, otherwise the alert - * tls.Alert.Description for why the certificate failed. - * depth The current index in the chain, where 0 is the server's cert. - * certs The certificate chain, *NOTE* if the server was anonymous then - * the chain will be empty. - * - * The function returns true on success and on failure either the appropriate - * tls.Alert.Description or an object with 'alert' set to the appropriate - * tls.Alert.Description and 'message' set to a custom error message. If true - * is not returned then the connection will abort using, in order of - * availability, first the returned alert description, second the preVerify - * alert description, and lastly the default 'bad_certificate'. - * - * There are three callbacks that can be used to make use of client-side - * certificates where each takes the TLS connection as the first parameter: - * - * getCertificate(conn, hint) - * The second parameter is a hint as to which certificate should be - * returned. If the connection entity is a client, then the hint will be - * the CertificateRequest message from the server that is part of the - * TLS protocol. If the connection entity is a server, then it will be - * the servername list provided via an SNI extension the ClientHello, if - * one was provided (empty array if not). The hint can be examined to - * determine which certificate to use (advanced). Most implementations - * will just return a certificate. The return value must be a - * PEM-formatted certificate or an array of PEM-formatted certificates - * that constitute a certificate chain, with the first in the array/chain - * being the client's certificate. - * getPrivateKey(conn, certificate) - * The second parameter is an forge.pki X.509 certificate object that - * is associated with the requested private key. The return value must - * be a PEM-formatted private key. - * getSignature(conn, bytes, callback) - * This callback can be used instead of getPrivateKey if the private key - * is not directly accessible in javascript or should not be. For - * instance, a secure external web service could provide the signature - * in exchange for appropriate credentials. The second parameter is a - * string of bytes to be signed that are part of the TLS protocol. These - * bytes are used to verify that the private key for the previously - * provided client-side certificate is accessible to the client. The - * callback is a function that takes 2 parameters, the TLS connection - * and the RSA encrypted (signed) bytes as a string. This callback must - * be called once the signature is ready. - * - * @param options the options for this connection: - * server: true if the connection is server-side, false for client. - * sessionId: a session ID to reuse, null for a new connection. - * caStore: an array of certificates to trust. - * sessionCache: a session cache to use. - * cipherSuites: an optional array of cipher suites to use, - * see tls.CipherSuites. - * connected: function(conn) called when the first handshake completes. - * virtualHost: the virtual server name to use in a TLS SNI extension. - * verifyClient: true to require a client certificate in server mode, - * 'optional' to request one, false not to (default: false). - * verify: a handler used to custom verify certificates in the chain. - * verifyOptions: an object with options for the certificate chain validation. - * See documentation of pki.verifyCertificateChain for possible options. - * verifyOptions.verify is ignored. If you wish to specify a verify handler - * use the verify key. - * getCertificate: an optional callback used to get a certificate or - * a chain of certificates (as an array). - * getPrivateKey: an optional callback used to get a private key. - * getSignature: an optional callback used to get a signature. - * tlsDataReady: function(conn) called when TLS protocol data has been - * prepared and is ready to be used (typically sent over a socket - * connection to its destination), read from conn.tlsData buffer. - * dataReady: function(conn) called when application data has - * been parsed from a TLS record and should be consumed by the - * application, read from conn.data buffer. - * closed: function(conn) called when the connection has been closed. - * error: function(conn, error) called when there was an error. - * deflate: function(inBytes) if provided, will deflate TLS records using - * the deflate algorithm if the server supports it. - * inflate: function(inBytes) if provided, will inflate TLS records using - * the deflate algorithm if the server supports it. - * - * @return the new TLS connection. - */ - forge.tls.createConnection = tls.createConnection; - - var aesCipherSuites = createCommonjsModule(function (module) { - /** - * A Javascript implementation of AES Cipher Suites for TLS. - * - * @author Dave Longley - * - * Copyright (c) 2009-2015 Digital Bazaar, Inc. - * - */ - - - - - var tls = module.exports = forge.tls; - - /** - * Supported cipher suites. - */ - tls.CipherSuites['TLS_RSA_WITH_AES_128_CBC_SHA'] = { - id: [0x00, 0x2f], - name: 'TLS_RSA_WITH_AES_128_CBC_SHA', - initSecurityParameters: function(sp) { - sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes; - sp.cipher_type = tls.CipherType.block; - sp.enc_key_length = 16; - sp.block_length = 16; - sp.fixed_iv_length = 16; - sp.record_iv_length = 16; - sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1; - sp.mac_length = 20; - sp.mac_key_length = 20; - }, - initConnectionState: initConnectionState - }; - tls.CipherSuites['TLS_RSA_WITH_AES_256_CBC_SHA'] = { - id: [0x00, 0x35], - name: 'TLS_RSA_WITH_AES_256_CBC_SHA', - initSecurityParameters: function(sp) { - sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes; - sp.cipher_type = tls.CipherType.block; - sp.enc_key_length = 32; - sp.block_length = 16; - sp.fixed_iv_length = 16; - sp.record_iv_length = 16; - sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1; - sp.mac_length = 20; - sp.mac_key_length = 20; - }, - initConnectionState: initConnectionState - }; - - function initConnectionState(state, c, sp) { - var client = (c.entity === forge.tls.ConnectionEnd.client); - - // cipher setup - state.read.cipherState = { - init: false, - cipher: forge.cipher.createDecipher('AES-CBC', client ? - sp.keys.server_write_key : sp.keys.client_write_key), - iv: client ? sp.keys.server_write_IV : sp.keys.client_write_IV - }; - state.write.cipherState = { - init: false, - cipher: forge.cipher.createCipher('AES-CBC', client ? - sp.keys.client_write_key : sp.keys.server_write_key), - iv: client ? sp.keys.client_write_IV : sp.keys.server_write_IV - }; - state.read.cipherFunction = decrypt_aes_cbc_sha1; - state.write.cipherFunction = encrypt_aes_cbc_sha1; - - // MAC setup - state.read.macLength = state.write.macLength = sp.mac_length; - state.read.macFunction = state.write.macFunction = tls.hmac_sha1; - } - - /** - * Encrypts the TLSCompressed record into a TLSCipherText record using AES - * in CBC mode. - * - * @param record the TLSCompressed record to encrypt. - * @param s the ConnectionState to use. - * - * @return true on success, false on failure. - */ - function encrypt_aes_cbc_sha1(record, s) { - var rval = false; - - // append MAC to fragment, update sequence number - var mac = s.macFunction(s.macKey, s.sequenceNumber, record); - record.fragment.putBytes(mac); - s.updateSequenceNumber(); - - // TLS 1.1+ use an explicit IV every time to protect against CBC attacks - var iv; - if(record.version.minor === tls.Versions.TLS_1_0.minor) { - // use the pre-generated IV when initializing for TLS 1.0, otherwise use - // the residue from the previous encryption - iv = s.cipherState.init ? null : s.cipherState.iv; - } else { - iv = forge.random.getBytesSync(16); - } - - s.cipherState.init = true; - - // start cipher - var cipher = s.cipherState.cipher; - cipher.start({iv: iv}); - - // TLS 1.1+ write IV into output - if(record.version.minor >= tls.Versions.TLS_1_1.minor) { - cipher.output.putBytes(iv); - } - - // do encryption (default padding is appropriate) - cipher.update(record.fragment); - if(cipher.finish(encrypt_aes_cbc_sha1_padding)) { - // set record fragment to encrypted output - record.fragment = cipher.output; - record.length = record.fragment.length(); - rval = true; - } - - return rval; - } - - /** - * Handles padding for aes_cbc_sha1 in encrypt mode. - * - * @param blockSize the block size. - * @param input the input buffer. - * @param decrypt true in decrypt mode, false in encrypt mode. - * - * @return true on success, false on failure. - */ - function encrypt_aes_cbc_sha1_padding(blockSize, input, decrypt) { - /* The encrypted data length (TLSCiphertext.length) is one more than the sum - of SecurityParameters.block_length, TLSCompressed.length, - SecurityParameters.mac_length, and padding_length. - - The padding may be any length up to 255 bytes long, as long as it results in - the TLSCiphertext.length being an integral multiple of the block length. - Lengths longer than necessary might be desirable to frustrate attacks on a - protocol based on analysis of the lengths of exchanged messages. Each uint8 - in the padding data vector must be filled with the padding length value. - - The padding length should be such that the total size of the - GenericBlockCipher structure is a multiple of the cipher's block length. - Legal values range from zero to 255, inclusive. This length specifies the - length of the padding field exclusive of the padding_length field itself. - - This is slightly different from PKCS#7 because the padding value is 1 - less than the actual number of padding bytes if you include the - padding_length uint8 itself as a padding byte. */ - if(!decrypt) { - // get the number of padding bytes required to reach the blockSize and - // subtract 1 for the padding value (to make room for the padding_length - // uint8) - var padding = blockSize - (input.length() % blockSize); - input.fillWithByte(padding - 1, padding); - } - return true; - } - - /** - * Handles padding for aes_cbc_sha1 in decrypt mode. - * - * @param blockSize the block size. - * @param output the output buffer. - * @param decrypt true in decrypt mode, false in encrypt mode. - * - * @return true on success, false on failure. - */ - function decrypt_aes_cbc_sha1_padding(blockSize, output, decrypt) { - var rval = true; - if(decrypt) { - /* The last byte in the output specifies the number of padding bytes not - including itself. Each of the padding bytes has the same value as that - last byte (known as the padding_length). Here we check all padding - bytes to ensure they have the value of padding_length even if one of - them is bad in order to ward-off timing attacks. */ - var len = output.length(); - var paddingLength = output.last(); - for(var i = len - 1 - paddingLength; i < len - 1; ++i) { - rval = rval && (output.at(i) == paddingLength); - } - if(rval) { - // trim off padding bytes and last padding length byte - output.truncate(paddingLength + 1); - } - } - return rval; - } - - /** - * Decrypts a TLSCipherText record into a TLSCompressed record using - * AES in CBC mode. - * - * @param record the TLSCipherText record to decrypt. - * @param s the ConnectionState to use. - * - * @return true on success, false on failure. - */ - function decrypt_aes_cbc_sha1(record, s) { - var rval = false; - - var iv; - if(record.version.minor === tls.Versions.TLS_1_0.minor) { - // use pre-generated IV when initializing for TLS 1.0, otherwise use the - // residue from the previous decryption - iv = s.cipherState.init ? null : s.cipherState.iv; - } else { - // TLS 1.1+ use an explicit IV every time to protect against CBC attacks - // that is appended to the record fragment - iv = record.fragment.getBytes(16); - } - - s.cipherState.init = true; - - // start cipher - var cipher = s.cipherState.cipher; - cipher.start({iv: iv}); - - // do decryption - cipher.update(record.fragment); - rval = cipher.finish(decrypt_aes_cbc_sha1_padding); - - // even if decryption fails, keep going to minimize timing attacks - - // decrypted data: - // first (len - 20) bytes = application data - // last 20 bytes = MAC - var macLen = s.macLength; - - // create a random MAC to check against should the mac length check fail - // Note: do this regardless of the failure to keep timing consistent - var mac = forge.random.getBytesSync(macLen); - - // get fragment and mac - var len = cipher.output.length(); - if(len >= macLen) { - record.fragment = cipher.output.getBytes(len - macLen); - mac = cipher.output.getBytes(macLen); - } else { - // bad data, but get bytes anyway to try to keep timing consistent - record.fragment = cipher.output.getBytes(); - } - record.fragment = forge.util.createBuffer(record.fragment); - record.length = record.fragment.length(); - - // see if data integrity checks out, update sequence number - var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record); - s.updateSequenceNumber(); - rval = compareMacs(s.macKey, mac, mac2) && rval; - return rval; - } - - /** - * Safely compare two MACs. This function will compare two MACs in a way - * that protects against timing attacks. - * - * TODO: Expose elsewhere as a utility API. - * - * See: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ - * - * @param key the MAC key to use. - * @param mac1 as a binary-encoded string of bytes. - * @param mac2 as a binary-encoded string of bytes. - * - * @return true if the MACs are the same, false if not. - */ - function compareMacs(key, mac1, mac2) { - var hmac = forge.hmac.create(); - - hmac.start('SHA1', key); - hmac.update(mac1); - mac1 = hmac.digest().getBytes(); - - hmac.start(null, null); - hmac.update(mac2); - mac2 = hmac.digest().getBytes(); - - return mac1 === mac2; - } - }); - - /** - * Debugging support for web applications. - * - * @author David I. Lehn - * - * Copyright 2008-2013 Digital Bazaar, Inc. - */ - - - /* DEBUG API */ - var debug = forge.debug = forge.debug || {}; - - // Private storage for debugging. - // Useful to expose data that is otherwise unviewable behind closures. - // NOTE: remember that this can hold references to data and cause leaks! - // format is "forge._debug.. = data" - // Example: - // (function() { - // var cat = 'forge.test.Test'; // debugging category - // var sState = {...}; // local state - // forge.debug.set(cat, 'sState', sState); - // })(); - forge.debug.storage = {}; - - /** - * Gets debug data. Omit name for all cat data Omit name and cat for - * all data. - * - * @param cat name of debugging category. - * @param name name of data to get (optional). - * @return object with requested debug data or undefined. - */ - forge.debug.get = function(cat, name) { - var rval; - if(typeof(cat) === 'undefined') { - rval = forge.debug.storage; - } else if(cat in forge.debug.storage) { - if(typeof(name) === 'undefined') { - rval = forge.debug.storage[cat]; - } else { - rval = forge.debug.storage[cat][name]; - } - } - return rval; - }; - - /** - * Sets debug data. - * - * @param cat name of debugging category. - * @param name name of data to set. - * @param data data to set. - */ - forge.debug.set = function(cat, name, data) { - if(!(cat in forge.debug.storage)) { - forge.debug.storage[cat] = {}; - } - forge.debug.storage[cat][name] = data; - }; - - /** - * Clears debug data. Omit name for all cat data. Omit name and cat for - * all data. - * - * @param cat name of debugging category. - * @param name name of data to clear or omit to clear entire category. - */ - forge.debug.clear = function(cat, name) { - if(typeof(cat) === 'undefined') { - forge.debug.storage = {}; - } else if(cat in forge.debug.storage) { - if(typeof(name) === 'undefined') { - delete forge.debug.storage[cat]; - } else { - delete forge.debug.storage[cat][name]; - } - } - }; - - var sha512_1 = createCommonjsModule(function (module) { - /** - * Secure Hash Algorithm with a 1024-bit block size implementation. - * - * This includes: SHA-512, SHA-384, SHA-512/224, and SHA-512/256. For - * SHA-256 (block size 512 bits), see sha256.js. - * - * See FIPS 180-4 for details. - * - * @author Dave Longley - * - * Copyright (c) 2014-2015 Digital Bazaar, Inc. - */ - - - - - var sha512 = module.exports = forge.sha512 = forge.sha512 || {}; - - // SHA-512 - forge.md.sha512 = forge.md.algorithms.sha512 = sha512; - - // SHA-384 - var sha384 = forge.sha384 = forge.sha512.sha384 = forge.sha512.sha384 || {}; - sha384.create = function() { - return sha512.create('SHA-384'); - }; - forge.md.sha384 = forge.md.algorithms.sha384 = sha384; - - // SHA-512/256 - forge.sha512.sha256 = forge.sha512.sha256 || { - create: function() { - return sha512.create('SHA-512/256'); - } - }; - forge.md['sha512/256'] = forge.md.algorithms['sha512/256'] = - forge.sha512.sha256; - - // SHA-512/224 - forge.sha512.sha224 = forge.sha512.sha224 || { - create: function() { - return sha512.create('SHA-512/224'); - } - }; - forge.md['sha512/224'] = forge.md.algorithms['sha512/224'] = - forge.sha512.sha224; - - /** - * Creates a SHA-2 message digest object. - * - * @param algorithm the algorithm to use (SHA-512, SHA-384, SHA-512/224, - * SHA-512/256). - * - * @return a message digest object. - */ - sha512.create = function(algorithm) { - // do initialization as necessary - if(!_initialized) { - _init(); - } - - if(typeof algorithm === 'undefined') { - algorithm = 'SHA-512'; - } - - if(!(algorithm in _states)) { - throw new Error('Invalid SHA-512 algorithm: ' + algorithm); - } - - // SHA-512 state contains eight 64-bit integers (each as two 32-bit ints) - var _state = _states[algorithm]; - var _h = null; - - // input buffer - var _input = forge.util.createBuffer(); - - // used for 64-bit word storage - var _w = new Array(80); - for(var wi = 0; wi < 80; ++wi) { - _w[wi] = new Array(2); - } - - // determine digest length by algorithm name (default) - var digestLength = 64; - switch(algorithm) { - case 'SHA-384': - digestLength = 48; - break; - case 'SHA-512/256': - digestLength = 32; - break; - case 'SHA-512/224': - digestLength = 28; - break; - } - - // message digest object - var md = { - // SHA-512 => sha512 - algorithm: algorithm.replace('-', '').toLowerCase(), - blockLength: 128, - digestLength: digestLength, - // 56-bit length of message so far (does not including padding) - messageLength: 0, - // true message length - fullMessageLength: null, - // size of message length in bytes - messageLengthSize: 16 - }; - - /** - * Starts the digest. - * - * @return this digest object. - */ - md.start = function() { - // up to 56-bit message length for convenience - md.messageLength = 0; - - // full message length (set md.messageLength128 for backwards-compatibility) - md.fullMessageLength = md.messageLength128 = []; - var int32s = md.messageLengthSize / 4; - for(var i = 0; i < int32s; ++i) { - md.fullMessageLength.push(0); - } - _input = forge.util.createBuffer(); - _h = new Array(_state.length); - for(var i = 0; i < _state.length; ++i) { - _h[i] = _state[i].slice(0); - } - return md; - }; - // start digest automatically for first time - md.start(); - - /** - * Updates the digest with the given message input. The given input can - * treated as raw input (no encoding will be applied) or an encoding of - * 'utf8' maybe given to encode the input using UTF-8. - * - * @param msg the message input to update with. - * @param encoding the encoding to use (default: 'raw', other: 'utf8'). - * - * @return this digest object. - */ - md.update = function(msg, encoding) { - if(encoding === 'utf8') { - msg = forge.util.encodeUtf8(msg); - } - - // update message length - var len = msg.length; - md.messageLength += len; - len = [(len / 0x100000000) >>> 0, len >>> 0]; - for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { - md.fullMessageLength[i] += len[1]; - len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); - md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; - len[0] = ((len[1] / 0x100000000) >>> 0); - } - - // add bytes to input buffer - _input.putBytes(msg); - - // process bytes - _update(_h, _w, _input); - - // compact input buffer every 2K or if empty - if(_input.read > 2048 || _input.length() === 0) { - _input.compact(); - } - - return md; - }; - - /** - * Produces the digest. - * - * @return a byte buffer containing the digest value. - */ - md.digest = function() { - /* Note: Here we copy the remaining bytes in the input buffer and - add the appropriate SHA-512 padding. Then we do the final update - on a copy of the state so that if the user wants to get - intermediate digests they can do so. */ - - /* Determine the number of bytes that must be added to the message - to ensure its length is congruent to 896 mod 1024. In other words, - the data to be digested must be a multiple of 1024 bits (or 128 bytes). - This data includes the message, some padding, and the length of the - message. Since the length of the message will be encoded as 16 bytes (128 - bits), that means that the last segment of the data must have 112 bytes - (896 bits) of message and padding. Therefore, the length of the message - plus the padding must be congruent to 896 mod 1024 because - 1024 - 128 = 896. - - In order to fill up the message length it must be filled with - padding that begins with 1 bit followed by all 0 bits. Padding - must *always* be present, so if the message length is already - congruent to 896 mod 1024, then 1024 padding bits must be added. */ - - var finalBlock = forge.util.createBuffer(); - finalBlock.putBytes(_input.bytes()); - - // compute remaining size to be digested (include message length size) - var remaining = ( - md.fullMessageLength[md.fullMessageLength.length - 1] + - md.messageLengthSize); - - // add padding for overflow blockSize - overflow - // _padding starts with 1 byte with first bit is set (byte value 128), then - // there may be up to (blockSize - 1) other pad bytes - var overflow = remaining & (md.blockLength - 1); - finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); - - // serialize message length in bits in big-endian order; since length - // is stored in bytes we multiply by 8 and add carry from next int - var next, carry; - var bits = md.fullMessageLength[0] * 8; - for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { - next = md.fullMessageLength[i + 1] * 8; - carry = (next / 0x100000000) >>> 0; - bits += carry; - finalBlock.putInt32(bits >>> 0); - bits = next >>> 0; - } - finalBlock.putInt32(bits); - - var h = new Array(_h.length); - for(var i = 0; i < _h.length; ++i) { - h[i] = _h[i].slice(0); - } - _update(h, _w, finalBlock); - var rval = forge.util.createBuffer(); - var hlen; - if(algorithm === 'SHA-512') { - hlen = h.length; - } else if(algorithm === 'SHA-384') { - hlen = h.length - 2; - } else { - hlen = h.length - 4; - } - for(var i = 0; i < hlen; ++i) { - rval.putInt32(h[i][0]); - if(i !== hlen - 1 || algorithm !== 'SHA-512/224') { - rval.putInt32(h[i][1]); - } - } - return rval; - }; - - return md; - }; - - // sha-512 padding bytes not initialized yet - var _padding = null; - var _initialized = false; - - // table of constants - var _k = null; - - // initial hash states - var _states = null; - - /** - * Initializes the constant tables. - */ - function _init() { - // create padding - _padding = String.fromCharCode(128); - _padding += forge.util.fillString(String.fromCharCode(0x00), 128); - - // create K table for SHA-512 - _k = [ - [0x428a2f98, 0xd728ae22], [0x71374491, 0x23ef65cd], - [0xb5c0fbcf, 0xec4d3b2f], [0xe9b5dba5, 0x8189dbbc], - [0x3956c25b, 0xf348b538], [0x59f111f1, 0xb605d019], - [0x923f82a4, 0xaf194f9b], [0xab1c5ed5, 0xda6d8118], - [0xd807aa98, 0xa3030242], [0x12835b01, 0x45706fbe], - [0x243185be, 0x4ee4b28c], [0x550c7dc3, 0xd5ffb4e2], - [0x72be5d74, 0xf27b896f], [0x80deb1fe, 0x3b1696b1], - [0x9bdc06a7, 0x25c71235], [0xc19bf174, 0xcf692694], - [0xe49b69c1, 0x9ef14ad2], [0xefbe4786, 0x384f25e3], - [0x0fc19dc6, 0x8b8cd5b5], [0x240ca1cc, 0x77ac9c65], - [0x2de92c6f, 0x592b0275], [0x4a7484aa, 0x6ea6e483], - [0x5cb0a9dc, 0xbd41fbd4], [0x76f988da, 0x831153b5], - [0x983e5152, 0xee66dfab], [0xa831c66d, 0x2db43210], - [0xb00327c8, 0x98fb213f], [0xbf597fc7, 0xbeef0ee4], - [0xc6e00bf3, 0x3da88fc2], [0xd5a79147, 0x930aa725], - [0x06ca6351, 0xe003826f], [0x14292967, 0x0a0e6e70], - [0x27b70a85, 0x46d22ffc], [0x2e1b2138, 0x5c26c926], - [0x4d2c6dfc, 0x5ac42aed], [0x53380d13, 0x9d95b3df], - [0x650a7354, 0x8baf63de], [0x766a0abb, 0x3c77b2a8], - [0x81c2c92e, 0x47edaee6], [0x92722c85, 0x1482353b], - [0xa2bfe8a1, 0x4cf10364], [0xa81a664b, 0xbc423001], - [0xc24b8b70, 0xd0f89791], [0xc76c51a3, 0x0654be30], - [0xd192e819, 0xd6ef5218], [0xd6990624, 0x5565a910], - [0xf40e3585, 0x5771202a], [0x106aa070, 0x32bbd1b8], - [0x19a4c116, 0xb8d2d0c8], [0x1e376c08, 0x5141ab53], - [0x2748774c, 0xdf8eeb99], [0x34b0bcb5, 0xe19b48a8], - [0x391c0cb3, 0xc5c95a63], [0x4ed8aa4a, 0xe3418acb], - [0x5b9cca4f, 0x7763e373], [0x682e6ff3, 0xd6b2b8a3], - [0x748f82ee, 0x5defb2fc], [0x78a5636f, 0x43172f60], - [0x84c87814, 0xa1f0ab72], [0x8cc70208, 0x1a6439ec], - [0x90befffa, 0x23631e28], [0xa4506ceb, 0xde82bde9], - [0xbef9a3f7, 0xb2c67915], [0xc67178f2, 0xe372532b], - [0xca273ece, 0xea26619c], [0xd186b8c7, 0x21c0c207], - [0xeada7dd6, 0xcde0eb1e], [0xf57d4f7f, 0xee6ed178], - [0x06f067aa, 0x72176fba], [0x0a637dc5, 0xa2c898a6], - [0x113f9804, 0xbef90dae], [0x1b710b35, 0x131c471b], - [0x28db77f5, 0x23047d84], [0x32caab7b, 0x40c72493], - [0x3c9ebe0a, 0x15c9bebc], [0x431d67c4, 0x9c100d4c], - [0x4cc5d4be, 0xcb3e42b6], [0x597f299c, 0xfc657e2a], - [0x5fcb6fab, 0x3ad6faec], [0x6c44198c, 0x4a475817] - ]; - - // initial hash states - _states = {}; - _states['SHA-512'] = [ - [0x6a09e667, 0xf3bcc908], - [0xbb67ae85, 0x84caa73b], - [0x3c6ef372, 0xfe94f82b], - [0xa54ff53a, 0x5f1d36f1], - [0x510e527f, 0xade682d1], - [0x9b05688c, 0x2b3e6c1f], - [0x1f83d9ab, 0xfb41bd6b], - [0x5be0cd19, 0x137e2179] - ]; - _states['SHA-384'] = [ - [0xcbbb9d5d, 0xc1059ed8], - [0x629a292a, 0x367cd507], - [0x9159015a, 0x3070dd17], - [0x152fecd8, 0xf70e5939], - [0x67332667, 0xffc00b31], - [0x8eb44a87, 0x68581511], - [0xdb0c2e0d, 0x64f98fa7], - [0x47b5481d, 0xbefa4fa4] - ]; - _states['SHA-512/256'] = [ - [0x22312194, 0xFC2BF72C], - [0x9F555FA3, 0xC84C64C2], - [0x2393B86B, 0x6F53B151], - [0x96387719, 0x5940EABD], - [0x96283EE2, 0xA88EFFE3], - [0xBE5E1E25, 0x53863992], - [0x2B0199FC, 0x2C85B8AA], - [0x0EB72DDC, 0x81C52CA2] - ]; - _states['SHA-512/224'] = [ - [0x8C3D37C8, 0x19544DA2], - [0x73E19966, 0x89DCD4D6], - [0x1DFAB7AE, 0x32FF9C82], - [0x679DD514, 0x582F9FCF], - [0x0F6D2B69, 0x7BD44DA8], - [0x77E36F73, 0x04C48942], - [0x3F9D85A8, 0x6A1D36C8], - [0x1112E6AD, 0x91D692A1] - ]; - - // now initialized - _initialized = true; - } - - /** - * Updates a SHA-512 state with the given byte buffer. - * - * @param s the SHA-512 state to update. - * @param w the array to use to store words. - * @param bytes the byte buffer to update with. - */ - function _update(s, w, bytes) { - // consume 512 bit (128 byte) chunks - var t1_hi, t1_lo; - var t2_hi, t2_lo; - var s0_hi, s0_lo; - var s1_hi, s1_lo; - var ch_hi, ch_lo; - var maj_hi, maj_lo; - var a_hi, a_lo; - var b_hi, b_lo; - var c_hi, c_lo; - var d_hi, d_lo; - var e_hi, e_lo; - var f_hi, f_lo; - var g_hi, g_lo; - var h_hi, h_lo; - var i, hi, lo, w2, w7, w15, w16; - var len = bytes.length(); - while(len >= 128) { - // the w array will be populated with sixteen 64-bit big-endian words - // and then extended into 64 64-bit words according to SHA-512 - for(i = 0; i < 16; ++i) { - w[i][0] = bytes.getInt32() >>> 0; - w[i][1] = bytes.getInt32() >>> 0; - } - for(; i < 80; ++i) { - // for word 2 words ago: ROTR 19(x) ^ ROTR 61(x) ^ SHR 6(x) - w2 = w[i - 2]; - hi = w2[0]; - lo = w2[1]; - - // high bits - t1_hi = ( - ((hi >>> 19) | (lo << 13)) ^ // ROTR 19 - ((lo >>> 29) | (hi << 3)) ^ // ROTR 61/(swap + ROTR 29) - (hi >>> 6)) >>> 0; // SHR 6 - // low bits - t1_lo = ( - ((hi << 13) | (lo >>> 19)) ^ // ROTR 19 - ((lo << 3) | (hi >>> 29)) ^ // ROTR 61/(swap + ROTR 29) - ((hi << 26) | (lo >>> 6))) >>> 0; // SHR 6 - - // for word 15 words ago: ROTR 1(x) ^ ROTR 8(x) ^ SHR 7(x) - w15 = w[i - 15]; - hi = w15[0]; - lo = w15[1]; - - // high bits - t2_hi = ( - ((hi >>> 1) | (lo << 31)) ^ // ROTR 1 - ((hi >>> 8) | (lo << 24)) ^ // ROTR 8 - (hi >>> 7)) >>> 0; // SHR 7 - // low bits - t2_lo = ( - ((hi << 31) | (lo >>> 1)) ^ // ROTR 1 - ((hi << 24) | (lo >>> 8)) ^ // ROTR 8 - ((hi << 25) | (lo >>> 7))) >>> 0; // SHR 7 - - // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^64 (carry lo overflow) - w7 = w[i - 7]; - w16 = w[i - 16]; - lo = (t1_lo + w7[1] + t2_lo + w16[1]); - w[i][0] = (t1_hi + w7[0] + t2_hi + w16[0] + - ((lo / 0x100000000) >>> 0)) >>> 0; - w[i][1] = lo >>> 0; - } - - // initialize hash value for this chunk - a_hi = s[0][0]; - a_lo = s[0][1]; - b_hi = s[1][0]; - b_lo = s[1][1]; - c_hi = s[2][0]; - c_lo = s[2][1]; - d_hi = s[3][0]; - d_lo = s[3][1]; - e_hi = s[4][0]; - e_lo = s[4][1]; - f_hi = s[5][0]; - f_lo = s[5][1]; - g_hi = s[6][0]; - g_lo = s[6][1]; - h_hi = s[7][0]; - h_lo = s[7][1]; - - // round function - for(i = 0; i < 80; ++i) { - // Sum1(e) = ROTR 14(e) ^ ROTR 18(e) ^ ROTR 41(e) - s1_hi = ( - ((e_hi >>> 14) | (e_lo << 18)) ^ // ROTR 14 - ((e_hi >>> 18) | (e_lo << 14)) ^ // ROTR 18 - ((e_lo >>> 9) | (e_hi << 23))) >>> 0; // ROTR 41/(swap + ROTR 9) - s1_lo = ( - ((e_hi << 18) | (e_lo >>> 14)) ^ // ROTR 14 - ((e_hi << 14) | (e_lo >>> 18)) ^ // ROTR 18 - ((e_lo << 23) | (e_hi >>> 9))) >>> 0; // ROTR 41/(swap + ROTR 9) - - // Ch(e, f, g) (optimized the same way as SHA-1) - ch_hi = (g_hi ^ (e_hi & (f_hi ^ g_hi))) >>> 0; - ch_lo = (g_lo ^ (e_lo & (f_lo ^ g_lo))) >>> 0; - - // Sum0(a) = ROTR 28(a) ^ ROTR 34(a) ^ ROTR 39(a) - s0_hi = ( - ((a_hi >>> 28) | (a_lo << 4)) ^ // ROTR 28 - ((a_lo >>> 2) | (a_hi << 30)) ^ // ROTR 34/(swap + ROTR 2) - ((a_lo >>> 7) | (a_hi << 25))) >>> 0; // ROTR 39/(swap + ROTR 7) - s0_lo = ( - ((a_hi << 4) | (a_lo >>> 28)) ^ // ROTR 28 - ((a_lo << 30) | (a_hi >>> 2)) ^ // ROTR 34/(swap + ROTR 2) - ((a_lo << 25) | (a_hi >>> 7))) >>> 0; // ROTR 39/(swap + ROTR 7) - - // Maj(a, b, c) (optimized the same way as SHA-1) - maj_hi = ((a_hi & b_hi) | (c_hi & (a_hi ^ b_hi))) >>> 0; - maj_lo = ((a_lo & b_lo) | (c_lo & (a_lo ^ b_lo))) >>> 0; - - // main algorithm - // t1 = (h + s1 + ch + _k[i] + _w[i]) modulo 2^64 (carry lo overflow) - lo = (h_lo + s1_lo + ch_lo + _k[i][1] + w[i][1]); - t1_hi = (h_hi + s1_hi + ch_hi + _k[i][0] + w[i][0] + - ((lo / 0x100000000) >>> 0)) >>> 0; - t1_lo = lo >>> 0; - - // t2 = s0 + maj modulo 2^64 (carry lo overflow) - lo = s0_lo + maj_lo; - t2_hi = (s0_hi + maj_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - t2_lo = lo >>> 0; - - h_hi = g_hi; - h_lo = g_lo; - - g_hi = f_hi; - g_lo = f_lo; - - f_hi = e_hi; - f_lo = e_lo; - - // e = (d + t1) modulo 2^64 (carry lo overflow) - lo = d_lo + t1_lo; - e_hi = (d_hi + t1_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - e_lo = lo >>> 0; - - d_hi = c_hi; - d_lo = c_lo; - - c_hi = b_hi; - c_lo = b_lo; - - b_hi = a_hi; - b_lo = a_lo; - - // a = (t1 + t2) modulo 2^64 (carry lo overflow) - lo = t1_lo + t2_lo; - a_hi = (t1_hi + t2_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - a_lo = lo >>> 0; - } - - // update hash state (additional modulo 2^64) - lo = s[0][1] + a_lo; - s[0][0] = (s[0][0] + a_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[0][1] = lo >>> 0; - - lo = s[1][1] + b_lo; - s[1][0] = (s[1][0] + b_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[1][1] = lo >>> 0; - - lo = s[2][1] + c_lo; - s[2][0] = (s[2][0] + c_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[2][1] = lo >>> 0; - - lo = s[3][1] + d_lo; - s[3][0] = (s[3][0] + d_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[3][1] = lo >>> 0; - - lo = s[4][1] + e_lo; - s[4][0] = (s[4][0] + e_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[4][1] = lo >>> 0; - - lo = s[5][1] + f_lo; - s[5][0] = (s[5][0] + f_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[5][1] = lo >>> 0; - - lo = s[6][1] + g_lo; - s[6][0] = (s[6][0] + g_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[6][1] = lo >>> 0; - - lo = s[7][1] + h_lo; - s[7][0] = (s[7][0] + h_hi + ((lo / 0x100000000) >>> 0)) >>> 0; - s[7][1] = lo >>> 0; - - len -= 128; - } - } - }); - - /** - * Copyright (c) 2019 Digital Bazaar, Inc. - */ - - - - var asn1$2 = forge.asn1; - - var privateKeyValidator$1 = { - // PrivateKeyInfo - name: 'PrivateKeyInfo', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.SEQUENCE, - constructed: true, - value: [{ - // Version (INTEGER) - name: 'PrivateKeyInfo.version', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.INTEGER, - constructed: false, - capture: 'privateKeyVersion' - }, { - // privateKeyAlgorithm - name: 'PrivateKeyInfo.privateKeyAlgorithm', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'AlgorithmIdentifier.algorithm', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.OID, - constructed: false, - capture: 'privateKeyOid' - }] - }, { - // PrivateKey - name: 'PrivateKeyInfo', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.OCTETSTRING, - constructed: false, - capture: 'privateKey' - }] - }; - - var publicKeyValidator$1 = { - name: 'SubjectPublicKeyInfo', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.SEQUENCE, - constructed: true, - captureAsn1: 'subjectPublicKeyInfo', - value: [{ - name: 'SubjectPublicKeyInfo.AlgorithmIdentifier', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.SEQUENCE, - constructed: true, - value: [{ - name: 'AlgorithmIdentifier.algorithm', - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.OID, - constructed: false, - capture: 'publicKeyOid' - }] - }, - // capture group for ed25519PublicKey - { - tagClass: asn1$2.Class.UNIVERSAL, - type: asn1$2.Type.BITSTRING, - constructed: false, - composed: true, - captureBitStringValue: 'ed25519PublicKey' - } - // FIXME: this is capture group for rsaPublicKey, use it in this API or - // discard? - /* { - // subjectPublicKey - name: 'SubjectPublicKeyInfo.subjectPublicKey', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.BITSTRING, - constructed: false, - value: [{ - // RSAPublicKey - name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey', - tagClass: asn1.Class.UNIVERSAL, - type: asn1.Type.SEQUENCE, - constructed: true, - optional: true, - captureAsn1: 'rsaPublicKey' - }] - } */ - ] - }; - - var asn1Validator = { - privateKeyValidator: privateKeyValidator$1, - publicKeyValidator: publicKeyValidator$1 - }; - - /** - * JavaScript implementation of Ed25519. - * - * Copyright (c) 2017-2019 Digital Bazaar, Inc. - * - * This implementation is based on the most excellent TweetNaCl which is - * in the public domain. Many thanks to its contributors: - * - * https://github.com/dchest/tweetnacl-js - */ - - - - - - - var publicKeyValidator$2 = asn1Validator.publicKeyValidator; - var privateKeyValidator$2 = asn1Validator.privateKeyValidator; - - if(typeof BigInteger$4 === 'undefined') { - var BigInteger$4 = forge.jsbn.BigInteger; - } - - var ByteBuffer = forge.util.ByteBuffer; - var NativeBuffer = typeof Buffer === 'undefined' ? Uint8Array : Buffer; - - /* - * Ed25519 algorithms, see RFC 8032: - * https://tools.ietf.org/html/rfc8032 - */ - forge.pki = forge.pki || {}; - var ed25519_1 = forge.pki.ed25519 = forge.ed25519 = forge.ed25519 || {}; - var ed25519 = forge.ed25519; - - ed25519.constants = {}; - ed25519.constants.PUBLIC_KEY_BYTE_LENGTH = 32; - ed25519.constants.PRIVATE_KEY_BYTE_LENGTH = 64; - ed25519.constants.SEED_BYTE_LENGTH = 32; - ed25519.constants.SIGN_BYTE_LENGTH = 64; - ed25519.constants.HASH_BYTE_LENGTH = 64; - - ed25519.generateKeyPair = function(options) { - options = options || {}; - var seed = options.seed; - if(seed === undefined) { - // generate seed - seed = forge.random.getBytesSync(ed25519.constants.SEED_BYTE_LENGTH); - } else if(typeof seed === 'string') { - if(seed.length !== ed25519.constants.SEED_BYTE_LENGTH) { - throw new TypeError( - '"seed" must be ' + ed25519.constants.SEED_BYTE_LENGTH + - ' bytes in length.'); - } - } else if(!(seed instanceof Uint8Array)) { - throw new TypeError( - '"seed" must be a node.js Buffer, Uint8Array, or a binary string.'); - } - - seed = messageToNativeBuffer({message: seed, encoding: 'binary'}); - - var pk = new NativeBuffer(ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); - var sk = new NativeBuffer(ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); - for(var i = 0; i < 32; ++i) { - sk[i] = seed[i]; - } - crypto_sign_keypair(pk, sk); - return {publicKey: pk, privateKey: sk}; - }; - - /** - * Converts a private key from a RFC8410 ASN.1 encoding. - * - * @param obj - The asn1 representation of a private key. - * - * @returns {Object} keyInfo - The key information. - * @returns {Buffer|Uint8Array} keyInfo.privateKeyBytes - 32 private key bytes. - */ - ed25519.privateKeyFromAsn1 = function(obj) { - var capture = {}; - var errors = []; - var valid = forge.asn1.validate(obj, privateKeyValidator$2, capture, errors); - if(!valid) { - var error = new Error('Invalid Key.'); - error.errors = errors; - throw error; - } - var oid = forge.asn1.derToOid(capture.privateKeyOid); - var ed25519Oid = forge.oids.EdDSA25519; - if(oid !== ed25519Oid) { - throw new Error('Invalid OID "' + oid + '"; OID must be "' + - ed25519Oid + '".'); - } - var privateKey = capture.privateKey; - // manually extract the private key bytes from nested octet string, see FIXME: - // https://github.com/digitalbazaar/forge/blob/master/lib/asn1.js#L542 - var privateKeyBytes = messageToNativeBuffer({ - message: forge.asn1.fromDer(privateKey).value, - encoding: 'binary' - }); - // TODO: RFC8410 specifies a format for encoding the public key bytes along - // with the private key bytes. `publicKeyBytes` can be returned in the - // future. https://tools.ietf.org/html/rfc8410#section-10.3 - return {privateKeyBytes: privateKeyBytes}; - }; - - /** - * Converts a public key from a RFC8410 ASN.1 encoding. - * - * @param obj - The asn1 representation of a public key. - * - * @return {Buffer|Uint8Array} - 32 public key bytes. - */ - ed25519.publicKeyFromAsn1 = function(obj) { - // get SubjectPublicKeyInfo - var capture = {}; - var errors = []; - var valid = forge.asn1.validate(obj, publicKeyValidator$2, capture, errors); - if(!valid) { - var error = new Error('Invalid Key.'); - error.errors = errors; - throw error; - } - var oid = forge.asn1.derToOid(capture.publicKeyOid); - var ed25519Oid = forge.oids.EdDSA25519; - if(oid !== ed25519Oid) { - throw new Error('Invalid OID "' + oid + '"; OID must be "' + - ed25519Oid + '".'); - } - var publicKeyBytes = capture.ed25519PublicKey; - if(publicKeyBytes.length !== ed25519.constants.PUBLIC_KEY_BYTE_LENGTH) { - throw new Error('Key length is invalid.'); - } - return messageToNativeBuffer({ - message: publicKeyBytes, - encoding: 'binary' - }); - }; - - ed25519.publicKeyFromPrivateKey = function(options) { - options = options || {}; - var privateKey = messageToNativeBuffer({ - message: options.privateKey, encoding: 'binary' - }); - if(privateKey.length !== ed25519.constants.PRIVATE_KEY_BYTE_LENGTH) { - throw new TypeError( - '"options.privateKey" must have a byte length of ' + - ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); - } - - var pk = new NativeBuffer(ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); - for(var i = 0; i < pk.length; ++i) { - pk[i] = privateKey[32 + i]; - } - return pk; - }; - - ed25519.sign = function(options) { - options = options || {}; - var msg = messageToNativeBuffer(options); - var privateKey = messageToNativeBuffer({ - message: options.privateKey, - encoding: 'binary' - }); - if(privateKey.length === ed25519.constants.SEED_BYTE_LENGTH) { - var keyPair = ed25519.generateKeyPair({seed: privateKey}); - privateKey = keyPair.privateKey; - } else if(privateKey.length !== ed25519.constants.PRIVATE_KEY_BYTE_LENGTH) { - throw new TypeError( - '"options.privateKey" must have a byte length of ' + - ed25519.constants.SEED_BYTE_LENGTH + ' or ' + - ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); - } - - var signedMsg = new NativeBuffer( - ed25519.constants.SIGN_BYTE_LENGTH + msg.length); - crypto_sign(signedMsg, msg, msg.length, privateKey); - - var sig = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH); - for(var i = 0; i < sig.length; ++i) { - sig[i] = signedMsg[i]; - } - return sig; - }; - - ed25519.verify = function(options) { - options = options || {}; - var msg = messageToNativeBuffer(options); - if(options.signature === undefined) { - throw new TypeError( - '"options.signature" must be a node.js Buffer, a Uint8Array, a forge ' + - 'ByteBuffer, or a binary string.'); - } - var sig = messageToNativeBuffer({ - message: options.signature, - encoding: 'binary' - }); - if(sig.length !== ed25519.constants.SIGN_BYTE_LENGTH) { - throw new TypeError( - '"options.signature" must have a byte length of ' + - ed25519.constants.SIGN_BYTE_LENGTH); - } - var publicKey = messageToNativeBuffer({ - message: options.publicKey, - encoding: 'binary' - }); - if(publicKey.length !== ed25519.constants.PUBLIC_KEY_BYTE_LENGTH) { - throw new TypeError( - '"options.publicKey" must have a byte length of ' + - ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); - } - - var sm = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH + msg.length); - var m = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH + msg.length); - var i; - for(i = 0; i < ed25519.constants.SIGN_BYTE_LENGTH; ++i) { - sm[i] = sig[i]; - } - for(i = 0; i < msg.length; ++i) { - sm[i + ed25519.constants.SIGN_BYTE_LENGTH] = msg[i]; - } - return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); - }; - - function messageToNativeBuffer(options) { - var message = options.message; - if(message instanceof Uint8Array || message instanceof NativeBuffer) { - return message; - } - - var encoding = options.encoding; - if(message === undefined) { - if(options.md) { - // TODO: more rigorous validation that `md` is a MessageDigest - message = options.md.digest().getBytes(); - encoding = 'binary'; - } else { - throw new TypeError('"options.message" or "options.md" not specified.'); - } - } - - if(typeof message === 'string' && !encoding) { - throw new TypeError('"options.encoding" must be "binary" or "utf8".'); - } - - if(typeof message === 'string') { - if(typeof Buffer !== 'undefined') { - return Buffer.from(message, encoding); - } - message = new ByteBuffer(message, encoding); - } else if(!(message instanceof ByteBuffer)) { - throw new TypeError( - '"options.message" must be a node.js Buffer, a Uint8Array, a forge ' + - 'ByteBuffer, or a string with "options.encoding" specifying its ' + - 'encoding.'); - } - - // convert to native buffer - var buffer = new NativeBuffer(message.length()); - for(var i = 0; i < buffer.length; ++i) { - buffer[i] = message.at(i); - } - return buffer; - } - - var gf0 = gf(); - var gf1 = gf([1]); - var D$1 = gf([ - 0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, - 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]); - var D2 = gf([ - 0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, - 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]); - var X = gf([ - 0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, - 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]); - var Y = gf([ - 0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, - 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]); - var L = new Float64Array([ - 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, - 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); - var I = gf([ - 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, - 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); - - // TODO: update forge buffer implementation to use `Buffer` or `Uint8Array`, - // whichever is available, to improve performance - function sha512(msg, msgLen) { - // Note: `out` and `msg` are NativeBuffer - var md = forge.md.sha512.create(); - var buffer = new ByteBuffer(msg); - md.update(buffer.getBytes(msgLen), 'binary'); - var hash = md.digest().getBytes(); - if(typeof Buffer !== 'undefined') { - return Buffer.from(hash, 'binary'); - } - var out = new NativeBuffer(ed25519.constants.HASH_BYTE_LENGTH); - for(var i = 0; i < 64; ++i) { - out[i] = hash.charCodeAt(i); - } - return out; - } - - function crypto_sign_keypair(pk, sk) { - var p = [gf(), gf(), gf(), gf()]; - var i; - - var d = sha512(sk, 32); - d[0] &= 248; - d[31] &= 127; - d[31] |= 64; - - scalarbase(p, d); - pack(pk, p); - - for(i = 0; i < 32; ++i) { - sk[i + 32] = pk[i]; - } - return 0; - } - - // Note: difference from C - smlen returned, not passed as argument. - function crypto_sign(sm, m, n, sk) { - var i, j, x = new Float64Array(64); - var p = [gf(), gf(), gf(), gf()]; - - var d = sha512(sk, 32); - d[0] &= 248; - d[31] &= 127; - d[31] |= 64; - - var smlen = n + 64; - for(i = 0; i < n; ++i) { - sm[64 + i] = m[i]; - } - for(i = 0; i < 32; ++i) { - sm[32 + i] = d[32 + i]; - } - - var r = sha512(sm.subarray(32), n + 32); - reduce(r); - scalarbase(p, r); - pack(sm, p); - - for(i = 32; i < 64; ++i) { - sm[i] = sk[i]; - } - var h = sha512(sm, n + 64); - reduce(h); - - for(i = 32; i < 64; ++i) { - x[i] = 0; - } - for(i = 0; i < 32; ++i) { - x[i] = r[i]; - } - for(i = 0; i < 32; ++i) { - for(j = 0; j < 32; j++) { - x[i + j] += h[i] * d[j]; - } - } - - modL(sm.subarray(32), x); - return smlen; - } - - function crypto_sign_open(m, sm, n, pk) { - var i, mlen; - var t = new NativeBuffer(32); - var p = [gf(), gf(), gf(), gf()], - q = [gf(), gf(), gf(), gf()]; - - mlen = -1; - if(n < 64) { - return -1; - } - - if(unpackneg(q, pk)) { - return -1; - } - - for(i = 0; i < n; ++i) { - m[i] = sm[i]; - } - for(i = 0; i < 32; ++i) { - m[i + 32] = pk[i]; - } - var h = sha512(m, n); - reduce(h); - scalarmult(p, q, h); - - scalarbase(q, sm.subarray(32)); - add(p, q); - pack(t, p); - - n -= 64; - if(crypto_verify_32(sm, 0, t, 0)) { - for(i = 0; i < n; ++i) { - m[i] = 0; - } - return -1; - } - - for(i = 0; i < n; ++i) { - m[i] = sm[i + 64]; - } - mlen = n; - return mlen; - } - - function modL(r, x) { - var carry, i, j, k; - for(i = 63; i >= 32; --i) { - carry = 0; - for(j = i - 32, k = i - 12; j < k; ++j) { - x[j] += carry - 16 * x[i] * L[j - (i - 32)]; - carry = (x[j] + 128) >> 8; - x[j] -= carry * 256; - } - x[j] += carry; - x[i] = 0; - } - carry = 0; - for(j = 0; j < 32; ++j) { - x[j] += carry - (x[31] >> 4) * L[j]; - carry = x[j] >> 8; - x[j] &= 255; - } - for(j = 0; j < 32; ++j) { - x[j] -= carry * L[j]; - } - for(i = 0; i < 32; ++i) { - x[i + 1] += x[i] >> 8; - r[i] = x[i] & 255; - } - } - - function reduce(r) { - var x = new Float64Array(64); - for(var i = 0; i < 64; ++i) { - x[i] = r[i]; - r[i] = 0; - } - modL(r, x); - } - - function add(p, q) { - var a = gf(), b = gf(), c = gf(), - d = gf(), e = gf(), f = gf(), - g = gf(), h = gf(), t = gf(); - - Z(a, p[1], p[0]); - Z(t, q[1], q[0]); - M(a, a, t); - A$1(b, p[0], p[1]); - A$1(t, q[0], q[1]); - M(b, b, t); - M(c, p[3], q[3]); - M(c, c, D2); - M(d, p[2], q[2]); - A$1(d, d, d); - Z(e, b, a); - Z(f, d, c); - A$1(g, d, c); - A$1(h, b, a); - - M(p[0], e, f); - M(p[1], h, g); - M(p[2], g, f); - M(p[3], e, h); - } - - function cswap(p, q, b) { - for(var i = 0; i < 4; ++i) { - sel25519(p[i], q[i], b); - } - } - - function pack(r, p) { - var tx = gf(), ty = gf(), zi = gf(); - inv25519(zi, p[2]); - M(tx, p[0], zi); - M(ty, p[1], zi); - pack25519(r, ty); - r[31] ^= par25519(tx) << 7; - } - - function pack25519(o, n) { - var i, j, b; - var m = gf(), t = gf(); - for(i = 0; i < 16; ++i) { - t[i] = n[i]; - } - car25519(t); - car25519(t); - car25519(t); - for(j = 0; j < 2; ++j) { - m[0] = t[0] - 0xffed; - for(i = 1; i < 15; ++i) { - m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); - m[i-1] &= 0xffff; - } - m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); - b = (m[15] >> 16) & 1; - m[14] &= 0xffff; - sel25519(t, m, 1 - b); - } - for (i = 0; i < 16; i++) { - o[2 * i] = t[i] & 0xff; - o[2 * i + 1] = t[i] >> 8; - } - } - - function unpackneg(r, p) { - var t = gf(), chk = gf(), num = gf(), - den = gf(), den2 = gf(), den4 = gf(), - den6 = gf(); - - set25519(r[2], gf1); - unpack25519(r[1], p); - S(num, r[1]); - M(den, num, D$1); - Z(num, num, r[2]); - A$1(den, r[2], den); - - S(den2, den); - S(den4, den2); - M(den6, den4, den2); - M(t, den6, num); - M(t, t, den); - - pow2523(t, t); - M(t, t, num); - M(t, t, den); - M(t, t, den); - M(r[0], t, den); - - S(chk, r[0]); - M(chk, chk, den); - if(neq25519(chk, num)) { - M(r[0], r[0], I); - } - - S(chk, r[0]); - M(chk, chk, den); - if(neq25519(chk, num)) { - return -1; - } - - if(par25519(r[0]) === (p[31] >> 7)) { - Z(r[0], gf0, r[0]); - } - - M(r[3], r[0], r[1]); - return 0; - } - - function unpack25519(o, n) { - var i; - for(i = 0; i < 16; ++i) { - o[i] = n[2 * i] + (n[2 * i + 1] << 8); - } - o[15] &= 0x7fff; - } - - function pow2523(o, i) { - var c = gf(); - var a; - for(a = 0; a < 16; ++a) { - c[a] = i[a]; - } - for(a = 250; a >= 0; --a) { - S(c, c); - if(a !== 1) { - M(c, c, i); - } - } - for(a = 0; a < 16; ++a) { - o[a] = c[a]; - } - } - - function neq25519(a, b) { - var c = new NativeBuffer(32); - var d = new NativeBuffer(32); - pack25519(c, a); - pack25519(d, b); - return crypto_verify_32(c, 0, d, 0); - } - - function crypto_verify_32(x, xi, y, yi) { - return vn(x, xi, y, yi, 32); - } - - function vn(x, xi, y, yi, n) { - var i, d = 0; - for(i = 0; i < n; ++i) { - d |= x[xi + i] ^ y[yi + i]; - } - return (1 & ((d - 1) >>> 8)) - 1; - } - - function par25519(a) { - var d = new NativeBuffer(32); - pack25519(d, a); - return d[0] & 1; - } - - function scalarmult(p, q, s) { - var b, i; - set25519(p[0], gf0); - set25519(p[1], gf1); - set25519(p[2], gf1); - set25519(p[3], gf0); - for(i = 255; i >= 0; --i) { - b = (s[(i / 8)|0] >> (i & 7)) & 1; - cswap(p, q, b); - add(q, p); - add(p, p); - cswap(p, q, b); - } - } - - function scalarbase(p, s) { - var q = [gf(), gf(), gf(), gf()]; - set25519(q[0], X); - set25519(q[1], Y); - set25519(q[2], gf1); - M(q[3], X, Y); - scalarmult(p, q, s); - } - - function set25519(r, a) { - var i; - for(i = 0; i < 16; i++) { - r[i] = a[i] | 0; - } - } - - function inv25519(o, i) { - var c = gf(); - var a; - for(a = 0; a < 16; ++a) { - c[a] = i[a]; - } - for(a = 253; a >= 0; --a) { - S(c, c); - if(a !== 2 && a !== 4) { - M(c, c, i); - } - } - for(a = 0; a < 16; ++a) { - o[a] = c[a]; - } - } - - function car25519(o) { - var i, v, c = 1; - for(i = 0; i < 16; ++i) { - v = o[i] + c + 65535; - c = Math.floor(v / 65536); - o[i] = v - c * 65536; - } - o[0] += c - 1 + 37 * (c - 1); - } - - function sel25519(p, q, b) { - var t, c = ~(b - 1); - for(var i = 0; i < 16; ++i) { - t = c & (p[i] ^ q[i]); - p[i] ^= t; - q[i] ^= t; - } - } - - function gf(init) { - var i, r = new Float64Array(16); - if(init) { - for(i = 0; i < init.length; ++i) { - r[i] = init[i]; - } - } - return r; - } - - function A$1(o, a, b) { - for(var i = 0; i < 16; ++i) { - o[i] = a[i] + b[i]; - } - } - - function Z(o, a, b) { - for(var i = 0; i < 16; ++i) { - o[i] = a[i] - b[i]; - } - } - - function S(o, a) { - M(o, a, a); - } - - function M(o, a, b) { - var v, c, - t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, - t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, - t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, - t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, - b0 = b[0], - b1 = b[1], - b2 = b[2], - b3 = b[3], - b4 = b[4], - b5 = b[5], - b6 = b[6], - b7 = b[7], - b8 = b[8], - b9 = b[9], - b10 = b[10], - b11 = b[11], - b12 = b[12], - b13 = b[13], - b14 = b[14], - b15 = b[15]; - - v = a[0]; - t0 += v * b0; - t1 += v * b1; - t2 += v * b2; - t3 += v * b3; - t4 += v * b4; - t5 += v * b5; - t6 += v * b6; - t7 += v * b7; - t8 += v * b8; - t9 += v * b9; - t10 += v * b10; - t11 += v * b11; - t12 += v * b12; - t13 += v * b13; - t14 += v * b14; - t15 += v * b15; - v = a[1]; - t1 += v * b0; - t2 += v * b1; - t3 += v * b2; - t4 += v * b3; - t5 += v * b4; - t6 += v * b5; - t7 += v * b6; - t8 += v * b7; - t9 += v * b8; - t10 += v * b9; - t11 += v * b10; - t12 += v * b11; - t13 += v * b12; - t14 += v * b13; - t15 += v * b14; - t16 += v * b15; - v = a[2]; - t2 += v * b0; - t3 += v * b1; - t4 += v * b2; - t5 += v * b3; - t6 += v * b4; - t7 += v * b5; - t8 += v * b6; - t9 += v * b7; - t10 += v * b8; - t11 += v * b9; - t12 += v * b10; - t13 += v * b11; - t14 += v * b12; - t15 += v * b13; - t16 += v * b14; - t17 += v * b15; - v = a[3]; - t3 += v * b0; - t4 += v * b1; - t5 += v * b2; - t6 += v * b3; - t7 += v * b4; - t8 += v * b5; - t9 += v * b6; - t10 += v * b7; - t11 += v * b8; - t12 += v * b9; - t13 += v * b10; - t14 += v * b11; - t15 += v * b12; - t16 += v * b13; - t17 += v * b14; - t18 += v * b15; - v = a[4]; - t4 += v * b0; - t5 += v * b1; - t6 += v * b2; - t7 += v * b3; - t8 += v * b4; - t9 += v * b5; - t10 += v * b6; - t11 += v * b7; - t12 += v * b8; - t13 += v * b9; - t14 += v * b10; - t15 += v * b11; - t16 += v * b12; - t17 += v * b13; - t18 += v * b14; - t19 += v * b15; - v = a[5]; - t5 += v * b0; - t6 += v * b1; - t7 += v * b2; - t8 += v * b3; - t9 += v * b4; - t10 += v * b5; - t11 += v * b6; - t12 += v * b7; - t13 += v * b8; - t14 += v * b9; - t15 += v * b10; - t16 += v * b11; - t17 += v * b12; - t18 += v * b13; - t19 += v * b14; - t20 += v * b15; - v = a[6]; - t6 += v * b0; - t7 += v * b1; - t8 += v * b2; - t9 += v * b3; - t10 += v * b4; - t11 += v * b5; - t12 += v * b6; - t13 += v * b7; - t14 += v * b8; - t15 += v * b9; - t16 += v * b10; - t17 += v * b11; - t18 += v * b12; - t19 += v * b13; - t20 += v * b14; - t21 += v * b15; - v = a[7]; - t7 += v * b0; - t8 += v * b1; - t9 += v * b2; - t10 += v * b3; - t11 += v * b4; - t12 += v * b5; - t13 += v * b6; - t14 += v * b7; - t15 += v * b8; - t16 += v * b9; - t17 += v * b10; - t18 += v * b11; - t19 += v * b12; - t20 += v * b13; - t21 += v * b14; - t22 += v * b15; - v = a[8]; - t8 += v * b0; - t9 += v * b1; - t10 += v * b2; - t11 += v * b3; - t12 += v * b4; - t13 += v * b5; - t14 += v * b6; - t15 += v * b7; - t16 += v * b8; - t17 += v * b9; - t18 += v * b10; - t19 += v * b11; - t20 += v * b12; - t21 += v * b13; - t22 += v * b14; - t23 += v * b15; - v = a[9]; - t9 += v * b0; - t10 += v * b1; - t11 += v * b2; - t12 += v * b3; - t13 += v * b4; - t14 += v * b5; - t15 += v * b6; - t16 += v * b7; - t17 += v * b8; - t18 += v * b9; - t19 += v * b10; - t20 += v * b11; - t21 += v * b12; - t22 += v * b13; - t23 += v * b14; - t24 += v * b15; - v = a[10]; - t10 += v * b0; - t11 += v * b1; - t12 += v * b2; - t13 += v * b3; - t14 += v * b4; - t15 += v * b5; - t16 += v * b6; - t17 += v * b7; - t18 += v * b8; - t19 += v * b9; - t20 += v * b10; - t21 += v * b11; - t22 += v * b12; - t23 += v * b13; - t24 += v * b14; - t25 += v * b15; - v = a[11]; - t11 += v * b0; - t12 += v * b1; - t13 += v * b2; - t14 += v * b3; - t15 += v * b4; - t16 += v * b5; - t17 += v * b6; - t18 += v * b7; - t19 += v * b8; - t20 += v * b9; - t21 += v * b10; - t22 += v * b11; - t23 += v * b12; - t24 += v * b13; - t25 += v * b14; - t26 += v * b15; - v = a[12]; - t12 += v * b0; - t13 += v * b1; - t14 += v * b2; - t15 += v * b3; - t16 += v * b4; - t17 += v * b5; - t18 += v * b6; - t19 += v * b7; - t20 += v * b8; - t21 += v * b9; - t22 += v * b10; - t23 += v * b11; - t24 += v * b12; - t25 += v * b13; - t26 += v * b14; - t27 += v * b15; - v = a[13]; - t13 += v * b0; - t14 += v * b1; - t15 += v * b2; - t16 += v * b3; - t17 += v * b4; - t18 += v * b5; - t19 += v * b6; - t20 += v * b7; - t21 += v * b8; - t22 += v * b9; - t23 += v * b10; - t24 += v * b11; - t25 += v * b12; - t26 += v * b13; - t27 += v * b14; - t28 += v * b15; - v = a[14]; - t14 += v * b0; - t15 += v * b1; - t16 += v * b2; - t17 += v * b3; - t18 += v * b4; - t19 += v * b5; - t20 += v * b6; - t21 += v * b7; - t22 += v * b8; - t23 += v * b9; - t24 += v * b10; - t25 += v * b11; - t26 += v * b12; - t27 += v * b13; - t28 += v * b14; - t29 += v * b15; - v = a[15]; - t15 += v * b0; - t16 += v * b1; - t17 += v * b2; - t18 += v * b3; - t19 += v * b4; - t20 += v * b5; - t21 += v * b6; - t22 += v * b7; - t23 += v * b8; - t24 += v * b9; - t25 += v * b10; - t26 += v * b11; - t27 += v * b12; - t28 += v * b13; - t29 += v * b14; - t30 += v * b15; - - t0 += 38 * t16; - t1 += 38 * t17; - t2 += 38 * t18; - t3 += 38 * t19; - t4 += 38 * t20; - t5 += 38 * t21; - t6 += 38 * t22; - t7 += 38 * t23; - t8 += 38 * t24; - t9 += 38 * t25; - t10 += 38 * t26; - t11 += 38 * t27; - t12 += 38 * t28; - t13 += 38 * t29; - t14 += 38 * t30; - // t15 left as is - - // first car - c = 1; - v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; - v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; - v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; - v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; - v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; - v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; - v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; - v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; - v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; - v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; - v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; - v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; - v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; - v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; - v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; - v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; - t0 += c-1 + 37 * (c-1); - - // second car - c = 1; - v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; - v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; - v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; - v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; - v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; - v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; - v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; - v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; - v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; - v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; - v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; - v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; - v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; - v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; - v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; - v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; - t0 += c-1 + 37 * (c-1); - - o[ 0] = t0; - o[ 1] = t1; - o[ 2] = t2; - o[ 3] = t3; - o[ 4] = t4; - o[ 5] = t5; - o[ 6] = t6; - o[ 7] = t7; - o[ 8] = t8; - o[ 9] = t9; - o[10] = t10; - o[11] = t11; - o[12] = t12; - o[13] = t13; - o[14] = t14; - o[15] = t15; - } - - /** - * Javascript implementation of RSA-KEM. - * - * @author Lautaro Cozzani Rodriguez - * @author Dave Longley - * - * Copyright (c) 2014 Lautaro Cozzani - * Copyright (c) 2014 Digital Bazaar, Inc. - */ - - - - - - var kem = forge.kem = forge.kem || {}; - - var BigInteger$5 = forge.jsbn.BigInteger; - - /** - * The API for the RSA Key Encapsulation Mechanism (RSA-KEM) from ISO 18033-2. - */ - forge.kem.rsa = {}; - - /** - * Creates an RSA KEM API object for generating a secret asymmetric key. - * - * The symmetric key may be generated via a call to 'encrypt', which will - * produce a ciphertext to be transmitted to the recipient and a key to be - * kept secret. The ciphertext is a parameter to be passed to 'decrypt' which - * will produce the same secret key for the recipient to use to decrypt a - * message that was encrypted with the secret key. - * - * @param kdf the KDF API to use (eg: new forge.kem.kdf1()). - * @param options the options to use. - * [prng] a custom crypto-secure pseudo-random number generator to use, - * that must define "getBytesSync". - */ - forge.kem.rsa.create = function(kdf, options) { - options = options || {}; - var prng = options.prng || forge.random; - - var kem = {}; - - /** - * Generates a secret key and its encapsulation. - * - * @param publicKey the RSA public key to encrypt with. - * @param keyLength the length, in bytes, of the secret key to generate. - * - * @return an object with: - * encapsulation: the ciphertext for generating the secret key, as a - * binary-encoded string of bytes. - * key: the secret key to use for encrypting a message. - */ - kem.encrypt = function(publicKey, keyLength) { - // generate a random r where 1 < r < n - var byteLength = Math.ceil(publicKey.n.bitLength() / 8); - var r; - do { - r = new BigInteger$5( - forge.util.bytesToHex(prng.getBytesSync(byteLength)), - 16).mod(publicKey.n); - } while(r.compareTo(BigInteger$5.ONE) <= 0); - - // prepend r with zeros - r = forge.util.hexToBytes(r.toString(16)); - var zeros = byteLength - r.length; - if(zeros > 0) { - r = forge.util.fillString(String.fromCharCode(0), zeros) + r; - } - - // encrypt the random - var encapsulation = publicKey.encrypt(r, 'NONE'); - - // generate the secret key - var key = kdf.generate(r, keyLength); - - return {encapsulation: encapsulation, key: key}; - }; - - /** - * Decrypts an encapsulated secret key. - * - * @param privateKey the RSA private key to decrypt with. - * @param encapsulation the ciphertext for generating the secret key, as - * a binary-encoded string of bytes. - * @param keyLength the length, in bytes, of the secret key to generate. - * - * @return the secret key as a binary-encoded string of bytes. - */ - kem.decrypt = function(privateKey, encapsulation, keyLength) { - // decrypt the encapsulation and generate the secret key - var r = privateKey.decrypt(encapsulation, 'NONE'); - return kdf.generate(r, keyLength); - }; - - return kem; - }; - - // TODO: add forge.kem.kdf.create('KDF1', {md: ..., ...}) API? - - /** - * Creates a key derivation API object that implements KDF1 per ISO 18033-2. - * - * @param md the hash API to use. - * @param [digestLength] an optional digest length that must be positive and - * less than or equal to md.digestLength. - * - * @return a KDF1 API object. - */ - forge.kem.kdf1 = function(md, digestLength) { - _createKDF(this, md, 0, digestLength || md.digestLength); - }; - - /** - * Creates a key derivation API object that implements KDF2 per ISO 18033-2. - * - * @param md the hash API to use. - * @param [digestLength] an optional digest length that must be positive and - * less than or equal to md.digestLength. - * - * @return a KDF2 API object. - */ - forge.kem.kdf2 = function(md, digestLength) { - _createKDF(this, md, 1, digestLength || md.digestLength); - }; - - /** - * Creates a KDF1 or KDF2 API object. - * - * @param md the hash API to use. - * @param counterStart the starting index for the counter. - * @param digestLength the digest length to use. - * - * @return the KDF API object. - */ - function _createKDF(kdf, md, counterStart, digestLength) { - /** - * Generate a key of the specified length. - * - * @param x the binary-encoded byte string to generate a key from. - * @param length the number of bytes to generate (the size of the key). - * - * @return the key as a binary-encoded string. - */ - kdf.generate = function(x, length) { - var key = new forge.util.ByteBuffer(); - - // run counter from counterStart to ceil(length / Hash.len) - var k = Math.ceil(length / digestLength) + counterStart; - - var c = new forge.util.ByteBuffer(); - for(var i = counterStart; i < k; ++i) { - // I2OSP(i, 4): convert counter to an octet string of 4 octets - c.putInt32(i); - - // digest 'x' and the counter and add the result to the key - md.start(); - md.update(x + c.getBytes()); - var hash = md.digest(); - key.putBytes(hash.getBytes(digestLength)); - } - - // truncate to the correct key length - key.truncate(key.length() - length); - return key.getBytes(); - }; - } - - /** - * Cross-browser support for logging in a web application. - * - * @author David I. Lehn - * - * Copyright (c) 2008-2013 Digital Bazaar, Inc. - */ - - - - /* LOG API */ - var log = forge.log = forge.log || {}; - - /** - * Application logging system. - * - * Each logger level available as it's own function of the form: - * forge.log.level(category, args...) - * The category is an arbitrary string, and the args are the same as - * Firebug's console.log API. By default the call will be output as: - * 'LEVEL [category] , args[1], ...' - * This enables proper % formatting via the first argument. - * Each category is enabled by default but can be enabled or disabled with - * the setCategoryEnabled() function. - */ - // list of known levels - forge.log.levels = [ - 'none', 'error', 'warning', 'info', 'debug', 'verbose', 'max']; - // info on the levels indexed by name: - // index: level index - // name: uppercased display name - var sLevelInfo = {}; - // list of loggers - var sLoggers = []; - /** - * Standard console logger. If no console support is enabled this will - * remain null. Check before using. - */ - var sConsoleLogger = null; - - // logger flags - /** - * Lock the level at the current value. Used in cases where user config may - * set the level such that only critical messages are seen but more verbose - * messages are needed for debugging or other purposes. - */ - forge.log.LEVEL_LOCKED = (1 << 1); - /** - * Always call log function. By default, the logging system will check the - * message level against logger.level before calling the log function. This - * flag allows the function to do its own check. - */ - forge.log.NO_LEVEL_CHECK = (1 << 2); - /** - * Perform message interpolation with the passed arguments. "%" style - * fields in log messages will be replaced by arguments as needed. Some - * loggers, such as Firebug, may do this automatically. The original log - * message will be available as 'message' and the interpolated version will - * be available as 'fullMessage'. - */ - forge.log.INTERPOLATE = (1 << 3); - - // setup each log level - for(var i = 0; i < forge.log.levels.length; ++i) { - var level = forge.log.levels[i]; - sLevelInfo[level] = { - index: i, - name: level.toUpperCase() - }; - } - - /** - * Message logger. Will dispatch a message to registered loggers as needed. - * - * @param message message object - */ - forge.log.logMessage = function(message) { - var messageLevelIndex = sLevelInfo[message.level].index; - for(var i = 0; i < sLoggers.length; ++i) { - var logger = sLoggers[i]; - if(logger.flags & forge.log.NO_LEVEL_CHECK) { - logger.f(message); - } else { - // get logger level - var loggerLevelIndex = sLevelInfo[logger.level].index; - // check level - if(messageLevelIndex <= loggerLevelIndex) { - // message critical enough, call logger - logger.f(logger, message); - } - } - } - }; - - /** - * Sets the 'standard' key on a message object to: - * "LEVEL [category] " + message - * - * @param message a message log object - */ - forge.log.prepareStandard = function(message) { - if(!('standard' in message)) { - message.standard = - sLevelInfo[message.level].name + - //' ' + +message.timestamp + - ' [' + message.category + '] ' + - message.message; - } - }; - - /** - * Sets the 'full' key on a message object to the original message - * interpolated via % formatting with the message arguments. - * - * @param message a message log object. - */ - forge.log.prepareFull = function(message) { - if(!('full' in message)) { - // copy args and insert message at the front - var args = [message.message]; - args = args.concat([] || message['arguments']); - // format the message - message.full = forge.util.format.apply(this, args); - } - }; - - /** - * Applies both preparseStandard() and prepareFull() to a message object and - * store result in 'standardFull'. - * - * @param message a message log object. - */ - forge.log.prepareStandardFull = function(message) { - if(!('standardFull' in message)) { - // FIXME implement 'standardFull' logging - forge.log.prepareStandard(message); - message.standardFull = message.standard; - } - }; - - // create log level functions - { - // levels for which we want functions - var levels = ['error', 'warning', 'info', 'debug', 'verbose']; - for(var i = 0; i < levels.length; ++i) { - // wrap in a function to ensure proper level var is passed - (function(level) { - // create function for this level - forge.log[level] = function(category, message/*, args...*/) { - // convert arguments to real array, remove category and message - var args = Array.prototype.slice.call(arguments).slice(2); - // create message object - // Note: interpolation and standard formatting is done lazily - var msg = { - timestamp: new Date(), - level: level, - category: category, - message: message, - 'arguments': args - /*standard*/ - /*full*/ - /*fullMessage*/ - }; - // process this message - forge.log.logMessage(msg); - }; - })(levels[i]); - } - } - - /** - * Creates a new logger with specified custom logging function. - * - * The logging function has a signature of: - * function(logger, message) - * logger: current logger - * message: object: - * level: level id - * category: category - * message: string message - * arguments: Array of extra arguments - * fullMessage: interpolated message and arguments if INTERPOLATE flag set - * - * @param logFunction a logging function which takes a log message object - * as a parameter. - * - * @return a logger object. - */ - forge.log.makeLogger = function(logFunction) { - var logger = { - flags: 0, - f: logFunction - }; - forge.log.setLevel(logger, 'none'); - return logger; - }; - - /** - * Sets the current log level on a logger. - * - * @param logger the target logger. - * @param level the new maximum log level as a string. - * - * @return true if set, false if not. - */ - forge.log.setLevel = function(logger, level) { - var rval = false; - if(logger && !(logger.flags & forge.log.LEVEL_LOCKED)) { - for(var i = 0; i < forge.log.levels.length; ++i) { - var aValidLevel = forge.log.levels[i]; - if(level == aValidLevel) { - // set level - logger.level = level; - rval = true; - break; - } - } - } - - return rval; - }; - - /** - * Locks the log level at its current value. - * - * @param logger the target logger. - * @param lock boolean lock value, default to true. - */ - forge.log.lock = function(logger, lock) { - if(typeof lock === 'undefined' || lock) { - logger.flags |= forge.log.LEVEL_LOCKED; - } else { - logger.flags &= ~forge.log.LEVEL_LOCKED; - } - }; - - /** - * Adds a logger. - * - * @param logger the logger object. - */ - forge.log.addLogger = function(logger) { - sLoggers.push(logger); - }; - - // setup the console logger if possible, else create fake console.log - if(typeof(console) !== 'undefined' && 'log' in console) { - var logger; - if(console.error && console.warn && console.info && console.debug) { - // looks like Firebug-style logging is available - // level handlers map - var levelHandlers = { - error: console.error, - warning: console.warn, - info: console.info, - debug: console.debug, - verbose: console.debug - }; - var f = function(logger, message) { - forge.log.prepareStandard(message); - var handler = levelHandlers[message.level]; - // prepend standard message and concat args - var args = [message.standard]; - args = args.concat(message['arguments'].slice()); - // apply to low-level console function - handler.apply(console, args); - }; - logger = forge.log.makeLogger(f); - } else { - // only appear to have basic console.log - var f = function(logger, message) { - forge.log.prepareStandardFull(message); - console.log(message.standardFull); - }; - logger = forge.log.makeLogger(f); - } - forge.log.setLevel(logger, 'debug'); - forge.log.addLogger(logger); - sConsoleLogger = logger; - } else { - // define fake console.log to avoid potential script errors on - // browsers that do not have console logging - console = { - log: function() {} - }; - } - - /* - * Check for logging control query vars. - * - * console.level= - * Set's the console log level by name. Useful to override defaults and - * allow more verbose logging before a user config is loaded. - * - * console.lock= - * Lock the console log level at whatever level it is set at. This is run - * after console.level is processed. Useful to force a level of verbosity - * that could otherwise be limited by a user config. - */ - if(sConsoleLogger !== null) { - var query = forge.util.getQueryVariables(); - if('console.level' in query) { - // set with last value - forge.log.setLevel( - sConsoleLogger, query['console.level'].slice(-1)[0]); - } - if('console.lock' in query) { - // set with last value - var lock = query['console.lock'].slice(-1)[0]; - if(lock == 'true') { - forge.log.lock(sConsoleLogger); - } - } - } - - // provide public access to console logger - forge.log.consoleLogger = sConsoleLogger; - - var pkcs7 = createCommonjsModule(function (module) { - /** - * Javascript implementation of PKCS#7 v1.5. - * - * @author Stefan Siegl - * @author Dave Longley - * - * Copyright (c) 2012 Stefan Siegl - * Copyright (c) 2012-2015 Digital Bazaar, Inc. - * - * Currently this implementation only supports ContentType of EnvelopedData, - * EncryptedData, or SignedData at the root level. The top level elements may - * contain only a ContentInfo of ContentType Data, i.e. plain data. Further - * nesting is not (yet) supported. - * - * The Forge validators for PKCS #7's ASN.1 structures are available from - * a separate file pkcs7asn1.js, since those are referenced from other - * PKCS standards like PKCS #12. - */ - - - - - - - - - - - - // shortcut for ASN.1 API - var asn1 = forge.asn1; - - // shortcut for PKCS#7 API - var p7 = module.exports = forge.pkcs7 = forge.pkcs7 || {}; - - /** - * Converts a PKCS#7 message from PEM format. - * - * @param pem the PEM-formatted PKCS#7 message. - * - * @return the PKCS#7 message. - */ - p7.messageFromPem = function(pem) { - var msg = forge.pem.decode(pem)[0]; - - if(msg.type !== 'PKCS7') { - var error = new Error('Could not convert PKCS#7 message from PEM; PEM ' + - 'header type is not "PKCS#7".'); - error.headerType = msg.type; - throw error; - } - if(msg.procType && msg.procType.type === 'ENCRYPTED') { - throw new Error('Could not convert PKCS#7 message from PEM; PEM is encrypted.'); - } - - // convert DER to ASN.1 object - var obj = asn1.fromDer(msg.body); - - return p7.messageFromAsn1(obj); - }; - - /** - * Converts a PKCS#7 message to PEM format. - * - * @param msg The PKCS#7 message object - * @param maxline The maximum characters per line, defaults to 64. - * - * @return The PEM-formatted PKCS#7 message. - */ - p7.messageToPem = function(msg, maxline) { - // convert to ASN.1, then DER, then PEM-encode - var pemObj = { - type: 'PKCS7', - body: asn1.toDer(msg.toAsn1()).getBytes() - }; - return forge.pem.encode(pemObj, {maxline: maxline}); - }; - - /** - * Converts a PKCS#7 message from an ASN.1 object. - * - * @param obj the ASN.1 representation of a ContentInfo. - * - * @return the PKCS#7 message. - */ - p7.messageFromAsn1 = function(obj) { - // validate root level ContentInfo and capture data - var capture = {}; - var errors = []; - if(!asn1.validate(obj, p7.asn1.contentInfoValidator, capture, errors)) { - var error = new Error('Cannot read PKCS#7 message. ' + - 'ASN.1 object is not an PKCS#7 ContentInfo.'); - error.errors = errors; - throw error; - } - - var contentType = asn1.derToOid(capture.contentType); - var msg; - - switch(contentType) { - case forge.pki.oids.envelopedData: - msg = p7.createEnvelopedData(); - break; - - case forge.pki.oids.encryptedData: - msg = p7.createEncryptedData(); - break; - - case forge.pki.oids.signedData: - msg = p7.createSignedData(); - break; - - default: - throw new Error('Cannot read PKCS#7 message. ContentType with OID ' + - contentType + ' is not (yet) supported.'); - } - - msg.fromAsn1(capture.content.value[0]); - return msg; - }; - - p7.createSignedData = function() { - var msg = null; - msg = { - type: forge.pki.oids.signedData, - version: 1, - certificates: [], - crls: [], - // TODO: add json-formatted signer stuff here? - signers: [], - // populated during sign() - digestAlgorithmIdentifiers: [], - contentInfo: null, - signerInfos: [], - - fromAsn1: function(obj) { - // validate SignedData content block and capture data. - _fromAsn1(msg, obj, p7.asn1.signedDataValidator); - msg.certificates = []; - msg.crls = []; - msg.digestAlgorithmIdentifiers = []; - msg.contentInfo = null; - msg.signerInfos = []; - - if(msg.rawCapture.certificates) { - var certs = msg.rawCapture.certificates.value; - for(var i = 0; i < certs.length; ++i) { - msg.certificates.push(forge.pki.certificateFromAsn1(certs[i])); - } - } - - // TODO: parse crls - }, - - toAsn1: function() { - // degenerate case with no content - if(!msg.contentInfo) { - msg.sign(); - } - - var certs = []; - for(var i = 0; i < msg.certificates.length; ++i) { - certs.push(forge.pki.certificateToAsn1(msg.certificates[i])); - } - - var crls = []; - // TODO: implement CRLs - - // [0] SignedData - var signedData = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // Version - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(msg.version).getBytes()), - // DigestAlgorithmIdentifiers - asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SET, true, - msg.digestAlgorithmIdentifiers), - // ContentInfo - msg.contentInfo - ]) - ]); - if(certs.length > 0) { - // [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL - signedData.value[0].value.push( - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, certs)); - } - if(crls.length > 0) { - // [1] IMPLICIT CertificateRevocationLists OPTIONAL - signedData.value[0].value.push( - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, crls)); - } - // SignerInfos - signedData.value[0].value.push( - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, - msg.signerInfos)); - - // ContentInfo - return asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // ContentType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(msg.type).getBytes()), - // [0] SignedData - signedData - ]); - }, - - /** - * Add (another) entity to list of signers. - * - * Note: If authenticatedAttributes are provided, then, per RFC 2315, - * they must include at least two attributes: content type and - * message digest. The message digest attribute value will be - * auto-calculated during signing and will be ignored if provided. - * - * Here's an example of providing these two attributes: - * - * forge.pkcs7.createSignedData(); - * p7.addSigner({ - * issuer: cert.issuer.attributes, - * serialNumber: cert.serialNumber, - * key: privateKey, - * digestAlgorithm: forge.pki.oids.sha1, - * authenticatedAttributes: [{ - * type: forge.pki.oids.contentType, - * value: forge.pki.oids.data - * }, { - * type: forge.pki.oids.messageDigest - * }] - * }); - * - * TODO: Support [subjectKeyIdentifier] as signer's ID. - * - * @param signer the signer information: - * key the signer's private key. - * [certificate] a certificate containing the public key - * associated with the signer's private key; use this option as - * an alternative to specifying signer.issuer and - * signer.serialNumber. - * [issuer] the issuer attributes (eg: cert.issuer.attributes). - * [serialNumber] the signer's certificate's serial number in - * hexadecimal (eg: cert.serialNumber). - * [digestAlgorithm] the message digest OID, as a string, to use - * (eg: forge.pki.oids.sha1). - * [authenticatedAttributes] an optional array of attributes - * to also sign along with the content. - */ - addSigner: function(signer) { - var issuer = signer.issuer; - var serialNumber = signer.serialNumber; - if(signer.certificate) { - var cert = signer.certificate; - if(typeof cert === 'string') { - cert = forge.pki.certificateFromPem(cert); - } - issuer = cert.issuer.attributes; - serialNumber = cert.serialNumber; - } - var key = signer.key; - if(!key) { - throw new Error( - 'Could not add PKCS#7 signer; no private key specified.'); - } - if(typeof key === 'string') { - key = forge.pki.privateKeyFromPem(key); - } - - // ensure OID known for digest algorithm - var digestAlgorithm = signer.digestAlgorithm || forge.pki.oids.sha1; - switch(digestAlgorithm) { - case forge.pki.oids.sha1: - case forge.pki.oids.sha256: - case forge.pki.oids.sha384: - case forge.pki.oids.sha512: - case forge.pki.oids.md5: - break; - default: - throw new Error( - 'Could not add PKCS#7 signer; unknown message digest algorithm: ' + - digestAlgorithm); - } - - // if authenticatedAttributes is present, then the attributes - // must contain at least PKCS #9 content-type and message-digest - var authenticatedAttributes = signer.authenticatedAttributes || []; - if(authenticatedAttributes.length > 0) { - var contentType = false; - var messageDigest = false; - for(var i = 0; i < authenticatedAttributes.length; ++i) { - var attr = authenticatedAttributes[i]; - if(!contentType && attr.type === forge.pki.oids.contentType) { - contentType = true; - if(messageDigest) { - break; - } - continue; - } - if(!messageDigest && attr.type === forge.pki.oids.messageDigest) { - messageDigest = true; - if(contentType) { - break; - } - continue; - } - } - - if(!contentType || !messageDigest) { - throw new Error('Invalid signer.authenticatedAttributes. If ' + - 'signer.authenticatedAttributes is specified, then it must ' + - 'contain at least two attributes, PKCS #9 content-type and ' + - 'PKCS #9 message-digest.'); - } - } - - msg.signers.push({ - key: key, - version: 1, - issuer: issuer, - serialNumber: serialNumber, - digestAlgorithm: digestAlgorithm, - signatureAlgorithm: forge.pki.oids.rsaEncryption, - signature: null, - authenticatedAttributes: authenticatedAttributes, - unauthenticatedAttributes: [] - }); - }, - - /** - * Signs the content. - * @param options Options to apply when signing: - * [detached] boolean. If signing should be done in detached mode. Defaults to false. - */ - sign: function(options) { - options = options || {}; - // auto-generate content info - if(typeof msg.content !== 'object' || msg.contentInfo === null) { - // use Data ContentInfo - msg.contentInfo = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // ContentType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(forge.pki.oids.data).getBytes()) - ]); - - // add actual content, if present - if('content' in msg) { - var content; - if(msg.content instanceof forge.util.ByteBuffer) { - content = msg.content.bytes(); - } else if(typeof msg.content === 'string') { - content = forge.util.encodeUtf8(msg.content); - } - - if (options.detached) { - msg.detachedContent = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, content); - } else { - msg.contentInfo.value.push( - // [0] EXPLICIT content - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - content) - ])); - } - } - } - - // no signers, return early (degenerate case for certificate container) - if(msg.signers.length === 0) { - return; - } - - // generate digest algorithm identifiers - var mds = addDigestAlgorithmIds(); - - // generate signerInfos - addSignerInfos(mds); - }, - - verify: function() { - throw new Error('PKCS#7 signature verification not yet implemented.'); - }, - - /** - * Add a certificate. - * - * @param cert the certificate to add. - */ - addCertificate: function(cert) { - // convert from PEM - if(typeof cert === 'string') { - cert = forge.pki.certificateFromPem(cert); - } - msg.certificates.push(cert); - }, - - /** - * Add a certificate revokation list. - * - * @param crl the certificate revokation list to add. - */ - addCertificateRevokationList: function(crl) { - throw new Error('PKCS#7 CRL support not yet implemented.'); - } - }; - return msg; - - function addDigestAlgorithmIds() { - var mds = {}; - - for(var i = 0; i < msg.signers.length; ++i) { - var signer = msg.signers[i]; - var oid = signer.digestAlgorithm; - if(!(oid in mds)) { - // content digest - mds[oid] = forge.md[forge.pki.oids[oid]].create(); - } - if(signer.authenticatedAttributes.length === 0) { - // no custom attributes to digest; use content message digest - signer.md = mds[oid]; - } else { - // custom attributes to be digested; use own message digest - // TODO: optimize to just copy message digest state if that - // feature is ever supported with message digests - signer.md = forge.md[forge.pki.oids[oid]].create(); - } - } - - // add unique digest algorithm identifiers - msg.digestAlgorithmIdentifiers = []; - for(var oid in mds) { - msg.digestAlgorithmIdentifiers.push( - // AlgorithmIdentifier - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(oid).getBytes()), - // parameters (null) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ])); - } - - return mds; - } - - function addSignerInfos(mds) { - var content; - - if (msg.detachedContent) { - // Signature has been made in detached mode. - content = msg.detachedContent; - } else { - // Note: ContentInfo is a SEQUENCE with 2 values, second value is - // the content field and is optional for a ContentInfo but required here - // since signers are present - // get ContentInfo content - content = msg.contentInfo.value[1]; - // skip [0] EXPLICIT content wrapper - content = content.value[0]; - } - - if(!content) { - throw new Error( - 'Could not sign PKCS#7 message; there is no content to sign.'); - } - - // get ContentInfo content type - var contentType = asn1.derToOid(msg.contentInfo.value[0].value); - - // serialize content - var bytes = asn1.toDer(content); - - // skip identifier and length per RFC 2315 9.3 - // skip identifier (1 byte) - bytes.getByte(); - // read and discard length bytes - asn1.getBerValueLength(bytes); - bytes = bytes.getBytes(); - - // digest content DER value bytes - for(var oid in mds) { - mds[oid].start().update(bytes); - } - - // sign content - var signingTime = new Date(); - for(var i = 0; i < msg.signers.length; ++i) { - var signer = msg.signers[i]; - - if(signer.authenticatedAttributes.length === 0) { - // if ContentInfo content type is not "Data", then - // authenticatedAttributes must be present per RFC 2315 - if(contentType !== forge.pki.oids.data) { - throw new Error( - 'Invalid signer; authenticatedAttributes must be present ' + - 'when the ContentInfo content type is not PKCS#7 Data.'); - } - } else { - // process authenticated attributes - // [0] IMPLICIT - signer.authenticatedAttributesAsn1 = asn1.create( - asn1.Class.CONTEXT_SPECIFIC, 0, true, []); - - // per RFC 2315, attributes are to be digested using a SET container - // not the above [0] IMPLICIT container - var attrsAsn1 = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.SET, true, []); - - for(var ai = 0; ai < signer.authenticatedAttributes.length; ++ai) { - var attr = signer.authenticatedAttributes[ai]; - if(attr.type === forge.pki.oids.messageDigest) { - // use content message digest as value - attr.value = mds[signer.digestAlgorithm].digest(); - } else if(attr.type === forge.pki.oids.signingTime) { - // auto-populate signing time if not already set - if(!attr.value) { - attr.value = signingTime; - } - } - - // convert to ASN.1 and push onto Attributes SET (for signing) and - // onto authenticatedAttributesAsn1 to complete SignedData ASN.1 - // TODO: optimize away duplication - attrsAsn1.value.push(_attributeToAsn1(attr)); - signer.authenticatedAttributesAsn1.value.push(_attributeToAsn1(attr)); - } - - // DER-serialize and digest SET OF attributes only - bytes = asn1.toDer(attrsAsn1).getBytes(); - signer.md.start().update(bytes); - } - - // sign digest - signer.signature = signer.key.sign(signer.md, 'RSASSA-PKCS1-V1_5'); - } - - // add signer info - msg.signerInfos = _signersToAsn1(msg.signers); - } - }; - - /** - * Creates an empty PKCS#7 message of type EncryptedData. - * - * @return the message. - */ - p7.createEncryptedData = function() { - var msg = null; - msg = { - type: forge.pki.oids.encryptedData, - version: 0, - encryptedContent: { - algorithm: forge.pki.oids['aes256-CBC'] - }, - - /** - * Reads an EncryptedData content block (in ASN.1 format) - * - * @param obj The ASN.1 representation of the EncryptedData content block - */ - fromAsn1: function(obj) { - // Validate EncryptedData content block and capture data. - _fromAsn1(msg, obj, p7.asn1.encryptedDataValidator); - }, - - /** - * Decrypt encrypted content - * - * @param key The (symmetric) key as a byte buffer - */ - decrypt: function(key) { - if(key !== undefined) { - msg.encryptedContent.key = key; - } - _decryptContent(msg); - } - }; - return msg; - }; - - /** - * Creates an empty PKCS#7 message of type EnvelopedData. - * - * @return the message. - */ - p7.createEnvelopedData = function() { - var msg = null; - msg = { - type: forge.pki.oids.envelopedData, - version: 0, - recipients: [], - encryptedContent: { - algorithm: forge.pki.oids['aes256-CBC'] - }, - - /** - * Reads an EnvelopedData content block (in ASN.1 format) - * - * @param obj the ASN.1 representation of the EnvelopedData content block. - */ - fromAsn1: function(obj) { - // validate EnvelopedData content block and capture data - var capture = _fromAsn1(msg, obj, p7.asn1.envelopedDataValidator); - msg.recipients = _recipientsFromAsn1(capture.recipientInfos.value); - }, - - toAsn1: function() { - // ContentInfo - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // ContentType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(msg.type).getBytes()), - // [0] EnvelopedData - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // Version - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(msg.version).getBytes()), - // RecipientInfos - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, - _recipientsToAsn1(msg.recipients)), - // EncryptedContentInfo - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, - _encryptedContentToAsn1(msg.encryptedContent)) - ]) - ]) - ]); - }, - - /** - * Find recipient by X.509 certificate's issuer. - * - * @param cert the certificate with the issuer to look for. - * - * @return the recipient object. - */ - findRecipient: function(cert) { - var sAttr = cert.issuer.attributes; - - for(var i = 0; i < msg.recipients.length; ++i) { - var r = msg.recipients[i]; - var rAttr = r.issuer; - - if(r.serialNumber !== cert.serialNumber) { - continue; - } - - if(rAttr.length !== sAttr.length) { - continue; - } - - var match = true; - for(var j = 0; j < sAttr.length; ++j) { - if(rAttr[j].type !== sAttr[j].type || - rAttr[j].value !== sAttr[j].value) { - match = false; - break; - } - } - - if(match) { - return r; - } - } - - return null; - }, - - /** - * Decrypt enveloped content - * - * @param recipient The recipient object related to the private key - * @param privKey The (RSA) private key object - */ - decrypt: function(recipient, privKey) { - if(msg.encryptedContent.key === undefined && recipient !== undefined && - privKey !== undefined) { - switch(recipient.encryptedContent.algorithm) { - case forge.pki.oids.rsaEncryption: - case forge.pki.oids.desCBC: - var key = privKey.decrypt(recipient.encryptedContent.content); - msg.encryptedContent.key = forge.util.createBuffer(key); - break; - - default: - throw new Error('Unsupported asymmetric cipher, ' + - 'OID ' + recipient.encryptedContent.algorithm); - } - } - - _decryptContent(msg); - }, - - /** - * Add (another) entity to list of recipients. - * - * @param cert The certificate of the entity to add. - */ - addRecipient: function(cert) { - msg.recipients.push({ - version: 0, - issuer: cert.issuer.attributes, - serialNumber: cert.serialNumber, - encryptedContent: { - // We simply assume rsaEncryption here, since forge.pki only - // supports RSA so far. If the PKI module supports other - // ciphers one day, we need to modify this one as well. - algorithm: forge.pki.oids.rsaEncryption, - key: cert.publicKey - } - }); - }, - - /** - * Encrypt enveloped content. - * - * This function supports two optional arguments, cipher and key, which - * can be used to influence symmetric encryption. Unless cipher is - * provided, the cipher specified in encryptedContent.algorithm is used - * (defaults to AES-256-CBC). If no key is provided, encryptedContent.key - * is (re-)used. If that one's not set, a random key will be generated - * automatically. - * - * @param [key] The key to be used for symmetric encryption. - * @param [cipher] The OID of the symmetric cipher to use. - */ - encrypt: function(key, cipher) { - // Part 1: Symmetric encryption - if(msg.encryptedContent.content === undefined) { - cipher = cipher || msg.encryptedContent.algorithm; - key = key || msg.encryptedContent.key; - - var keyLen, ivLen, ciphFn; - switch(cipher) { - case forge.pki.oids['aes128-CBC']: - keyLen = 16; - ivLen = 16; - ciphFn = forge.aes.createEncryptionCipher; - break; - - case forge.pki.oids['aes192-CBC']: - keyLen = 24; - ivLen = 16; - ciphFn = forge.aes.createEncryptionCipher; - break; - - case forge.pki.oids['aes256-CBC']: - keyLen = 32; - ivLen = 16; - ciphFn = forge.aes.createEncryptionCipher; - break; - - case forge.pki.oids['des-EDE3-CBC']: - keyLen = 24; - ivLen = 8; - ciphFn = forge.des.createEncryptionCipher; - break; - - default: - throw new Error('Unsupported symmetric cipher, OID ' + cipher); - } - - if(key === undefined) { - key = forge.util.createBuffer(forge.random.getBytes(keyLen)); - } else if(key.length() != keyLen) { - throw new Error('Symmetric key has wrong length; ' + - 'got ' + key.length() + ' bytes, expected ' + keyLen + '.'); - } - - // Keep a copy of the key & IV in the object, so the caller can - // use it for whatever reason. - msg.encryptedContent.algorithm = cipher; - msg.encryptedContent.key = key; - msg.encryptedContent.parameter = forge.util.createBuffer( - forge.random.getBytes(ivLen)); - - var ciph = ciphFn(key); - ciph.start(msg.encryptedContent.parameter.copy()); - ciph.update(msg.content); - - // The finish function does PKCS#7 padding by default, therefore - // no action required by us. - if(!ciph.finish()) { - throw new Error('Symmetric encryption failed.'); - } - - msg.encryptedContent.content = ciph.output; - } - - // Part 2: asymmetric encryption for each recipient - for(var i = 0; i < msg.recipients.length; ++i) { - var recipient = msg.recipients[i]; - - // Nothing to do, encryption already done. - if(recipient.encryptedContent.content !== undefined) { - continue; - } - - switch(recipient.encryptedContent.algorithm) { - case forge.pki.oids.rsaEncryption: - recipient.encryptedContent.content = - recipient.encryptedContent.key.encrypt( - msg.encryptedContent.key.data); - break; - - default: - throw new Error('Unsupported asymmetric cipher, OID ' + - recipient.encryptedContent.algorithm); - } - } - } - }; - return msg; - }; - - /** - * Converts a single recipient from an ASN.1 object. - * - * @param obj the ASN.1 RecipientInfo. - * - * @return the recipient object. - */ - function _recipientFromAsn1(obj) { - // validate EnvelopedData content block and capture data - var capture = {}; - var errors = []; - if(!asn1.validate(obj, p7.asn1.recipientInfoValidator, capture, errors)) { - var error = new Error('Cannot read PKCS#7 RecipientInfo. ' + - 'ASN.1 object is not an PKCS#7 RecipientInfo.'); - error.errors = errors; - throw error; - } - - return { - version: capture.version.charCodeAt(0), - issuer: forge.pki.RDNAttributesAsArray(capture.issuer), - serialNumber: forge.util.createBuffer(capture.serial).toHex(), - encryptedContent: { - algorithm: asn1.derToOid(capture.encAlgorithm), - parameter: capture.encParameter.value, - content: capture.encKey - } - }; - } - - /** - * Converts a single recipient object to an ASN.1 object. - * - * @param obj the recipient object. - * - * @return the ASN.1 RecipientInfo. - */ - function _recipientToAsn1(obj) { - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // Version - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(obj.version).getBytes()), - // IssuerAndSerialNumber - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // Name - forge.pki.distinguishedNameToAsn1({attributes: obj.issuer}), - // Serial - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - forge.util.hexToBytes(obj.serialNumber)) - ]), - // KeyEncryptionAlgorithmIdentifier - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // Algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(obj.encryptedContent.algorithm).getBytes()), - // Parameter, force NULL, only RSA supported for now. - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ]), - // EncryptedKey - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - obj.encryptedContent.content) - ]); - } - - /** - * Map a set of RecipientInfo ASN.1 objects to recipient objects. - * - * @param infos an array of ASN.1 representations RecipientInfo (i.e. SET OF). - * - * @return an array of recipient objects. - */ - function _recipientsFromAsn1(infos) { - var ret = []; - for(var i = 0; i < infos.length; ++i) { - ret.push(_recipientFromAsn1(infos[i])); - } - return ret; - } - - /** - * Map an array of recipient objects to ASN.1 RecipientInfo objects. - * - * @param recipients an array of recipientInfo objects. - * - * @return an array of ASN.1 RecipientInfos. - */ - function _recipientsToAsn1(recipients) { - var ret = []; - for(var i = 0; i < recipients.length; ++i) { - ret.push(_recipientToAsn1(recipients[i])); - } - return ret; - } - - /** - * Converts a single signerInfo object to an ASN.1 object. - * - * @param obj the signerInfo object. - * - * @return the ASN.1 representation of a SignerInfo. - */ - function _signerToAsn1(obj) { - // SignerInfo - var rval = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // version - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - asn1.integerToDer(obj.version).getBytes()), - // issuerAndSerialNumber - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // name - forge.pki.distinguishedNameToAsn1({attributes: obj.issuer}), - // serial - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, - forge.util.hexToBytes(obj.serialNumber)) - ]), - // digestAlgorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(obj.digestAlgorithm).getBytes()), - // parameters (null) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ]) - ]); - - // authenticatedAttributes (OPTIONAL) - if(obj.authenticatedAttributesAsn1) { - // add ASN.1 previously generated during signing - rval.value.push(obj.authenticatedAttributesAsn1); - } - - // digestEncryptionAlgorithm - rval.value.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(obj.signatureAlgorithm).getBytes()), - // parameters (null) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') - ])); - - // encryptedDigest - rval.value.push(asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, obj.signature)); - - // unauthenticatedAttributes (OPTIONAL) - if(obj.unauthenticatedAttributes.length > 0) { - // [1] IMPLICIT - var attrsAsn1 = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, []); - for(var i = 0; i < obj.unauthenticatedAttributes.length; ++i) { - var attr = obj.unauthenticatedAttributes[i]; - attrsAsn1.values.push(_attributeToAsn1(attr)); - } - rval.value.push(attrsAsn1); - } - - return rval; - } - - /** - * Map an array of signer objects to ASN.1 objects. - * - * @param signers an array of signer objects. - * - * @return an array of ASN.1 SignerInfos. - */ - function _signersToAsn1(signers) { - var ret = []; - for(var i = 0; i < signers.length; ++i) { - ret.push(_signerToAsn1(signers[i])); - } - return ret; - } - - /** - * Convert an attribute object to an ASN.1 Attribute. - * - * @param attr the attribute object. - * - * @return the ASN.1 Attribute. - */ - function _attributeToAsn1(attr) { - var value; - - // TODO: generalize to support more attributes - if(attr.type === forge.pki.oids.contentType) { - value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(attr.value).getBytes()); - } else if(attr.type === forge.pki.oids.messageDigest) { - value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - attr.value.bytes()); - } else if(attr.type === forge.pki.oids.signingTime) { - /* Note per RFC 2985: Dates between 1 January 1950 and 31 December 2049 - (inclusive) MUST be encoded as UTCTime. Any dates with year values - before 1950 or after 2049 MUST be encoded as GeneralizedTime. [Further,] - UTCTime values MUST be expressed in Greenwich Mean Time (Zulu) and MUST - include seconds (i.e., times are YYMMDDHHMMSSZ), even where the - number of seconds is zero. Midnight (GMT) must be represented as - "YYMMDD000000Z". */ - // TODO: make these module-level constants - var jan_1_1950 = new Date('1950-01-01T00:00:00Z'); - var jan_1_2050 = new Date('2050-01-01T00:00:00Z'); - var date = attr.value; - if(typeof date === 'string') { - // try to parse date - var timestamp = Date.parse(date); - if(!isNaN(timestamp)) { - date = new Date(timestamp); - } else if(date.length === 13) { - // YYMMDDHHMMSSZ (13 chars for UTCTime) - date = asn1.utcTimeToDate(date); - } else { - // assume generalized time - date = asn1.generalizedTimeToDate(date); - } - } - - if(date >= jan_1_1950 && date < jan_1_2050) { - value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false, - asn1.dateToUtcTime(date)); - } else { - value = asn1.create( - asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false, - asn1.dateToGeneralizedTime(date)); - } - } - - // TODO: expose as common API call - // create a RelativeDistinguishedName set - // each value in the set is an AttributeTypeAndValue first - // containing the type (an OID) and second the value - return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // AttributeType - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(attr.type).getBytes()), - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ - // AttributeValue - value - ]) - ]); - } - - /** - * Map messages encrypted content to ASN.1 objects. - * - * @param ec The encryptedContent object of the message. - * - * @return ASN.1 representation of the encryptedContent object (SEQUENCE). - */ - function _encryptedContentToAsn1(ec) { - return [ - // ContentType, always Data for the moment - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(forge.pki.oids.data).getBytes()), - // ContentEncryptionAlgorithmIdentifier - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - // Algorithm - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, - asn1.oidToDer(ec.algorithm).getBytes()), - // Parameters (IV) - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - ec.parameter.getBytes()) - ]), - // [0] EncryptedContent - asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, - ec.content.getBytes()) - ]) - ]; - } - - /** - * Reads the "common part" of an PKCS#7 content block (in ASN.1 format) - * - * This function reads the "common part" of the PKCS#7 content blocks - * EncryptedData and EnvelopedData, i.e. version number and symmetrically - * encrypted content block. - * - * The result of the ASN.1 validate and capture process is returned - * to allow the caller to extract further data, e.g. the list of recipients - * in case of a EnvelopedData object. - * - * @param msg the PKCS#7 object to read the data to. - * @param obj the ASN.1 representation of the content block. - * @param validator the ASN.1 structure validator object to use. - * - * @return the value map captured by validator object. - */ - function _fromAsn1(msg, obj, validator) { - var capture = {}; - var errors = []; - if(!asn1.validate(obj, validator, capture, errors)) { - var error = new Error('Cannot read PKCS#7 message. ' + - 'ASN.1 object is not a supported PKCS#7 message.'); - error.errors = error; - throw error; - } - - // Check contentType, so far we only support (raw) Data. - var contentType = asn1.derToOid(capture.contentType); - if(contentType !== forge.pki.oids.data) { - throw new Error('Unsupported PKCS#7 message. ' + - 'Only wrapped ContentType Data supported.'); - } - - if(capture.encryptedContent) { - var content = ''; - if(forge.util.isArray(capture.encryptedContent)) { - for(var i = 0; i < capture.encryptedContent.length; ++i) { - if(capture.encryptedContent[i].type !== asn1.Type.OCTETSTRING) { - throw new Error('Malformed PKCS#7 message, expecting encrypted ' + - 'content constructed of only OCTET STRING objects.'); - } - content += capture.encryptedContent[i].value; - } - } else { - content = capture.encryptedContent; - } - msg.encryptedContent = { - algorithm: asn1.derToOid(capture.encAlgorithm), - parameter: forge.util.createBuffer(capture.encParameter.value), - content: forge.util.createBuffer(content) - }; - } - - if(capture.content) { - var content = ''; - if(forge.util.isArray(capture.content)) { - for(var i = 0; i < capture.content.length; ++i) { - if(capture.content[i].type !== asn1.Type.OCTETSTRING) { - throw new Error('Malformed PKCS#7 message, expecting ' + - 'content constructed of only OCTET STRING objects.'); - } - content += capture.content[i].value; - } - } else { - content = capture.content; - } - msg.content = forge.util.createBuffer(content); - } - - msg.version = capture.version.charCodeAt(0); - msg.rawCapture = capture; - - return capture; - } - - /** - * Decrypt the symmetrically encrypted content block of the PKCS#7 message. - * - * Decryption is skipped in case the PKCS#7 message object already has a - * (decrypted) content attribute. The algorithm, key and cipher parameters - * (probably the iv) are taken from the encryptedContent attribute of the - * message object. - * - * @param The PKCS#7 message object. - */ - function _decryptContent(msg) { - if(msg.encryptedContent.key === undefined) { - throw new Error('Symmetric key not available.'); - } - - if(msg.content === undefined) { - var ciph; - - switch(msg.encryptedContent.algorithm) { - case forge.pki.oids['aes128-CBC']: - case forge.pki.oids['aes192-CBC']: - case forge.pki.oids['aes256-CBC']: - ciph = forge.aes.createDecryptionCipher(msg.encryptedContent.key); - break; - - case forge.pki.oids['desCBC']: - case forge.pki.oids['des-EDE3-CBC']: - ciph = forge.des.createDecryptionCipher(msg.encryptedContent.key); - break; - - default: - throw new Error('Unsupported symmetric cipher, OID ' + - msg.encryptedContent.algorithm); - } - ciph.start(msg.encryptedContent.parameter); - ciph.update(msg.encryptedContent.content); - - if(!ciph.finish()) { - throw new Error('Symmetric decryption failed.'); - } - - msg.content = ciph.output; - } - } - }); - - var ssh_1 = createCommonjsModule(function (module) { - /** - * Functions to output keys in SSH-friendly formats. - * - * This is part of the Forge project which may be used under the terms of - * either the BSD License or the GNU General Public License (GPL) Version 2. - * - * See: https://github.com/digitalbazaar/forge/blob/cbebca3780658703d925b61b2caffb1d263a6c1d/LICENSE - * - * @author https://github.com/shellac - */ - - - - - - - - var ssh = module.exports = forge.ssh = forge.ssh || {}; - - /** - * Encodes (and optionally encrypts) a private RSA key as a Putty PPK file. - * - * @param privateKey the key. - * @param passphrase a passphrase to protect the key (falsy for no encryption). - * @param comment a comment to include in the key file. - * - * @return the PPK file as a string. - */ - ssh.privateKeyToPutty = function(privateKey, passphrase, comment) { - comment = comment || ''; - passphrase = passphrase || ''; - var algorithm = 'ssh-rsa'; - var encryptionAlgorithm = (passphrase === '') ? 'none' : 'aes256-cbc'; - - var ppk = 'PuTTY-User-Key-File-2: ' + algorithm + '\r\n'; - ppk += 'Encryption: ' + encryptionAlgorithm + '\r\n'; - ppk += 'Comment: ' + comment + '\r\n'; - - // public key into buffer for ppk - var pubbuffer = forge.util.createBuffer(); - _addStringToBuffer(pubbuffer, algorithm); - _addBigIntegerToBuffer(pubbuffer, privateKey.e); - _addBigIntegerToBuffer(pubbuffer, privateKey.n); - - // write public key - var pub = forge.util.encode64(pubbuffer.bytes(), 64); - var length = Math.floor(pub.length / 66) + 1; // 66 = 64 + \r\n - ppk += 'Public-Lines: ' + length + '\r\n'; - ppk += pub; - - // private key into a buffer - var privbuffer = forge.util.createBuffer(); - _addBigIntegerToBuffer(privbuffer, privateKey.d); - _addBigIntegerToBuffer(privbuffer, privateKey.p); - _addBigIntegerToBuffer(privbuffer, privateKey.q); - _addBigIntegerToBuffer(privbuffer, privateKey.qInv); - - // optionally encrypt the private key - var priv; - if(!passphrase) { - // use the unencrypted buffer - priv = forge.util.encode64(privbuffer.bytes(), 64); - } else { - // encrypt RSA key using passphrase - var encLen = privbuffer.length() + 16 - 1; - encLen -= encLen % 16; - - // pad private key with sha1-d data -- needs to be a multiple of 16 - var padding = _sha1(privbuffer.bytes()); - - padding.truncate(padding.length() - encLen + privbuffer.length()); - privbuffer.putBuffer(padding); - - var aeskey = forge.util.createBuffer(); - aeskey.putBuffer(_sha1('\x00\x00\x00\x00', passphrase)); - aeskey.putBuffer(_sha1('\x00\x00\x00\x01', passphrase)); - - // encrypt some bytes using CBC mode - // key is 40 bytes, so truncate *by* 8 bytes - var cipher = forge.aes.createEncryptionCipher(aeskey.truncate(8), 'CBC'); - cipher.start(forge.util.createBuffer().fillWithByte(0, 16)); - cipher.update(privbuffer.copy()); - cipher.finish(); - var encrypted = cipher.output; - - // Note: this appears to differ from Putty -- is forge wrong, or putty? - // due to padding we finish as an exact multiple of 16 - encrypted.truncate(16); // all padding - - priv = forge.util.encode64(encrypted.bytes(), 64); - } - - // output private key - length = Math.floor(priv.length / 66) + 1; // 64 + \r\n - ppk += '\r\nPrivate-Lines: ' + length + '\r\n'; - ppk += priv; - - // MAC - var mackey = _sha1('putty-private-key-file-mac-key', passphrase); - - var macbuffer = forge.util.createBuffer(); - _addStringToBuffer(macbuffer, algorithm); - _addStringToBuffer(macbuffer, encryptionAlgorithm); - _addStringToBuffer(macbuffer, comment); - macbuffer.putInt32(pubbuffer.length()); - macbuffer.putBuffer(pubbuffer); - macbuffer.putInt32(privbuffer.length()); - macbuffer.putBuffer(privbuffer); - - var hmac = forge.hmac.create(); - hmac.start('sha1', mackey); - hmac.update(macbuffer.bytes()); - - ppk += '\r\nPrivate-MAC: ' + hmac.digest().toHex() + '\r\n'; - - return ppk; - }; - - /** - * Encodes a public RSA key as an OpenSSH file. - * - * @param key the key. - * @param comment a comment. - * - * @return the public key in OpenSSH format. - */ - ssh.publicKeyToOpenSSH = function(key, comment) { - var type = 'ssh-rsa'; - comment = comment || ''; - - var buffer = forge.util.createBuffer(); - _addStringToBuffer(buffer, type); - _addBigIntegerToBuffer(buffer, key.e); - _addBigIntegerToBuffer(buffer, key.n); - - return type + ' ' + forge.util.encode64(buffer.bytes()) + ' ' + comment; - }; - - /** - * Encodes a private RSA key as an OpenSSH file. - * - * @param key the key. - * @param passphrase a passphrase to protect the key (falsy for no encryption). - * - * @return the public key in OpenSSH format. - */ - ssh.privateKeyToOpenSSH = function(privateKey, passphrase) { - if(!passphrase) { - return forge.pki.privateKeyToPem(privateKey); - } - // OpenSSH private key is just a legacy format, it seems - return forge.pki.encryptRsaPrivateKey(privateKey, passphrase, - {legacy: true, algorithm: 'aes128'}); - }; - - /** - * Gets the SSH fingerprint for the given public key. - * - * @param options the options to use. - * [md] the message digest object to use (defaults to forge.md.md5). - * [encoding] an alternative output encoding, such as 'hex' - * (defaults to none, outputs a byte buffer). - * [delimiter] the delimiter to use between bytes for 'hex' encoded - * output, eg: ':' (defaults to none). - * - * @return the fingerprint as a byte buffer or other encoding based on options. - */ - ssh.getPublicKeyFingerprint = function(key, options) { - options = options || {}; - var md = options.md || forge.md.md5.create(); - - var type = 'ssh-rsa'; - var buffer = forge.util.createBuffer(); - _addStringToBuffer(buffer, type); - _addBigIntegerToBuffer(buffer, key.e); - _addBigIntegerToBuffer(buffer, key.n); - - // hash public key bytes - md.start(); - md.update(buffer.getBytes()); - var digest = md.digest(); - if(options.encoding === 'hex') { - var hex = digest.toHex(); - if(options.delimiter) { - return hex.match(/.{2}/g).join(options.delimiter); - } - return hex; - } else if(options.encoding === 'binary') { - return digest.getBytes(); - } else if(options.encoding) { - throw new Error('Unknown encoding "' + options.encoding + '".'); - } - return digest; - }; - - /** - * Adds len(val) then val to a buffer. - * - * @param buffer the buffer to add to. - * @param val a big integer. - */ - function _addBigIntegerToBuffer(buffer, val) { - var hexVal = val.toString(16); - // ensure 2s complement +ve - if(hexVal[0] >= '8') { - hexVal = '00' + hexVal; - } - var bytes = forge.util.hexToBytes(hexVal); - buffer.putInt32(bytes.length); - buffer.putBytes(bytes); - } - - /** - * Adds len(val) then val to a buffer. - * - * @param buffer the buffer to add to. - * @param val a string. - */ - function _addStringToBuffer(buffer, val) { - buffer.putInt32(val.length); - buffer.putString(val); - } - - /** - * Hashes the arguments into one value using SHA-1. - * - * @return the sha1 hash of the provided arguments. - */ - function _sha1() { - var sha = forge.md.sha1.create(); - var num = arguments.length; - for (var i = 0; i < num; ++i) { - sha.update(arguments[i]); - } - return sha.digest(); - } - }); - - /** - * Support for concurrent task management and synchronization in web - * applications. - * - * @author Dave Longley - * @author David I. Lehn - * - * Copyright (c) 2009-2013 Digital Bazaar, Inc. - */ - - - - - - // logging category - var cat = 'forge.task'; - - // track tasks for debugging - var sTasks = {}; - var sNextTaskId = 0; - // debug access - forge.debug.set(cat, 'tasks', sTasks); - - // a map of task type to task queue - var sTaskQueues = {}; - // debug access - forge.debug.set(cat, 'queues', sTaskQueues); - - // name for unnamed tasks - var sNoTaskName = '?'; - - // maximum number of doNext() recursions before a context swap occurs - // FIXME: might need to tweak this based on the browser - var sMaxRecursions = 30; - - // time slice for doing tasks before a context swap occurs - // FIXME: might need to tweak this based on the browser - var sTimeSlice = 20; - - /** - * Task states. - * - * READY: ready to start processing - * RUNNING: task or a subtask is running - * BLOCKED: task is waiting to acquire N permits to continue - * SLEEPING: task is sleeping for a period of time - * DONE: task is done - * ERROR: task has an error - */ - var READY = 'ready'; - var RUNNING = 'running'; - var BLOCKED = 'blocked'; - var SLEEPING = 'sleeping'; - var DONE = 'done'; - var ERROR = 'error'; - - /** - * Task actions. Used to control state transitions. - * - * STOP: stop processing - * START: start processing tasks - * BLOCK: block task from continuing until 1 or more permits are released - * UNBLOCK: release one or more permits - * SLEEP: sleep for a period of time - * WAKEUP: wakeup early from SLEEPING state - * CANCEL: cancel further tasks - * FAIL: a failure occured - */ - var STOP = 'stop'; - var START = 'start'; - var BLOCK = 'block'; - var UNBLOCK = 'unblock'; - var SLEEP = 'sleep'; - var WAKEUP = 'wakeup'; - var CANCEL = 'cancel'; - var FAIL = 'fail'; - - /** - * State transition table. - * - * nextState = sStateTable[currentState][action] - */ - var sStateTable = {}; - - sStateTable[READY] = {}; - sStateTable[READY][STOP] = READY; - sStateTable[READY][START] = RUNNING; - sStateTable[READY][CANCEL] = DONE; - sStateTable[READY][FAIL] = ERROR; - - sStateTable[RUNNING] = {}; - sStateTable[RUNNING][STOP] = READY; - sStateTable[RUNNING][START] = RUNNING; - sStateTable[RUNNING][BLOCK] = BLOCKED; - sStateTable[RUNNING][UNBLOCK] = RUNNING; - sStateTable[RUNNING][SLEEP] = SLEEPING; - sStateTable[RUNNING][WAKEUP] = RUNNING; - sStateTable[RUNNING][CANCEL] = DONE; - sStateTable[RUNNING][FAIL] = ERROR; - - sStateTable[BLOCKED] = {}; - sStateTable[BLOCKED][STOP] = BLOCKED; - sStateTable[BLOCKED][START] = BLOCKED; - sStateTable[BLOCKED][BLOCK] = BLOCKED; - sStateTable[BLOCKED][UNBLOCK] = BLOCKED; - sStateTable[BLOCKED][SLEEP] = BLOCKED; - sStateTable[BLOCKED][WAKEUP] = BLOCKED; - sStateTable[BLOCKED][CANCEL] = DONE; - sStateTable[BLOCKED][FAIL] = ERROR; - - sStateTable[SLEEPING] = {}; - sStateTable[SLEEPING][STOP] = SLEEPING; - sStateTable[SLEEPING][START] = SLEEPING; - sStateTable[SLEEPING][BLOCK] = SLEEPING; - sStateTable[SLEEPING][UNBLOCK] = SLEEPING; - sStateTable[SLEEPING][SLEEP] = SLEEPING; - sStateTable[SLEEPING][WAKEUP] = SLEEPING; - sStateTable[SLEEPING][CANCEL] = DONE; - sStateTable[SLEEPING][FAIL] = ERROR; - - sStateTable[DONE] = {}; - sStateTable[DONE][STOP] = DONE; - sStateTable[DONE][START] = DONE; - sStateTable[DONE][BLOCK] = DONE; - sStateTable[DONE][UNBLOCK] = DONE; - sStateTable[DONE][SLEEP] = DONE; - sStateTable[DONE][WAKEUP] = DONE; - sStateTable[DONE][CANCEL] = DONE; - sStateTable[DONE][FAIL] = ERROR; - - sStateTable[ERROR] = {}; - sStateTable[ERROR][STOP] = ERROR; - sStateTable[ERROR][START] = ERROR; - sStateTable[ERROR][BLOCK] = ERROR; - sStateTable[ERROR][UNBLOCK] = ERROR; - sStateTable[ERROR][SLEEP] = ERROR; - sStateTable[ERROR][WAKEUP] = ERROR; - sStateTable[ERROR][CANCEL] = ERROR; - sStateTable[ERROR][FAIL] = ERROR; - - /** - * Creates a new task. - * - * @param options options for this task - * run: the run function for the task (required) - * name: the run function for the task (optional) - * parent: parent of this task (optional) - * - * @return the empty task. - */ - var Task = function(options) { - // task id - this.id = -1; - - // task name - this.name = options.name || sNoTaskName; - - // task has no parent - this.parent = options.parent || null; - - // save run function - this.run = options.run; - - // create a queue of subtasks to run - this.subtasks = []; - - // error flag - this.error = false; - - // state of the task - this.state = READY; - - // number of times the task has been blocked (also the number - // of permits needed to be released to continue running) - this.blocks = 0; - - // timeout id when sleeping - this.timeoutId = null; - - // no swap time yet - this.swapTime = null; - - // no user data - this.userData = null; - - // initialize task - // FIXME: deal with overflow - this.id = sNextTaskId++; - sTasks[this.id] = this; - }; - - /** - * Logs debug information on this task and the system state. - */ - Task.prototype.debug = function(msg) { - msg = msg || ''; - forge.log.debug(cat, msg, - '[%s][%s] task:', this.id, this.name, this, - 'subtasks:', this.subtasks.length, - 'queue:', sTaskQueues); - }; - - /** - * Adds a subtask to run after task.doNext() or task.fail() is called. - * - * @param name human readable name for this task (optional). - * @param subrun a function to run that takes the current task as - * its first parameter. - * - * @return the current task (useful for chaining next() calls). - */ - Task.prototype.next = function(name, subrun) { - // juggle parameters if it looks like no name is given - if(typeof(name) === 'function') { - subrun = name; - - // inherit parent's name - name = this.name; - } - // create subtask, set parent to this task, propagate callbacks - var subtask = new Task({ - run: subrun, - name: name, - parent: this - }); - // start subtasks running - subtask.state = RUNNING; - subtask.type = this.type; - subtask.successCallback = this.successCallback || null; - subtask.failureCallback = this.failureCallback || null; - - // queue a new subtask - this.subtasks.push(subtask); - - return this; - }; - - /** - * Adds subtasks to run in parallel after task.doNext() or task.fail() - * is called. - * - * @param name human readable name for this task (optional). - * @param subrun functions to run that take the current task as - * their first parameter. - * - * @return the current task (useful for chaining next() calls). - */ - Task.prototype.parallel = function(name, subrun) { - // juggle parameters if it looks like no name is given - if(forge.util.isArray(name)) { - subrun = name; - - // inherit parent's name - name = this.name; - } - // Wrap parallel tasks in a regular task so they are started at the - // proper time. - return this.next(name, function(task) { - // block waiting for subtasks - var ptask = task; - ptask.block(subrun.length); - - // we pass the iterator from the loop below as a parameter - // to a function because it is otherwise included in the - // closure and changes as the loop changes -- causing i - // to always be set to its highest value - var startParallelTask = function(pname, pi) { - forge.task.start({ - type: pname, - run: function(task) { - subrun[pi](task); - }, - success: function(task) { - ptask.unblock(); - }, - failure: function(task) { - ptask.unblock(); - } - }); - }; - - for(var i = 0; i < subrun.length; i++) { - // Type must be unique so task starts in parallel: - // name + private string + task id + sub-task index - // start tasks in parallel and unblock when the finish - var pname = name + '__parallel-' + task.id + '-' + i; - var pi = i; - startParallelTask(pname, pi); - } - }); - }; - - /** - * Stops a running task. - */ - Task.prototype.stop = function() { - this.state = sStateTable[this.state][STOP]; - }; - - /** - * Starts running a task. - */ - Task.prototype.start = function() { - this.error = false; - this.state = sStateTable[this.state][START]; - - // try to restart - if(this.state === RUNNING) { - this.start = new Date(); - this.run(this); - runNext(this, 0); - } - }; - - /** - * Blocks a task until it one or more permits have been released. The - * task will not resume until the requested number of permits have - * been released with call(s) to unblock(). - * - * @param n number of permits to wait for(default: 1). - */ - Task.prototype.block = function(n) { - n = typeof(n) === 'undefined' ? 1 : n; - this.blocks += n; - if(this.blocks > 0) { - this.state = sStateTable[this.state][BLOCK]; - } - }; - - /** - * Releases a permit to unblock a task. If a task was blocked by - * requesting N permits via block(), then it will only continue - * running once enough permits have been released via unblock() calls. - * - * If multiple processes need to synchronize with a single task then - * use a condition variable (see forge.task.createCondition). It is - * an error to unblock a task more times than it has been blocked. - * - * @param n number of permits to release (default: 1). - * - * @return the current block count (task is unblocked when count is 0) - */ - Task.prototype.unblock = function(n) { - n = typeof(n) === 'undefined' ? 1 : n; - this.blocks -= n; - if(this.blocks === 0 && this.state !== DONE) { - this.state = RUNNING; - runNext(this, 0); - } - return this.blocks; - }; - - /** - * Sleep for a period of time before resuming tasks. - * - * @param n number of milliseconds to sleep (default: 0). - */ - Task.prototype.sleep = function(n) { - n = typeof(n) === 'undefined' ? 0 : n; - this.state = sStateTable[this.state][SLEEP]; - var self = this; - this.timeoutId = setTimeout(function() { - self.timeoutId = null; - self.state = RUNNING; - runNext(self, 0); - }, n); - }; - - /** - * Waits on a condition variable until notified. The next task will - * not be scheduled until notification. A condition variable can be - * created with forge.task.createCondition(). - * - * Once cond.notify() is called, the task will continue. - * - * @param cond the condition variable to wait on. - */ - Task.prototype.wait = function(cond) { - cond.wait(this); - }; - - /** - * If sleeping, wakeup and continue running tasks. - */ - Task.prototype.wakeup = function() { - if(this.state === SLEEPING) { - cancelTimeout(this.timeoutId); - this.timeoutId = null; - this.state = RUNNING; - runNext(this, 0); - } - }; - - /** - * Cancel all remaining subtasks of this task. - */ - Task.prototype.cancel = function() { - this.state = sStateTable[this.state][CANCEL]; - // remove permits needed - this.permitsNeeded = 0; - // cancel timeouts - if(this.timeoutId !== null) { - cancelTimeout(this.timeoutId); - this.timeoutId = null; - } - // remove subtasks - this.subtasks = []; - }; - - /** - * Finishes this task with failure and sets error flag. The entire - * task will be aborted unless the next task that should execute - * is passed as a parameter. This allows levels of subtasks to be - * skipped. For instance, to abort only this tasks's subtasks, then - * call fail(task.parent). To abort this task's subtasks and its - * parent's subtasks, call fail(task.parent.parent). To abort - * all tasks and simply call the task callback, call fail() or - * fail(null). - * - * The task callback (success or failure) will always, eventually, be - * called. - * - * @param next the task to continue at, or null to abort entirely. - */ - Task.prototype.fail = function(next) { - // set error flag - this.error = true; - - // finish task - finish(this, true); - - if(next) { - // propagate task info - next.error = this.error; - next.swapTime = this.swapTime; - next.userData = this.userData; - - // do next task as specified - runNext(next, 0); - } else { - if(this.parent !== null) { - // finish root task (ensures it is removed from task queue) - var parent = this.parent; - while(parent.parent !== null) { - // propagate task info - parent.error = this.error; - parent.swapTime = this.swapTime; - parent.userData = this.userData; - parent = parent.parent; - } - finish(parent, true); - } - - // call failure callback if one exists - if(this.failureCallback) { - this.failureCallback(this); - } - } - }; - - /** - * Asynchronously start a task. - * - * @param task the task to start. - */ - var start = function(task) { - task.error = false; - task.state = sStateTable[task.state][START]; - setTimeout(function() { - if(task.state === RUNNING) { - task.swapTime = +new Date(); - task.run(task); - runNext(task, 0); - } - }, 0); - }; - - /** - * Run the next subtask or finish this task. - * - * @param task the task to process. - * @param recurse the recursion count. - */ - var runNext = function(task, recurse) { - // get time since last context swap (ms), if enough time has passed set - // swap to true to indicate that doNext was performed asynchronously - // also, if recurse is too high do asynchronously - var swap = - (recurse > sMaxRecursions) || - (+new Date() - task.swapTime) > sTimeSlice; - - var doNext = function(recurse) { - recurse++; - if(task.state === RUNNING) { - if(swap) { - // update swap time - task.swapTime = +new Date(); - } - - if(task.subtasks.length > 0) { - // run next subtask - var subtask = task.subtasks.shift(); - subtask.error = task.error; - subtask.swapTime = task.swapTime; - subtask.userData = task.userData; - subtask.run(subtask); - if(!subtask.error) { - runNext(subtask, recurse); - } - } else { - finish(task); - - if(!task.error) { - // chain back up and run parent - if(task.parent !== null) { - // propagate task info - task.parent.error = task.error; - task.parent.swapTime = task.swapTime; - task.parent.userData = task.userData; - - // no subtasks left, call run next subtask on parent - runNext(task.parent, recurse); - } - } - } - } - }; - - if(swap) { - // we're swapping, so run asynchronously - setTimeout(doNext, 0); - } else { - // not swapping, so run synchronously - doNext(recurse); - } - }; - - /** - * Finishes a task and looks for the next task in the queue to start. - * - * @param task the task to finish. - * @param suppressCallbacks true to suppress callbacks. - */ - var finish = function(task, suppressCallbacks) { - // subtask is now done - task.state = DONE; - - delete sTasks[task.id]; - - // only do queue processing for root tasks - if(task.parent === null) { - // report error if queue is missing - if(!(task.type in sTaskQueues)) { - forge.log.error(cat, - '[%s][%s] task queue missing [%s]', - task.id, task.name, task.type); - } else if(sTaskQueues[task.type].length === 0) { - // report error if queue is empty - forge.log.error(cat, - '[%s][%s] task queue empty [%s]', - task.id, task.name, task.type); - } else if(sTaskQueues[task.type][0] !== task) { - // report error if this task isn't the first in the queue - forge.log.error(cat, - '[%s][%s] task not first in queue [%s]', - task.id, task.name, task.type); - } else { - // remove ourselves from the queue - sTaskQueues[task.type].shift(); - // clean up queue if it is empty - if(sTaskQueues[task.type].length === 0) { - /* Note: Only a task can delete a queue of its own type. This - is used as a way to synchronize tasks. If a queue for a certain - task type exists, then a task of that type is running. - */ - delete sTaskQueues[task.type]; - } else { - sTaskQueues[task.type][0].start(); - } - } - - if(!suppressCallbacks) { - // call final callback if one exists - if(task.error && task.failureCallback) { - task.failureCallback(task); - } else if(!task.error && task.successCallback) { - task.successCallback(task); - } - } - } - }; - - /* Tasks API */ - var task = forge.task = forge.task || {}; - - /** - * Starts a new task that will run the passed function asynchronously. - * - * In order to finish the task, either task.doNext() or task.fail() - * *must* be called. - * - * The task must have a type (a string identifier) that can be used to - * synchronize it with other tasks of the same type. That type can also - * be used to cancel tasks that haven't started yet. - * - * To start a task, the following object must be provided as a parameter - * (each function takes a task object as its first parameter): - * - * { - * type: the type of task. - * run: the function to run to execute the task. - * success: a callback to call when the task succeeds (optional). - * failure: a callback to call when the task fails (optional). - * } - * - * @param options the object as described above. - */ - forge.task.start = function(options) { - // create a new task - var task = new Task({ - run: options.run, - name: options.name || sNoTaskName - }); - task.type = options.type; - task.successCallback = options.success || null; - task.failureCallback = options.failure || null; - - // append the task onto the appropriate queue - if(!(task.type in sTaskQueues)) { - // create the queue with the new task - sTaskQueues[task.type] = [task]; - start(task); - } else { - // push the task onto the queue, it will be run after a task - // with the same type completes - sTaskQueues[options.type].push(task); - } - }; - - /** - * Cancels all tasks of the given type that haven't started yet. - * - * @param type the type of task to cancel. - */ - forge.task.cancel = function(type) { - // find the task queue - if(type in sTaskQueues) { - // empty all but the current task from the queue - sTaskQueues[type] = [sTaskQueues[type][0]]; - } - }; - - /** - * Creates a condition variable to synchronize tasks. To make a task wait - * on the condition variable, call task.wait(condition). To notify all - * tasks that are waiting, call condition.notify(). - * - * @return the condition variable. - */ - forge.task.createCondition = function() { - var cond = { - // all tasks that are blocked - tasks: {} - }; - - /** - * Causes the given task to block until notify is called. If the task - * is already waiting on this condition then this is a no-op. - * - * @param task the task to cause to wait. - */ - cond.wait = function(task) { - // only block once - if(!(task.id in cond.tasks)) { - task.block(); - cond.tasks[task.id] = task; - } - }; - - /** - * Notifies all waiting tasks to wake up. - */ - cond.notify = function() { - // since unblock() will run the next task from here, make sure to - // clear the condition's blocked task list before unblocking - var tmp = cond.tasks; - cond.tasks = {}; - for(var id in tmp) { - tmp[id].unblock(); - } - }; - - return cond; - }; - - /** - * Node.js module for Forge. - * - * @author Dave Longley - * - * Copyright 2011-2016 Digital Bazaar, Inc. - */ - var lib$1 = forge; - - /** - * Verify the Sec-WebSocket-Accept header field by computing its expected value. - * @param {Uint8Array} key 4-bytes sec-websocket-key used for client handshake - * @param {string} resp received header field value string - * @returns boolean true if the received value is the expected - * @private - */ - function verifySecWebSocketAccept(key, resp) { - const fromHexString = hexString => - new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); - - const keyb64 = naclUtil.encodeBase64(key); - let hashed = lib$1.md.sha1.create(); - hashed.update(keyb64 + GUID); - const hashedBytes = fromHexString(hashed.digest().toHex()); - const expected = naclUtil.encodeBase64(hashedBytes); - return resp === expected; - } - - // Utilities - - /** - * A MessageEvent implementation for Node. - * - * @private - */ - class MessageEvent$1 { - constructor(type, init = undefined) { - this.type = type; - if (init) { - this.data = init.data; - this.origin = init.origin; - this.lastEventId = init.lastEventId; - this.channel = init.channel; - this.source = init.source; - this.port = init.port; - } - } - } - - /** - * A CloseEvent implementation for Node. - * - * @private - */ - class CloseEvent$1 extends MessageEvent$1 { - constructor(type, init = undefined) { - super(type, init); - if (init) { - this.wasClean = init.wasClean; - this.code = init.code; - this.reason = init.reason; - } - } - } - - /** - * Simple implementation of EventTarget. - * See {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget}. - * - * Used for mocking browsers' DOM EventTarget. - * - * @private - */ - class EventTarget$1 { - constructor() { - this.listeners = {}; - } - - addEventListener(type, callback) { - if (!(type in this.listeners)) { - this.listeners[type] = []; - } - this.listeners[type].push(callback); - } - - removeEventListener(type, callback) { - if (!(type in this.listeners)) { - return; - } - const stack = this.listeners[type]; - for (let i = 0, l = stack.length; i < l; i++) { - if (stack[i] === callback) { - stack.splice(i, 1); - return; - } - } - } - - dispatchEvent(event) { - if (!(event.type in this.listeners)) { - return true; - } - const stack = this.listeners[event.type].slice(); - - for (let i = 0, l = stack.length; i < l; i++) { - stack[i].call(this, event); - } - return !event.defaultPrevented; - - } - - } - - /* - * Mocks for use in node/broswer. - */ - - let EventTargetClass; - let MessageEventClass; - let BlobClass; - let CloseEventClass; - - if (lib_3) { - // running in node - EventTargetClass = EventTarget$1; - MessageEventClass = MessageEvent$1; - BlobClass = require("cross-blob"); - CloseEventClass = CloseEvent$1; - } else { - EventTargetClass = EventTarget; - MessageEventClass = MessageEvent; - BlobClass = Blob; - CloseEventClass = CloseEvent; - } - - /** - * Packet handling for WebSockets. - */ - - /** - * Return a handler for received websocket packets when in open state, for given WebSocket. - * @param {WebSocket} ws websocket handling the packets. - * @param {Boolean} noMasking disable masking of frames sent, for testing purposes only - * @private - */ - function onOpenMessage(ws, noMasking = false) { - return (pkt) => { - - // add the packet to the stream handler - ws._streamHandler.add(pkt); - - let frame; - // process all frames that are ready - while ((frame = ws._streamHandler.get()) !== undefined) { - ws._frameDefragmenter.add(frame); - } - - while ((frame = ws._frameDefragmenter.get()) !== undefined) { - if (isControlFrame(frame.opcode)) { - handleControlFrame(ws, frame, noMasking); - } else { - handleDataFrame(ws, frame); - } - } - - }; - } - - /** - * Handle a data frame. - * - * @param {WebSocket} ws websocket handling the frame - * @param {Frame} dataFrame frame to handle - * @private - */ - function handleDataFrame(ws, dataFrame) { - if (dataFrame.payload === undefined) { - return; - } - - // wrap to event - let eventData; - try { - if (dataFrame.opcode === opcodes.text) { - eventData = naclUtil.encodeUTF8(dataFrame.payload); - } else if (dataFrame.opcode === opcodes.binary) { - if (ws.binaryType === binaryTypes.blob) { - eventData = new Blob([dataFrame.payload]); - } else if (ws.binaryType === binaryTypes.arraybuffer) { - eventData = dataFrame.payload.buffer; - } - } else { - console.warn(`unknown opcode: ${dataFrame.opcode}, dropping frame`); - return; - } - } catch (err) { - console.warn(`error: tried to decode websocket data packet: ${err}`); - return; - } - let event = new MessageEventClass( - "message", - { - data: eventData, - origin: ws._url.href, - lastEventId: "", // TODO ? - source: null, // TODO ? - ports: [], // TODO ? - } - ); - - ws._received(event); - ws.__onmessage(event); // user defined handler - } - - /** - * Handle a control frame. - * - * @param {WebSocket} ws websocket handling the frame - * @param {Frame} controlFrame frame to handle - * @param {Boolean} noMasking disable masking of frames sent, for testing purposes only - * @private - */ - function handleControlFrame(ws, controlFrame, noMasking) { - const payload = controlFrame.payload; - switch (controlFrame.opcode) { - case opcodes.close: { - // status and reason are parsed but not needed for now - // the whole payload is echoed back - let status = 1005; - let reason = ""; - if (payload.length >= 2) { - status = payload[0] << 8 + payload[1]; - let reasonBytes = payload.slice(2); - if (reasonBytes.length > 0) { - // read reason - reason = naclUtil.encodeUTF8(reasonBytes); - } - } - - if (!ws._the_websocket_closing_handshake_is_started) { - // send back a close frame - ws._closing(); - - // if present, echo back status and reason - // otherwise use defaults - if (payload.length >= 2) { - // 2-byte unsigned integer - status = (payload[0] << 8) + payload[1]; - if (payload.length > 2) { - reason = naclUtil.encodeUTF8(payload.slice(2)); - } - } - - if (noMasking) { - ws._socket.send(closeFrame(status, reason, new Uint8Array(4))); - } else { - ws._socket.send(closeFrame(status, reason)); - } - // end of the closing handshake - ws._close_the_websocket_connection(); - } else { - // end of the closing handshake - ws._close_the_websocket_connection(); - } - break; - } - case opcodes.ping: { - // send back a pong frame, with received (decoded) payload if any - if (noMasking) { - ws._socket.send(pongFrame(payload, new Uint8Array(4))); - } else { - ws._socket.send(pongFrame(payload)); - } - break; - } - } - return; - } - - /** - * HTTP packet parsing utilities. - */ - - /** - * Parse the headers of a HTTP packet. - * No validation is performed on fields and keys. - * - * @param {string} headers HTTP headers - * @returns a dictionnary of key-values in the header, - * if multiple header key is present, values will be comma separated - * the header field names and values are set to lower-case, except for case-sensitive values - * @private - */ - function parseHeaders(headers) { - let parsed = {}; - - if (!headers) { return parsed; } - - headers.split('\r\n') - .forEach(line => { - // split header line in key - value - let i = line.indexOf(':'); - let key = line.substr(0, i).trim().toLowerCase(); - let val; - // Header fields names should be case-insensitive (RFC2616 4.2) - // So we only use lower case versions, except for 'sec-websocket' headers. - // For some reason WebSocket servers do not understand lower case 'sec-websocket' headers. - if (key != "sec-websocket-accept" && key != "sec-websocket-key") { - val = line.substr(i + 1).trim().toLowerCase(); - } else { - val = line.substr(i + 1).trim(); - } - - if (key) { - parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; - } - }); - - return parsed; - } - - /** - * The interface between a stream-oriented socket to a WebSocket. - * Reconstruct websocket frames from stream messages. - * - * To be used when receiving data from the TCP stream, - * feed this data into the add() method, - * and use get() method to poll for ready frames. - * - * @private - */ - class StreamHandler { - constructor() { - // the queue containing ready websocket frames - this._outputQueue = []; - // the buffer containing remaining bytes to be consumed - // invariant: the start of the buffer corresponds to the start of a websocket frame - this._buffer = []; - } - - /** - * Add a received packet. - * After this call, zero, one or more frames may be used by calling get() multiple times. - * @param {Uint8Array} data raw data taken from the streaming socket - */ - add(data) { - this._buffer.push(...data); - - // consume buffer to add new ready frames to the output queue - let frame; - while ((frame = this._consume()) !== undefined) { - this._outputQueue.push(frame); - } - } - - /** - * Return the next websocket frame. - * @returns {Uint8Array | undefined} a raw websocket frame - * or undefined if no frame is ready. - */ - get() { - return this._outputQueue.shift(); - } - - - /** - * Try to consume buffer into a websocket frame. - * @returns {Uint8Array} the websocket frame constructed, or undefined if not successful - */ - _consume() { - // check if we have a full frame header in the buffer - const headerLen = nextHeaderLength(this._buffer); - if (headerLen === 0) { - return undefined; - } - - // we have a full frame header available - // parse it to get the payload length - const payloadLen = headerPayloadLength(this._buffer.slice(0, headerLen)); - - // check if we have the payload ready in the buffer - if (this._buffer.length < (headerLen + payloadLen)) { - return undefined; - } - - // we can extract a frame from the buffer - let rawFrame = this._buffer.splice(0, headerLen + payloadLen); - - // unmask if needed - let frame = unmaskFrame(rawFrame, headerLen); - - return new Uint8Array(frame); - } - } - - /** - * Unmask websocket frame if needed. - * - * @param {Array} frame byte array - * @param {number} headerLen the length of the header in the frame - * @returns {Array} the unmasked frame - * @private - */ - function unmaskFrame(frame, headerLen) { - const pLen = frame[1] & 127; - - let maskIndex; - if (pLen < 126) { - maskIndex = 2; - } else if (pLen === 127) { - maskIndex = 4; - } else { - maskIndex = 10; - } - let maskingKey = frame.slice(maskIndex, maskIndex + 4); - - const payload = maskWithKey(frame.slice(headerLen), maskingKey); - - frame.slice(0, headerLen).push(...payload); - - return frame; - } - - /** - * Returns the payload length from a frame header. - * @param {Array} header the input header, assumed valid and no extra bytes, only contains bytes - * @returns {number} the length of the payload associated with the header - * @private - */ - function headerPayloadLength(header) { - const pLen = header[1] & 127; // 7 last bits of 2nd byte - - if (pLen < 126) { - return pLen; - } else if (pLen === 126) { - // if 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length - return (header[2] << 8) + header[3]; - } else if (pLen === 127) { - // if 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length - let len = 0; - - for (let i = 0; i < 8; i++) { - len += (header[2 + i] << (8 * (7 - i))); - } - return len; - } - } - - /** - * Try to read a header from the start of the input buffer. - * @param {Array} data input buffer, contaning only bytes - * @returns {boolean} the byte length of the header contained in the start of the input buffer if any, 0 otherwise - * @private - */ - function nextHeaderLength(data) { - // a frame header is between 2 and 12 bytes long - if (data.length < 2) { return 0; } - - const mask = (data[1] & 128) === 128; // mask is true if mask is set in header - const payloadLen = data[1] & 127; // 7 last bits of 2nd byte - - // now check all the cases... - - if (!mask && payloadLen < 126) { - // header length is 2B - return 2; - } else if (!mask && payloadLen === 126) { - // header length is (2 + 2) = 4B - if (data.length < 4) { return 0; } else { return 4; } - } else if (!mask && payloadLen === 127) { - // header length is (2 + 8) = 10B - if (data.length < 10) { return 0; } else { return 10; } - } else if (mask && payloadLen < 126) { - // header length is (2 + 4) = 6B - if (data.length < 6) { return 0; } else { return 6; } - } else if (mask && payloadLen === 126) { - // header length is (2 + 2 + 4) = 8B - if (data.length < 8) { return 0; } else { return 8; } - } else if (mask && payloadLen === 127) { - // header length is (2 + 8 + 4) = 14B - if (data.length < 14) { return 0; } else { return 14; } - } - } - - /** - * Defragments WebSocket frames - * Used when receiving websocket frames that may have been fragmented. - * - * @private - */ - class FrameDefragmenter { - - constructor() { - this._outputQueue = []; - this._parsed = undefined; - } - - - /** - * Add a received frame, that may be fragmented. - * - * @param {frame} Uint8Array packet received, unmasked - * @throws error when fed out of order frames - * @return {undefined} control frame if given packet is a control frame, undefined otherwise - */ - add(frame) { - let parsed = FrameDefragmenter._fields(frame); - - if (parsed === undefined) { - console.warn("received websocket frame could not be parsed"); - return undefined; - } - - if (isControlFrame(parsed['opcode'])) { - this._outputQueue.push(new Frame( - parsed["rsv1"] === 1, - parsed["rsv2"] === 1, - parsed["rsv3"] === 1, - parsed["opcode"], - parsed["payload data"], - )); - return; - } - - const fin = parsed["fin"]; - const opcode = parsed["opcode"]; - - if (this._parsed === undefined) { - if (fin && opcode !== opcodes.continuation) { - // unfragmented - this._outputQueue.push(new Frame( - parsed["rsv1"] === 1, - parsed["rsv2"] === 1, - parsed["rsv3"] === 1, - parsed["opcode"], - parsed["payload data"], - )); - this._parsed = undefined; - return; - } else if (!fin && opcode !== opcodes.continuation) { - // first fragmented frame - this._parsed = parsed; - return; - } else { - throw `Error: FrameBuilder was given an out of order frame`; - } - } else { - if (!fin && opcode === opcodes.continuation) { - // continuation frame - // append the payload to the current fragments' payload - this._parsed["payload data"] = concatenate(this._parsed["payload data"], parsed["payload data"]); - return; - } else if (fin && opcode === opcodes.continuation) { - // last fragmented frame - // append the payload to the current fragments' payload - this._parsed["payload data"] = concatenate(this._parsed["payload data"], parsed["payload data"]); - - this._outputQueue.push(new Frame( - this._parsed["rsv1"] === 1, - this._parsed["rsv2"] === 1, - this._parsed["rsv3"] === 1, - this._parsed["opcode"], - this._parsed["payload data"], - )); - this._parsed = undefined; - return; - } else { - throw `Error: FrameBuilder was given an out of order frame`; - } - } - } - - /** - * Return the next websocket frame. - * @returns {Uint8Array | undefined} an unfragmented websocket frame - * or undefined if no frame is ready. - */ - get() { - return this._outputQueue.shift(); - } - - /** - * Parse a websocket frame into key-value fields. - * Do not decode payload if masked. - * - * @private - * @param {Uint8Array} frame an encapsulated websocket frame, or undefined if error - * @returns dictionnary of fields and fields values of the encapsulated packet, or undefined if packet is invalid - * keys are a subset of ['fin', 'rsv1', 'rsv2', 'rsv3', 'opcode', 'mask', 'Payload Len', 'masking-key', 'payload data'] - * or undefined if the frame is bogus - */ - static _fields(frame) { - let parsed = {}; - let restLen = frame.byteLength; - if (restLen < 2) { - // bogus frame - return undefined; - } - - let byteIterator = frame.entries(); - - // first byte - const bits0 = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split('').map(c => c === "1" ? 1 : 0); - parsed["fin"] = bits0[0]; - parsed["rsv1"] = bits0[1]; - parsed["rsv2"] = bits0[2]; - parsed["rsv3"] = bits0[3]; - parsed["opcode"] = parseInt(bits0.slice(4, 8).join(''), 2); - restLen--; - - // second byte - const bits1 = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split('').map(c => c === "1" ? 1 : 0); - parsed["mask"] = bits1[0]; - parsed["payload len"] = parseInt(bits1.slice(1, 8).join(''), 2); - restLen--; - - // rest - - if (parsed["payload len"] == 126) { - // if 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length - if (restLen < 2) { - console.warn("error: received websocket frame with incorrect 'payload len'"); - return undefined; - } - let pLen = (byteIterator.next().value[1]).toString(2).padStart(8, '0').split(''); - pLen = pLen.concat((byteIterator.next().value[1]).toString(2).padStart(8, '0').split('')); - parsed["payload len"] = parseInt(pLen.join(""), 2); - restLen -= 2; - } else if (parsed["payload len"] == 127) { - // if 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the most significant bit MUST be 0) are the payload length - if (restLen < 8) { - console.warn("error: received websocket frame with incorrect 'payload len'"); - return undefined; - } - let pLenBits = []; - for (let i = 0; i < 8; i++) { - pLenBits = pLenBits.concat((byteIterator.next().value[1]).toString(2).padStart(8, '0').split('')); - } - parsed["payload len"] = parseInt(pLenBits.join(""), 2); - restLen -= 8; - } - - if (parsed["mask"]) { - // next 4 bytes is the masking key - if (restLen < 4) { - console.warn("error: received websocket frame with masking"); - return undefined; - } - let maskingKeyBits = ""; - for (let i = 0; i < 4; i++) { - maskingKeyBits += (byteIterator.next().value[1]).toString(2).padStart(8, '0'); - } - parsed["masking-key"] = parseInt(maskingKeyBits, 2); - restLen -= 4; - } - - if (restLen <= 0) { - parsed["payload data"] = new Uint8Array(0); - } else { - // parsed["payload data"] = frame.slice(-restLen); - parsed["payload data"] = frame.slice(-parsed["payload len"]); - } - - return parsed; - } - - } - - /** - * A definition of a WebSocket client. - * - * @module websocket-client - */ - - let binaryTypes = { - blob: "blob", - arraybuffer: "arraybuffer", - }; - - /** - * An abstract WebSocket client. - * - * Uses an underlying socket to be supplied by implementing classes when calling {@linkcode WebSocketClient._start_opening_handshake}. - */ - class WebSocketClient extends EventTargetClass { - // CONSTANTS - // static getters are used to implement static constants - static get CONNECTING() { return 0; } - static get OPEN() { return 1; } - static get CLOSING() { return 2; } - static get CLOSED() { return 3; } - - constructor(url, protocols = []) { - super(); - - if (protocols.length > 0) { - console.error(`websocket subprotocols are not yet supported: ${protocols}`); - } - - // url - this._url = new URL(url); - - // TODO: see https://www.w3.org/TR/websockets/#dom-websocket-bufferedamount - // need to use the underlying buffer measures as well, - // lightnion-js uses lnn.stream.tcp.cache.length - this._bufferedAmount = 0; - - this._extensions = ""; - this._protocol = ""; - this._readyState = WebSocketClient.CONNECTING; - this._binaryType = binaryTypes.blob; // defaults - - // 'private' event handlers - // these are the handlers called by the underlying socket - // each of them will call the user-defined handler (e.g. this.onmessage) after some processing - this.__onclose = (event) => { this.onclose(event); }; - this.__onerror = (event) => { this.onerror(event); }; - this.__onmessage = (event) => { this.onmessage(event); }; - this.__onopen = (event) => { this.onopen(event); }; - - // 'public' event handlers - this._onclose = () => { }; - this._onerror = () => { }; - this._onmessage = () => { }; - this._onopen = () => { }; - - - // true if the closing handshake has been initiated - this._the_websocket_closing_handshake_is_started = false; - - // for translation of stream to frames - this._streamHandler = new StreamHandler(); - - // for reception of fragmented message - this._frameDefragmenter = new FrameDefragmenter(); - - // check if duplicates in protocols - // TODO - // if (new Set(this.protocols).size != this.protocols.length) { - // throw SyntaxError(`duplicates in protocols: ${this.protocols}`); - // } - - - let origin = ""; - if (!lib_3) { - origin = new URL(window.location.href); - } else { - origin = "http://localhost/"; - } - - // parse url - let secure; - try { - secure = parseURL(this._url)[3]; - } catch (err) { - throw SyntaxError(`could not parse url: ${err}`); - } - - if (secure && origin.protocol !== "https") { - throw Error(`SecurityError: cannot open non-secure websocket from a secure origin`); - } - - // transport level socket connection - // should be set when the handshake is requested - this._socket = undefined; - } - - // PROPERTIES - - // url: read-only DOMString - get url() { - return this._url.href; - } - - // readyState: read-only unsigned short - get readyState() { - return this._readyState; - } - - // bufferedAmount: read-only unsigned long - get bufferedAmount() { - return this._bufferedAmount; - } - - // extensions: read-only DOMString - get extensions() { - return this._extensions; - } - - // protocol: read-only DOMString - get protocol() { - return this._protocol; - } - - // binaryType: DOMString - get binaryType() { return this._binaryType; } - set binaryType(binaryType) { - switch (binaryType) { - case "blob": - this._binaryType = binaryTypes.blob; - break; - case "arraybuffer": - this._binaryType = binaryTypes.arraybuffer; - break; - default: - throw new SyntaxError(`websocket binaryType cannot be set to ${binaryType}, allowed values are 'blob' and 'arraybuffer'`); - } - } - - - // EVENT HANDLERS - - /** - * Get the onopen handler. - */ - get onopen() { - return this._onopen; - } - /** - * Set the onopen handler. - */ - set onopen(onopen) { - this._onopen = onopen; - } - - /** - * Get the onmessage handler. - */ - get onmessage() { - return this._onmessage; - } - - /** - * Set the onmessage handler. - */ - set onmessage(onmessage) { - this._onmessage = onmessage; - } - - /** - * Get the onerror handler. - */ - get onerror() { - return this._onerror; - } - /** - * Set the onerror handler. - */ - set onerror(onerror) { - this._onerror = onerror; - } - - /** - * Get the onclose handler. - */ - get onclose() { - return this._onclose; - } - /** - * Set the onclose handler. - */ - set onclose(onclose) { - this._onclose = onclose; - } - - - // INTERFACE METHODS - - /** - * Send to the websocket endpoint. - * @param {string|Blob|ArrayBuffer|ArrayBufferView} data the payload to send - */ - send(data) { - // FIXME: bufferedAmount, closing handshake started - - if (!(this._socket)) { - throw `Socket not initialized`; - } - - if (this._readyState === WebSocketClient.CONNECTING) { - throw `InvalidStateError: cannot send data while websocket is in CONNECTING state`; - } - - let frame; - if (typeof data === "string") { - // convert data to a sequence of Unicode characters - const payload = naclUtil.decodeUTF8(data); - if (this._readyState === WebSocketClient.OPEN) { - frame = new Frame(false, false, false, opcodes.text, payload); - } - } else if (data instanceof Blob) { - frame = new Frame(false, false, false, opcodes.binary, data); - } else if (data instanceof ArrayBuffer) { - frame = new Frame(false, false, false, opcodes.binary, data); - } else { - // assume ArrayBufferView - // send data stored in the section of the buffer described by the ArrayBuffer object that the ArrayBufferView object references - frame = new Frame(false, false, false, opcodes.binary, data); - } - - if (frame) { - // console.debug("[WS] sending websocket message"); - // console.debug(frame); - this._socket.send(frame.encapsulate()); - } else { - // not connected or closing, ... - return; - } - } - - /** - * Close the WebSocket connection. - * @param {int} code - * @param {DOMString} reason - */ - close(code, reason) { - // check code - if (code && (code !== 1000 || (code >= 3000 && code <= 4999))) { - throw Error(`InvalidAccessError: code must be 1000 or in the range 3000-4999`); - } - - if (reason) { - const unicodeReason = naclUtil.encodeUTF8(reason); - if (unicodeReason.byteLength > 123) { - throw SyntaxError(`reason is too long: ${reason}`); - } - } - - if (this._readyState === WebSocketClient.CLOSED || this._readyState === WebSocketClient.CLOSING) { - // do nothing - return; - } else if (this._readyState !== WebSocketClient.OPEN) { - // connection not yet established - // fail the websocket connection and set the readyState attribute's value to CLOSING - this._closing(); - this._fail_the_websocket_connection(); - } else if (!this._the_websocket_closing_handshake_is_started) { - // the closing handshake has not yet been started - // start the closing handshake and set the readyState attribute's value to CLOSING - this._closing(); - this._start_the_websocket_closing_handshake(code, reason); - } else { - this._closing(); - } - } - - // CLOSING THE CONNECTION - // https://tools.ietf.org/html/rfc6455#section-7 - - /** - * Close the WebSocket Connection - * @private - */ - _close_the_websocket_connection() { - // cleanly close the TLS & TCP connection - if (this._socket) { - this._socket.close(); - } - this._readyState = WebSocketClient.CLOSED; - this._closed(true); - } - - /** - * Start the WebSocket Closing Handshake - * @param {int} code status code for closing the connection - * @param {reason} string reason for closing the connection - * @private - */ - _start_the_websocket_closing_handshake(code, reason = undefined) { - if (!(this._socket)) { - throw `Socket not initialized`; - } - - this._the_websocket_closing_handshake_is_started = true; - this._socket.send(closeFrame(code, reason)); - - // wait for the close control frame from the endpoint - // and _close_the_websocket_connection - // this is done in the onmessage callback - } - - /** - * Fail the WebSocket Connection. - * @private - */ - _fail_the_websocket_connection() { - this._close_the_websocket_connection(); - } - - // TASKS - - /** - * Task to run when "the WebSocket connection is established" - * @private - */ - _established() { - // 1. change the readyState attribute's value to OPEN - this._readyState = WebSocketClient.OPEN; - - // 2. TODO: change the extensions attribute's value to the extensions in use, if is not the null value - // this._extensions = - - // 3. TODO: change the protocol attribute's value to the subprotocol in use, if is not the null value - // this._protocol = - - // 4. TODO: act as if the user agent had received a set-cookie-string consisting of the cookies - // set during the server's opening handshake, for the URL url given to the WebSocket() constructor - // document.cookie = - - // 5. fire a simple event named open at the WebSocket object - this.dispatchEvent(new Event("open")); - } - - /** - * Task to run when "a WebSocket message has been received" - * @private - */ - _received(event) { - - // 1. If the readyState attribute's value is not OPEN (1), then abort these steps - if (this._readyState !== WebSocketClient.OPEN) { - return; - } - - // 2. let event be an event that uses the MessageEvent interface, - // with the event type message, which does not bubble, is not cancelable, - // and has no default action. - // 3. initialize event's origin attribute to the Unicode serialization of the origin of the URL - // that was passed to the WebSocket object's constructor. - // 4. - if type indicates that the data is Text, then initialize event's data attribute to data - // - if type indicates that the data is Binary, and binaryType is set to "blob", - // then initialize event's data attribute to a new Blob object that represents data as its raw data - // - if type indicates that the data is Binary, and binaryType is set to "arraybuffer", - // then initialize event's data attribute to a new read-only ArrayBuffer object whose contents are data - - // 2+3+4 already done before - - let e = new MessageEventClass("message", { - origin: this._url.href, - data: event.data, - }); - - // 5. dispatch event at the WebSocket object. - this.dispatchEvent(e); - } - - /** - * Task to run when "the WebSocket closing handshake is started" - * @private - */ - _closing() { - // change the readyState attribute to CLOSING (2) - this._readyState = WebSocketClient.CLOSING; - } - - - /** - * Task to run when "the WebSocket connection is closed" - * @private - */ - _closed(wasClean, code = 1005, reason = "") { - // 1. change the readyState attribute's value to CLOSED (3) - this._readyState = WebSocketClient.CLOSED; - - // 2. if the user agent was required to fail the WebSocket connection - // or the WebSocket connection is closed with prejudice, - // fire a simple event named error at the WebSocket object - - // TODO - - // 3. Create an event that uses the CloseEvent interface, - // with the event type close, which does not bubble, is not cancelable, has no default action, - // whose wasClean attribute is initialized to true if the connection closed cleanly and false otherwise, - // whose code attribute is initialized to the WebSocket connection close code, - // and whose reason attribute is initialized to the WebSocket connection close reason decoded as UTF-8, - // with error handling, and dispatch the event at the WebSocket object - - const event = new CloseEventClass("close", { - wasClean: wasClean, - code: code, - reason: reason, - }); - - this.dispatchEvent(event); - } - - // Handshake helper methods - - /** - * Perform the opening websocket handshake. - * Non-blocking, as needed when calling the method in the constructor. - * - * This method should be called by the constructor of the derived class, - * setting the socket specific to this derived class. - * - * @param socket underlying socket - */ - _start_opening_handshake(socket) { - // TODO: check interface - this._socket = socket; - - // parse url - let host, port, ressourceName, secure; - try { - [host, port, ressourceName, secure] = parseURL(this._url); - } catch (err) { - throw SyntaxError(`could not parse url: ${err}`); - } - - // perform handshake - this.__do_opening_handhake(host, port, ressourceName, secure).then(() => { - this._established(); - this._socket.onmessage = onOpenMessage(this); - this.__onopen(); - }).catch(() => { - this._readyState = WebSocketClient.CLOSED; - this._fail_the_websocket_connection(); - }); - } - - - /** - * Perform the WebSocket connection handshake. - * - * @returns Promise that resolves when connection was successfully established, - * or rejects otherwise with an error message. - * @private - */ - __do_opening_handhake(host, port, ressourceName, secure) { - if (secure) { - console.error("secure websocket not yet supported"); - } - - return new Promise((resolve, reject) => { - if (!(this._socket)) { - reject(`Socket not initialized`); - } - - let statusLine = ""; - let headerLines = []; - - const [clientHS, secWebSocketKey] = clientHandshake(host, port, ressourceName); - - // change onmessage of underlying socket - this._socket.onmessage = (pkt) => { // TODO: refactor to avoid request ? - let payload = naclUtil.encodeUTF8(pkt); - - // parse received packet as a HTTP websocket connection response - let lines = payload.split("\r\n"); - if (lines.length < 1) { - reject(`failed to connect to websocket: received empty http response`); - } - - if (statusLine) { - // following message (response was fragmented) - headerLines = headerLines.concat(lines); - } else { - // first message - statusLine = lines[0].split(" "); - headerLines = headerLines.concat(lines.slice(1)); - - // status code verification - if (statusLine.length < 3) { - reject(`failed to connect to websocket: invalid status line ${statusLine.join(" ")}`); - return; - } - - const statusCode = statusLine[1]; - - if (statusCode != "101") { - reject(`failed to connect to websocket: got status code ${statusCode}`); - return; - } - } - - if (headerLines[headerLines.length - 1] !== "") { - return; - } else { - // last line of headers, no body expected - // this means that this is the last packet expected - let headers = parseHeaders(headerLines.join("\r\n")); - - // verification of the headers - - // check for the upgrade header field - if (!("upgrade" in headers) || !(headers["upgrade"].toLowerCase().split(", ").includes("websocket"))) { - reject(`failed to connect to websoket: server handshake response invalid, does not contain 'upgrade: websocket' header line: ${headers}`); - return; - } - - // check for the connection header field - if (!("connection" in headers) || !(headers["connection"].toLowerCase().split(", ").includes("upgrade"))) { - reject(`failed to connect to websocket: server handshake response invalid, does not contain 'connection: upgrade' header line: ${headers}`); - return; - } - - // check for the sec-websocket-accept header field - if (!("sec-websocket-accept" in headers)) { - reject(`failed to connect to websocket: server handshake response invalid, does not contain 'sec-websocket-accept' header line: ${headers}`); - return; - } - - if (!verifySecWebSocketAccept(secWebSocketKey, headers["sec-websocket-accept"].trim())) { - reject(`failed to connect to websocket: 'sec-websocket-accept' could not be verified`); - return; - } - - // check for the sec-websocket-extensions header field - if ("sec-websocket-extensions" in headers) { - const serverExtensions = headers["sec-websocket-extensions"].split(", "); - // TODO: no support for extensions - if (serverExtensions.length > 1 || serverExtensions[0] !== "") { - reject(`failed to connect to websocket: extensions are not supported: ${headers["sec-websocket-extensions"]}`); - return; - } - } - - // check for the sec-websocket-protocol header field - if ("sec-websocket-protocol" in headers) { - const serverSubProtocols = headers["sec-websocket-protocol"].split(", "); - // TODO: no support for subprotocols - if (serverSubProtocols.length > 1 || serverSubProtocols[0] !== "") { - reject(`failed to connect to websocket: sub protocols are not supported: ${headers["sec-websocket-protocol"]}`); - return; - } - } - - resolve(); - } - }; - this._socket.send(naclUtil.decodeUTF8(clientHS)); - }); - - } - - } - - /** - * Helpers for the lightnion js-client code. - */ - - /** - * A Lightnion tunelled TCP socket. - * @private - */ - class LTCP { - // TODO: onclose - constructor(host) { - this.connected = false; - // TODO: document - // onmessage takes a UInt8Array argument - this.onmessage = (msg) => { console.error(`LTCP received non-handled message: ${msg}`); }; - this.host = host; - } - - send() { - throw "LTPC: undefined send method"; - } - } - - /** - * Connect to a Lightnion Proxy. - * @param {string} lnnHost host of the lightnion proxy - * @param {Number} lnnPort port of the lightnion proxy - * @returns a promise that resolves on connection success, and rejects in case of a failure; - * in case of success, return the lightnion endpoint, in case of failure, an error message - * @private - */ - function lnnOpen(lnnHost, lnnPort) { - return new Promise((resolve, reject) => { - lnn$2.open(lnnHost, lnnPort, function (endpoint) { - if (endpoint.state != lnn$2.state.success) { - console.error("lightnion proxy connection failed"); - reject(`could not connect to lightnion proxy at ${lnnHost}:${lnnPort}`); - } - console.debug("lightnion proxy connection established"); - resolve(endpoint); - }); - }); - } - - // Connect to TCP endpoint - // return a promise that resolves on connection success, and rejects in case of failure - // in case of succes, return a TCP object, in case of failure, an error message - /** - * Connect to a TCP endpoint through a Lightnion proxy. - * - * @param lnnEndpoint the lightnion proxy endpoint object, returned by {@link lnnOpen} - * @param host host of the TCP endpoint - * @param port port of the TCP endpoint - * @private - */ - function ltcpOpen(lnnEndpoint, host, port) { - - return new Promise((resolve, reject) => { - - let ltcp = new LTCP(host); - - function handler(socket) { - - let pkt; - - switch (socket.state) { - case lnn$2.state.created: - ltcp.connected = true; - ltcp.send = socket.send; - resolve(ltcp); - break; - case lnn$2.state.pending: - pkt = socket.recv(); - if (pkt !== undefined) { - ltcp.onmessage(pkt); - } - break; - case lnn$2.state.success: - ltcp.connected = false; - reject(`could not connect to TCP host at ${host}:${port}`); - break; - } - } - lnn$2.stream.tcp(lnnEndpoint, host, port, handler); - }); - } - - // TLS support. - // Uses forge.tls module. - // TODO: tests. - // export function ltlsOpen(lnnEndpoint, host, port) { - - // return ltcpOpen(lnnEndpoint, host, port).then(ltcp => { - // console.debug("tcp socket connected") - // return new Promise((resolve, reject) => { - // let tlsSocket = new LTCP(host); - - // // create tls client working on tcp - // let tlsClient = forge.tls.createConnection({ - // // see: https://github.com/digitalbazaar/forge#tls - // server: false, - // verify: function (connection, verified, depth, certs) { - // // FIXME - // return true; // skip cert. verif. (testing) - // }, - // connected: function (connection) { - // // (tls handshake finished, now ready to send) - // tlsSocket.onmessage = (req) => { tlsClient.process(lnn.enc.bin(req.recv())); }; - // tlsSocket.send = tlsClient.send; - // resolve(tlsSocket); - // }, - // tlsDataReady: function (connection) { - // // TLS -> TCP - // // (decode binary data into array before processing) - // ltcp.send(lnn.dec.bin(connection.tlsData.getBytes())); - // }, - // dataReady: function (connection) { - // // TLS -> Application - // // (receive decrypted data from the tls transport) - // var data = connection.data.getBytes(); - // onReceive(data); - // }, - // closed: function (connection) { - // console.info("tls connection closed"); - // }, - // error: function (connection, err) { - // console.error(`tls connection error: ${err}`); - // } - // }); - // console.debug("initiating tls handshake"); - // tlsClient.handshake(); - // }); - // }); - // } - - /** - * @module lightnion-websocket - */ - // import { ltlsOpen } from "./lightnion-helpers.js"; // TODO: TLS support - - /** - * LightnionWebSocket is a WebSocket client tunnelled through Lightnion. - */ - class LightnionWebSocket extends WebSocketClient { - - /** - * Create a LightnionWebSocket, a WebSocket tunelled through Tor via a Lightnion proxy. - * - * @param {string} url the WebSocket server URL - * @param {array} protocols a list of subprotocols to use, currently not-supported - * @param {string} lightnionHost the lightnion proxy host - * @param {Number} lightnionPort the lightnion proxy port - */ - constructor(url, protocols = [], lightnionHost = "localhost", lightnionPort = 4990) { - let urlP = new URL(url); - - let port = urlP.port; - if (!port) { - port = urlP.protocol == "ws:" ? "80" : "443"; - } - - super(urlP, protocols); - - // user defined event handlers - this.onmessage = () => { }; - this.onopen = () => { }; - this.onclose = () => { }; - this.onerror = () => { }; - - // schedule the tcp handshake to start when the underlying socket is ready - lnnOpen(lightnionHost, lightnionPort).then(lnnEndpoint => { - // open tcp socket to host, through lightnion - return ltcpOpen(lnnEndpoint, urlP.hostname, port); - // or open a tls socket - // return ltlsOpen(lnnEndpoint, urlP.hostname, port); - }).then(ltcp => { - console.debug("[LTCP]: connected"); - - // start websocket handshake protocol - this._start_opening_handshake(ltcp); - - // install handlers - this.__onmessage = (event) => { - this.onmessage(event); - }; - this.__onopen = (event) => { - this.onopen(event); - }; - this.__onclose = (event) => { - this.onclose(event); - }; - this.__onerror = (event) => { - this.onerror(event); - }; - - }); - } - } - - /* - * Exprots for Lightnion WebSocket Client. - * To use as a library. - */ - - /** - * @module lnn - */ - - if (!lib_3) { - // saving WebSocket default - // when using lightnion with redirected WebSockets, - // the client must still create a WebSocket to the lightnion proxy - // hence we save the standard WebSocket as _WebSocket - window._WebSocket = WebSocket; - } - - // header - let lnn$2 = lnn$1; - - // api - lnn$2.fast = fast; - lnn$2.auth = auth; - lnn$2.open = open; - lnn$2.agents = agents; - lnn$2.send_req = send_req; - lnn$2.http_request = http_request; - - // consensus parser - lnn$2.consensusParser = consensusParser; - - // endpoint - lnn$2.endpoint = endpoint; - - // get - lnn$2.get = {}; - lnn$2.get.guard = guard; - lnn$2.get.consensus = consensus; - lnn$2.get.descriptors = descriptors; - lnn$2.get.consensus_raw = consensus_raw; - lnn$2.get.descriptors_raw = descriptors_raw; - lnn$2.get.signing_keys = signing_keys; - - // io - lnn$2.io = {}; - lnn$2.io.polling = polling; - lnn$2.io.socket = socket; - - // ntor - lnn$2.ntor = ntor; - - // onion - lnn$2.onion = {}; - lnn$2.onion.ctr = ctr; - lnn$2.onion.sha = sha; - lnn$2.onion.forward = forward; - lnn$2.onion.backward = backward; - lnn$2.onion.build = build; - lnn$2.onion.peel = peel; - - // parser - lnn$2.parser = parser; - - // path - lnn$2.path = path; - - // post - lnn$2.post = {}; - lnn$2.post.create = create; - lnn$2.post.circuit_info = circuit_info; - lnn$2.post.handshake = handshake; - lnn$2.post.channel = channel; - lnn$2.post.extend = extend; - lnn$2.post.close = close; - - // relay - lnn$2.relay = relay; - - // signature - lnn$2.signature = {}; - lnn$2.signature.verify = verify; - lnn$2.signature.get_hash = get_hash; - lnn$2.signature.verify_key = verify_key; - lnn$2.signature.get_sig_and_keys_digests = get_sig_and_keys_digests; - lnn$2.signature.get_signature_big_int = get_signature_big_int; - lnn$2.signature.get_hash_from_rsa_cipher = get_hash_from_rsa_cipher; - - // stream - lnn$2.stream = stream; - - // utils - lnn$2.enc = {}; - lnn$2.enc.bits = enc.bits; - lnn$2.enc.utf8 = enc.utf8; - lnn$2.enc.base64 = enc.base64; - lnn$2.enc.bin = enc.bin; - - lnn$2.dec = {}; - lnn$2.dec.bits = dec.bits; - lnn$2.dec.utf8 = dec.utf8; - lnn$2.dec.base64 = dec.base64; - lnn$2.dec.bin = dec.bin; - - // websocket - lnn$2.websocket = LightnionWebSocket; - - window.lnn = lnn$2; - - exports.lnn = lnn$2; - - return exports; - -}({})); -//# sourceMappingURL=lightnion.bundle.js.map diff --git a/js-client/vendor/sjcl b/js-client/vendor/sjcl deleted file mode 160000 index 85caa53..0000000 --- a/js-client/vendor/sjcl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 85caa53c281eeeb502310013312c775d35fe0867 diff --git a/lightnion/__init__.py b/lightnion/__init__.py index dec53af..e811d8c 100644 --- a/lightnion/__init__.py +++ b/lightnion/__init__.py @@ -5,15 +5,11 @@ import lightnion.cell import lightnion.cache -import lightnion.socket -import lightnion.link import lightnion.create import lightnion.onion -import lightnion.hop import lightnion.consensus import lightnion.descriptors -import lightnion.extend import lightnion.signature diff --git a/lightnion/cell/__init__.py b/lightnion/cell/__init__.py deleted file mode 100644 index 17c0f0e..0000000 --- a/lightnion/cell/__init__.py +++ /dev/null @@ -1,89 +0,0 @@ -from .. import constants -from . import view - -class cmd(view.enum(1)): - PADDING = 0x00 - CREATE = 0x01 - CREATED = 0x02 - RELAY = 0x03 - DESTROY = 0x04 - CREATE_FAST = 0x05 - CREATED_FAST = 0x06 - VERSIONS = 0x07 - NETINFO = 0x08 - RELAY_EARLY = 0x09 - CREATE2 = 0x0a - CREATED2 = 0x0b - PADDING_NEGOTIATE = 0x0c - VPADDING = 0x80 - CERTS = 0x81 - AUTH_CHALLENGE = 0x82 - AUTHENTICATE = 0x83 - AUTHORIZE = 0x84 - - @property - def is_fixed(self): - return not self.is_variable - - @property - def is_variable(self): - if bool(0x80 & self._value_): - return True - return self._value_ == int(cmd.VERSIONS) - -header_view = view.fields( - circuit_id=view.uint(4), cmd=cmd) -header_legacy_view = view.fields( - circuit_id=view.uint(2), cmd=cmd, length=view.cache(view.uint, init=[2])) -header_variable_view = view.fields( - circuit_id=view.uint(4), cmd=cmd, length=view.cache(view.uint, init=[2])) - -class cell_view(view.packet): - _whitelist = [header_view, header_legacy_view, header_variable_view] - def __init__(self, header): - if header not in self._whitelist: - raise ValueError('Invalid header type: {}'.format(header)) - super().__init__(header_view=header, fixed_size=constants.payload_len) - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd.is_fixed == self.fixed_size - -variable_size = view.like(cell_view(header_variable_view), 'variable_size') -legacy_size = view.like(cell_view(header_legacy_view), 'legacy_size') -fixed_size = view.like(cell_view(header_view), 'fixed_size') - -header = view.like(header_view, 'header') -header_legacy = view.like(header_legacy_view, 'header_legacy') -header_variable = view.like(header_variable_view, 'header_variable') - -def pad(payload): - try: - payload = payload.raw - except AttributeError: - pass - - cell_header = header(payload) - if not cell_header.valid: - raise RuntimeError('Invalid cell header: {}'.format(cell_header.raw)) - - length = constants.payload_len + cell_header.width - if not cell_header.cmd.is_fixed: - cell_header = header_variable(payload) - if not cell_header.valid: - raise RuntimeError( - 'Invalid variable cell header: {}'.format(cell_header.raw)) - - length = cell_header.length + cell_header.width - if length > constants.max_payload_len: - raise RuntimeError('Invalid cell length: {}'.format(length)) - - return payload.ljust(length, b'\x00') - -from . import address -from . import ( - padding, relay, destroy, create_fast, created_fast, versions, netinfo, - relay_early, create2, created2, certs, challenge) diff --git a/lightnion/cell/address.py b/lightnion/cell/address.py deleted file mode 100644 index c6c25cb..0000000 --- a/lightnion/cell/address.py +++ /dev/null @@ -1,55 +0,0 @@ -from . import view as _view - -import ipaddress - -class addr_type(_view.enum(1, cached=True)): - HOSTNAME = 0x00 - IPV4_ADDR = 0x04 - IPV6_ADDR = 0x06 - ERROR_TRANS = 0xF0 - ERROR_NON_TRANS = 0xF1 - -header_view = _view.fields(**{ - 'type': addr_type, - 'length': _view.cache(_view.uint, init=[1])}) - -class address_view(_view.packet): - _default_extra_fields = ['type'] - _default_header_view = header_view - _default_data_name = 'host' - - def __init__(self, *kargs, **kwargs): - super().__init__(*kargs, **kwargs) - - length = self.header._fields['length'] - self._fields['host'] = _view.union( - view_table={ - addr_type.HOSTNAME: _view.codec('utf8', size=length), - addr_type.IPV4_ADDR: _view.ip_address(version=4), - addr_type.IPV6_ADDR: _view.ip_address(version=6), - addr_type.ERROR_TRANS: _view.data(length), - addr_type.ERROR_NON_TRANS: _view.data(length) - }, union_tag=self.header._fields['type']) - -view = address_view() -address = _view.like(view, 'address') - -def pack(host, type_hint=None): - if type_hint is None: - try: - ipaddress.IPv4Address(host) - type_hint = addr_type.IPV4_ADDR - except ValueError: - ipaddress.IPv6Address(host) - type_hint = addr_type.IPV6_ADDR - - base = address(b'') - base.header.set(**{'type': type_hint, 'length': 0}) - - length = base._view.host.width() - if length == 0: - length = len(host) - base.header.set(length=length) - - base.set(host=host) - return base diff --git a/lightnion/cell/certs.py b/lightnion/cell/certs.py deleted file mode 100644 index a9b028c..0000000 --- a/lightnion/cell/certs.py +++ /dev/null @@ -1,42 +0,0 @@ -from .. import cell as _cell -from . import view as _view - -class cert_type(_view.enum(1)): - RSA_SIGNED_LINK_KEY = 0x01 - RSA_SELF_SIGNED_IDENTITY = 0x02 - RSA_SIGNED_AUTHENTICATE = 0x03 - ED_SIGNED_SIGNING_KEY = 0x04 - ED_SIGNED_TLS_LINK = 0x05 - ED_SIGNED_AUTHENTICATE = 0x06 - RSA_SIGNED_ED_IDENTITY = 0x07 - -cert_header_view = _view.fields( - **{'type': cert_type, 'clen': _view.cache(_view.uint, init=[2])}) -cert_view = _view.packet(header_view=cert_header_view, field_name='clen') - -certs_header_view = _view.fields(quantity=_view.cache(_view.uint, init=[1])) -class _certs_view(_view.packet): - _default_header_view = certs_header_view - _default_field_name = 'quantity' - _default_data_name = 'listing' - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self._fields['listing'] = _view.series(cert_view, - self._fields['header'].quantity) - -certs_view = _certs_view() -class cell_view(_view.packet): - _default_header_view = _cell.header_variable_view - _default_data_name = 'certs' - _default_data_view = certs_view - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.CERTS - -view = cell_view() -cell = _view.like(view, 'certs_cell') diff --git a/lightnion/cell/challenge.py b/lightnion/cell/challenge.py deleted file mode 100644 index e53d3d6..0000000 --- a/lightnion/cell/challenge.py +++ /dev/null @@ -1,49 +0,0 @@ -from .. import cell as _cell -from . import view as _view -from . import common - -import os - -class auth_type(_view.enum(2)): - RSA_AUTH = 0x01 - ED_AUTH = 0x03 - -auth_header_view = _view.fields( - challenge=_view.data(32), - quantity=common.length_halved_view(2)) - -class _auth_view(_view.packet): - _default_header_view = auth_header_view - _default_data_name = 'methods' - _max_size = 2 * auth_type.width() - - def __init__(self, *kargs, **kwargs): - super().__init__(*kargs, **kwargs) - self._fields['methods'] = _view.series( - auth_type, self._fields['header'].quantity) - -auth_view = _auth_view() -class cell_view(_view.packet): - _default_header_view = _cell.header_variable_view - _default_data_view = auth_view - _default_data_name = 'auth' - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.AUTH_CHALLENGE - -view = cell_view() -cell = _view.like(view, 'auth_challenge_cell') - -def pack(*methods, challenge=None): - if challenge is None: - challenge = os.urandom(32) - - base = cell(b'') - base.header.set(circuit_id=0, cmd=_cell.cmd.AUTH_CHALLENGE, length=0) - base.auth.set(challenge=challenge, quantity=len(methods), methods=methods) - base.set(length=base.auth.width) - return base diff --git a/lightnion/cell/common.py b/lightnion/cell/common.py deleted file mode 100644 index 68d8e82..0000000 --- a/lightnion/cell/common.py +++ /dev/null @@ -1,16 +0,0 @@ -from . import view as _view - -class length_halved_view(_view.cache(_view.uint)): - def cache(self): - return super().cache() // 2 - - def iseven(self): - return bool(self._cache.value % 2 == 0) - - def write(self, payload=b'', value=None): - return super().write(payload, value * 2) - - def valid(self, payload=b''): - if not super().valid(payload): - return False - return self.value(payload) > 0 and self.cached() and self.iseven() diff --git a/lightnion/cell/create2.py b/lightnion/cell/create2.py deleted file mode 100644 index b0f29c5..0000000 --- a/lightnion/cell/create2.py +++ /dev/null @@ -1,34 +0,0 @@ -from .. import cell as _cell -from . import view as _view - -create_header_view = _view.fields(**{ - 'type': _cell.relay.extend2.handshake_type, - 'length': _view.cache(_view.uint, init=[2])}) - -class create_view(_view.packet): - _default_header_view = create_header_view - -class cell_view(_view.packet): - _default_header_view = _cell.header_view - _default_data_name = 'create2' - _default_data_view = create_view() - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.CREATE2 - -view = cell_view() -cell = _view.like(view, 'create2_cell') - -def pack(circuit_id, handshake_data): - base = cell(b'') - base.set( - circuit_id=circuit_id, - cmd=_cell.cmd.CREATE2, - create2=dict(**{'type': _cell.relay.extend2.handshake_type.NTOR, - 'length': len(handshake_data), - 'data': handshake_data})) - return base diff --git a/lightnion/cell/create_fast.py b/lightnion/cell/create_fast.py deleted file mode 100644 index e91d625..0000000 --- a/lightnion/cell/create_fast.py +++ /dev/null @@ -1,33 +0,0 @@ -from .. import constants -from .. import cell as _cell -from . import view as _view - -import os - -create_fast_view = _view.fields(material=_view.data(constants.hash_len)) - -class cell_view(_view.packet): - _default_header_view = _cell.header_view - _default_data_name = 'create_fast' - _default_data_view = create_fast_view - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.CREATE_FAST - -view = cell_view() -cell = _view.like(view, 'create_fast_cell') - -def pack(circuit_id, material=None): - if material is None: - material = os.urandom(constants.hash_len) - - base = cell(b'') - base.set( - circuit_id=circuit_id, - cmd=_cell.cmd.CREATE_FAST, - create_fast=dict(material=material)) - return base diff --git a/lightnion/cell/created2.py b/lightnion/cell/created2.py deleted file mode 100644 index afa8fd1..0000000 --- a/lightnion/cell/created2.py +++ /dev/null @@ -1,22 +0,0 @@ -from .. import cell as _cell -from . import view as _view - -created_header_view = _view.fields(length=_view.cache(_view.uint, init=[2])) - -class created_view(_view.packet): - _default_header_view = created_header_view - -class cell_view(_view.packet): - _default_header_view = _cell.header_view - _default_data_name = 'created2' - _default_data_view = created_view() - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.CREATED2 - -view = cell_view() -cell = _view.like(view, 'created2_cell') diff --git a/lightnion/cell/created_fast.py b/lightnion/cell/created_fast.py deleted file mode 100644 index 14c7410..0000000 --- a/lightnion/cell/created_fast.py +++ /dev/null @@ -1,32 +0,0 @@ -from .. import constants - -from .. import cell as _cell -from . import view as _view - -import os - -created_fast_view = _view.fields(material=_view.data(constants.hash_len), - derivative=_view.data(constants.hash_len)) - -class cell_view(_view.packet): - _default_header_view = _cell.header_view - _default_data_name = 'created_fast' - _default_data_view = created_fast_view - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.CREATED_FAST - -view = cell_view() -cell = _view.like(view, 'created_fast_cell') - -def pack(circuit_id, material, derivative): - base = cell(b'') - base.set( - circuit_id=circuit_id, - cmd=_cell.cmd.CREATED_FAST, - created_fast=dict(material=material, derivative=derivative)) - return base diff --git a/lightnion/cell/destroy.py b/lightnion/cell/destroy.py deleted file mode 100644 index bba0d36..0000000 --- a/lightnion/cell/destroy.py +++ /dev/null @@ -1,37 +0,0 @@ -from .. import cell as _cell -from . import view as _view - -class reason(_view.enum(1)): - NONE = 0x00 - PROTOCOL = 0x01 - INTERNAL = 0x02 - REQUESTED = 0x03 - HIBERNATING = 0x04 - RESOURCELIMIT = 0x05 - CONNECTFAILED = 0x06 - OR_IDENTITY = 0x07 - OR_CONN_CLOSED = 0x08 - FINISHED = 0x09 - TIMEOUT = 0x0a - DESTROYED = 0x0b - NOSUCHSERVICE = 0x0c - -class cell_view(_view.packet): - _default_header_view = _cell.header_view - _default_data_name = 'reason' - _default_data_view = reason - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.DESTROY - -view = cell_view() -cell = _view.like(view, 'destroy_cell') - -def pack(circuit_id, reason): - base = cell(b'') - base.set(circuit_id=circuit_id, cmd=_cell.cmd.DESTROY, reason=reason) - return base diff --git a/lightnion/cell/netinfo.py b/lightnion/cell/netinfo.py deleted file mode 100644 index 1791111..0000000 --- a/lightnion/cell/netinfo.py +++ /dev/null @@ -1,64 +0,0 @@ -from .. import cell as _cell -from . import view as _view - -import time - -netinfo_header_view = _view.fields(timestamp=_view.uint(4), - other=_cell.address.view, quantity=_view.cache(_view.uint, init=[1])) - -class _netinfo_view(_view.packet): - _default_header_view = netinfo_header_view - _default_field_name = 'quantity' - _default_data_name = 'addresses' - - _addr_type_whitelist = [ - _cell.address.addr_type.IPV4_ADDR, _cell.address.addr_type.IPV6_ADDR] - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self._fields['addresses'] = _view.series(_cell.address.view, - self._fields['header'].quantity) - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - number = self.header.value(payload, field='quantity') - offset = self.offset(payload, field='addresses') - for i in range(number): - roff = self.addresses.offset(payload[offset:], field=i) - addr = self.addresses.item.type.value(payload[offset+roff:]) - if addr not in self._addr_type_whitelist: - return False - return True - -netinfo_view = _netinfo_view() -class cell_view(_view.packet): - _default_header_view = _cell.header_view - _default_data_name = 'netinfo' - _default_data_view = netinfo_view - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.NETINFO - -view = cell_view() -cell = _view.like(view, 'netinfo_cell') - -def pack(other_address, *addresses, timestamp=None): - if timestamp is None: - timestamp = int(time.time()) - - base = cell(b'') - base.set( - circuit_id=0, - cmd=_cell.cmd.NETINFO, - netinfo=dict( - timestamp=timestamp, - other=_cell.address.pack(other_address).value(), - quantity=len(addresses), - addresses=[_cell.address.pack(a).value() for a in addresses])) - return base diff --git a/lightnion/cell/padding.py b/lightnion/cell/padding.py deleted file mode 100644 index 4b42e59..0000000 --- a/lightnion/cell/padding.py +++ /dev/null @@ -1,21 +0,0 @@ -from .. import cell as _cell -from . import view as _view - -class cell_view(_view.packet): - _default_header_view = _cell.header_view - _default_fixed_size = 0 - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.PADDING - -view = cell_view() -cell = _view.like(view, 'padding_cell') - -def pack(): - base = cell(b'') - base.set(circuit_id=0, cmd=_cell.cmd.PADDING) - return base diff --git a/lightnion/cell/relay/__init__.py b/lightnion/cell/relay/__init__.py deleted file mode 100644 index 9c0dfda..0000000 --- a/lightnion/cell/relay/__init__.py +++ /dev/null @@ -1,147 +0,0 @@ -from ... import constants - -from ... import cell as _cell -from .. import view as _view - -payload_len = constants.payload_len - 11 - -class cmd(_view.enum(1)): - RELAY_BEGIN = 0x01 - RELAY_DATA = 0x02 - RELAY_END = 0x03 - RELAY_CONNECTED = 0x04 - RELAY_SENDME = 0x05 - RELAY_EXTEND = 0x06 - RELAY_EXTENDED = 0x07 - RELAY_TRUNCATE = 0x08 - RELAY_TRUNCATED = 0x09 - RELAY_DROP = 0x0a - RELAY_RESOLVE = 0x0b - RELAY_RESOLVED = 0x0c - RELAY_BEGIN_DIR = 0x0d - RELAY_EXTEND2 = 0x0e - RELAY_EXTENDED2 = 0x0f - - @property - def is_forward(self): - return self in [ - cmd.RELAY_BEGIN, - cmd.RELAY_DATA, - cmd.RELAY_END, - cmd.RELAY_SENDME, - cmd.RELAY_EXTEND, - cmd.RELAY_TRUNCATE, - cmd.RELAY_DROP, - cmd.RELAY_RESOLVE, - cmd.RELAY_BEGIN_DIR, - cmd.RELAY_EXTEND2] - - @property - def is_backward(self): - return self in [ - cmd.RELAY_DATA, - cmd.RELAY_END, - cmd.RELAY_CONNECTED, - cmd.RELAY_SENDME, - cmd.RELAY_EXTENDED, - cmd.RELAY_TRUNCATED, - cmd.RELAY_DROP, - cmd.RELAY_RESOLVED, - cmd.RELAY_EXTENDED2] - - @property - def is_circuit(self): - return self in [ - cmd.RELAY_BEGIN, - cmd.RELAY_DATA, - cmd.RELAY_END, - cmd.RELAY_CONNECTED, - cmd.RELAY_SENDME, - cmd.RELAY_RESOLVE, - cmd.RELAY_RESOLVED, - cmd.RELAY_BEGIN_DIR] - - @property - def is_control(self): - return self in [ - cmd.RELAY_SENDME, - cmd.RELAY_EXTEND, - cmd.RELAY_EXTENDED, - cmd.RELAY_TRUNCATE, - cmd.RELAY_TRUNCATED, - cmd.RELAY_DROP, - cmd.RELAY_EXTEND2, - cmd.RELAY_EXTENDED2] - -relay_header_view = _view.fields( - cmd=cmd, - recognized=_view.data(2), - stream_id=_view.uint(2), - digest=_view.data(4), - length=_view.cache(_view.uint, init=[2])) - -class relay_view(_view.packet): - _default_header_view = relay_header_view - _max_size = payload_len - - def valid(self, payload=b''): - if not self.header.valid(payload): - return False - - if not self.header.value(payload, 'recognized') == b'\x00\x00': - return True - - return super().valid(payload) - -payload_view = relay_view() -payload = _view.like(payload_view, 'relay_payload') - -class cell_view(_view.packet): - _default_data_view = payload_view - _default_data_name = 'relay' - _default_fixed_size = constants.payload_len - _default_header_view = _cell.header_view - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - if not cell_cmd == _cell.cmd.RELAY: - return False - - offset = self.offset(payload, field='relay') - circuit_id = self.header.value(payload, field='circuit_id') - relay_cmd = self.relay.header.value(payload[offset:], field='cmd') - if circuit_id == 0 and not relay_cmd.is_control: - return False - return True - -view = cell_view() -cell = _view.like(view, 'relay_cell') - -def _pack_details(base, cmd, recognized, stream_id, digest, data): - base.relay.header.set( - cmd=cmd, - recognized=recognized, - stream_id=stream_id, - digest=digest, - length=len(data)) - base.set(relay=dict(data=data)) - - # Preemptively add \x00 padding (as it is included within digests) - base.relay.raw = base.relay.raw.ljust(constants.payload_len, b'\x00') - if not base.valid: - raise RuntimeError( - 'Invalid RELAY cell after padding: {}'.format(base.raw)) - - return base - -def pack(circuit_id, cmd, data, recognized=b'\x00\x00', *, stream_id, digest): - base = cell(b'') - base.header.set( - circuit_id=circuit_id, - cmd=_cell.cmd.RELAY) - return _pack_details(base, cmd, recognized, stream_id, digest, data) - -from . import extend2, extended2 diff --git a/lightnion/cell/relay/extend2.py b/lightnion/cell/relay/extend2.py deleted file mode 100644 index 328c018..0000000 --- a/lightnion/cell/relay/extend2.py +++ /dev/null @@ -1,116 +0,0 @@ -import base64 - -from ... import cell as _cell -from .. import view as _view - -class linkspec_type(_view.enum(1, cached=True)): - TLS_TCP_4 = 0x00 - TLS_TCP_6 = 0x01 - LEGACY_ID = 0x02 - ED_ID = 0x03 - -linkspec_header_view = _view.fields(**{ - 'type': linkspec_type, - 'length': _view.cache(_view.uint, init=[1])}) - -class linkspec_view(_view.packet): - _default_extra_fields = ['type'] - _default_header_view = linkspec_header_view - - def __init__(self, *kargs, **kwargs): - super().__init__(*kargs, **kwargs) - - self._fields['data'] = _view.union( - view_table={ - linkspec_type.TLS_TCP_4: _view.fields( - addr=_view.ip_address(version=4), port=_view.uint(2)), - linkspec_type.TLS_TCP_6: _view.fields( - addr=_view.ip_address(version=6), port=_view.uint(2)), - linkspec_type.LEGACY_ID: _view.data(20), - linkspec_type.ED_ID: _view.data(32) - }, union_tag=self.header._fields['type']) -linkspec = _view.like(linkspec_view(), 'linkspec') - -linkspecs_header_view = _view.fields( - quantity=_view.cache(_view.uint, init=[1])) - -class linkspecs_view(_view.packet): - _default_header_view = linkspecs_header_view - _default_field_name = 'quantity' - _default_data_name = 'specs' - - def __init__(self, *kargs, **kwargs): - super().__init__(*kargs, **kwargs) - self._fields['specs'] = _view.series(linkspec_view(), - self._fields['header'].quantity) - -class handshake_type(_view.enum(2)): - # TAP = 0x0001 # TODO: add support for TAP handshakes? - NTOR = 0x0002 - -extend2_header_view = _view.fields(**{'link': linkspecs_view(), - 'type': handshake_type, 'length': _view.cache(_view.uint, init=[2])}) - -class extend2_view(_view.packet): - _default_header_view = extend2_header_view - -view = extend2_view() -payload = _view.like(view, 'extend2_payload') - -def _pack_linkspec_addr(addr, port): - addr = _cell.address.pack(addr) - - base = linkspec(b'') - if addr['type'] == _cell.address.addr_type.IPV4_ADDR: - base.type = linkspec_type.TLS_TCP_4 - elif addr['type'] == _cell.address.addr_type.IPV6_ADDR: - base.type = linkspec_type.TLS_TCP_6 - else: - raise RuntimeError('Invalid address: {}'.format(addr)) - - base.length = 0 - base.data.addr = addr.host - base.data.port = port - - base.set(length=base.data.width) - return base - -def _pack_linkspec_identity(identity): - if isinstance(identity, str): - identity = base64.b64decode(identity + '====') - - base = linkspec(b'') - if len(identity) == 20: - base.type = linkspec_type.LEGACY_ID - elif len(identity) == 32: - base.type = linkspec_type.ED_ID - else: - raise RuntimeError('Invalid identity: {}'.format(identity)) - - base.length = 0 - base.data = identity - - base.set(length=len(identity)) - return base - -def pack(handshake, addresses=[], identities=[]): - if len(addresses) < 1: - raise RuntimeError('Expect at least one address!') - if len(identities) > 2: - raise RuntimeError('Expect at most two identities!') - - specs = [] - for addr, port in addresses: - specs.append(_pack_linkspec_addr(addr, port).value()) - - for identity in identities: - specs.append(_pack_linkspec_identity(identity).value()) - - if not any([s['type'] == linkspec_type.ED_ID for s in specs]): - raise RuntimeError('Require at least one ed25519 identity!') - - base = payload(b'') - base.header.link.set(quantity=len(specs), specs=specs) - base.header.set(**{'type': handshake_type.NTOR, 'length': len(handshake)}) - base.set(data=handshake) - return base diff --git a/lightnion/cell/relay/extended2.py b/lightnion/cell/relay/extended2.py deleted file mode 100644 index 92b8112..0000000 --- a/lightnion/cell/relay/extended2.py +++ /dev/null @@ -1,10 +0,0 @@ -from ... import cell as _cell -from .. import view as _view - -extended2_header_view = _view.fields(length=_view.cache(_view.uint, init=[2])) - -class extended2_view(_view.packet): - _default_header_view = extended2_header_view - -view = extended2_view() -payload = _view.like(view, 'extended2_payload') diff --git a/lightnion/cell/relay_early.py b/lightnion/cell/relay_early.py deleted file mode 100644 index e9a3825..0000000 --- a/lightnion/cell/relay_early.py +++ /dev/null @@ -1,37 +0,0 @@ -from .. import constants - -from .. import cell as _cell -from . import view as _view - -from . import relay - -class cell_view(_view.packet): - _default_data_view = relay.payload_view - _default_data_name = 'relay' - _default_fixed_size = constants.payload_len - _default_header_view = _cell.header_view - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - if not cell_cmd == _cell.cmd.RELAY_EARLY: - return False - - offset = self.offset(payload, field='relay') - circuit_id = self.header.value(payload, field='circuit_id') - relay_cmd = self.relay.header.value(payload[offset:], field='cmd') - if circuit_id == 0 and not relay_cmd.is_control: - return False - return True - -view = cell_view() -cell = _view.like(view, 'relay_early_cell') - -def pack(circuit_id, cmd, data, recognized=b'\x00\x00', *, stream_id, digest): - base = cell(b'') - base.header.set( - circuit_id=circuit_id, - cmd=_cell.cmd.RELAY_EARLY) - return relay._pack_details(base, cmd, recognized, stream_id, digest, data) diff --git a/lightnion/cell/versions.py b/lightnion/cell/versions.py deleted file mode 100644 index d4b9478..0000000 --- a/lightnion/cell/versions.py +++ /dev/null @@ -1,68 +0,0 @@ -from .. import constants -from . import common - -from .. import cell as _cell -from . import view as _view - -header_view = _view.fields( - circuit_id=_view.uint(2), - cmd=_cell.cmd, - length=common.length_halved_view(2)) - -class cell_view(_view.packet): - def __init__(self, header=header_view): - super().__init__(header_view=header, data_name='versions') - self._fields['versions'] = _view.series( - _view.uint(2), header.length) - self._max_size = 64 * 2 - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - cell_cmd = self.header.value(payload, field='cmd') - return cell_cmd == _cell.cmd.VERSIONS - -view = cell_view() -cell = _view.like(view, 'versions_cell') -header = _view.like(header_view, 'versions_header') - -def pack(versions): - vercell = cell(b'') - vercell.header.set( - circuit_id=0, - cmd=_cell.cmd.VERSIONS, - length=len(versions)) - vercell.set(versions=versions) - return vercell - -def recv(peer): - answer = peer.recv(_cell.header_legacy_view.width()) - - header = _cell.header_legacy(answer) - if not header.valid: - raise RuntimeError('Invalid v2 cell header: {}'.format(header.raw)) - if not header.cmd == _cell.cmd.VERSIONS: - raise RuntimeError('Expecting VERSIONS, got: {}'.format(header.cmd)) - - length = header.length - if length > constants.max_payload_len: - raise RuntimeError('VERSIONS cell too long: {}'.format(header.length)) - - answer += peer.recv(length) - if not view.valid(answer): - raise RuntimeError('Invalid VERSIONS cell: {}'.format(answer)) - - return cell(answer) - -def send(peer, payload): - try: - payload = payload.raw - except AttributeError: - pass - - vercell = cell(payload) - if not vercell.valid: - raise RuntimeError('VERSIONS cell invalid: {}'.format(payload)) - - return peer.sendall(payload) diff --git a/lightnion/cell/view.py b/lightnion/cell/view.py deleted file mode 100644 index 9930091..0000000 --- a/lightnion/cell/view.py +++ /dev/null @@ -1,887 +0,0 @@ -import collections -import threading -import ipaddress -import inspect -import codecs -import enum as _enum - -class basic: - def width(self, payload=b''): - raise NotImplementedError - - def valid(self, payload=b''): - raise NotImplementedError - - def value(self, payload=b'', field=None): - raise NotImplementedError - - def write(self, payload=b'', value=None, **kwargs): - raise NotImplementedError - - def __contains__(self, field): - return False - -class composite(basic): - def write(self, payload=b'', value=None, **kwargs): - raise NotImplementedError - - def __len__(self): - raise NotImplementedError - - def __contains__(self, field): - raise NotImplementedError - - def __getitem__(self, field): - raise NotImplementedError - -class uint(basic): - def __init__(self, size, byteorder='big'): - if size < 1: - raise ValueError('Invalid uint size: {}'.format(size)) - if byteorder not in ['big', 'little']: - raise ValueError('Invalid uint byteorder: {}'.format(byteorder)) - self.byteorder = byteorder - self.size = size - - def width(self, payload=b''): - return self.size - - def valid(self, payload=b''): - return len(payload) >= self.size - - def value(self, payload=b'', field=None): - return int.from_bytes(payload[:self.size], byteorder=self.byteorder) - - def write(self, payload=b'', value=None, **kwargs): - value = int(value).to_bytes(self.size, byteorder=self.byteorder) - return value + payload[self.size:] - -def enum(size, byteorder='big', typename=None, cached=False): - if typename is not None and not typename.isidentifier(): - raise ValueError('Typename {} is not an identifier'.format(typename)) - - @_enum.unique - class _anonymous_enum(_enum.Enum): - def __new__(cls, value): - member = object.__new__(cls) - member._value_ = value - return member - - @classmethod - def width(cls, payload=b''): - return size - - @classmethod - def valid(cls, payload=b''): - if len(payload) < size: - return False - - try: - cls.value(payload) - return True - except ValueError: - return False - - def __int__(self): - return self._value_ - - @classmethod - def value(cls, payload=b'', field=None): - value = int.from_bytes(payload[:size], byteorder='big') - return cls(value) - - @classmethod - def write(cls, payload=b'', value=None, **kwargs): - value = int(cls(value)).to_bytes(size, byteorder='big') - return value + payload[size:] - - if cached: - class _anonymous_cached_enum(_anonymous_enum): - @classmethod - def cache(cls): - if not cls.cached(): - raise RuntimeError('Bounded value unknown at runtime: ' - + 'Have you called .value() of parent view yet?') - return cls._cache.value - - @classmethod - def cached(cls): - return cls._cache.value is not None - - @classmethod - def value(cls, payload=b'', field=None): - value = int.from_bytes(payload[:size], byteorder='big') - cls._cache.value = cls(value) - return cls.cache() - - @classmethod - def write(cls, payload=b'', value=None, **kwargs): - cls._cache.value = cls(value) - packed = int(cls.cache()).to_bytes(size, byteorder='big') - return packed + payload[size:] - - _anonymous_cached_enum._cache = threading.local() - _anonymous_cached_enum._cache.value = None - _anonymous_enum = _anonymous_cached_enum - - if typename is not None: - _anonymous_enum.__qualname__ = typename - return _anonymous_enum - -class data(basic): - def __init__(self, size): - if isinstance(size, int) and not size < 0: - fixed = True - elif isview(size) and iscached(size): - fixed = False - else: - raise ValueError('Invalid size: {}'.format(size)) - self.length = size - self.fixed = fixed - - @property - def size(self): - if self.fixed: - return self.length - return self.length.cache() - - def width(self, payload=b''): - return self.size - - def valid(self, payload=b''): - if not self.fixed and not self.length.cached(): - return False - return len(payload) >= self.size - - def value(self, payload=b'', field=None): - return payload[:self.size] - - def write(self, payload=b'', value=None, **kwargs): - if len(value) != self.size: - raise ValueError('Invalid value size: {} instead of {}'.format( - len(value), self.size)) - return value + payload[self.size:] - -class fields(composite): - def __init__(self, **kwargs): - for key, view in kwargs.items(): - if not isview(view): - raise TypeError('Field {} is not a view: {}'.format(key, view)) - self._fields = collections.OrderedDict(kwargs) - - def list_fields(self): - return list(self._fields) - - def visit(self, payload=b'', operator=lambda v, p: v.width(p)): - results = [] - for _, view in self._fields.items(): - width = view.width(payload) - results.append(operator(view, payload)) - payload = payload[width:] - return results - - def offset(self, payload=b'', field=None): - if field not in self: - raise ValueError('Field {} not in fields'.format(field)) - - offset = 0 - for key, view in self._fields.items(): - if key == field: - return offset - width = view.width(payload) - offset += width - payload = payload[width:] - - def width(self, payload=b''): - return sum(self.visit(payload, lambda v, p: v.width(p))) - - def valid(self, payload=b''): - for field, view in self._fields.items(): - if not view.valid(payload): - return False - width = view.width(payload) - payload = payload[width:] - return True - - def value(self, payload=b'', field=None): - if field is None: - values = self.visit(payload, lambda v, p: v.value(p)) - return {key: value - for (key, _), value in zip(self._fields.items(), values)} - - offset = self.offset(payload, field) - return self._fields[field].value(payload[offset:]) - - def write(self, payload=b'', value=None, **kwargs): - if len(kwargs) > 0: - if value is not None: - raise RuntimeError('Conflict: value and kwargs both given.') - value = kwargs - - for field, svalue in value.items(): - offset = self.offset(payload, field) - svalue = self._fields[field].write(payload[offset:], svalue) - payload = payload[:offset] + svalue - return payload - - def __len__(self): - return len(self._fields) - - def __contains__(self, field): - return field in self._fields - - def __getitem__(self, field): - return self.__getattr__(field) - - def __getattr__(self, field): - if field.startswith('__'): - raise AttributeError - return self._fields[field] - -class packet(fields): - _max_size = 1024 * 1024 - _default_extra_fields = None - _default_header_view = None - _default_field_name = 'length' - _default_fixed_size = 0 - _default_data_view = data - _default_data_name = 'data' - - def __init__(self, header_view=None, fixed_size=None, field_name=None, - data_name=None, data_view=None, extra_fields=None): - - if extra_fields is None: - extra_fields = self._default_extra_fields - if extra_fields is None: - extra_fields = [] - if header_view is None: - header_view = self._default_header_view - if field_name is None: - field_name = self._default_field_name - if fixed_size is None: - fixed_size = self._default_fixed_size - if data_view is None: - data_view = self._default_data_view - if data_name is None: - data_name = self._default_data_name - - if not isinstance(header_view, fields): - raise TypeError('Header not a view.fields: {}'.format(header_view)) - - self._fixed_size = True - if field_name in header_view: - self._fixed_size = False - extra_fields.append(field_name) - - if inspect.isclass(data_view): - if self._fixed_size: - data_view = data_view(fixed_size) - else: - data_view = data_view(header_view._fields[field_name]) - - if not isview(data_view): - raise TypeError('Data view not a view: {}'.format(data_view)) - - self._extra_fields = extra_fields - self._field_name = field_name - self._data_name = data_name - super().__init__(**{'header': header_view, data_name: data_view}) - - @property - def fixed_size(self): - return self._fixed_size - - def list_fields(self): - return list(self._fields) + self.header.list_fields() - - def cache_fields(self, payload=b'', value=None): - for field in self._extra_fields: - self.header.value(payload, field) - - def offset(self, payload=b'', field=None): - if field in self._fields: - return super().offset(payload, field=field) - return self.header.offset(payload, field=field) - - def width(self, payload=b''): - if len(self._extra_fields) > 0: - self.cache_fields(payload) - return super().width(payload) - - def valid(self, payload=b''): - if not self.header.valid(payload): - return False - if len(self._extra_fields) > 0: - self.cache_fields(payload) - if not self.fixed_size: - width = self.header.value(payload, self._field_name) - if width > self._max_size: - return False - return super().valid(payload) - - def value(self, payload=b'', field=None): - if field == self._data_name: - if len(self._extra_fields) > 0: - self.cache_fields(payload) - return super().value(payload, self._data_name) - elif field is None: - whole = self.header.value(payload, field=None) - whole[self._data_name] = self.value(payload, self._data_name) - return whole - return self.header.value(payload, field) - - def write(self, payload=b'', value=None, **kwargs): - if len(kwargs) > 0: - if value is not None: - raise RuntimeError('Conflict: value and kwargs both given.') - value = kwargs - - if 'header' in value: - payload = super().write(payload, header=value['header']) - value = dict(value) - del value['header'] - - if len(self._extra_fields) > 0 and self._data_name in value: - self.cache_fields(payload) - - if self._data_name in value: - if len(value) > 1: - headers = dict(value) - del headers[self._data_name] - payload = self.header.write(payload, headers) - - return super().write(payload, - **{self._data_name: value[self._data_name]}) - - return self.header.write(payload, value) - - def __len__(self): - return len(self.header) + 1 - - def __contains__(self, field): - return field in self._fields or field in self.header - - def __getitem__(self, field): - return self.__getattr__(field) - - def __getattr__(self, field): - if field.startswith('__'): - raise AttributeError - if field in ['header', self._data_name]: - return self._fields[field] - return self.header[field] - -class series(composite): - max_quantity = 32 - def __init__(self, item_view, n): - if isinstance(n, int) and not n < 1: - fixed = True - elif isview(n) and iscached(n): - fixed = False - else: - raise ValueError('Invalid quantity: {}'.format(n)) - self.length = n - self.fixed = fixed - self.item = item_view - - @property - def quantity(self): - if self.fixed: - return self.length - return self.length.cache() - - def offset(self, payload=b'', field=None): - field = int(field) - if not self.quantity > field: - raise IndexError('Invalid item index: {}'.format(field)) - - total_offset = 0 - for _ in range(field): - width = self.item.width(payload) - payload = payload[width:] - total_offset += width - return total_offset - - def width(self, payload=b''): - offset = self.offset(payload, self.quantity - 1) - return offset + self.item.width(payload[offset:]) - - def valid(self, payload=b''): - if self.quantity > self.max_quantity: - return False - - for _ in range(self.quantity): - if not self.item.valid(payload): - return False - width = self.item.width(payload) - payload = payload[width:] - return True - - def value(self, payload=b'', field=None): - if field is None: - results = [] - for _ in range(self.quantity): - results.append(self.item.value(payload)) - width = self.item.width(payload) - payload = payload[width:] - return results - - field = int(field) - if not self.quantity > field: - raise IndexError('Invalid item index: {}'.format(field)) - - return self.item.value(payload[self.offset(payload, field):]) - - def write(self, payload=b'', value=None, **kwargs): - if len(kwargs) > 0: - if value is not None: - raise RuntimeError('Conflict: value and kwargs both given.') - value = kwargs - - if isinstance(value, (list, tuple)): - if len(value) > self.quantity: - raise ValueError( - 'Input list too long: {} out of {} items'.format( - len(value), self.quantity)) - return self.write(payload, dict(enumerate(value))) - - for field, svalue in sorted(value.items()): - field = int(field) - offset = self.offset(payload, field) - svalue = self.item.write(payload[offset:], svalue) - payload = payload[:offset] + svalue - return payload - - def __len__(self): - return self.quantity - - def __contains__(self, field): - try: - return int(field) < self.quantity - except ValueError: - return False - - def __getitem__(self, field): - return self.item - -class union(composite): - def __init__(self, view_table, union_tag): - for key, view in view_table.items(): - if not isview(view): - raise TypeError('Union of {} not a view: {}'.format(key, view)) - - self.view_table = view_table - self.union_tag = union_tag - - @property - def tag(self): - return self.union_tag.cache() - - @property - def active_view(self): - return self.view_table[self.tag] - - def offset(self, payload=b'', field=None): - return 0 - - def width(self, payload=b''): - return self.active_view.width(payload) - - def valid(self, payload=b''): - if self.tag not in self.view_table: - return False - - return self.active_view.valid(payload) - - def value(self, payload=b'', field=None): - return self.active_view.value(payload, field) - - def write(self, payload=b'', value=None, **kwargs): - return self.active_view.write(payload, value=value, **kwargs) - - def __contains__(self, field): - return field in self.active_view - - def __getitem__(self, field): - return self.active_view.__getitem__(field) - -class wrapper: - '''This is a view bound to raw bytes. - - See self.fields to list fields within the view. - See help(self._view) for details on the underlying view.''' - - def __init__(self, parent_view): - if not isview(parent_view): - raise TypeError('Wrapping not a view: {}'.format(parent_view)) - self._view = parent_view - - @property - def raw(self): - raise NotImplementedError - - @raw.setter - def raw(self, value): - raise NotImplementedError - - @property - def width(self): - return self._view.width(self.raw) - - @property - def valid(self): - return self._view.valid(self.raw) - - @property - def fields(self, wrapper_attr=['raw']): - if (hasattr(self._view, 'list_fields') - and inspect.ismethod(self._view.list_fields)): - return wrapper_attr + self._view.list_fields() - return wrapper_attr - - @property - def truncated(self): - return self.raw[:self.width] - - def offset(self, field): - return self._view.offset(self.raw, field) - - def value(self, field=None): - if field is None: - return self._view.value(self.raw) - return self._view.value(self.raw, field=field) - - def write(self, value=None, **kwargs): - self.raw = self._view.write(self.raw, value, **kwargs) - - def set(self, *kargs, **kwargs): - self.write(*kargs, **kwargs) - self.finalize(truncate=True) - - def finalize(self, truncate=True): - if truncate: - self.raw = self.truncated - if not self.valid: - raise RuntimeError('Invalid payload for {} view: {}'.format( - self._view, self.raw)) - - def __len__(self): - if not iscomposite(self._view): - raise NotImplementedError - return len(self._view) - - def __contains__(self, field): - if not iscomposite(self._view): - raise NotImplementedError - return field in self._view - - def __getitem__(self, field): - return self.__getattr__(str(field)) - - def __setitem__(self, field, value): - self.__setattr__(str(field), value) - - def __setattr__(self, field, value): - if (not field.startswith('_') - and iscomposite(self._view) and field in self._view): - self.write(value={field: value}) - else: - object.__setattr__(self, field, value) - - def __getattr__(self, field): - if field.startswith('__'): - raise AttributeError - if iscomposite(self._view) and field in self._view: - subview = self._view[field] - if iscomposite(subview): - return bind(subview, self, field) - return self._view.value(self.raw, field) - -def _forward_init(cls, args): - if args is None: - return cls - - if isinstance(args, dict): - if len(args) == 2 and 'kargs' in args and 'kwargs' in args: - return cls(*args['kargs'], **args['kwargs']) - if len(args) == 1 and 'kwargs' in args: - return cls(**args['kwargs']) - if len(args) == 1 and 'kargs' in args: - return cls(*args['kargs']) - - return cls(**args) - return cls(*args) - -def bind(parent_view, parent_wrapper, parent_field=None, init=[]): - class _anonymous_subwrapper(wrapper): - def __init__(self): - super().__init__(parent_view) - self._parent = parent_wrapper - self._field = parent_field - - @property - def raw(self): - if self._field is None: - return self._parent.raw - offset = self._parent.offset(self._field) - return self._parent.raw[offset:] - - @raw.setter - def raw(self, value): - if self._field is None: - self._parent.raw = value - return - parent = self._parent.raw - offset = self._parent.offset(self._field) - parent = parent[:offset] + value + parent[offset + len(value):] - self._parent.raw = parent - - typename = str(parent_field) - if typename is not None: - if not typename.isidentifier(): - try: - if int(typename) >= 0: - typename = 'idx_{}'.format(typename) - except ValueError: - pass - - if typename.isidentifier(): - _anonymous_subwrapper.__name__ = '{}'.format(typename) - - _anonymous_subwrapper.__qualname__ = '{}.{}'.format( - parent_wrapper.__class__.__qualname__, _anonymous_subwrapper.__name__) - return _forward_init(_anonymous_subwrapper, init) - -def like(parent_view, typename=None, init=None): - if typename is not None and not typename.isidentifier(): - raise ValueError('Typename {} is not an identifier'.format(typename)) - - class _anonymous_wrapper(wrapper): - def __init__(self, raw): - super().__init__(parent_view) - self._raw = raw - - @property - def raw(self): - return self._raw - - @raw.setter - def raw(self, value): - self._raw = value - - if typename is not None: - _anonymous_wrapper.__qualname__ = 'wrapper.{}'.format(typename) - _anonymous_wrapper.__name__ = '{}_wrapper'.format(typename) - - return _forward_init(_anonymous_wrapper, init) - -def cache(base, typename=None, init=None): - if typename is not None and not typename.isidentifier(): - raise ValueError('Typename {} is not an identifier'.format(typename)) - - if not inspect.isclass(base): - raise TypeError('Expect a class: {} is not.'.format(base)) - - if issubclass(base, _enum.Enum): - raise TypeError('Use view.enum(cached=True) to cache enumerations.') - - if iscached(base): - raise TypeError('Class {} already cached.'.format(base)) - - class _anonymous_cached_view(base): - def __init__(self, *kargs, **kwargs): - '''See help({}.__init__) for an accurate signature.'''.format( - base.__qualname__) - - base.__init__(self, *kargs, **kwargs) - self._cache = threading.local() - self._cache.value = None - - def cache(self): - if not self.cached(): - raise RuntimeError('Bounded value unknown at runtime: ' - + 'Have you called .value() of parent view yet?') - return self._cache.value - - def cached(self): - return self._cache.value is not None - - def value(self, payload=b'', field=None): - self._cache.value = super().value(payload) - return self.cache() - - def write(self, payload=b'', *kargs, **kwargs): - payload = super().write(payload, *kargs, **kwargs) - self._cache.value = super().value(payload) - return payload - - _anonymous_cached_view.__qualname__ = 'cached.{}'.format(base.__name__) - _anonymous_cached_view.__name__ = 'cached_{}'.format(base.__name__) - if typename is not None: - _anonymous_cached_view.__name__ = typename - - return _forward_init(_anonymous_cached_view, init) - -def isview(item): - if not hasattr(item, 'width') or not inspect.ismethod(item.width): - return False - if not hasattr(item, 'valid') or not inspect.ismethod(item.valid): - return False - if not hasattr(item, 'value') or not inspect.ismethod(item.value): - return False - if not hasattr(item, 'write') or not inspect.ismethod(item.write): - return False - return True - -def iscached(item): - if not hasattr(item, 'cache') or not inspect.ismethod(item.cache): - return False - if not hasattr(item, 'cached') or not inspect.ismethod(item.cache): - return False - return True - -def iscomposite(item): - if isinstance(item, union): - if not item.union_tag.cached(): - return True - return isinstance(item.active_view, composite) - return isinstance(item, composite) - -class ip_address(data): - def __init__(self, *, version): - if version not in [4, 6]: - raise ValueError('Invalid IP version: {}'.format(version)) - - if version == 4: - self._ip_type = ipaddress.IPv4Address - super().__init__(4) - else: - self._ip_type = ipaddress.IPv6Address - super().__init__(16) - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - try: - self.value(payload) - return True - except ipaddress.AddressValueError: - return False - - def value(self, payload=b'', field=None): - value = super().value(payload) - return self._ip_type(value) - - def write(self, payload=b'', value=None, **kwargs): - if not isinstance(value, self._ip_type): - value = self._ip_type(value) - return super().write(payload, value=value.packed) - -class codec(data): - @staticmethod - def _is_text_encoding(c): - try: - codecs.encode(b'', c) - return False - except BaseException: - pass - - try: - if not isinstance(codecs.encode('', c), bytes): - return False - return True - except BaseException: - return False - - @staticmethod - def _is_bytes_mapping(c): - if codec._is_text_encoding(c): - return False - - try: - if not isinstance(codecs.encode(b'', c), bytes): - return False - return True - except BaseException: - return False - - @staticmethod - def _is_text_mapping(c): - return c in ['rot_13', 'rot13'] - - @staticmethod - def _build_encode_chain(codecs): - encode_chain = [] - is_input_str = True - for c in codecs: - if codec._is_text_encoding(c): - encode_chain.append((is_input_str, c)) - is_input_str = bool(not is_input_str) - continue - if codec._is_text_encoding(c) and not is_input_str: - raise ValueError( - 'Got bytes for {} in chain: {}'.format(c, codecs)) - if codec._is_bytes_mapping(c) and is_input_str: - raise ValueError( - 'Got str for {} in chain: {}'.format(c, codecs)) - encode_chain.append((True, c)) - - if is_input_str: - raise ValueError( - 'Chain encodes to str instead of bytes: {}'.format(codecs)) - return encode_chain - - @staticmethod - def _build_decode_chain(codecs): - decode_chain = [] - is_input_str = False - for c in reversed(codecs): - if codec._is_text_encoding(c): - decode_chain.append((is_input_str, c)) - is_input_str = bool(not is_input_str) - continue - if codec._is_text_encoding(c) and not is_input_str: - raise ValueError( - 'Got bytes for {} in chain: {}'.format(c, codecs)) - if codec._is_bytes_mapping(c) and is_input_str: - raise ValueError( - 'Got str for {} in chain: {}'.format(c, codecs)) - decode_chain.append((False, c)) - - if not is_input_str: - raise ValueError( - 'Chain decodes to bytes instead of str: {}'.format(codecs)) - return decode_chain - - def __init__(self, *codecs, size): - self.encode_chain = codec._build_encode_chain(codecs) - self.decode_chain = codec._build_decode_chain(codecs) - super().__init__(size) - - def valid(self, payload=b''): - if not super().valid(payload): - return False - - try: - self.value(payload) - return True - except ValueError: - return False - - def value(self, payload=b'', field=None): - value = super().value(payload) - for use_encode, c in self.decode_chain: - if use_encode: - value = codecs.encode(value, c) - else: - value = codecs.decode(value, c) - return value - - def write(self, payload=b'', value=None, **kwargs): - for use_encode, c in self.encode_chain: - if use_encode: - value = codecs.encode(value, c) - else: - value = codecs.decode(value, c) - return super().write(payload, value=value) diff --git a/lightnion/consensus.py b/lightnion/consensus.py index 428c319..da4e1c9 100644 --- a/lightnion/consensus.py +++ b/lightnion/consensus.py @@ -786,43 +786,6 @@ def extract_nodes_digests_micro(consensus_raw): return digests_bytes -def download(state, flavor='microdesc', cache=True): - if flavor not in ['unflavored', 'microdesc']: - raise NotImplementedError( - 'Consensus flavor "{}" not supported.'.format(flavor)) - - if cache: - try: - return state, lnn.cache.consensus.get(flavor) - except BaseException: - pass - - endpoint = '/tor/status-vote/current/consensus' - if flavor == 'microdesc': - endpoint += '-microdesc' - - ip = '%s:%d'%('127.0.0.1',7000) #for real tor, change to 9051 - keys = get_signing_keys_info(ip) - state, cons = lnn.hop.directory_query(state, endpoint) - - cons_original = cons - cons, http = consume_http(cons) - - if flavor != 'microdesc': - if not lnn.signature.verify(cons.decode('utf-8'), keys): - raise RuntimeError('Consensus Verification Failed') - - consensus, remaining = parse(cons_original, flavor=flavor) - - if consensus is None or remaining is None or not len(remaining) == 0: - raise RuntimeError('Unable to parse downloaded consensus!') - - if cache: - lnn.cache.consensus.put(consensus) - - return state, consensus - - def download_direct(hostname, port, flavor='microdesc'): """Retrieve consensus via a direct HTTP connection. :param hostname: host name of the node from which to retrieve the consensus. @@ -855,6 +818,7 @@ def download_direct(hostname, port, flavor='microdesc'): return consensus, keys + def download_raw(hostname, port, flavor='unflavored'): """Retrieve raw consensus via a direct HTTP connection. :param hostname: host name of the node from which to retrieve the consensus. diff --git a/lightnion/create.py b/lightnion/create.py deleted file mode 100644 index 3ccb4c9..0000000 --- a/lightnion/create.py +++ /dev/null @@ -1,280 +0,0 @@ -import collections -import base64 -import queue -import time -import asyncio -import logging - -import nacl.public - -import lightnion as lnn - -class circuit(collections.namedtuple('circuit', ['id', 'material'])): - stream_windows = None # per-stream window (see onion._auto_sendme hack) - last_stream_id = 0 - destroyed = False - window = None # per-circuit window (see onion._auto_sendme hack) - reason = None - queue = None - - def put(self, payload): - return self.queue.put(payload) - - def get(self, block=True): - return self.queue.get(block=block) - - -async def fast_async(link): - """Use a CREATE_FAST cell to initiate a one-hop circuit. - - The expected transcript is: - - (... perform a proper link handshake here ...) - - Onion Proxy (client) Onion Router (server) - - / [ 7] :------ CREATE_FAST¹ -------> [8] - | [10] <------ CREATED_FAST -------: [9] - | - | Shared circuit key (via KDF-TOR²) - \ - - ¹The initiator picks an available circuit ID (CircID) with its most - significant bit equal to 1 (v4-or-higher links). - - :param link: a link.link object, see: link.initiate - - :returns: a onion.state object, see: onion.state - """ - - # Pick an available ID (link version > 3) - link.last_id += 1 - circuit_id = 0x80000000 + link.last_id - while circuit_id in link.circuits: - circuit_id += 1 - - # Sanity checks - try: - packed = lnn.cell.view.uint(4).write(value=circuit_id) - assert circuit_id == lnn.cell.view.uint(4).value(packed) - except (OverflowError, AssertionError): - link.last_id = 0 - raise RuntimeError('Erroneous circuit ID: {} ({})'.format( - circuit_id, packed)) - - # Send CREATE_FAST cell (contains OP material) - op_cell = lnn.cell.create_fast.pack(circuit_id) - await link.send_async(op_cell) - - # (register a dummy circuit first to reuse the circuit API) - dummy = circuit(circuit_id, None) - await link.register_async(dummy) - - # Receive CREATED_FAST cell (contains OR material and key confirmation) - try: - or_cell = lnn.cell.created_fast.cell(await link.get_async(dummy)) - except KeyError: - raise RuntimeError('Got DESTROY cell while creating circuit.') - - # (unregister the dummy circuit before validation/material confirmation) - await link.unregister_async(dummy) - if not or_cell.valid: - raise RuntimeError('Got invalid CREATED cell: {}'.format(or_cell.raw)) - - # Compute KDF-TOR on OP+OR materials - material = lnn.crypto.kdf_tor( - op_cell.create_fast.material + or_cell.created_fast.material) - - # Confirm shared derived material - if not material.key_hash == or_cell.created_fast.derivative: - raise RuntimeError( - 'Invalid CREATE_FAST, invalid KDF-TOR confirmation: '.format( - (material.key_hash, or_cell.created_fast.derivative))) - - # Register the real circuit - final = circuit(circuit_id, material) - await link.register_async(final) - - return lnn.onion.state(link, final) - - -def fast(link): - """Use a CREATE_FAST cell to initiate a one-hop circuit. - - The expected transcript is: - - (... perform a proper link handshake here ...) - - Onion Proxy (client) Onion Router (server) - - / [ 7] :------ CREATE_FAST¹ -------> [8] - | [10] <------ CREATED_FAST -------: [9] - | - | Shared circuit key (via KDF-TOR²) - \ - - ¹The initiator picks an available circuit ID (CircID) with its most - significant bit equal to 1 (v4-or-higher links). - - :param link: a link.link object, see: link.initiate - - :returns: a onion.state object, see: onion.state - """ - - # Pick an available ID (link version > 3) - link.last_id += 1 - circuit_id = 0x80000000 + link.last_id - while circuit_id in link.circuits: - circuit_id += 1 - - # Sanity checks - try: - packed = lnn.cell.view.uint(4).write(value=circuit_id) - assert circuit_id == lnn.cell.view.uint(4).value(packed) - except (OverflowError, AssertionError): - link.last_id = 0 - raise RuntimeError('Erroneous circuit ID: {} ({})'.format( - circuit_id, packed)) - - # Send CREATE_FAST cell (contains OP material) - op_cell = lnn.cell.create_fast.pack(circuit_id) - link.send(op_cell) - - # (register a dummy circuit first to reuse the circuit API) - dummy = circuit(circuit_id, None) - link.register(dummy) - - # Receive CREATED_FAST cell (contains OR material and key confirmation) - try: - or_cell = lnn.cell.created_fast.cell(link.get(dummy)) - except KeyError: - raise RuntimeError('Got DESTROY cell while creating circuit.') - - # (unregister the dummy circuit before validation/material confirmation) - link.unregister(dummy) - if not or_cell.valid: - raise RuntimeError('Got invalid CREATED cell: {}'.format(or_cell.raw)) - - # Compute KDF-TOR on OP+OR materials - material = lnn.crypto.kdf_tor( - op_cell.create_fast.material + or_cell.created_fast.material) - - # Confirm shared derived material - if not material.key_hash == or_cell.created_fast.derivative: - raise RuntimeError( - 'Invalid CREATE_FAST, invalid KDF-TOR confirmation: '.format( - (material.key_hash, or_cell.created_fast.derivative))) - - # Register the real circuit - final = circuit(circuit_id, material) - link.register(final) - - return lnn.onion.state(link, final) - - -def ntor_raw(link, payload, timeout=None): - # Pick an available ID (link version > 3) - link.last_id += 1 - circuit_id = 0x80000000 + link.last_id - while circuit_id in link.circuits: - circuit_id += 1 - - # Sanity checks - try: - packed = lnn.cell.view.uint(4).write(value=circuit_id) - assert circuit_id == lnn.cell.view.uint(4).value(packed) - except (OverflowError, AssertionError): - link.last_id = 0 - raise RuntimeError('Erroneous circuit ID: {} ({})'.format( - circuit_id, packed)) - - # Build a CREATE2 cell containing this first handshake part - handshake = lnn.cell.create2.pack(circuit_id, payload) - - # Change: Instead, the handshake data is send to the client with the handshake data. - return circuit_id, lnn.cell.pad(handshake) - - -def ntor_raw2(circuit_id, payload): - - # Build a CREATE2 cell containing this first handshake part - handshake = lnn.cell.create2.pack(circuit_id, payload) - - # The handshake data is send to the client. - return lnn.cell.pad(handshake) - - -# Was in the method above, before. -def ntor_handshake(link, circuit_id, handshake, timeout=None): - link.send(handshake) - - # (register a dummy circuit first to reuse the circuit API) - dummy = circuit(circuit_id, None) - link.register(dummy) - - # Receive answers - cell = None - try: - if timeout is None: - cell = lnn.cell.created2.cell(link.get(dummy)) - else: - for _ in range(10): - try: - cell = lnn.cell.created2.cell( - link.get(dummy, block=False)) - break - except queue.Empty: - time.sleep(timeout / 10) - if cell is None: - link.unregister(dummy) - raise RuntimeError('Got timeout while creating circuit.') - except KeyError: - raise RuntimeError('Got DESTROY cell while creating circuit.') - - # (unregister the dummy circuit before validation/material confirmation) - link.unregister(dummy) - if not cell.valid: - raise RuntimeError('Got invalid CREATED2 cell: {}'.format(cell.raw)) - - return cell.created2.data - - -async def ntor_async(link, descriptor): - identity = base64.b64decode(descriptor['router']['identity'] + '====') - onion_key = base64.b64decode(descriptor['ntor-onion-key'] + '====') - - # Perform the first part of our handshake - ephemeral_key, payload = lnn.crypto.ntor.hand(identity, onion_key) - - circuit_id, payload = await ntor_raw_async(link, payload) - - # Perform the last part of our handshake - material = lnn.crypto.ntor.shake(ephemeral_key, payload, - identity, onion_key, length=92) - - # Register the real circuit - final = circuit(circuit_id, lnn.crypto.ntor.kdf(material)) - await link.register_async(final) - - return lnn.onion.state(link, final) - - -def ntor(link, descriptor): - identity = base64.b64decode(descriptor['router']['identity'] + '====') - onion_key = base64.b64decode(descriptor['ntor-onion-key'] + '====') - - # Perform the first part of our handshake - ephemeral_key, payload = lnn.crypto.ntor.hand(identity, onion_key) - - circuit_id, handshake = ntor_raw(link, payload) - payload = ntor_handshake(link, circuit_id, handshake) - - # Perform the last part of our handshake - material = lnn.crypto.ntor.shake(ephemeral_key, payload, - identity, onion_key, length=92) - - # Register the real circuit - final = circuit(circuit_id, lnn.crypto.ntor.kdf(material)) - link.register(final) - - return lnn.onion.state(link, final) diff --git a/lightnion/descriptors.py b/lightnion/descriptors.py index e57959e..e18c7b7 100644 --- a/lightnion/descriptors.py +++ b/lightnion/descriptors.py @@ -543,96 +543,6 @@ def _download_raw_by_digests(host, port, digests, endpoint, separator): return desc -def download(state, cons=None, flavor='microdesc', cache=True, fail_on_missing=False): - logging.warning('Use DEPRECATED method descriptor.download()!') - - if cons is None: - state, cons = consensus.download(state, flavor=flavor, cache=cache) - if cons is None: - return state, None - elif isinstance(cons, list): - cons = dict(routers=cons) - elif isinstance(cons, str): - digest_name = 'micro-digest' if flavor == 'microdesc' else 'digest' - cons = dict(routers={digest_name: cons}) - elif 'routers' not in cons and 'identity' in cons: - cons = dict(routers=[cons]) - - if not isinstance(cons, dict): - raise RuntimeError('Expecting a dict for cons, got: {}'.format(cons)) - - digests = [] - if flavor == 'microdesc': - digests = [router['micro-digest'] for router in cons['routers']] - endpoint = '/tor/micro/d/' - separator = '-' - else: - digests = [router['digest'] for router in cons['routers']] - digests = [base64.b64decode(d + '====').hex() for d in digests] - endpoint = '/tor/server/d/' - separator = '+' - - # retrieve descriptors from cache - descriptors = [] - partial_digests = digests - if cache: - digest_name = 'micro-digest' if flavor == 'microdesc' else 'digest' - cached_digests = [] - for digest in digests: - try: - descriptor = lnn.cache.descriptors.get(flavor, digest) - descriptors.append(descriptor) - cached_digests.append(digest) - except BaseException: - pass - partial_digests = [d for d in digests if d not in cached_digests] - - for query in batch_query(partial_digests, endpoint, separator): - state, answer = lnn.hop.directory_query(state, query) - - if answer is None or len(answer) == 0: - continue - - new_batch, remaining = parse_descriptors(answer, flavor=flavor) - if new_batch is None or remaining is None or len(remaining) > 0: - raise RuntimeError('Unable to parse descriptors.') - - if (len(new_batch['descriptors']) == 0 - and not new_batch['http']['code'] == '404'): - raise RuntimeError( - 'No descriptor listed. http={}.'.format(new_batch['http'])) - - if new_batch is not None: - descriptors += new_batch['descriptors'] - - if flavor == 'microdesc': - obtained = [d['micro-digest'] for d in descriptors] - else: - obtained = [d['digest'] for d in descriptors] - obtained = [base64.b64decode(d + '====').hex() for d in obtained] - - invalid = [] - for digest in digests: - if digest in obtained: - obtained.remove(digest) - else: - invalid.append(digest) - - if not len(obtained) == 0: - raise RuntimeError('Mismatched digest afterward! {} vs {}'.format( - sorted(invalid), sorted(obtained))) - - if fail_on_missing and len(invalid) > 0: - raise RuntimeError('Missing {} digests in answer: {}'.format( - len(invalid), invalid)) - - if cache: - for descriptor in descriptors: - lnn.cache.descriptors.put(descriptor) - - return state, descriptors - - def download_authority(state): state, answer = lnn.hop.directory_query(state, '/tor/server/authority') if answer is None or len(answer) == 0: diff --git a/lightnion/onion.py b/lightnion/onion.py deleted file mode 100644 index d102edb..0000000 --- a/lightnion/onion.py +++ /dev/null @@ -1,270 +0,0 @@ -import cryptography -import hashlib -import copy - -import lightnion as lnn - -class state: - '''Handle Tor onion-encryption cryptographic states. - - *For now, only handle cryptography as an initiator (as an OP to an OR).* - - TODO: add support for __init__(link, circuit, initiator={True,False}) - - Status Condition - - backward decryptor provided initiator=True - encryptor (none) initiator=False - digest provided - forward decryptor (none) initiator=False - encryptor provided initiator=True - digest provided - ''' - - def __init__(self, link, circuit, early_count=8): - '''Build a new onion-encryption state from a link and circuit. - - :params link: a link object (see link.link) - :params circuit: a circuit object (see create.circuit) - :params int early_count: first `early_count` cells will be RELAY_EARLY - ''' - self.circuit = circuit - self.link = link - - self._inner = None - self.early_count = early_count - - self._last_material = None - self._reset_digest(circuit.material) - self._reset_encryption(circuit.material) - - @property - def depth(self): - '''Number of inner layers in the onion.''' - if self._inner is None: - return 0 - return self._inner.depth + 1 - - @property - def early_count(self): - '''Number of remaining RELAY_EARLY cells before sending RELAY cells.''' - - if self._inner is None: - return self._early_count - return self._inner.early_count - - @early_count.setter - def early_count(self, value): - '''Setter for self.early_count.''' - - if self._inner is None: - self._early_count = value - else: - raise RuntimeError( - 'Unable to set RELAY_EARLY counter from the outer layers!') - - def wrap(self, inner): - '''Wraps an inner state w/ self as outer state (see lightnion.extend). - - Usage: - 1. A one-hop circuit is build with stateA. - 2. A key exchange is made through stateA to get stateB. - 3. Then, call stateA.wrap(stateB) to properly wrap the onion. - - Usage: - 1. A two-hop circuit is build with state{A,B}. - 2. A key exchange is made through state{A,B} to get stateC. - 3. Then, call statea.wrap(stateC) to properly wrap the onion. - - *Note: should not be called explicitly.* - ''' - if self._inner is None: - inner._early_count = self._early_count - self._inner = inner - else: - self._inner.wrap(inner) - - def _reset_encryption(self, material): - '''Initialize stateful stream cipher with cryptographic material. - - :params material: shared material w/ {forward,backward}_key - - *Note: should not be called explicitly.* - ''' - if self._last_material == material: - raise RuntimeError('Unsafe! Do NOT reset w/ same material!') - self._last_material = material - - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives.ciphers import ( - algorithms, modes, Cipher - ) - - # Tor uses AES128-CTR with IV=0 as stream cipher - nonce_size = algorithms.AES.block_size // 8 - zeroed_ctr = modes.CTR(b'\x00' * nonce_size) - - # Initiate forward/backward encryption/decryption (as OP) TODO: add OR - self.forward_encryptor = Cipher( - algorithms.AES(material.forward_key), - zeroed_ctr, default_backend()).encryptor() - self.backward_decryptor = Cipher( - algorithms.AES(material.backward_key), - zeroed_ctr, default_backend()).decryptor() - - def _reset_digest(self, material): - '''Seed stateful 'running digests' used to authenticate payloads. - - :params material: shared material w/ {forward,backward}_key - - *Note: should not be called explicitly.* - ''' - self.forward_digest = hashlib.sha1(material.forward_digest) - self.backward_digest = hashlib.sha1(material.backward_digest) - - def _clone(self): - '''Non-recursive clone of current cryptographic state. - - Whenever it is required to rollback after an error, you can use this - function to give yourself a clone of the current state. - - *Note: does not clone inner cryptographic states.* - ''' - - child = state(self.link, self.circuit) - - # Clone digest state (use of hashlib's native hash copy) - child.forward_digest = self.forward_digest.copy() - child.backward_digest = self.backward_digest.copy() - - # Clone encryption state (use of python's ad-hoc copy) - child.forward_encryptor = copy.copy(self.forward_encryptor) - child.backward_decryptor = copy.copy(self.backward_decryptor) - - # Don't forget to propagate the RELAY_EARLY count - child._early_count = self._early_count - - # (note: we don't recursively clone inner layers of state) - child._inner = self._inner - - return child - -def core(state, command, payload=b'', stream_id=0): - '''Build a RELAY{_EARLY,} cell as an onion core (plaintext w/ `state`) - - :param state: a state object (see onion.state) - :param str command: RELAY{_EARLY,} cell command (see cell.relay.cmd) - :param bytes payload: RELAY{_EARLY,} cell content (default: b'') - :param int stream_id: RELAY{_EARLY,} stream ID (default: 0) - - :returns: a tuple (updated state, cell) - - *Note: should not be called explicitly.* - ''' - rollback = state._clone() - - # Send RELAY_EARLY cells first - relay_pack = lnn.cell.relay.pack - if rollback.early_count > 0: - rollback.early_count -= 1 - relay_pack = lnn.cell.relay_early.pack - - # Compute the cell with a zeroed 'digest' field. - cell = relay_pack( - circuit_id=state.circuit.id, - cmd=command, - data=payload, - stream_id=stream_id, - digest=b'\x00\x00\x00\x00') - - # Update the "running digest" - rollback.forward_digest.update(cell.relay.raw) - - # Write the "running digest" - full_digest = rollback.forward_digest.digest() - cell.relay.digest = full_digest[:cell.relay._view.digest.width()] - - # Encrypt the to-be-encrypted parts & build final cell - cell.relay.raw = rollback.forward_encryptor.update(cell.relay.raw) - - return rollback, cell - -def build(state, command, payload=b'', stream_id=0): - '''Build a RELAY{_EARLY,} cell. - - :param state: a state object (see onion.state) - :param str command: RELAY{_EARLY,} cell command (see cell.relay.cmd) - :param bytes payload: RELAY{_EARLY,} cell content (default: b'') - :param int stream_id: RELAY{_EARLY,} stream ID (default: 0) - - :returns: a tuple (updated state, cell) - - *Note: returns an updated state that MUST be used afterwards.* - ''' - if state.depth == 0: - return core(state, command, payload, stream_id) - rollback = state._clone() - - # Retrieve the inner layer of the onion - rollback._inner, cell = build(rollback._inner, command, payload, stream_id) - - # Wraps the layer with our outer layer of encryption - cell.relay.raw = rollback.forward_encryptor.update(cell.relay.raw) - - return rollback, cell - -def recognize(state, cell, backward=True): - '''Attempt to recognize a RELAY{_EARLY,} cell. - - :param state: a state object (see onion.state) - :param cell: a RELAY{_EARLY,} cell object (see cell.relay.cell) - :param bool backward: is it backward? or else forward? (default: True) - - :returns: a tuple (updated state, bool) - - *Note: returns an updated state that MUST be used afterwards.* - ''' - rollback = state._clone() - - # We expect the recognized field to be zeroed upon successful decryption - if not cell.relay.recognized == b'\x00\x00': - return state, False - - # We build a copy of the cell with a zeroed 'digest field' - cell_digest = cell.relay.digest - cell.relay.digest = b'\x00\x00\x00\x00' - - # Update the digest state accordingly (backward or forward) - digest = rollback.backward_digest if backward else rollback.forward_digest - digest.update(cell.relay.raw) - - # Check if the computed digest match the cell digest - if not cell_digest == digest.digest()[:cell.relay._view.digest.width()]: - return state, False - - # Update state iff the digests matched - return rollback, True - -def peel(state, cell): - '''Decrypt a RELAY{_EARLY,} cell using provided `state`. - - :param state: a state object (see onion.state) - :param cell: a RELAY{_EARLY,} cell object (see cell.relay.cell) - - :returns: a tuple (updated state, decrypted cell) - - *Note: returns an updated state that MUST be used afterwards.* - ''' - rollback = state._clone() - - cell.relay.raw = rollback.backward_decryptor.update(cell.relay.raw) - if rollback.depth == 0: - rollback, recognized = recognize(rollback, cell) - if not recognized: - raise RuntimeError( - 'Got an unrecognized RELAY cell: {}'.format(cell.raw)) - - return rollback, cell - - rollback._inner, cell = peel(rollback._inner, cell) - return rollback, cell diff --git a/lightnion/proxy/__init__.py b/lightnion/proxy/__init__.py index 680f2b2..c6573dd 100644 --- a/lightnion/proxy/__init__.py +++ b/lightnion/proxy/__init__.py @@ -1,6 +1,6 @@ - fake_circuit_id = 0x80000000 api_version = 0.1 base_url = '/lightnion/api/v{}'.format(api_version) -from . import parts, auth, jobs, link + +from . import cell, parts, auth, jobs, link diff --git a/lightnion/proxy/cell.py b/lightnion/proxy/cell.py new file mode 100644 index 0000000..dfb35be --- /dev/null +++ b/lightnion/proxy/cell.py @@ -0,0 +1,243 @@ +""" +Cell handling classes. +""" + +import time +import secrets +import socket + +from enum import IntEnum + +ENDIANNESS = 'big' +PAYLOAD_SIZE_MAX = 509 + +class Command(IntEnum): + """Cell type.""" + PADDING = 0 + CREATE = 1 + CREATED = 2 + RELAY = 3 + DESTROY = 4 + CREATE_FAST = 5 + CREATED_FAST = 6 + VERSIONS = 7 + NETINFO = 8 + RELAY_EARLY = 9 + CREATE2 = 10 + CREATED2 = 11 + PADDING_NEGOTIAT = 12 + VPADDING = 128 + CERTS = 129 + AUTH_CHALLENGE = 130 + AUTHENTICATE = 131 + AUTHORIZE = 132 + + def is_variable_length(self): + """If the cell type indicate a cell of variable length.""" + return self.value == 7 or self.value > 127 + + + @classmethod + def from_bytes(cls, raw): + """Cell type from command byte.""" + return cls(int.from_bytes(raw, ENDIANNESS)) + + + def to_bytes(self): + """Byte representation.""" + return (self.value).to_bytes(1, ENDIANNESS) + + +class DestroyReason(IntEnum): + NONE = 0 + PROTOCOL = 1 + INTERNAL = 2 + REQUESTED = 3 + HIBERNATING = 4 + RESOURCELIMIT = 5 + CONNECTFAILED = 6 + OR_IDENTITY = 7 + OR_CONN_CLOSED = 8 + FINISHED = 9 + TIMEOUT = 10 + DESTROYED = 11 + NOSUCHSERVICE = 12 + + + @classmethod + def from_bytes(cls, raw): + """Cell type from command byte.""" + return cls(int.from_bytes(raw, ENDIANNESS)) + + + def to_bytes(self): + """Byte representation.""" + return (self.value).to_bytes(1, ENDIANNESS) + + +class Cell: + """Representation of a non-version, non-netinfo Tor cell.""" + + SIZE = 514 + + CIRCUIT_ID = 0 + CIRCUIT_ID_SIZE = 4 + CIRCUIT_ID_END = 4 + COMMAND = 4 + LENGTH = 5 + LENGTH_SIZE = 2 + LENGTH_END = 7 + PAYLOAD_BEGIN = 7 + + + @classmethod + def set_circuit_id(cls, cell_raw, circuit_id): + circuit_id_b = circuit_id.to_bytes(cls.CIRCUIT_ID_SIZE, ENDIANNESS) + cell = cell_raw[cls.CIRCUIT_ID_END:] + return circuit_id_b + cell + + + @classmethod + def circuit_id(cls, cell_raw): + return int.from_bytes(cell_raw[cls.CIRCUIT_ID:cls.CIRCUIT_ID_END], ENDIANNESS) + + + @classmethod + def command(cls, cell_raw): + return Command(cell_raw[cls.COMMAND]) + + + @classmethod + def length(cls, cell_raw): + return int.from_bytes(cell_raw[cls.LENGTH:cls.LENGTH_END], ENDIANNESS) + + + @classmethod + def raw_from_buffer(cls, buffer): + buf_len = len(buffer) + # len(cell_id + command + payload_size) == 7 + header_len = 7 + if buf_len < header_len: + return None, buffer + + cmd = cls.command(buffer) + + if cmd.is_variable_length(): + length = cls.length(buffer) + header_len + else: + length = cls.SIZE + + if buf_len < length: + return None, buffer + + return buffer[:length], buffer[length:] + + @classmethod + def pad(cls, cell_raw): + cell_len = len(cell_raw) + padding_size = cls.SIZE - cell_len + if padding_size > 0: + padding = secrets.token_bytes(padding_size) + else: + padding = b'' + + return cell_raw + padding + + +class CellVersion: + """Representation of a versions cell.""" + + CMD = Command.VERSIONS.to_bytes() + LENGTH = 3 + LENGTH_SIZE = 2 + LENGTH_END = 5 + VERSION_SIZE = 2 + + + def __init__(self, versions): + self.versions = versions + + + def payload_size(self): + return self.VERSION_SIZE * len(self.versions) + + + @classmethod + def length(cls, cell_raw): + return int.from_bytes(cell_raw[cls.LENGTH:cls.LENGTH_END], ENDIANNESS) + + + @classmethod + def from_bytes(cls, cell_raw): + versions = list() + for i in range(5, len(cell_raw), 2): + version = int.from_bytes(cell_raw[i:i+2], ENDIANNESS) + versions.append(version) + + return cls(versions) + + + def to_bytes(self): + size_b = self.payload_size().to_bytes(self.LENGTH_SIZE, ENDIANNESS) + cell_id = b'\x00\x00' + + cell = cell_id + self.CMD + size_b + + for version in self.versions: + cell += version.to_bytes(self.VERSION_SIZE, ENDIANNESS) + + return cell + + +class CellNetInfo: + """Representation of a netinfo cell.""" + + SIZE = 514 + CMD = Command.NETINFO.to_bytes() + + + @classmethod + def to_bytes(cls, host): + if host == 'localhost': + # Binary representation of 127.0.0.1 + addr = b'\x7f\x00\x00\x01' + else: + addr = socket.inet_aton(host) + + tstmp = int(time.time()).to_bytes(4, ENDIANNESS) + + addr_len = len(addr) + + if addr_len == 4: + addr_t = b'\x04' + else: + addr_t = b'\x06' + + addr_len_b = addr_len.to_bytes(1, ENDIANNESS) + + cell_len = 11 + addr_len + cell_id = b'\x00\x00\x00\x00' + + cell = cell_id + cls.CMD + tstmp + addr_t + addr_len_b + addr + + # padding with \x00 + cell += bytearray(cls.SIZE - cell_len) + + return cell + + +class CellDestroy: + SIZE = 514 + CMD = Command.DESTROY + + def __init__(self, circuit_id, reason): + self.circuit_id = circuit_id + self.reason = reason + + def to_bytes(self): + circuit_id_b = self.circuit_id.to_bytes(4, ENDIANNESS) + cmd = self.CMD.to_bytes() + reason = self.reason.to_bytes() + cell_len = 6 + padding = bytearray(self.SIZE - cell_len) + return circuit_id_b + cmd + reason + padding diff --git a/lightnion/proxy/forward.py b/lightnion/proxy/forward.py index a31fe2e..616c0b5 100644 --- a/lightnion/proxy/forward.py +++ b/lightnion/proxy/forward.py @@ -302,21 +302,21 @@ async def create_channel(): logging.info('Create new channel.') #ntor = payload['ntor'] - auth = None - if 'auth' in payload: - auth = payload['auth'] - if app.clerk.auth is None: - quart.abort(400) - - select_path = False - if 'select_path' in payload: - if payload['select_path'] == "true": - select_path = True - - if not select_path: - app.clerk.wait_for_consensus() - try: + auth = None + if payload and 'auth' in payload: + auth = payload['auth'] + if app.clerk.auth is None: + quart.abort(400) + + select_path = False + if payload and 'select_path' in payload: + if payload['select_path'] == "true": + select_path = True + + if not select_path: + app.clerk.wait_for_consensus() + #data = app.clerk.create.perform(data) ckt_info = app.clerk.channel_manager.create_channel( app.clerk.consensus, app.clerk.descriptors, select_path) if auth is not None: @@ -324,12 +324,13 @@ async def create_channel(): ckt_info = app.clerk.auth.perform(auth,ckt_info) response = quart.jsonify(ckt_info) - return response, 201 # Created except Exception as e: logging.exception(e) quart.abort(503) + return response, 201 # Created + @app.route(url + '/channels/', methods=['DELETE']) async def delete_channel(uid): diff --git a/lightnion/proxy/jobs.py b/lightnion/proxy/jobs.py index 6cde3ea..c5b96dd 100644 --- a/lightnion/proxy/jobs.py +++ b/lightnion/proxy/jobs.py @@ -8,7 +8,6 @@ import lightnion as lnn from . import parts, base_url, fake_circuit_id import lightnion.path_selection -import lightnion.utils class InvalidTokenException(Exception): @@ -156,14 +155,9 @@ def create_channel(self, consensus, descriptors, select_path): if self.link is None: raise LinkNotInitializedException() - #ntor_bin = base64.b64decode(ntor) - cid = self.link.gen_cid() token = self.gen_token_from_cid(cid) - #cell = lnn.create.ntor_raw2(cid, ntor_bin) - #cell = base64.b64encode(cell).decode('utf-8') - self.channels[cid] = Channel(token, cid) if not select_path: @@ -196,10 +190,9 @@ async def destroy_circuit_from_client(self, channel): # Send a cell to the link to delete the circuit in the relay. cid = channel.cid - reason = lnn.cell.destroy.reason.REQUESTED + reason = lnn.proxy.cell.DestroyReason.REQUESTED - cell = lnn.cell.destroy.pack(cid, reason) - cell_padded = lnn.cell.pad(cell) + cell_padded = lnn.proxy.cell.CellDestroy(cid, reason).to_bytes() await self.link.to_send.put(cell_padded) @@ -240,7 +233,7 @@ async def schedule_to_send(self, cell, cid): Scedule the data to be send to the correct channel. :param cell: cell to be send. """ - logging.debug('ChanMgr: Begin adding data to sending queue of channel {}.'.format(cid)) + logging.info('ChanMgr: Begin adding data to sending queue of channel {}.'.format(cid)) if cid not in self.channels.keys(): logging.warning('ChanMgr: Channel {} does not exists.'.format(cid)) @@ -255,19 +248,14 @@ async def schedule_to_send(self, cell, cid): #raise CircuitDoesNotExistException(cid) # If the cell command to delete the circuit, - header = lnn.cell.header(cell) - if header.cmd is lnn.cell.cmd.DESTROY: - cell_validation = lnn.cell.destroy.cell(cell) - logging.warning('ChanMgr: DESTROY cell received for channel {}, reason: {}.'.format(cid, cell_validation.reason)) - if not cell_validation.valid: - logging.debug('ChanMgr: Invalid DESTROY in channel {}.'.format(cid)) - #raise InvalidDestroyCellException() - else: - await self.destroy_circuit_from_link(channel) + cmd = lnn.proxy.cell.Cell.command(cell) + + if cmd == lnn.proxy.cell.Command.DESTROY: + #await self.destroy_circuit_from_link(channel) return - cell_padded = lnn.cell.pad(cell) + cell_padded = lnn.proxy.cell.Cell.pad(cell) await channel.to_send.put(cell_padded) @@ -367,7 +355,7 @@ async def _send(self, ws, channel): try: cell = await channel.to_send.get() - cell = lnn.cell.pad(cell) + cell = lnn.proxy.cell.Cell.pad(cell) await ws.send(cell) self.cell_sent += 1 diff --git a/lightnion/proxy/link.py b/lightnion/proxy/link.py index f32e0ed..00f5ba6 100644 --- a/lightnion/proxy/link.py +++ b/lightnion/proxy/link.py @@ -4,8 +4,6 @@ import asyncio import lightnion as lnn -import lightnion.cell -import lightnion.utils from lightnion.proxy import fake_circuit_id @@ -30,6 +28,7 @@ class InvalidVersionCellException(Exception): class NoSupportedVersionException(Exception): pass + class Link: def __init__(self, guard, versions=(4,5)): """ @@ -105,34 +104,21 @@ async def schedule_to_send(self, cell_raw, channel): """ # Set correct circuit id. - cell = lnn.cell.header_view.write(cell_raw, circuit_id=channel.cid) - #cell = lnn.utils.cell_set_cid(cell_raw, channel.cid) - - header = lnn.cell.header(cell) - #cmd = lnn.utils.cell_get_cmd(cell) - #if cmd == 3: - # cell = lnn.utils.cell_pad_rnd(cell) - #else: - # cell = lnn.utils.cell_pad_null(cell) - - #if cmd == 4: - if header.cmd is lnn.cell.cmd.DESTROY: + cell = lnn.proxy.cell.Cell.set_circuit_id(cell_raw, channel.cid) + + cmd = lnn.proxy.cell.Cell.command(cell_raw) + if cmd == lnn.proxy.cell.Command.DESTROY: logging.debug('Link: channel {} asks for the circuit to be destroyed.'.format(channel.cid)) - cell_validation = lnn.cell.destroy.cell(cell) - #if not lnn.utils.cell_is_valid(cell): - if not cell_validation.valid: - logging.debug('Link: Channel {} attempted to send an invalid cell.'.format(channel.cid)) - return - #raise InvalidDestroyCellException() + + # TODO (improvement) Ensures cell is valid. # Mark the channel as destroyed if not channel.destroyed.is_set(): channel.destroyed.set() - cell_padded = lnn.cell.pad(cell) + cell_padded = lnn.proxy.cell.Cell.pad(cell) await self.to_send.put(cell_padded) - #await self.to_send.put(cell) logging.debug('Link: Scheduled data from channel {} to be send.'.format(channel.cid)) @@ -147,7 +133,7 @@ async def _recv(self, reader): """ while not reader.at_eof(): - data = await reader.read(65536) + data = await reader.read(4096) data = self.buffer + data @@ -156,45 +142,40 @@ async def _recv(self, reader): # Let the channel manager do the multiplexing. #logging.debug('Link: Received data\n{}'.format(data)) - (cell, data) = lnn.utils.cell_slice_old(data) + cell, data = lnn.proxy.cell.Cell.raw_from_buffer(data) - data_cells = b'' - cells = [] + #data_cells = b'' while cell is not None: - data_cells += cell - cells.append(cell) + #data_cells += cell logging.debug('Link: Spliced a cell. {}... {} bytes.'.format(cell[:20], len(cell))) # Analyse header to select correct channel. - header = lnn.cell.header(cell) - cid = header.circuit_id - #cid = lnn.utils.cell_get_cid(cell) + cid = lnn.proxy.cell.Cell.circuit_id(cell) if cid == 0: await self._handle_tor_cmd_cell(cell) else: # Replace the real circuit id by a dummy one. - cell_mut = lnn.cell.header_view.write(cell, circuit_id=fake_circuit_id) - #cell_mut = lnn.utils.cell_set_cid(cell, fake_circuit_id) + cell_mut = lnn.proxy.cell.Cell.set_circuit_id(cell, fake_circuit_id) self.cell_recv += 1 logging.info('cell {} recv by relay: {}'.format(self.cell_recv, cell[:20].hex())) await self.channel_manager.schedule_to_send(cell_mut, cid) - (cell, data) = lnn.utils.cell_slice_old(data) + cell, data = lnn.proxy.cell.Cell.raw_from_buffer(data) - data_cells = data_cells + data + #data_cells = data_cells + data - if data_cells != data_initial: - logging.warning('CELL SLICING MANGLE THE DATA') - logging.warning('INITIAL:\n{}'.format(data_initial.hex())) - logging.warning('CELLS:\n{}'.format(data_cells.hex())) - logging.warning('PREV BUFFER:\n{}'.format(self.buffer.hex())) - logging.warning('NEXT BUFFER:\n{}'.format(data.hex())) + #if data_cells != data_initial: + # logging.warning('CELL SLICING MANGLE THE DATA') + # logging.warning('INITIAL:\n{}'.format(data_initial.hex())) + # logging.warning('CELLS:\n{}'.format(data_cells.hex())) + # logging.warning('PREV BUFFER:\n{}'.format(self.buffer.hex())) + # logging.warning('NEXT BUFFER:\n{}'.format(data.hex())) - # At the end we keep the beginning of the next cell. + # At the end we keep the start of the next cell if needed. self.buffer = data @@ -227,54 +208,34 @@ async def _negociate_version(self, reader, writer, versions): logging.debug('Link: Begin version negociation.') # Ask the relay which versions it supports. - #payload = lnn.cell.versions.pack(versions) - payload = lnn.utils.cell_version_build(versions) - - #await lnn.cell.versions.send_async(writer, payload) - # Code from this method inlined here: - - #payload = payload.raw - - #vercell = lnn.cell.versions.cell(payload) - #if not vercell.valid: - # raise InvalidVersionCellException() + cell_version = lnn.proxy.cell.CellVersion(versions) + payload = cell_version.to_bytes() writer.write(payload) await writer.drain() - logging.debug('Link: Sent version cell: {}.'.format(payload)) + #logging.debug('Link: Sent version cell: {}.'.format(payload)) - #vercell = await lnn.cell.versions.recv_async(reader) - # Code from this method inlined here: - - #answer = await reader.read(lnn.cell.header_legacy_view.width()) answer = await reader.read(5) - #header = lnn.cell.header_legacy(answer) - #if not header.valid: - # raise InvalidCellHeaderException() - #if not header.cmd == lnn.cell.cmd.VERSIONS: - # raise InvalidVersionCellException() + # TODO (improvement) Ensures cell is valid. - #length = header.length - length = lnn.utils.cell_version_get_len(answer) + length = lnn.proxy.cell.CellVersion.length(answer) - if length > lnn.constants.max_payload_len: + if length > lnn.proxy.cell.PAYLOAD_SIZE_MAX: raise InvalidVersionCellException() answer += await reader.read(length) - #if not lnn.cell.versions.view.valid(answer): - # raise InvalidVersionCellException() - logging.debug('Link: Received version cell: {}'.format(answer)) + # TODO (improvement) Ensures cell is valid. + + #logging.debug('Link: Received version cell: {}'.format(answer)) - #vercell = lnn.cell.versions.cell(answer) - versions_res = lnn.utils.cell_version_get_versions(answer) + cell = lnn.proxy.cell.CellVersion.from_bytes(answer) - #common_versions = set(vercell.versions).intersection(versions) - common_versions = set(versions_res).intersection(versions) + common_versions = set(cell.versions).intersection(versions) - if len(common_versions) < 1: + if not common_versions: raise NoSupportedVersionException() max_version = max(common_versions) @@ -340,37 +301,15 @@ async def _handler(self, host, port, ctxt, versions): #logging.debug('Link: Received handshake cells:\n{}'.format(cells_raw)) - (cell, cells_raw) = lnn.utils.cell_slice(cells_raw) - #certs_cell = lnn.cell.certs.cell(cell) - certs_cell = cell - #logging.debug('Link: Certs cell:\n{}... {} bytes.'.format(certs_cell.raw[:20], len(certs_cell.raw))) - logging.debug('Link: Certs cell: {}... {} bytes.'.format(certs_cell[:20], len(certs_cell))) + certs_cell, cells_raw = lnn.proxy.cell.Cell.raw_from_buffer(cells_raw) + auth_cell, cells_raw = lnn.proxy.cell.Cell.raw_from_buffer(cells_raw) + netinfo_cell, cells_raw = lnn.proxy.cell.Cell.raw_from_buffer(cells_raw) - (cell, cells_raw) = lnn.utils.cell_slice(cells_raw) - #auth_cell = lnn.cell.challenge.cell(cell) - auth_cell = cell - #logging.debug('Link: Auth cell:\n{}... {} bytes.'.format(auth_cell.raw[:20], len(auth_cell.raw))) - logging.debug('Link: Auth cell: {}... {} bytes.'.format(auth_cell[:20], len(auth_cell))) - - (cell, cells_raw) = lnn.utils.cell_slice(cells_raw) - #netinfo_cell = lnn.cell.netinfo.cell(cell) - netinfo_cell = cell - #logging.debug('Link: Netinfo cell:\n{}... {} bytes.'.format(netinfo_cell.raw[:20], len(netinfo_cell.raw))) - logging.debug('Link: Netinfo cell: {}... {} bytes.'.format(netinfo_cell[:20], len(netinfo_cell))) - - # Validation of handshake cells given by the relay. - #if not certs_cell.valid: - # raise InvalidCertsCellException() - - #if not auth_cell.valid: - # raise InvalidAuthCellException() - - #if not netinfo_cell.valid: - # raise InvalidNetInfoCellException() + # TODO (improvement) Ensures cells are valid. # Send the NETINFO without doing any further authentication. - #netinfo_cell = lnn.cell.pad(lnn.cell.netinfo.pack(host)) - netinfo_cell = lnn.utils.cell_netinfo_build(host) + + netinfo_cell = lnn.proxy.cell.CellNetInfo.to_bytes(host) writer.write(netinfo_cell) await writer.drain() @@ -385,15 +324,6 @@ async def _handler(self, host, port, ctxt, versions): done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - #while not reader.at_eof(): - # done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - # if tasks[0].done() or tasks[0].cancelled(): - # tasks[0] = asyncio.create_task(self._recv(reader)) - # logging.debug('Link: New recv task created.') - # if tasks[1].done() or tasks[1].cancelled(): - # tasks[1] = asyncio.create_task(self._send(writer)) - # logging.debug('Link: New send task created.') - # Proper termination of communications. for task in tasks: if not task.cancelled(): diff --git a/lightnion/proxy/parts.py b/lightnion/proxy/parts.py index 46f1aee..075dbfb 100644 --- a/lightnion/proxy/parts.py +++ b/lightnion/proxy/parts.py @@ -4,7 +4,7 @@ from cryptography.hazmat.primitives.ciphers.aead import AESGCM as gcm from cryptography.exceptions import InvalidTag -import lightnion as lnn +#import lightnion as lnn class crypto: def __init__(self): @@ -12,7 +12,7 @@ def __init__(self): self.gcm = gcm(gcm.generate_key(bit_length=128)) def compute_token(self, circuit_id, binding): - circuit_id = lnn.cell.view.uint(4).write(b'', circuit_id) + circuit_id = circuit_id.to_bytes(4, 'big') nonce = secrets.token_bytes(12) token = self.gcm.encrypt(nonce, circuit_id, self.binding + binding) diff --git a/lightnion/utils.py b/lightnion/utils.py deleted file mode 100644 index 35caf1c..0000000 --- a/lightnion/utils.py +++ /dev/null @@ -1,229 +0,0 @@ -import lightnion as lnn -import socket -import time -import os - -class InvalidCellHeaderException(Exception): - def __init__(self, header): - super().__init__('Invalid cell header: {}'.format(header)) - -class InvalidCellLengthException(Exception): - pass - - -cell_cmd_to_string = { - 0: "PADDING", - 1: "CREATE", - 2: "CREATED", - 3: "RELAY", - 4: "DESTROY", - 5: "CREATE_FAST", - 6: "CREATED_FAST", - 7: "VERSIONS", - 8: "NETINFO", - 9: "RELAY_EARLY", - 10: "CREATE2", - 11: "CREATED2", - 12: "PADDING_NEGOTIATE", - 128: "VPADDING", - 129: "CERTS", - 130: "AUTH_CHALLENGE", - 131: "AUTHENTICATE", - 132: "AUTHORIZE" -} - -def cell_to_str(cell): - return cell[:20].hex() - -def cell_get_cid(cell): - return int.from_bytes(cell[0:4], 'big') - - -def cell_set_cid(cell, cid): - return cid.to_bytes(4, 'big') + cell[4:] - - -def cell_get_cmd(cell): - return cell[4] - - -def cell_version_get_cmd(cell): - return cell[2] - - -def cell_get_len(cell): - return int.from_bytes(cell[5:7], 'big') - - -def cell_version_get_len(cell): - return int.from_bytes(cell[3:5], 'big') - - -def cell_pad_rnd(cell): - if cell_is_variable_length(cmd): - cell_len = 7 + cell_get_len(payload) - else: - cell_len = 514 - - if cell_len > len(cell): - return cell + os.urandom(cell_len - len(cell)) - else: - return cell - - -def cell_pad_null(cell): - if cell_is_variable_length(cmd): - cell_len = 7 + cell_get_len(payload) - else: - cell_len = 514 - - if cell_len > len(cell): - return cell + bytearray(cell_len - len(cell)) - else: - return cell - - -def cell_is_valid(cell): - cmd = cell_get_cmd(cell) - if cmd in cell_cmd_to_string.keys(): - return False - - cell_len = cell_get_len(cell) - if cell_len != len(cell): - return False - - # TODO: add some checks. - - return True - - -def cell_is_variable_length(cmd): - return cmd >= 128 or cmd == 7 - - -def cmd_to_str(cmd): - if cmd in cell_cmd_to_string.keys(): - return cell_cmd_to_string[cmd] - - return 'UNKNOWN ({})'.format(cmd) - - -def cell_version_build(versions): - cell = b'\x00\x00\x07' + (len(versions)*2).to_bytes(2, 'big') - - for version in versions: - cell += version.to_bytes(2, 'big') - - return cell - - -def cell_version_is_valid(cell): - cmd = cell_version_get_cmd(cell) - if cmd != 7: - return False - - cell_len = cell_version_get_len(cell) - if cell_len != len(cell): - return False - - # TODO: add some checks. - - return True - - -def cell_version_get_versions(cell): - return [int.from_bytes(cell[i:i+2], 'big') for i in range(5, len(cell), 2)] - - -def cell_netinfo_build(host): - tstmp = int(time.time()).to_bytes(4, 'big') - if host == 'localhost': - addr = b'\x7f\x00\x00\x01' - else: - addr = socket.inet_aton(host) - - addr_len = len(addr) - - if addr_len == 4: - addr_t = b'\x04' - else: - addr_t = b'\x06' - - cell = b'\x00\x00\x00\x00\x08' + tstmp + addr_t + addr_len.to_bytes(1, 'big') + addr - - # padding - cell += bytearray(514 - len(cell)) - - return cell - - -def cell_slice(payload): - """Retrieve the next cell from the payload and truncate that one. - :param payload: bytearray - """ - payload_len = len(payload) - if payload_len < 7: # (payload too small, need data) - return None, payload - - cmd = cell_get_cmd(payload) - - if cell_is_variable_length(cmd): - cell_len = 7 + cell_get_len(payload) - else: - cell_len = 514 - - if payload_len < cell_len: - return None, payload - - cell = payload[:cell_len] - - return cell, payload[cell_len:] - - -#def cell_version_slice(payload): -# payload_len = len(payload) -# if payload_len < 5: # (payload too small, need data) -# return None, payload -# -# cell_len = 5 + cell_version_get_len(payload) -# -# if payload_len < cell_len: -# return None, payload -# -# cell = payload[:cell_len] -# -# return cell, payload[cell_len:] - - -def cell_slice_old(payload): - """Retrieve the next cell from the payload and truncate that one. - :param payload: bytearray - """ - cell_header = lnn.cell.header(payload) - if len(payload) < cell_header.width: # (payload too small, need data) - return None, payload - - if not cell_header.valid: - raise InvalidCellHeaderException(cell_header.raw) - - length = cell_header.width + lnn.constants.payload_len - if not cell_header.cmd.is_fixed: - cell_header = lnn.cell.header_variable(payload) - if len(payload) < cell_header.width: # (payload too small, need data) - return None, payload - - if not cell_header.valid: - raise InvalidCellHeaderException(cell_header.raw) - - length = cell_header.width + cell_header.length - - if length > lnn.constants.max_payload_len: - raise InvalidCellLengthException() - - if len(payload) < length: - return None, payload - - cell = payload[:length] - - return cell, payload[length:] - diff --git a/tools/.extra/asyncio.py b/tools/.extra/asyncio.py deleted file mode 100644 index c1d64fd..0000000 --- a/tools/.extra/asyncio.py +++ /dev/null @@ -1,221 +0,0 @@ -# https://docs.python.org/3/library/asyncio-protocol.html - -# -# 1st draft (see below for 2nd draft) -# - -# perform handshake (as client) -> lnn.accept(handler) as server -async with lnn.link(host, port, *, ssl, transport=lnn.io.link) as link: - await link.write(*cells) # sends all cells provided - - async with link.fast(*, transport=lnn.io.circuit) as circuit: - async with link.ntor(descriptor, transport=lnn.io.circuit) as circuit: - circuit.write(*payloads) # sends all payloads provided (add header) - - # extend the circuit to target nodes - await circuit.extend(*descriptors) - - async with circuit.raw(*, transport=lnn.io.stream) as raw: - raw.write(*payloads) # sends all payloads provided (add header) - - # receive RELAY payloads - async for payload in raw: - # perform work - - async with circuit.dir(query, *, transport=lnn.io.stream) as request: - request.{headers,data,text, ...} # (query already performed) - - # returns the protocol - async with circuit.tcp(host, port, *, - protocol=lnn.io.socket, transport=lnn.io.stream) as socket: - - # socket-like interface - socket.send(data) - socket.recv() - -# class custom(lnn.io.{link,circuit,stream}): -# # custom control (or non-"relay_data") cells handling -# async def perform_control(self, cells): # (cells is an async generator) -# async for cell in super().perform_control(cells): -# # ... do some work ... -# if condition: -# yield cell # cells not yielded are hidden in lower layers - -# -# 2nd draft (see below for stack summary) -# - -async with lnn.link(host, port, handler=None, *, ssl, transport=lnn.t.link) as link: - # note that explicitly ssl=None must be stated to disable ssl cert. auth. - # (a context can be provided either way) - # - # if (handler == None), defaults to lnn.lp.initiator (if lnn.link) - # or lnn.lp.responder (if lnn.accept) - # - # (inherit from lnn.lp.basic) - # (context manager can only be used if (handler == None) here) - # - # See link.fast below for handler-related behaviors. - # - # - # lnn.link is a convenience wrapper around: - # lnn.create_link(lnn.io.ssl, lnn.lp.initiator, *kargs, * - # transport=lnn.t.link, loop=None) - # lnn.accept is a convenience wrapper around: - # lnn.create_link(lnn.io.ssl, lnn.lp.responder, *kargs, *, - # transport=lnn.t.link, loop=None) - # - # (where internally lnn.io.ssl is build using given lnn.lp, kargs & loop) - # - # - # They all have extra callbacks: - # raw(self, data) (called with raw incoming payloads) - # ready(self) (called when the link is ready) - # early(self, cell) (called before each cell is handled) - # control(self, cell) (called with control cells not handled) - # - # And expose: - # fast - # ntor - - async with link.fast(handler=None, *, transport=lnn.t.circuit) as circuit: - # if (handler == None), defaults to lnn.cp.fast (if link.fast) - # or lnn.cp.ntor (if link.ntor) - # (inherit from lnn.cp.basic) - # (context manager can only be used if (handler == None) here) - # - # - # link.fast is a convenience wrapper around: - # lnn.create_circuit(lnn.cp.fast, link, *kargs, *, - # transport=lnn.t.circuit) - # - # link.ntor is a convenience wrapper around: - # lnn.create_circuit(lnn.cp.ntor, link, *kargs, *, - # transport=lnn.t.circuit) - # - # (where protocol is build using link and *kargs) - # - # - # They all have extra callbacks: - # ready(self) (called when the circuit is ready) - # early(self, cell) (called before each cell is handled) - # control(self, cell) (called with control cells not handled) - # destroyed(self, reason) (called when a DESTROY cell comes) - # - # And expose: - # raw - # dir - # tcp - - # if handler is a callable, the transport is passed as: - async with link.fast(handler=None, *, transport=lnn.io.circuit) as circuit: - await handler(circuit) - - # thus expected call is: - asyncio.ensure_future(link.fast(handler)) - -# pre-build transports: -# lnn.t.link for lightnion.transports.link -# lnn.t.circuit for lightnion.transports.circuit -# lnn.t.stream for lightnion.transports.stream - -# pre-build protocols: -# lnn.lp for lightnion.link_protocols -# lnn.lp.basic -# lnn.lp.initiator -# lnn.lp.responder -# lnn.cp for lightnion.circuit_protocols -# lnn.cp.basic -# lnn.cp.raw -# lnn.cp.fast -# lnn.cp.ntor -# lnn.sp for lightnion.stream_protocols -# lnn.sp.basic -# lnn.sp.raw -# lnn.sp.dir -# lnn.sp.tcp -# lnn.dp for lightnion.data_protocols -# lnn.dp.basic -# lnn.dp.socket - -# stack summary -# -# · lnn.link -# | ~ lnn.create_link -# | -# | io -# | lnn.transports.link -# | lnn.link_protocols.{initiator, responder} (responder NOT implemented) -# | -# · link.{raw, fast, ntor} -# | ~ lnn.create_circuit -# | -# | lnn.transports.circuit -# | lnn.circuit_protocols.{raw, fast, ntor} -# | -# · circuit.{raw, dir, tcp} -# | ~ lnn.create_stream -# | -# | lnn.transports.stream -# | lnn.stream_protocols.{raw, dir, tcp} -# @ - -# raw protocols gives direct access to cell reader/writer -async with circuit.raw() as stream: - reader, writer = stream.get_transports() - -def handler(reader, writer): - pass - -asyncio.ensure_future(circuit.raw(handler)) - -# tcp also gives direct access, but to data reader/writer -async with circuit.tcp(host, port) as stream: - reader, writer = stream.get_transports() - -def handler(reader, writer): - pass - -asyncio.ensure_future(circuit.tcp(handler)) - -# dir is just like tcp, but sends a BEGIN_DIR instead - -# providing a lnn.adapters.socket(circuit) can be fun -# - returns an object that exposes main socket modules functions -# create_connection -# -# close -# getblocking -# gettimeout -# recv -# recvfrom -# recv_into -# send -# sendall -# sendfile -# setblocking -# settimeout -# -# # goals: -# # - have python native ssl module working -# # - have asyncio.get_event_loop().create_connection(sock=) working -# -# providing a lnn.adapters.requests(circuit) can be fun -# - returns an object that exposes main requests module functions -# -# adapters.HTTPAdapter (must work for both HTTP & HTTPs) -# Session (builds a session object, but with the right adapters) -# -# request -# head -# get -# post -# put -# patch -# delete -# -# providing a lnn.adapters.directory(circuit) can be fun -# - same a lnn.adapters.requests, but create dir streams instead -# -# adapters.HTTPAdapter (but building dir streams) -# diff --git a/tools/.extra/oldread.md b/tools/.extra/oldread.md deleted file mode 100644 index f97e042..0000000 --- a/tools/.extra/oldread.md +++ /dev/null @@ -1,262 +0,0 @@ -lightnion: Tor portable to the browser -===================================== - -**Note: lightlor is still at its early stages of development, do NOT use it for -anonymity.** - -This is an old `README.md` written during a long, sad – drunken – night… -or is it? In short, don't take any word here for granted. - -Content -------- - - - [Introduction](#introduction) - - [Quick Setup](#quick-setup) - - [Requirements](#requirements) - - [Frequently Asked Questions](#frequently-asked-questions) - - [Contribute](#contribute) - - [Contact](#contact) - - [License](#license) - -Introduction ------------- - -Kids these days worry about a lot of things: - - users wanting services designed with privacy in mind. - - users not wanting to download more than a webpage. - - users not wanting latency and high resources usage. - -**Lightnion** enables kids to build such applications in a world made of -browsers that are not the [Tor Browser](https://www.torproject.org/projects/torbrowser.html.en). - -It provides the following components: - - a lightweight client that can be easily embedded within a webpage. - - a forward proxy that does some heavy-lifting for clients. - - a reverse proxy that does the rest of the heavy-lifting. - -**Lightnion** lightweight client is a library that your javascript uses to talk -through Tor. Its forward proxy removes raw TCP between sandboxed code and onion -routers. Its reverse proxy removes the need of running TLS or HTTPS within a -webpage. - -It is also **not** production ready. - -Checkout [Frequently Asked Questions](#frequently-asked-question) for more -details. - -Quick setup ------------ - -Clone the repository and add it to your `PYTHONPATH`: -```sh -git clone --recurse-submodules https://github.com/spring-epfl/lightnion -cd lightnion -virtualenv venv -source venv/bin/activate -pip install -r requirements.txt -export PYTHONPATH="$PWD" -``` - -There is no online documentation for now. You'll find some examples under -`./examples`. - - -Requirements ------------- - -We do recommend using `chutney`, you'll find some instructions -within `./tools/chutney`. - -**Tested with `Python 3.6.5` against -`Tor version 0.3.3.6 (git-7dd0813e783ae16e)`.** - -If you need support for an older python or a newer Tor, please open an issue. - -Frequently Asked Questions --------------------------- - -If you have some questions, please open an issue starting with -`[FAQ] ` to get an answer or [contact us](#contact). - -You'll find below some answers to some frequently asked questions: - - - [Are you attempting to replace the Tor Browser?](#are-you-attempting-to-replace-the-tor-browser) - - [What can I expect lightnion to do for me?](#what-can-i-expect-lightnion-to-do-for-me) - - [How are you going to do that?](#how-are-you-going-to-do-that) - - [Why doing things in a browser?](#why-doing-things-in-a-browser) - - [Why javascript? Is is then unsafe?](#why-javascript-is-is-then-unsafe) - - [Does it protects me if I disable javascript?](#does-it-protects-me-if-i-disable-javascript) - - [Why not hacking the official Tor client?](#why-not-hacking-the-official-tor-client) - - [Why are you not using stem to do that?](#why-are-you-not-using-stem-to-do-that) - - [Why are you not using a pluggable transport to do that?](#why-are-you-not-using-a-pluggable-transport-to-do-that) - -### Are you attempting to replace the [Tor Browser](https://www.torproject.org/projects/torbrowser.html.en)? - -_No._ - -If you are an user worried about your privacy, using the Tor Browser is a [good -starting point](https://www.torproject.org/docs/faq.html.en#WhatIsTor). - -If you do not use the Tor Browser but -[still care](https://www.torproject.org/docs/faq.html.en#TBBOtherBrowser) -about privacy, you may someday enjoy web services that uses lightnion. - -If you are trying to build a web service designed with privacy in mind -and that works on any browser, lightnion may -[help you](#what-can-i-expect-lightnion-to-do-for-me). - -### What can I expect lightnion to do for me? - -_Not much if you are not building a web-based application._ - -First, start by reading: -[Are you attempting to replace the Tor Browser?](#are-you-attempting-to-replace-the-tor-browser). - -Now, if you are the one trying to build such privacy-enabled service, there is -not much that you can do against -[traffic analysis](https://www.torproject.org/about/overview.html.en#whyweneedtor). -Most chooses to tell their privacy-minded and tech-savvy users to get the Tor -Browser and leave other kinds of users aside. - -**Lightnion brings a different compromise into the picture:** your -privacy-minded and tech-savvy users will still be able to protect themselves, -however the other kinds will also interact with you through Tor and will have -some form of protection. - -The trick is that you will not be able to distinguish privacy-minded users from -other kinds of users. Thus, even getting few users to run signed software that -checks if your service does not misbehave can provide good incentives to remain -honest. - -To sum up, if you build such "privacy by default" service with lightnion, all -your users talk to you through Tor, get some protection and can at least trust -your reputation against the permanent scrutiny of anonymous privacy-minded -users hiding in the crowd. - -**Note that lightnion is still in the early stages of its development and need -more work to enforce those properties.** - -### How are you going to do that? - -_No idea, yet._ - -Lightnion is first and foremost a research project, its whole job is to figure -out how to achieve its goals. - -Please open an issue or [contact us](#contact) if you spot problems, have some -criticism or want to [contribute](#contribute). - -### Why doing things in a browser? - -_Because it is useful._ - -There is the [Tor Browser](https://www.torproject.org/projects/torbrowser.html.en) -and [several](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) -[other](https://guardianproject.info/apps/orbot/) -[ways](https://tails.boum.org/) to use the Tor network and its capabilities as -an user. - -Lightnion aims to bring Tor to users with nothing more than loading a webpage. -Hence yes: it does things in a browser. - -### Why javascript? Is is then unsafe? - -_Because browsers. Not more than running any web-based application._ - -The full answer is closely related to: - - [Why doing things in a browser?](#why-doing-things-in-a-browser) - - [What can I expect lightnion to do for me?](#what-can-i-expect-lightnion-to-do-for-me) - -Lightnion targets mostly web-based applications where the user only open a -webpage to use Tor. It can not afford nice things such as native clients, -extensions or the Tor Browser itself: the only way to go was to embed some -javascript in the webpage. - -As an user of a web-based service, you already put some trust in your service -that delivers nice code with no malicious intent. Lightnion only adds to this -code a tiny library that gives a way for the service to interact with its -servers through Tor. - -Lightnion is only as small step towards an ecosystem that brings privacy to the -masses. It does provide few other components that may help users to protect -themselves, however it will not prevent design mistakes in applications or some -malpractices. - -### Does it protects me if I disable javascript? - -_Lightnion does not provide any kind of protection before it is executed._ - -This question is best answered through a case study: imagine that lightnion is -integrated into an instant messaging client written in javascript. You first -download the webpage, then the client kicks in and send/receive all messages -through the Tor network. - -Every user that keeps its browser tab open for a long time starts to look the -same, providing some form of anonymity. However, if you disabled javascript in -the first place, you never were an user of this instant messaging service in -the first place. - -### Why not hacking the official Tor client? - -_Because it may have been counterproductive._ - -Lightnion was build with a side task of understanding in details what can be/can -not be done within the Tor protocol, and what needed to be implemented in -order to get the thing into a browser. This implementation acts as a -side-effect of such work. - -Note that some components of the official client are used or planned to be -used, mostly for the sensitive parts. - -### Why are you not using [stem](http://stem.torproject.org/) to do that? - -_Because lightnion started before stem gained more client capabilities._ - -Closely related to: -[Why not hacking the official Tor client?](#why-not-hacking-the-official-tor-client) - -Note that some components of stem have been previously used and some are still -used. - -### Why are you not using a [pluggable transport](https://gitweb.torproject.org/torspec.git/tree/pt-spec.txt) to do that? - -_For now._ - -Implementing a proper pluggable transport can enable lightnion to be more easily -integrated within the existing Tor ecosystem. However building such pluggable -transport is for now not a priority, lightnion needs more work to get to this -point. - ---- - -Contribute ----------- - -Feel free to contribute! - -If you want to make your time worth, do not hesitate to [contact us](#contact) -and to tell us what you want to do. - -Contact -------- - -Feel free to contact us: -``` - - carmela [dot] troncoso [at] epfl [dot] ch - - wouter [dot] lueks [at] epfl [dot] ch - - matthieu [at] daumas [dot] me -``` - -If you have bug reports or feature suggestions, please open an issue. - -License -------- - -This software is licensed under -[some license](LICENSE.txt_REPLACE_BEFORE_FIRST_RELEASE). -© 2018 Spring Lab (EPFL) and contributors. - -Note that the aforementioned `some license` mention should have been replaced -before the distribution of the project. If you are able to read this, please -[contact us](#contact) to report the issue or to obtain a copy of the license -we choose for the project. diff --git a/tools/.extra/spec.txt b/tools/.extra/spec.txt deleted file mode 100644 index dc7ab59..0000000 --- a/tools/.extra/spec.txt +++ /dev/null @@ -1,209 +0,0 @@ - -Summary: - - Can be used as proxy or pluggable transport. - - Add some headers during websocket UPGRADE handshake. - - Upon successful negotiation, gives access to a circuit. - - Upon failure, acts as if there is no websocket listener. - - Returns negotiation results in handshake answer. - -Notes: - - this "spec" is only notes, i.e. "brain farts". - - python websockets provides everything we need to bind unholy handshakes. - - -------------- -original file -------------- - -Some notes about anything I can think of in term of features and implementation -that can be included in lightnion. Note that here we assume that lightnion -provides no path selection mechanism -- also note that a client can recover at -any time a consensus or descriptors by doing an attempt without X-PNN-IDENTITY -and further perform signature validation and path selection locally. - -No mechanism for feature negotiation is provided to avoid trivial probing, note -that both PNN-OTP-SEED and PNN-HTTP-PROXY should be set to avoid active probes -(assuming a proper implementation of the lightnion proxy) - -lightnion config, only read once during startup: - PNN-LISTEN host:port (required) - incoming connections host:port - if lightnion is started as a plug. transport, host:port are overridden - PNN-ORPORT host:port:fast (required) - parent Tor node - if lightnion is started as a plug. transport, host:port are overridden - if :fast is omitted, attempts without X-PNN-NTOR will be unrecognized. - if :fast is present, lightnion circuit creation defaults to CREATE_FAST - whenever X-PNN-NTOR is omitted in the attempt. - PNN-PER-LINK nb (optional) - set the number of channel allocated per link, i.e. number of circuits - created before rotating a link. - (defaults to 16) - PNN-MAX-LINK nb (optional) - set the number of links that can exists in parallel. - (destroying oldest links first whenever needed) - (defaults to 64) - PNN-EXPIRACY seconds (optional) - number of seconds of inactivity before destroying channel. - (defaults to 600) - PNN-TIMEOUT seconds (optional) - number of seconds before timeout during circuit creation. - (defaults to 10) - PNN-SSL-CERT path (recommended) - if present, PNN-SSL-KEY must be set. - if present, lightnion will only accept TLS connections and will use the - certificate at the given path. - if not present, lightnion will not recognize attempts w/o X-PNN-NTOR. - PNN-SSL-KEY path (recommended) - if present, PNN-SSL-CERT must be set. - if present, lightnion will only accept TLS connections and will use the - key material at the given path. - if not present, lightnion will not recognize attempts w/o X-PNN-NTOR. - PNN-NTOR-AUTH hex/path (optional) - if present and either PNN-SSL-CERT or PNN-SSL-KEY is not set, lightnion - will not recognize attempts without a X-PNN-AUTH header. - if present, lightnion will accept X-PNN-AUTH headers if its value can - be interpreted as a valid x25519 key (either 32 hex-encoded bytes or a - path as described below). - if present and is not 64 hexadecimal digits, lightnion will interpret - the given value as the path of a PEM-encoded file and will take the - last 32 bytes of its base64-encoded material as key. - (effectively ignoring plausible x25519 ASN.1 headers) - if not present and either PNN-SSL-CERT or PNN-SSL-KEY is not present, - lightnion fails. - PNN-HTTP-PROXY protocol:host:port (experimental) - if not present, any unrecognized attempt will fail with no content, no - extra header and a status code of 400. - if present, any unrecognized attempt of opening a channel will be - forwarded as-is to the specified host:port and the answer, status code - and headers will be returned as-is to the client -- note that protocol - can only take "http" and "https" as value and that lightnion will - return a status code 500 without content nor extra header if it is - unable to complete the request. - PNN-OTP-SEED hex (experimental) - if present, lightnion will not recognize any attempt of opening any - channel without a valid X-PNN-OTP header and the hex-encoded seed - will be used to check validity. - (the seed must contain at least 32 bytes of uniform randomness and thus - lightnion will reject any seed shorter than 32 bytes) - PNN-MIN-POISSON milliseconds (experimental) - if not present, lightnion will not recognize any attempt that provides - a X-PNN-POISSON header. - if present, lightnion will not recognize any attempts that set a - X-PNN-POISSON header value below the value set here. - (should approximate PNN-LINK-POISSON * PNN-PER-LINK) - (recommended to 256) - PNN-LINK-POISSON milliseconds (experimental) - if present and PNN-MIN-POISSON not present, lightnion fails. - (defaults to 16) - -1. the client arrives, begin a websocket handshake providing extra headers: - - X-PNN-IDENTITY base64 (recommended) - target Tor node identity, must be the first X-PNN prefixed header and - must be equal to the parent Tor node identity to recognize the attempt. - if not present, defaults to the parent Tor node identity. - (can be used to implement header-based reverse proxies) - - X-PNN-NTOR base64 (recommended) - if present, a CREATE2 cell is send during circuit creation instead of a - CREATE_FAST cell, effectively performing a ntor handshake with parent - Tor node. - if present, lightnion will set X-PNN-NTORED header with the server - base64-encoded part of the handshake: - either a full identity+onionkey+pubkey - either a short only-pubkey - if X-PNN-NTOR is short, identity+onionkey used are of parent Tor node - - X-PNN-AUTH base64 (optional) - if present, it must be 32 base64-encoded bytes that represents an - x25519 public key. - if present, lightnion will perform a ntor handshake between the given - x25519 X-PNN-AUTH public key, the ntor onion key provided by - PNN-NTOR-AUTH and the identity set to parent Tor node's identity and - will only set X-PNN-DONE and X-PNN-AUTHED headers in the answer, - respectively to all X-PNN prefixed headers that should have been set - without X-PNN-AUTH in the attempt as a base64-encoded encrypted payload - and to the server base64-encoded part of the handshake. - (encryption uses here as key the first 32 bytes of the key material - issued during the handshake and as nonce the next 24 bytes) - - X-PNN-OTP hex (experimental) - if present, must be the last X-PNN prefixed header of the attempt. - if present and the server doesn't have PNN-OTP-SEED set, the attempt - will be unrecognized. - if not present and the server does have PNN-OTP-SEED set, the attempt - will be unrecognized. - if present and the server does have PNN-OTP-SEED set, the attempt will - be recognized if and only if X-PNN-OTP hex value is 128 digits (64 - bytes) and equal to TOTP with key set to all X-PNN prefixed headers - as set in the attempt except for X-PNN-OTP set to PNN-OTP-SEED, - separated by a new line and ordered as in the attempt, using the - default TOTP parameters and sha512 as hash function. - - X-PNN-POISSON milliseconds (experimental) - if present, lightnion will queue cells in both directions, each queue - emptying itself at intervals drawn from an exponential distribution - with an average set to the given milliseconds. - note that whenever a backward queue (from node to client) is empty, - a DROP cell is generated then queued. - note that each forward queue (from client to node) empties itself in - a common link queue that empties itself at intervals draw from an - exponential distribution with an average set to PNN-LINK-POISSON - milliseconds. - note that whenever a link queue is empty, a DROP cell is generated - then queued. - (DROP cells neither tags circuits nor links as active) - -2. the server creates a channel and its associated circuit for the client: - - a channel creation attempt can be either recognized or unrecognized, it - is recognized if all constraints put on X-PNN prefixed headers of the - attempt are filled. - - unrecognized channel creation attempts gives either 400 status codes with - no content and no extra headers or are forwarded as-is to PNN_HTTP_PROXY - if it was set during lightnion startup. - - circuit creation is attempted if and only if the attempt is recognized - and must be the last step performed during channel creation. - - if circuit creation timeouts, the channel creation failed and a status - code HTTP 503 is returned. - - every channel that does not receive messages from a client for more than - PNN-EXPIRACY is destroyed together with its circuit. - - whenever a link have no channel alive and is not the last link alive, it - is destroyed. - - after creating PNN-PER-LINK circuits for a link, a new link is created - and used for further circuits. - - the server attributes the circuit id used during creation to the channel - and will not use it again. - -3. the server gives an answer to the handshake and set several headers: - - X-PNN-IDENTITY base64 - target Tor node identity used as guard in this context, set whenever - X-PNN-DONE is not present - - X-PNN-NTORED base64 - set whenever X-PNN-NTOR was provided in the channel creation attempt, - except if X-PNN-DONE is present - - X-PNN-EXPIRACY seconds - set whenever PNN-EXPIRACY is different from its default value, - except if X-PNN-DONE is present - - X-PNN-DONE base64 - set whenever X-PNN-AUTH was provided in the channel creation attempt - - X-PNN-AUTHED base64 - set whenever X-PNN-DONE is present, see X-PNN-AUTH - - X-PNN-OTP-STAMP seconds - set as an integer equal to the unix timestamp as used during TOTP - whenever X-PNN-OTP was provided in the channel creation attempt, - except if X-PNN-DONE is present - -4. the server will forward binary data in both directions between the client - and the parent Tor node: - - every cell going from the client to the parent node will be dropped - whenever its circuit id is different from 0x80000000 or whenever its - command is different from 0x03 (RELAY cell). - - every cell going from the client to the parent node will see its circuit - id replaced by the id of the circuit id attached to the channel. - - every cell going from the parent node to the client will be dropped if - its command is different from 0x03 (RELAY cell). - - every cell going from the parent node to the client will see its circuit - id replaced by 0x80000000. - - if for any reason, the circuit attached to the channel is destroyed, the - channel is destroyed and its connection closed. - -Whenever encryption that are not explicitly required by the Tor protocol is -performed by lightnion or its client, we use xsalsa20-poly1305 authenticated -encryption as implemented by nacl via secretbox. This case is for now only used -whenever X-PNN-DONE is set. diff --git a/tools/authority_signing_keys.json b/tools/authority_signing_keys.json deleted file mode 100644 index ee92ef8..0000000 --- a/tools/authority_signing_keys.json +++ /dev/null @@ -1 +0,0 @@ -{"A678F6F1F0AC64A0EDA394CA68C285C44A44A2D7": {"pem": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAwd1uWVB62CLKAbSTmSnfBsWbYejL9FZHNxiV0UQmwrhd8aUu3wQ+\nXT3IbMhxa4rcApS6UoGSdJoUNbML4oTNyS70RwXohltZAQVhOoQj/4YnR5Fy9YMl\nQSXqnG2qwdGmuF8zZ/11BN6wpkN8AexIQCAseHNJEJwqgZLthFOvTKuVy91EEo2J\nEmE3JGcGw5BIXuKijiDZjFaLBj36r6hTesdDwntClXjFAxFSQKiL3a+KFEBiyJVj\nDePi1dNMKE59uzC+zSoLA+JFi6t/OyFIc2z3YW+Q3iYKZCp1txvakwflFfAcM/GJ\nd8rpXGcloBmILmDQnwRLuBOxMpBAmkmbkQIDAQAB\n-----END RSA PUBLIC KEY-----", "modulus": "24473184578997799380402320362520187170612739189449528191775883638006496297849520872842377613691272309268459058635815529816764967185520546708444388216733043376788087566041075770984179055741817154219703106079928281471402838683252605731123470652599857578630740156093578904108905251312805989471221655961291109670934043787090316196859522741244001046419412803093345507398016794786012490957476861789129226942849266768863110976701686486494738396792435154645682080689874094795663866459211160559276467461264031656831030819263686722244482520353380765625674851310384557514651874434405782148747548998939007362576116154638721981329", "exponent": "65537"}, "264792573EE7B00055E858E701CD4999810C6245": {"pem": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAphIwD4SYeaxNfvFjF4ETzolNU4rGU3rV1r+5skTaZBnKRXBaW16b\nCSp4KR+ZBhh7zb7cfN3F3gP6Z57TA5oB4Pf63GNr8mnmDh1/3KKjuNcRkPp0njVC\n9c2jWZAUrKb7F4drHYk3Uy1uWiYbS776fGbnTDep6ZQwGE1W4xmQMwHxOreqr1E7\nWSfmVyogY0lE2siOE/Z5IVhTi+kzhmV8bVUsKPsnOHQOD6jX3wHYIDda1c4fSzQp\n35l4Q9t9HJNPfiHJ1D0arlm4C9yJ7BhLPmoq478Qygu5XAHNW108bZKo9j3C1T1G\nyXYqVGlPY5nyPMBF0inTXXzvxElNcA0wXQIDAQAB\n-----END RSA PUBLIC KEY-----", "modulus": "20964527331642786625155753917780094334551719951352991458374196095381555724370709182443183958805627483991831411916979068452164921046705001544982496576097614601549169205085515343506076901591690637353094496110955161034814704134042997557903008293299090418571370466947553409752223504101682415304068953524853238676335788348708835518736503713338589848771791946942000072011849376973711551831007041139794493306770421269443011049620035609370885805641364823285812879360900871956992902302098754710365594473825824947161434659024694384644376211539983996335840623643245273712313899347313672847112390263693744907344677333217787588701", "exponent": "65537"}, "8224080532B17CA055166541855981A00DDD757A": {"pem": "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAuKhq7IEkj76YwHUZd+SUL3mUi6uLCDww3JAEoAtzl4oLb3CMMSs0\ngOwkzFczhACjHK+94NRr+X4zKKfoN/72jXyExKUs0PTUF/Yqv4LFtCp48ceEBis5\nWzGu9Mkos92Yw7h5RbvW1+lqebd0F3JEtD2N+K9h5J0asAR1sHaqgN+xfxBW3cyu\njVrGylVaN65eN7F9rG4EIdONsFLyeU8kDf4yFsLaD07cplmWEKnlAX1Ymde9RLLR\nlwTjmM0l87tC9jC6XUfo+YSZEpLU3aL3YGdZAHXhnufKXPJt2EEqZV6X0yYS3MVn\nxUbgNm866pveO4UmEI4tMAzLw2l/Ei0mLQIDAQAB\n-----END RSA PUBLIC KEY-----", "modulus": "23310897962769138579530152326984562325999560215117116919129440886711631616239421300051714984835221930637795748389388036883601867877727008937328098826789130648279058326197062730716900487679687074313249610539228941163039858132813382657896505476586242145526041067207939446105310645771615256817614938009928594448348184476836859457134806325264462938528057758565791649219667722068645137308602013243524623394038775533144406797285850118421769403100576832578919437294038109209727358762994648125083085984821064177287312130548098407133002465283265664620338393496658934130687942521913412195806448326412827524314091955207243900461", "exponent": "65537"}} \ No newline at end of file From 7703e10df7f66c02faece130d69d55b5e15325da Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Thu, 2 Apr 2020 09:55:36 +0200 Subject: [PATCH 14/30] Refactor keys handling (part 1). --- lightnion/consensus.py | 5 +- lightnion/keys.py | 93 +++++++++++++++++++++++ lightnion/proxy/forward.py | 7 +- tools/keys.py | 148 ------------------------------------- 4 files changed, 97 insertions(+), 156 deletions(-) create mode 100644 lightnion/keys.py delete mode 100644 tools/keys.py diff --git a/lightnion/consensus.py b/lightnion/consensus.py index da4e1c9..39f96de 100644 --- a/lightnion/consensus.py +++ b/lightnion/consensus.py @@ -8,7 +8,7 @@ import urllib.request import lightnion as lnn -from tools.keys import get_signing_keys_info +import lightnion.keys # TODO: remove extra (useless) checks/exceptions within this file @@ -804,8 +804,7 @@ def download_direct(hostname, port, flavor='microdesc'): res = urllib.request.urlopen(uri) cons = res.read() - ip = '%s:%d'%(hostname,port) - keys = get_signing_keys_info(ip) + keys = lnn.keys.fetch_and_parse_keys(hostname, port) if flavor != 'microdesc': if not lnn.signature.verify(cons.decode('utf-8'), keys): diff --git a/lightnion/keys.py b/lightnion/keys.py new file mode 100644 index 0000000..a51b313 --- /dev/null +++ b/lightnion/keys.py @@ -0,0 +1,93 @@ +import re + +import requests + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.serialization import load_pem_public_key + + +PATTERN_FINGERPRINT = r'fingerprint ([0-9A-Fa-f]+)' + +PATTERN_KEY = r"""dir-signing-key +(-----BEGIN RSA PUBLIC KEY----- +[A-Za-z0-9+/=\n]+ +-----END RSA PUBLIC KEY-----) +""" + + +def fetch_and_parse_keys(host, port=None, tls=True): + """Convenience function to call getch_keys() then parse_keys() if needed.""" + + keys_raw = fetch_keys(host, port, tls) + if keys_raw: + keys = parse_keys(keys_raw) + else: + keys = dict() + + return keys + + +def fetch_keys(host, port=None, tls=True): + """Retrieve the public signing keys from the host.""" + protocol = 'https' if tls else 'http' + path = "tor/keys/all" + + if port: + url = "{}://{}:{}/{}".format(protocol, host, port, path) + else: + url = "{}://{}/{}".format(protocol, host, path) + + res = requests.get(url) + + if res.status_code == 200 + return res.text + + return None + + +def extract_key_params(key_pem): + """Extract the exponent and modulus from a key in PEM format.""" + + key_pem_b = key_pem.encode("ASCII") + public_key = load_pem_public_key(key_pem_b, backend=default_backend()) + public_numbers = public_key.public_numbers() + modulus = public_numbers.n + exponent = public_numbers.e + + params = { + "pem": key_pem, + "modulus": str(modulus), + "exponent": str(exponent) + } + + return params + + +def parse_keys(keys_raw): + """Parse raw keys.""" + + regex_fingerprint = re.compile(PATTERN_FINGERPRINT) + regex_key = re.compile(PATTERN_KEY) + + keys = dict() + + for key_raw in keys_raw.split("dir-key-certificate-version "): + + # Extract fingerprint. + fingerprint_match = regex_fingerprint.search(key_raw) + if fingerprint_match: + fingerprint_groups = fingerprint_match.groups() + fingerprint = fingerprint_groups[0] + + # Extract signing key in PEM. + key_match = regex_key.search(key_raw) + if key_match: + key_groups = key_match.groups() + key_pem = key_groups[0] + + params = extract_key_params(key_pem) + + # Remember keys' parameters for each fingerprints. + keys[fingerprint] = params + + return keys diff --git a/lightnion/proxy/forward.py b/lightnion/proxy/forward.py index 616c0b5..4ac83e5 100644 --- a/lightnion/proxy/forward.py +++ b/lightnion/proxy/forward.py @@ -17,10 +17,8 @@ import lightnion as lnn import lightnion.path_selection import lightnion.proxy +import lightnion.keys -from tools.keys import get_signing_keys_info - -#from tools.keys import get_raw_signing_keys debug = True @@ -125,8 +123,7 @@ def retrieve_consensus(self): digests = lnn.consensus.extract_nodes_digests_unflavored(self.consensus_raw) self.descriptors_raw = lnn.descriptors.download_raw_by_digests_unflavored(host, port, digests) - keys = get_signing_keys_info('{}:{}'.format(host, port)) - self.signing_keys = keys + self.signing_keys = lnn.keys.fetch_and_parse_keys(host, port) #self.signing_keys_raw = get_raw_signing_keys('%s:%d'%(host, port)) self.mic_consensus_raw = lnn.consensus.download_raw(host, port, flavor='microdesc') diff --git a/tools/keys.py b/tools/keys.py deleted file mode 100644 index 2a65506..0000000 --- a/tools/keys.py +++ /dev/null @@ -1,148 +0,0 @@ -import os -import random -import requests -from Crypto.PublicKey import RSA -import json as js -import re - -# Those are the IP's addresses of the 9 authorities -ips = ['171.25.193.9:443', '86.59.21.38', '199.58.81.140', '204.13.164.118','66.111.2.131:9030', - '131.188.40.189', '128.31.0.34:9131', '154.35.175.225','193.23.244.244','194.109.206.212'] - - -def download_signing_keys(ip): - """Download the signing keys from the one of the authorities, parse the file and returns a dictionary - of identity digest and keys - :return: dictionary or none if there is a problem during the request""" - url = "http://{}/tor/keys/all".format(ip) - rq = requests.get(url) - - if rq.status_code == 200: - return parse_signing_keys(rq.text) - else: - return None - - -def parse_signing_keys(raw): - """Parse a raw file into a dictionary of fingerprint and keys - :param raw: the raw file - :return: dictionary mapping the fingerprints to a RSA key in pem format""" - - assert raw is not None - - lines = raw.split('\n') - count = 0 - keys = {} - next_fingerprint = None - - while count < len(lines): - if lines[count].startswith('fingerprint'): - if next_fingerprint is not None: - raise ValueError("File has not the expected format") - else: - next_fingerprint = lines[count].split(" ")[1] - - elif lines[count] == 'dir-signing-key': - count += 1 - key = lines[count] + '\n' - count += 1 - while lines[count] != '-----END RSA PUBLIC KEY-----': - key += lines[count] + '\n' - count += 1 - key += '-----END RSA PUBLIC KEY-----' - keys[next_fingerprint] = key - next_fingerprint = None - - count += 1 - - return keys - - -def get_signing_keys_info(ip = None, path = "./tools/authority_signing_keys.json"): - """ - Get the information of the authority router keys and save it to a json file. - - - :param path: where we want to save the json - """ - if ip is None: - ip = random.choice(ips) - - - keys_dict = download_signing_keys(ip) - if keys_dict is None: - raise ValueError("Error occurred during download of the keys") - - return to_json(keys_dict, path) - -def get_raw_signing_keys(ip = None): - """ - Get the information of the authority router keys and save it to a json file. - - - :param path: where we want to save the json - """ - if ip is None: - ip = random.choice(ips) - - url = "http://{}/tor/keys/all".format(ip) - rq = requests.get(url) - - if rq.status_code == 200: - return rq.text - else: - return None - -def get_chutney_keys_info(saving_path="./tools/chutney_authority_signing_keys.json"): - """ - This function scrap the chutney's authority keys - :param saving_path: where we want to save the json - """ - #change to your chutney dir. - rootdir = "/home/vagrant/chutney/net/nodes" - keys = "" - for d in os.listdir(rootdir): - pattern = re.compile('\d*a') - if pattern.match(d) is not None: - subdir = rootdir + "/" + d - with open(subdir + "/keys/authority_certificate", "r") as file2: - keys += file2.read() - keys = parse_signing_keys(keys) - return to_json(keys, saving_path) - - -def to_json(keys_dict, path): - """ - This function saves a mapping from fingerprint to PEM format keys on disk as a json where each key is saved as: - fingerprint:{ - pem: key_pem //the key in pem format - modulus: modulus //the modulus of the key - exponent: exponent //the exponent of the key - } - - :param keys_dict: - :param path: - :return: - """ - info = {} - for fingerprint in keys_dict.keys(): - key_pem = keys_dict[fingerprint] - key = RSA.importKey(key_pem) - modulus = key.n - exponent = key.e - - sub_dict = { - "pem": key_pem, - "modulus": str(modulus), - "exponent": str(exponent) - } - - info[fingerprint] = sub_dict - - info_json = js.dumps(info) - with open(path, "w") as file: - file.write(info_json) - - print("{} keys have been saved to {}".format(len(keys_dict.keys()), path)) - - return info From eed9a65e645035fce43e278c4ced2a85173cd0c1 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Mon, 6 Apr 2020 16:47:06 +0200 Subject: [PATCH 15/30] Remove deprecated path submodule. --- lightnion/proxy/forward.py | 1 - lightnion/proxy/path.py | 265 ------------------------------------- 2 files changed, 266 deletions(-) delete mode 100644 lightnion/proxy/path.py diff --git a/lightnion/proxy/forward.py b/lightnion/proxy/forward.py index 4ac83e5..40c0285 100644 --- a/lightnion/proxy/forward.py +++ b/lightnion/proxy/forward.py @@ -194,7 +194,6 @@ def get_guard(self): #nickname = guard['router']['nickname'] #fingerprint = guard['fingerprint'] #entry = [fingerprint, nickname] - #guard = lnn.proxy.path.convert(entry, consensus=self.consensus, expect='list')[0] logging.info('New guard relay selected.') logging.debug(guard) diff --git a/lightnion/proxy/path.py b/lightnion/proxy/path.py deleted file mode 100644 index 413dddb..0000000 --- a/lightnion/proxy/path.py +++ /dev/null @@ -1,265 +0,0 @@ -import multiprocessing -import threading -import logging -import atexit -import base64 -import queue -import time - -import stem -import stem.process -import stem.control - -# TODO: replace the whole content of this file with proper stuff! - -default_nb_worker = 2 - -class worker(threading.Thread): - def __init__(self, host, port, barrier, path_queue, batch_size): - super().__init__() - - self.mini_batch = batch_size // 8 if batch_size // 8 > 0 else 1 - self.batch_size = batch_size - self.path_queue = path_queue - self.barrier = barrier - self.count = 0 - self.finished = False - self.dead = False - self.port = port - self.host = host - - def run(self): - ctrl = stem.control.Controller.from_port(self.host, port=self.port) - ctrl.authenticate() - - first = self.barrier.wait() - if first == 0: - ctrl.drop_guards() - ctrl.signal(stem.Signal.NEWNYM) - self.barrier.wait() - - circs = [] - while not self.dead: - if self.count >= self.batch_size and not self.dead: - for circ in circs: - try: - ctrl.close_circuit(circ) - except (stem.ControllerError, ValueError): - pass - self.finished = True - self.count = 0 - - for _ in range(self.mini_batch): - if len(circs) > self.batch_size: - break - - try: - circs.append(ctrl.new_circuit()) - except stem.ControllerError as e: - pass - - fails = [] - for circ in circs: - try: - path = ctrl.get_circuit(circ).path - if len(path) == 3: - ctrl.close_circuit(circ) - self.path_queue.put(path) - self.count += 1 - else: - fails.append(circ) - except (stem.ControllerError, ValueError) as e: - pass - - circs = fails - self.barrier.wait() - - ctrl.close() - -_cached_tor = None -def get_tor(control_port=9051, socks_port=9050, msg_handler=None): - global _cached_tor - if _cached_tor is not None: - return _cached_tor - - tor = stem.process.launch_tor_with_config( - config={ - 'SocksPort': str(socks_port), - 'ControlPort': str(control_port), - 'PublishServerDescriptor': '0', - }, init_msg_handler=msg_handler) - atexit.register(tor.kill) - - _cached_tor = tor - -def emitter( - output_queue, - kill_queue, - control_host, - control_port, - batch=32, - target=1024, - nb_worker=default_nb_worker): - - # (shut up stem) - logging.getLogger(stem.__name__).setLevel(logging.ERROR) - - barrier = threading.Barrier(nb_worker) - path_queue = queue.Queue(maxsize=batch) - batch_size = target // nb_worker + 1 - - workers = [] - for _ in range(nb_worker): - workers.append( - worker( - control_host, - control_port, - barrier, - path_queue, - batch_size)) - - for w in workers: - w.start() - - guard, middle, exit = path_queue.get() - output_queue.put(guard) - output_queue.put((middle, exit)) - - while any([not w.finished for w in workers]): - new_guard, middle, exit = path_queue.get() - if new_guard != guard: - continue - - output_queue.put((middle, exit)) - if kill_queue.qsize() > 0: - for w in workers: - w.finished = True - - # (cleanup is useless as the process will die, but do it nonetheless) - barrier.abort() - for w in workers: - w.dead = True - - try: - for i in range(path_queue.qsize()): - path_queue.get_nowait() - except queue.Empty: - pass - - for w in workers: - w.join(0.1) - -class producer: - def __init__(self, process, path_queue, kill_queue, tor_process): - self.guard = path_queue.get() - self.process = process - self.path_queue = path_queue - self.kill_queue = kill_queue - self.tor_process = tor_process - - @property - def dead(self): - return not self.process.is_alive() - - @property - def empty(self): - return not (self.path_queue.qsize() > 0) - - def get(self): - return self.path_queue.get() - - def close(self): - try: - self.kill_queue.put_nowait([None]) - except queue.Full: - pass - - try: - self.path_queue.get_nowait() - except queue.Empty: - pass - -_default_tor = None -_default_socks_port = None -_default_control_port = None -def fetch( - batch=32, - target=1024, - nb_worker=2, - tor_process=None, - socks_port=None, - control_host='127.0.0.1', - control_port=None): - - global _default_tor, _default_socks_port, _default_control_port - if socks_port is None: - if _default_socks_port is None: - _default_socks_port = 9050 - socks_port = _default_socks_port - - if control_port is None: - if _default_control_port is None: - _default_control_port = 9051 - control_port = _default_control_port - - if tor_process is None: - if _default_tor is None: - _default_tor = get_tor( - socks_port=socks_port, - control_port=control_port, - msg_handler=None) - tor_process = _default_tor - - path_queue = multiprocessing.Queue(maxsize=batch) - kill_queue = multiprocessing.Queue(maxsize=1) - process = multiprocessing.Process(target=emitter, args=( - path_queue, - kill_queue, - control_host, - control_port, - batch, - target, - nb_worker)) - process.start() - - if not tor_process: - tor_process = None - - return producer(process, path_queue, kill_queue, tor_process) - -# TODO: check if this conversion fingerprint->descriptor is safe? -def convert(*entries, consensus, expect='fetch_format'): - if expect not in ['list', 'fetch_format']: - raise RuntimeError('Format unknown: {}'.format(expect)) - - if expect == 'fetch_format': - entries = [entries[0]] + [node for pair in entries[1] for node in pair] - guard, *paths = convert(*entries, consensus=consensus, expect='list') - paths = list(zip(paths[::2], paths[1::2])) - return guard, paths - - if expect == 'list': - pass - new_entries = [] - - by_identity = {r['identity']: r for r in consensus['routers']} - if len(by_identity) != len(consensus['routers']): - raise RuntimeError('Unsafe! Duplicates in the consensus!') - - for entry in entries: - fingerprint, nickname = entry - - as_identity = str(base64.b64encode(bytes.fromhex(fingerprint)), 'utf8') - as_identity = as_identity.replace('=', '') - - if as_identity not in by_identity: - raise RuntimeError('Unknown entity within consensus: {}'.format( - (entry, as_identity))) - - router = by_identity[as_identity] - if nickname != router['nickname']: - raise RuntimeError('Mismatched nickname: {} vs {}'.format(nickname, - router['nickname'])) - - new_entries.append(router) - return new_entries From ba30c44ffe1d95eb5ac72e65a447d0864ddb3ab5 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Wed, 8 Apr 2020 15:17:09 +0200 Subject: [PATCH 16/30] Remove obsolete caching mechanism. --- lightnion/cache.py | 111 ----------------------------------------- lightnion/consensus.py | 31 ------------ 2 files changed, 142 deletions(-) delete mode 100644 lightnion/cache.py diff --git a/lightnion/cache.py b/lightnion/cache.py deleted file mode 100644 index 4f972e9..0000000 --- a/lightnion/cache.py +++ /dev/null @@ -1,111 +0,0 @@ -import os -import time -import json -import shutil -import base64 -import logging - -cache_directory = '.lightnion-cache.d' - -def directory(base_dir=None): - if base_dir is None: - base_dir = os.getcwd() - base_dir = os.path.join(base_dir, cache_directory) - - if not os.path.isdir(base_dir): - logging.info( - 'Note: creating {} to cache descriptors.'.format(base_dir)) - os.mkdir(base_dir) - - if not os.path.isdir(base_dir): - raise RuntimeError( - 'Unable to fetch cache directory: {}'.format(base_dir)) - - return base_dir - -def purge(): - base_dir = directory() - logging.warning('Note: removing {} to purge cache.'.format(base_dir)) - shutil.rmtree(base_dir) - -class descriptors: - @staticmethod - def filename(descriptor, get=False): - base_dir = 'descriptors' - if 'micro' in descriptor['flavor']: - base_dir = 'micro-' + base_dir - base_dir = os.path.join(directory(), base_dir) - - if not os.path.isdir(base_dir): - os.mkdir(base_dir) - - field = 'digest' - if 'micro' in descriptor['flavor']: - field = 'micro-digest' - - digest = descriptor[field] - if (not get) or 'micro' in descriptor['flavor']: - digest = base64.b64decode(descriptor[field] + '====').hex() - - half_dir = os.path.join(base_dir, digest[:2]) - if not os.path.isdir(half_dir): - os.mkdir(half_dir) - - return os.path.join(half_dir, digest) - - @staticmethod - def put(descriptor): - filename = descriptors.filename(descriptor) - if os.path.isfile(filename): - return - with open(filename, 'w') as f: - json.dump(descriptor, f) - - @staticmethod - def get(flavor, digest): - field = 'digest' - if 'micro' in flavor: - field = 'micro-digest' - - descriptor = {'flavor': flavor, field: digest} - filename = descriptors.filename(descriptor, get=True) - with open(filename, 'r') as f: - descriptor = json.load(f) - - if not descriptor['flavor'] == flavor: - raise ValueError('Mismatched flavor.') - - new_digest = descriptor[field] - if not 'micro' in field: - new_digest = base64.b64decode(new_digest + '====').hex() - - if not new_digest == digest: - raise ValueError('Mismatched digest.') - - return descriptor - -class consensus: - @staticmethod - def filename(flavor): - return os.path.join(directory(), 'consensus-{}'.format(flavor)) - - @staticmethod - def put(fields): - filename = consensus.filename(fields['flavor']) - with open(filename, 'w') as f: - json.dump(fields, f) - - @staticmethod - def get(flavor): - filename = consensus.filename(flavor) - with open(filename, 'r') as f: - fields = json.load(f) - - if not fields['flavor'] == flavor: - raise ValueError('Mismatched flavor.') - - if fields['headers']['valid-until']['stamp'] < time.time(): - raise ValueError('Consensus need to be refreshed: {} < {}'.format( - fields['headers']['valid-until']['stamp'], time.time())) - - return fields diff --git a/lightnion/consensus.py b/lightnion/consensus.py index 39f96de..8eef8d1 100644 --- a/lightnion/consensus.py +++ b/lightnion/consensus.py @@ -791,7 +791,6 @@ def download_direct(hostname, port, flavor='microdesc'): :param hostname: host name of the node from which to retrieve the consensus. :param port: port of the node from which to retrieve the consensus. :param flavor: flavour of the consensus to retrieve. - :param cache: if the retrieved consensus should put in the cache. """ if flavor not in ['unflavored', 'microdesc']: @@ -836,33 +835,3 @@ def download_raw(hostname, port, flavor='unflavored'): cons = res.read().decode('utf-8') return cons - -def load(file_name, cache=True): - """Load the consensus from a file - :param file_name: the name of the file in consensus_file - :param cache: if we cache the newly downloaded consensus - :return: the parsed consensus""" - - abs_path = "/vagrant/consensus_files/"+file_name - - if not os.path.exists(abs_path): - raise FileNotFoundError() - - if cache: - try: - return lnn.cache.consensus.get("unflavored") - except BaseException: - pass - - with open(abs_path, "r") as file: - answer = file.read() - - consensus, remaining = consume_routers(answer) - - if consensus is None or remaining is None or not len(remaining) == 0: - raise RuntimeError('Unable to parse downloaded consensus!') - - if cache: - lnn.cache.consensus.put(consensus) - - return consensus From 32e356726fe32988f7cf52903599f8e5070ce171 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Wed, 15 Apr 2020 16:45:34 +0200 Subject: [PATCH 17/30] Use stem to manage guard and consensus renewal. --- lightnion/proxy/forward.py | 112 ++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/lightnion/proxy/forward.py b/lightnion/proxy/forward.py index a31fe2e..9c7b3be 100644 --- a/lightnion/proxy/forward.py +++ b/lightnion/proxy/forward.py @@ -10,9 +10,11 @@ from datetime import datetime, timedelta import quart +import stem import websockets from quart_cors import cors +from stem.control import EventType, Controller import lightnion as lnn import lightnion.path_selection @@ -37,11 +39,12 @@ logger.addHandler(handler) -class clerk(): - def __init__(self, slave_node, control_port, dir_port, compute_path, auth_dir=None): +class Clerk(): + def __init__(self, slave_node, control_port, dir_port, controller, compute_path, auth_dir=None): #super().__init__() logging.info('Bootstrapping clerk.') self.crypto = lnn.proxy.parts.crypto() + self.dead = False self.auth = None @@ -58,7 +61,6 @@ def __init__(self, slave_node, control_port, dir_port, compute_path, auth_dir=No else: logging.debug('Auth dir is None.') - self.retrieved_consensus = False self.consensus = None self.descriptors = None @@ -67,13 +69,13 @@ def __init__(self, slave_node, control_port, dir_port, compute_path, auth_dir=No self.mic_consensus_raw = None self.mic_descriptors_raw = None + self.consensus_init = False + #self.consm = None #self.descm = None self.signing_keys = None #self.signing_keys_raw = None - self.timer_consensus = None - self.guard_node = None self.control_port = control_port @@ -85,8 +87,13 @@ def __init__(self, slave_node, control_port, dir_port, compute_path, auth_dir=No self.channel_manager = None self.websocket_manager = None + self.controller = controller + self.controller.add_event_listener(self.handle_new_guard, EventType.GUARD) + self.controller.add_event_listener(self.retrieve_consensus, EventType.NEWCONSENSUS) + def prepare(self): + self.retrieve_consensus() guard = self.get_guard() self.link = lnn.proxy.link.Link(guard) @@ -98,21 +105,15 @@ def prepare(self): self.websocket_manager.set_channel_manager(self.channel_manager) - def retrieve_consensus(self): - """Retrieve relays data with direct HTTP connection and schedule its future retrival.""" - - # We tolerate that the system clock can be up to a few seconds too early. - refresh_tolerance_delay = 2.0 - min_delay = 120.0 # 2 minutes - max_time_until_invalid = 900.0 # 15 minutes + def retrieve_consensus(self, event=None): + """Retrieve relays data with direct HTTP connection.""" host = self.slave_node[0] port = self.dir_port - # retrieve consensus and descriptors if self.compute_path: - cons,sg_keys = lnn.consensus.download_direct(host, port, flavor='unflavored') + cons, sg_keys = lnn.consensus.download_direct(host, port, flavor='unflavored') desc = lnn.descriptors.download_direct(host, port, cons) self.consensus = cons self.signing_keys = sg_keys @@ -133,37 +134,14 @@ def retrieve_consensus(self): digests = lnn.consensus.extract_nodes_digests_micro(self.mic_consensus_raw) self.mic_descriptors_raw = lnn.descriptors.download_raw_by_digests_micro(host, port, digests) - try: - # Compute delay until retrival of the next consensus. - fresh_until = lnn.consensus.extract_date(self.consensus_raw, 'fresh-until') - now = datetime.utcnow() - delay = (fresh_until - now).total_seconds() + refresh_tolerance_delay - - if delay < min_delay: - valid_until = lnn.consensus.extract_date(self.consensus_raw, 'valid-until') - delay = (valid_until - now).total_seconds() - max_time_until_invalid - - delay = max(delay, min_delay) - - logging.debug('Delay until fetching next concensus: %f', delay) - - self.timer_consensus = threading.Timer(delay, clerk.retrieve_consensus, [self]) - self.timer_consensus.start() - self.retrieved_consensus = True - - except Exception as e: - logging.error(e) - raise e + self.consensus_init = True def wait_for_consensus(self): """Ensure a consensus is present in the clerk, and fetch a new one if it is not. """ - if not self.retrieved_consensus: - if self.timer_consensus is None: - self.retrieve_consensus() - while not self.retrieved_consensus: + while not self.consensus_init: logging.info('Wait for consensus...') time.sleep(1) @@ -179,14 +157,16 @@ def get_descriptor_unflavoured(self, router): return descriptor - def get_guard(self): + def handle_new_guard(self, event): + self.get_guard(renew=True) + + + def get_guard(self, renew=False): """Generate a guard :return: guard node """ - self.wait_for_consensus() - - if self.guard_node is None: + if renew or self.guard_node is None: # Use local node as the guard. #guard = lnn.path_selection.select_guard_from_consensus(self.consensus, self.descriptors) host = self.slave_node[0] @@ -256,7 +236,7 @@ async def get_consensus_raw(flavor): app.clerk.wait_for_consensus() cons = app.clerk.mic_consensus_raw if flavor == 'unflavored': - cons =app.clerk.consensus_raw + cons = app.clerk.consensus_raw return cons, 200 except Exception as e: @@ -318,10 +298,10 @@ async def create_channel(): try: #data = app.clerk.create.perform(data) - ckt_info = app.clerk.channel_manager.create_channel( app.clerk.consensus, app.clerk.descriptors, select_path) + ckt_info = app.clerk.channel_manager.create_channel(app.clerk.consensus, app.clerk.descriptors, select_path) if auth is not None: # TODO the proxy pack the ntor key in a tor cell, this can be done client side. - ckt_info = app.clerk.auth.perform(auth,ckt_info) + ckt_info = app.clerk.auth.perform(auth, ckt_info) response = quart.jsonify(ckt_info) return response, 201 # Created @@ -359,7 +339,6 @@ async def loop_signal_handler(signum, loop): """ logging.debug('Signal handler called.') - app.clerk.timer_consensus.cancel() await app.shutdown() await app.clerk.websocket_manager.stop() @@ -382,26 +361,29 @@ def main(port, slave_node, control_port, dir_port, compute_path, auth_dir=None): # from werkzeug import SharedDataMiddleware # app.wsgi_app = SharedDataMiddleware(app.wsgi_app, static_files) - app.clerk = clerk(slave_node, control_port, dir_port, compute_path, auth_dir) - logging.info('Bootstrapping HTTP server.') + with Controller.from_port(port=control_port) as controller: + controller.authenticate() - logging.getLogger(websockets.__name__).setLevel(logging.INFO) - asyncio.set_event_loop(asyncio.new_event_loop()) + app.clerk = Clerk(slave_node, control_port, dir_port, controller, compute_path, auth_dir) + logging.info('Bootstrapping HTTP server.') - app.clerk.prepare() + logging.getLogger(websockets.__name__).setLevel(logging.INFO) + asyncio.set_event_loop(asyncio.new_event_loop()) - loop = asyncio.get_event_loop() - for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT): - loop.add_signal_handler(s, lambda s=s: asyncio.create_task(loop_signal_handler(s, loop))) + app.clerk.prepare() - loop.set_exception_handler(None) + loop = asyncio.get_event_loop() + for s in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT): + loop.add_signal_handler(s, lambda s=s: asyncio.create_task(loop_signal_handler(s, loop))) - try: - loop.create_task(app.clerk.link.connection) - loop.create_task(app.clerk.websocket_manager.serve(loop)) - - app.run(host='0.0.0.0', port=port, debug=debug, loop=loop, use_reloader=False) - except Exception: - pass - finally: - loop.close() + loop.set_exception_handler(None) + + try: + loop.create_task(app.clerk.link.connection) + loop.create_task(app.clerk.websocket_manager.serve(loop)) + + app.run(host='0.0.0.0', port=port, debug=debug, loop=loop, use_reloader=False) + except Exception: + pass + finally: + loop.close() From f8979be9851ee8613df0f7d8d4a3d31561cb2927 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Wed, 15 Apr 2020 16:59:58 +0200 Subject: [PATCH 18/30] Update requirements. --- requirements-proxy.txt | 6 ------ requirements.txt | 9 ++++++++- 2 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 requirements-proxy.txt diff --git a/requirements-proxy.txt b/requirements-proxy.txt deleted file mode 100644 index 215b8cd..0000000 --- a/requirements-proxy.txt +++ /dev/null @@ -1,6 +0,0 @@ -cryptography -websockets -requests -asyncio -quart -Quart-CORS diff --git a/requirements.txt b/requirements.txt index 540742f..693f300 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,9 @@ -pynacl +Quart-CORS +asyncio +cryptography pycryptodome +pynacl +quart +requests +stem +websockets From 1d3429f60ef9e335e87c07258b19be5e76624fe6 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Wed, 15 Apr 2020 17:14:50 +0200 Subject: [PATCH 19/30] Silence Stem logger. --- lightnion/proxy/forward.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lightnion/proxy/forward.py b/lightnion/proxy/forward.py index 9452f7c..7146069 100644 --- a/lightnion/proxy/forward.py +++ b/lightnion/proxy/forward.py @@ -15,6 +15,7 @@ from quart_cors import cors from stem.control import EventType, Controller +from stem.util.log import get_logger import lightnion as lnn import lightnion.path_selection @@ -36,6 +37,8 @@ logger.setLevel(logging.WARNING) logger.addHandler(handler) +logger = get_logger() +logger.propagate = False class Clerk(): def __init__(self, slave_node, control_port, dir_port, controller, compute_path, auth_dir=None): @@ -124,7 +127,7 @@ def retrieve_consensus(self, event=None): digests = lnn.consensus.extract_nodes_digests_unflavored(self.consensus_raw) self.descriptors_raw = lnn.descriptors.download_raw_by_digests_unflavored(host, port, digests) - self.signing_keys = lnn.keys.fetch_and_parse_keys(host, port) + self.signing_keys = lnn.keys.fetch_and_parse_keys(host, port, tls=False) #self.signing_keys_raw = get_raw_signing_keys('%s:%d'%(host, port)) self.mic_consensus_raw = lnn.consensus.download_raw(host, port, flavor='microdesc') From 4ee7dfa5930f9ac8395b7be3385b6e93cd102fa7 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Wed, 15 Apr 2020 17:15:42 +0200 Subject: [PATCH 20/30] Remove deprecated submodules from __init__. --- lightnion/__init__.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lightnion/__init__.py b/lightnion/__init__.py index e811d8c..a647632 100644 --- a/lightnion/__init__.py +++ b/lightnion/__init__.py @@ -2,12 +2,6 @@ import lightnion.constants import lightnion.crypto -import lightnion.cell - -import lightnion.cache - -import lightnion.create -import lightnion.onion import lightnion.consensus import lightnion.descriptors From 93598a67481dfbb031ced56e7b8240c9cfd7103a Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Wed, 15 Apr 2020 17:19:53 +0200 Subject: [PATCH 21/30] Remove imports. --- lightnion/proxy/forward.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lightnion/proxy/forward.py b/lightnion/proxy/forward.py index 7146069..365420f 100644 --- a/lightnion/proxy/forward.py +++ b/lightnion/proxy/forward.py @@ -1,14 +1,9 @@ import asyncio -import base64 import logging import signal -import string import sys -import threading import time -from datetime import datetime, timedelta - import quart import stem import websockets From 6576899831cb1648596c07138d920183831f2217 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Fri, 17 Apr 2020 12:47:47 +0200 Subject: [PATCH 22/30] Remove tests no longer relevant. --- lightnion/tests/test_consensus_chutney.py | 26 ------- lightnion/tests/test_create_chutney.py | 36 ---------- lightnion/tests/test_descriptors_chutney.py | 39 ----------- lightnion/tests/test_extend_chutney.py | 68 ------------------- lightnion/tests/test_hop_chutney.py | 19 ------ lightnion/tests/test_link_chutney.py | 10 --- .../tests/test_path_selection_chutney.py | 16 ----- {lightnion/tests => tests}/__init__.py | 0 .../test_path_selection.py | 0 9 files changed, 214 deletions(-) delete mode 100644 lightnion/tests/test_consensus_chutney.py delete mode 100644 lightnion/tests/test_create_chutney.py delete mode 100644 lightnion/tests/test_descriptors_chutney.py delete mode 100644 lightnion/tests/test_extend_chutney.py delete mode 100644 lightnion/tests/test_hop_chutney.py delete mode 100644 lightnion/tests/test_link_chutney.py delete mode 100644 lightnion/tests/test_path_selection_chutney.py rename {lightnion/tests => tests}/__init__.py (100%) rename lightnion/tests/path_selection_test.py => tests/test_path_selection.py (100%) diff --git a/lightnion/tests/test_consensus_chutney.py b/lightnion/tests/test_consensus_chutney.py deleted file mode 100644 index 276af92..0000000 --- a/lightnion/tests/test_consensus_chutney.py +++ /dev/null @@ -1,26 +0,0 @@ -import lightnion as lnn - - -def test_download_unflavored(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - - # Downloading unflavored consensus - endpoint, unflavored = lnn.consensus.download(endpoint, - flavor='unflavored') - - assert True - - -def test_download_microdesc(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - - # Downloading microdesc consensus - endpoint, microdesc = lnn.consensus.download(endpoint, flavor='microdesc') - - assert True diff --git a/lightnion/tests/test_create_chutney.py b/lightnion/tests/test_create_chutney.py deleted file mode 100644 index d48682b..0000000 --- a/lightnion/tests/test_create_chutney.py +++ /dev/null @@ -1,36 +0,0 @@ -import lightnion as lnn - - -def test_fast(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - - # Simple creation of one-hop circuits with CREATE_FAST cells: - # - no public keys involved (only exchanging randomness through TLS). - # - used in Tor to connects to the guard (the first hop) to reduce load. - # Creating 10 one-hop circuits with CREATE_FAST cells - for i in range(10): - state = lnn.create.fast(link) - - assert True - - -def test_ntor(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - - # Retrieve cryptographic material through fast circuit - endpoint, authority = lnn.descriptors.download_authority(endpoint) - - # Perform "ntor" handshake with authority['router']['nickname'] - endpoint = lnn.create.ntor(link, authority) - - # Attempt to use the "ntor" circuit - endpoint, descriptor = lnn.descriptors.download_authority(endpoint) - - assert descriptor['digest'] == authority['digest'], \ - 'Descriptor digest: {}\n'.format(descriptor['digest']) + \ - 'Authority digest; {}\n'.format(authority['digest']) diff --git a/lightnion/tests/test_descriptors_chutney.py b/lightnion/tests/test_descriptors_chutney.py deleted file mode 100644 index 7fa0daa..0000000 --- a/lightnion/tests/test_descriptors_chutney.py +++ /dev/null @@ -1,39 +0,0 @@ -import lightnion as lnn - - -def test_download_microdesc(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - - # Downloading descriptors - endpoint, descriptors = lnn.descriptors.download(endpoint, - flavor='microdesc') - - assert True - - -def test_download_unflavored(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - - # Downloading descriptors - endpoint, undescriptors = lnn.descriptors.download(endpoint, - flavor='unflavored') - - assert True - - -def test_download_authority(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - - # Asking politely for our OR's descriptor - endpoint, authority = lnn.descriptors.download_authority(endpoint) - - assert True diff --git a/lightnion/tests/test_extend_chutney.py b/lightnion/tests/test_extend_chutney.py deleted file mode 100644 index 0d95231..0000000 --- a/lightnion/tests/test_extend_chutney.py +++ /dev/null @@ -1,68 +0,0 @@ -import lightnion as lnn - - -def test_circuit(): - import random - - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - - # Download our first hop's descriptor - endpoint, authority = lnn.descriptors.download_authority(endpoint) - - # Download a consensus - endpoint, cons = lnn.consensus.download(endpoint, flavor='unflavored') - - # Randomly pick few nodes (!! NOT a sane behavior, only to showcase API !!) - further_hops = [] - circuit_length = random.randint(2, 7) # (random circuit length to showcase) - - random.shuffle(cons['routers']) - for router in cons['routers']: - if len(further_hops) == circuit_length: - break - - # Skip our first node & already picked ones (no loop) - if router['digest'] == authority['digest']: - continue - if router['digest'] in [h['digest'] for h in further_hops]: - continue - - # Skip nodes that are not 'Fast' and 'Stable' - if 'Fast' not in router['flags'] or 'Stable' not in router['flags']: - continue - - # Skip nodes with old Tor versions - if not router['version'].startswith('Tor 0.3.'): - continue - - # Retrieve its descriptor - endpoint, nhop = lnn.descriptors.download( - endpoint, cons=router, flavor='unflavored') - nhop = nhop[0] # (expect only one entry with a matching digest) - - # Skip the entry if digests do not match (note: double-check here) - if router['digest'] != nhop['digest']: - continue - - # Skip if no ed25519 identity key available - if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': - continue - - # Keep the descriptor for later (to build the circuit) - further_hops.append(nhop) - - # Create a brand new circuit (to have spare RELAY_EARLY to extend it) - endpoint = lnn.create.fast(link) - - for nhop in further_hops: - # Extending to nhop['router']['nickname']: - # - remaining RELAY_EARLY: endpoint.early_count - endpoint = lnn.extend.circuit(endpoint, nhop) - - endpoint, authority = lnn.descriptors.download_authority(endpoint) - endpoint, ncons = lnn.consensus.download(endpoint, cache=False) - - assert True diff --git a/lightnion/tests/test_hop_chutney.py b/lightnion/tests/test_hop_chutney.py deleted file mode 100644 index 175e525..0000000 --- a/lightnion/tests/test_hop_chutney.py +++ /dev/null @@ -1,19 +0,0 @@ -import lightnion as lnn - - -def test_directory_query(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(address=addr, port=port) - endpoint = lnn.create.fast(link) - endpoint = lnn.hop.send(endpoint, lnn.cell.relay.cmd.RELAY_DROP) - - # Download the full consensus without compression - endpoint, full_answer = lnn.hop.directory_query(endpoint, - '/tor/status-vote/current/consensus', compression='identity') - - # Download the microdesc consensus with compression - endpoint, full_answer = lnn.hop.directory_query(endpoint, - '/tor/status-vote/current/consensus-microdesc') - - assert True diff --git a/lightnion/tests/test_link_chutney.py b/lightnion/tests/test_link_chutney.py deleted file mode 100644 index 21cba5c..0000000 --- a/lightnion/tests/test_link_chutney.py +++ /dev/null @@ -1,10 +0,0 @@ -import lightnion as lnn - - -def test_initiate(): - addr, port = '127.0.0.1', 5000 - - link = lnn.link.initiate(addr, port) - link.close() - - assert True diff --git a/lightnion/tests/test_path_selection_chutney.py b/lightnion/tests/test_path_selection_chutney.py deleted file mode 100644 index a870b73..0000000 --- a/lightnion/tests/test_path_selection_chutney.py +++ /dev/null @@ -1,16 +0,0 @@ -import lightnion as lnn - - -def test_select_path(): - addr, port = '127.0.0.1', 5000 - - # Download the consensus - lnn.cache.purge() - link = lnn.link.initiate(address=addr, port=port) - state = lnn.create.fast(link) - state, cons = lnn.consensus.download(state, flavor='unflavored') - - state, guard, middle, exit_node = lnn.path_selection.select_path( - cons['routers'], state, testing=True) - - assert True diff --git a/lightnion/tests/__init__.py b/tests/__init__.py similarity index 100% rename from lightnion/tests/__init__.py rename to tests/__init__.py diff --git a/lightnion/tests/path_selection_test.py b/tests/test_path_selection.py similarity index 100% rename from lightnion/tests/path_selection_test.py rename to tests/test_path_selection.py From b0adf6b1c93fea76df6fda8f32ccfec2e22082ab Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 28 Apr 2020 17:05:54 +0200 Subject: [PATCH 23/30] Refactor concensus and descriptors handling. --- lightnion/consensus.py | 1067 ++++++++++++------------------------ lightnion/descriptors.py | 752 +++++++++++-------------- lightnion/keys.py | 83 ++- lightnion/proxy/forward.py | 16 +- 4 files changed, 735 insertions(+), 1183 deletions(-) diff --git a/lightnion/consensus.py b/lightnion/consensus.py index 8eef8d1..ec6fe11 100644 --- a/lightnion/consensus.py +++ b/lightnion/consensus.py @@ -1,766 +1,410 @@ -from base64 import b64encode, b64decode -import datetime -import binascii -import time -import os -import re +""" +Refactored consensus parser +""" +import enum +import re import urllib.request +from base64 import b64decode +from datetime import datetime, timezone + import lightnion as lnn import lightnion.keys -# TODO: remove extra (useless) checks/exceptions within this file +RE_NETWORK_STATUS_VERSION = re.compile(r"network-status-version (\d+)") +RE_VOTE_STATUS = re.compile(r"vote-status (.+)") +RE_CONSENSUS_METHOD = re.compile(r"consensus-method (\d+)") +RE_VALID_AFTER = re.compile(r"valid-after (\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})") +RE_FRESH_UNTIL = re.compile(r"fresh-until (\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})") +RE_VALID_UNTIL = re.compile(r"valid-until (\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})") +RE_VOTING_DELAY = re.compile(r"voting-delay (\d+) (\d+)") +RE_CLIENT_VERSIONS = re.compile(r"client-versions (\S*)") +RE_SERVER_VERSIONS = re.compile(r"server-versions (\S*)") +RE_KNOWN_FLAGS = re.compile(r"known-flags (.+)") +RE_RECOMMENDED_CLIENT_PROTOCOLS = re.compile(r"recommended-client-protocols (.+)\n") +RE_RECOMMENDED_RELAY_PROTOCOLS = re.compile(r"recommended-relay-protocols (.+)\n") +RE_REQUIRED_CLIENT_PROTOCOLS = re.compile(r"required-client-protocols (.+)\n") +RE_REQUIRED_RELAY_PROTOCOLS = re.compile(r"required-relay-protocols (.+)\n") +RE_PARAMS = re.compile(r"params ((?:([^ =]+)=(\S+)) )+([^ =]+)=(\S+)") +RE_SHARED_RAND_PREVIOUS_VALUE = re.compile(r"shared-rand-previous-value (\d+) (\S+)") +RE_SHARED_RAND_CURRENT_VALUE = re.compile(r"shared-rand-current-value (\d+) (\S+)") +RE_DIR_SOURCE = re.compile(r"""dir-source (\S+) ([A-Za-z0-9]+) (\S+) (\S+) (\d+) (\d+) +contact (\S+) +vote-digest ([A-Za-z0-9]+)""") +RE_RELAYS = re.compile(r"(^r .+\n(?:(?:[aspvwm].+)\n)+)", re.M) + +RE_RELAY_R_U = re.compile(r"r (\S+) (\S+) (\S+) (\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) (\S+) (\d+) (\d+)") +RE_RELAY_R_M = re.compile(r"r (\S+) (\S+) (\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) (\S+) (\d+) (\d+)") +RE_RELAY_M = re.compile(r"\nm ([^\n]+)") +RE_RELAY_A = re.compile(r"\na (\S+):(\d+)") +RE_RELAY_S = re.compile(r"\ns ([^\n]+)") +RE_RELAY_V = re.compile(r"\nv (Tor \S+)") +RE_RELAY_PR = re.compile(r"\npr ([^\n]+)") +RE_RELAY_W = re.compile(r"\nw (Bandwidth)=(\d+)(?:\s([^= ]+)=(\S+))*") +RE_RELAY_P = re.compile(r"\np (accept|reject) (\S+)") +#RE_ = re.compile(r"") +RE_FOOTER = re.compile(r"directory-footer\nbandwidth-weights ([^\n]+)\n([A-Za-z0-9\n /=+-]+)") +RE_DIR_SIGN = re.compile(r"""directory-signature (.+) +-----BEGIN SIGNATURE----- +([0-9A-Za-z+/=\n]+) +-----END SIGNATURE----- +""") + +RE_RELAY_DIGEST_UNF = re.compile(r"^r \S+ \S+ (\S+)", re.MULTILINE) +RE_RELAY_DIGEST_MIC = re.compile(r'^m ([^\n]+)', re.MULTILINE) + + +class InvalidConsensus(Exception): + pass -def scrap(consensus, end_of_field): - """ - Consume lines upon matching a criterion. - Returns (consensus-without-first-line, first-line) - if end_of_field(first-line) returns True, - else returns (consensus-with-first-line, None) +class Flavor(enum.IntEnum): + UNFLAVORED = 0 + MICRO = 1 - :param bytes consensus: input which first line may be consumed - :param function end_of_field: passed a line, returns True when no match - :returns: a tuple (updated-consensus, next-field-or-None) - """ - if b'\n' not in consensus: - return consensus, None +class Consensus: + """Container for consensus handling methods.""" + + @staticmethod + def _search_re(string, regex): + # Convenience function to search for the first instance of the pattern. + match = regex.search(string) + if not match: + raise InvalidConsensus("Invalid format.") + + groups = match.groups() + return groups + + + @staticmethod + def _findall_re(string, regex): + # Convenience function to search for all instances of the pattern. + groups = regex.findall(string) + if not groups: + raise InvalidConsensus("Invalid format.") + + return groups + + + @staticmethod + def _parse_date(string, regex): + + groups = Consensus._search_re(string, regex) + + groups_int = [int(x) for x in groups] + timestamp = datetime(*groups_int, tzinfo=timezone.utc).timestamp() + + date_parsed = { + "date": "{}-{}-{}".format(*groups[:3]), + "time": "{}:{}:{}".format(*groups[3:]), + "stamp": timestamp + } + + return date_parsed + + + @staticmethod + def _parse_footer(string): + groups = Consensus._search_re(string, RE_FOOTER) + + bw_weights = dict() + bw_weights_raw = groups[0].split(" ") + for bw_weight_raw in bw_weights_raw: + key, value = bw_weight_raw.split("=") + bw_weights[key] = int(value) + + dir_signs = list() + groups_sign = Consensus._findall_re(groups[1], RE_DIR_SIGN) + for dir_sign_raw in groups_sign: + params = dir_sign_raw[0].split(" ") + if len(params) == 3: + algo, identity, digest = params + elif len(params) == 2: + algo = "sha1" + identity, digest = params - line, remaining = consensus.split(b'\n', 1) - if end_of_field(line): - return consensus, None - return remaining, line + signature = dir_sign_raw[1] + dir_sign = { + "Algorithm": algo, + "identity": identity, + "signing-key-digest": digest, + "signature": signature.replace("\n", "") + } -def scrap_signature(consensus, fix=b'SIGNATURE'): - """ - Consume a signature field if there is one to consume. + dir_signs.append(dir_sign) - :param bytes consensus: input which may start with a signature. + footer = { + "bandwidth-weights": bw_weights, + "directory-signatures": dir_signs + } - :returns: a tuple (updated-consensus, signature-or-None) - """ - if not consensus.startswith(b'-----BEGIN ' + fix + b'-----'): - return consensus, None + return footer - lines = consensus.split(b'\n', 22) # fits 0-1024o (for 256o sig) - try: - idx_endsig = lines.index(b'-----END ' + fix + b'-----') - except ValueError: - return consensus, None - remaining = b'\n'.join(lines[idx_endsig + 1:]) - content = b''.join(lines[1:idx_endsig]) - return remaining, content + @staticmethod + def _parse_protocols(string, regex): + params = Consensus._search_re(string, regex)[0].split(" ") + protocols = dict() -def parse_address(address): - """ - Take a Tor-formatted v4 or v6 IP address with a port, returns a - cleaned-up version. + for param in params: + key, value = param.split("=") + protocols[key] = Consensus._parse_protocols_vers(value) - :param str address: input address to be processed + return protocols - :returns: a tuple (address, port, guessed-type) where port is an - integer and guessed-type is 4 or 6 (IPv4 or IPv6). - """ - address = address.split(':') - address, port = ':'.join(address[:-1]), address[-1] - - guessed_type = 4 - if address.startswith('['): - address = address[1:] - guessed_type = 6 - if address.endswith(']') or guessed_type == 6: - if not address.endswith(']'): - raise RuntimeError( - 'Seems like an invalid IPv6: {}'.format(address)) - address = address[:-1] - guessed_type = 6 - if address.count(':') > 3: - if not guessed_type == 6: - raise RuntimeError( - 'Seems like an very odd IPv6: {}'.format(address)) - guessed_type = 6 - - return address, int(port), guessed_type - - -def parse_range_once(value, expand=True): - """ - Take Tor-formatted ranges, then returns it as a list of integers if - expanded or a mix of integers and ranges as [low, high] tuples. - - For example, we use it to parse "p" fields: - https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L2322 - :param str value: input value to be processed - :param bool expand: do we expand a range as integers? (default: True) + @staticmethod + def _parse_protocols_vers(proto): + versions = list() - :returns: a list of integers or a mix of integers and range list/tuples - """ - value = value.split(',') - subvalues = [] - for subvalue in value: - if '-' in subvalue: - low, high = [int(v) for v in subvalue.split('-')] - if expand: - subvalues += list(range(low, high + 1)) - elif low == high - 1: - subvalues += [low, high] + version_ranges = proto.split(",") + for version_range_raw in version_ranges: + if "-" in version_range_raw: + vmin, vmax = version_range_raw.split("-") + version_range = list(range(int(vmin), int(vmax) + 1)) + versions += version_range else: - subvalues += [[low, high]] - else: - subvalues += [int(subvalue)] - return subvalues - - -def parse_ranges(ranges, expand=True): - """ - Take Tor-formatted named ranges, then returns a keyword-based - dictionary of list of integers or mix of integers and range tuples (as - returned by parse_range_once), expanded or not. - - For example, we use it to parse "recommended-client-protocols" fields: - https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L780 - - :param str ranges: input ranges to be processed - :param bool expand: do we expand ranges as integers? (default: True) - - :returns: a dictionary with (range-name, range-content) items - """ - pairs = ranges.split(' ') - content = {} - for key, value in [pair.split('=') for pair in pairs if '=' in pair]: - content[key] = parse_range_once(value, expand) - return content - - -def parse_params(params): - """ - Take Tor-formatted parameters, then returns a keyword-based dictionary - of integers. - - For example, we use it to parse "params" fields: - https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L1820 - - :param str params: input params to be processed - - :returns: a dictionary with (param-name, param-integer-value) items - """ - pairs = params.split(' ') - content = dict() - for key, value in [pair.split('=') for pair in pairs]: - content[key] = int(value) - return content - - -def parse_fingerprint(payload): - asbytes = bytes.fromhex(payload) - fingers = asbytes.hex().upper() - fingers = ' '.join([fingers[i:i + 4] for i in range(0, len(fingers), 4)]) - if not fingers == payload: - raise RuntimeError( - 'Fingerprint not conform: {} vs {}'.format(fingers, payload)) - return fingers - - -def parse_base64(payload, decode=False): - """ - Take an input base64 string, decode it, re-encode it. - - For example, we use it to parse "shared-rand-current-value" fields: - https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L2069 - - :param str payload: input base64-encoded data - :param bool decode: return raw bytes (default: False) - - :returns: a base64-encoded string equivalent to the input - """ - decoded = b64decode(payload + '====') - value = str(b64encode(decoded), 'utf8') - - if not payload[-2:].count('=') == value[-2:].count('='): - value = value.rstrip('=') + '=' * payload[-2:].count('=') - - if not value == payload: - raise RuntimeError('Invalid base64 encoding: {} vs {}'.format( - value, payload)) - - if decode: - return decoded - - return value - - -def parse_time(timedate): - """ - Take a Tor-formatted (Y-m-d H:M:S) time, parse it, then returns the - corresponding date, time and datetime object. This function assumes - that the given time uses the UTC timezone – as it's the timezone used - into Tor consensuses. - - :param str timedate: input time and date to be parsed - - :returns: a tuple (date-str, time-str, datetime-object) - """ - when = datetime.datetime.strptime(timedate, '%Y-%m-%d %H:%M:%S') - - # convert to UTC-aware datetime object - when = datetime.datetime(*when.timetuple()[:6], - tzinfo=datetime.timezone.utc) - return (when.strftime('%Y-%m-%d'), when.strftime('%H:%M:%S'), when) - - -def consume_http(consensus): - """ - Consume HTTP headers if present, then returns the remaining input to be - further processed and a set of headers (or None, if none present). - - :param str consensus: input to be processed - - :returns: a tuple (remaining-input, headers-or-None) - """ - - def end_of_field(line): - return line[-1:] != b'\r' - - fields = dict(headers=dict()) - valid = False - while True: - consensus, header = scrap(consensus, end_of_field) - if header is None: - return consensus, fields if valid else None - - valid = True - if b' ' not in header: - continue - - header = header[:-1] - try: - header = str(header, 'utf8') - except Exception: - continue - - if header.startswith('HTTP/'): - version, fields['code'], _ = header.split(' ', 2) - fields['version'] = float(version.split('/', 1)[1]) - - keyword, content = header.split(' ', 1) - if keyword[-1:] == ':': - fields['headers'][keyword[:-1]] = content - - -def consume_headers(consensus, flavor='unflavored'): - """ - Consume consensus headers if present, then returns the remaining input - to be further processed and a set of headers (or None, if none - present). - - Will consume the following fields: - - network-status-version - - vote-status - - consensus-method - - valid-after - - fresh-until - - valid-until - - voting-delay - - client-versions - - server-versions - - known-flags - - recommended-client-protocols - - recommended-relay-protocols - - required-client-protocols - - required-relay-protocols - - params - - shared-rand-previous-value - - shared-rand-current-value - - :param str consensus: input to be processed - :param str flavor: consensus flavor ('unflavored' or 'microdesc') - - :returns: a tuple (remaining-input, headers-or-None) - """ - if flavor not in ['unflavored', 'microdesc']: - raise NotImplementedError( - 'Consensus flavor "{}" not supported.'.format(flavor)) - - whitelist = [ - b'network-status-version', b'vote-status', b'consensus-method', - b'valid-after', b'fresh-until', b'valid-until', b'voting-delay', - b'client-versions', b'server-versions', b'known-flags', - b'recommended-client-protocols', b'recommended-relay-protocols', - b'required-client-protocols', b'required-relay-protocols', b'params', - b'shared-rand-previous-value', b'shared-rand-current-value'] - - def end_of_field(line): - if b' ' not in line: - return True - keyword, _ = line.split(b' ', 1) - return keyword not in whitelist - - fields = dict() - valid = False - while True: - consensus, header = scrap(consensus, end_of_field) - if header is None: - return consensus, fields if valid else None - - valid = True - if b' ' not in header: - continue - - try: - header = str(header, 'utf8') - except: - continue + versions.append(int(version_range_raw)) - keyword, content = header.split(' ', 1) - if keyword == 'network-status-version': - content = content.split(' ', 1) - if len(content) == 1: - content.append('unflavored') - version, variant = content - content = dict(version=int(version), flavor=variant) + return versions - if not len(fields) == 0: - raise RuntimeError('Expecting {} as first field: {}'.format( - keyword, content)) - if not content['version'] >= 3: - raise RuntimeError('Expecting {} version >= 3 here: {}'.format( - keyword, content)) - if not content['flavor'] == flavor: - raise RuntimeError('Unmatched {} flavor {} here: {}'.format( - keyword, flavor, content)) - if keyword == 'consensus-method': - content = int(content) + @staticmethod + def _parse_relay_port_list(port_list_str): + ports_ranges = list() - if not content >= 26: - raise RuntimeError( - 'Consensus version >= 26 required: {}'.format(content)) - - if keyword in ['valid-after', 'fresh-until', 'valid-until']: - date, time_parsed, when = parse_time(content) - content = dict(date=date, time=time_parsed, stamp=when.timestamp()) - - if keyword == 'valid-after': - if not time.time() > content['stamp']: - raise RuntimeError('{} not yet valid! {}'.format( - keyword, content)) # valid-after - - if keyword == 'fresh-until': - if not content['stamp'] > fields['valid-after']['stamp']: - raise RuntimeError('{} not fresh! {}'.format( - keyword, content)) # fresh-until - - if keyword == 'valid-until': - if not time.time() < content['stamp']: - raise RuntimeError('{} no more valid! {}'.format( - keyword, content)) # valid-until - - if keyword == 'voting-delay': - vote, dist = content.split(' ', 1) - content = dict(vote=int(vote), dist=int(dist)) - - if keyword in ['client-versions', 'server-versions']: - content = content.split(',') - - if keyword == 'known-flags': - content = content.split(' ') - - if keyword.startswith(('recommended', 'required')): - content = parse_ranges(content) - - if keyword == 'params': - content = parse_params(content) - - if keyword.startswith('shared-rand'): - reveals, value = content.split(' ') - - value = parse_base64(value) - content = {'NumReveals': int(reveals), 'Value': value} - - if not content['NumReveals'] >= 0: - raise RuntimeError('{} must be >= 0 here: {}'.format( - keyword, content)) - - fields[keyword] = content - - -def consume_dir_sources(consensus): - """ - Consume directory source listing if present, then returns the remaining - input to be further processed and a set of directory sources (or None, - if none present). - - Will consume the following fields: - - dir-source - - contact - - vote-digest - - :param str consensus: input to be processed - - :returns: a tuple (remaining-input, headers-or-None) - """ - whitelist = [b'dir-source', b'contact', b'vote-digest'] - - def end_of_field(line): - if b' ' not in line: - return True - keyword, _ = line.split(b' ', 1) - return keyword not in whitelist - - fields = [] - valid = False - while True: - consensus, header = scrap(consensus, end_of_field) - if header is None: - if not valid: - return consensus, None - break - - valid = True - if b' ' not in header: - continue - - try: - header = str(header, 'utf8') - except: - continue - - keyword, content = header.split(' ', 1) - if keyword == 'vote-digest': - value = bytes.fromhex(content).hex() - if not value.lower() == content.lower(): - raise RuntimeError('Unmatched {} here: {} {}'.format( - keyword, value, content)) - content = value - - if keyword == 'dir-source': - nickname, identity, hostname, address, dirport, orport = ( - content.split(' ', 5)) - - value = bytes.fromhex(identity).hex() - if not value.lower() == identity.lower(): - raise RuntimeError('Unmatched {} here: {} {}'.format( - keyword, value, content)) - identity = value - - content = dict(nickname=nickname, identity=identity, - hostname=hostname, address=address, dirport=int(dirport), - orport=int(orport)) - - if not 0 < content['dirport'] < 65536: - raise RuntimeError('Invalid dirport here: {}'.format(content)) - if not 0 < content['orport'] < 65536: - raise RuntimeError('Invalid orport here: {}'.format(content)) - - if keyword != 'dir-source' and fields[-1][0] == 'dir-source': - if not (keyword not in fields[-1][1]): - raise RuntimeError( - 'Unexpected {} with: {}'.format(keyword, fields[-1])) - assert keyword not in fields[-1][1] - fields[-1][1][keyword] = content - continue - - fields.append((keyword, content)) - - full_entries_count = len([v for k, v in fields if k == 'dir-source']) - - if not full_entries_count == len(fields): - raise RuntimeError('Incomplete entry or corrupted?') - - if full_entries_count == len(fields): - fields = [v for k, v in fields] + ports_ranges_raw = port_list_str.split(",") + for ports_range_raw in ports_ranges_raw: + if "-" in ports_range_raw: + pmin, pmax = ports_range_raw.split("-") + ports_ranges.append([int(pmin), int(pmax)]) + else: + port = ports_range_raw + ports_ranges.append([int(port), int(port)]) + + return ports_ranges + + + @staticmethod + def _parse_relay_micro(string): + group_r = Consensus._search_re(string, RE_RELAY_R_M) + group_m = Consensus._search_re(string, RE_RELAY_M) + date_int = [int(x) for x in group_r[2:8]] + date_str = "{}-{}-{}".format(*group_r[2:5]) + time_str = "{}:{}:{}".format(*group_r[5:8]) + timestamp = datetime(*date_int, tzinfo=timezone.utc).timestamp() + + #group_a = Consensus._search_re(string, RE_RELAY_A) - return consensus, fields + flags = Consensus._search_re(string, RE_RELAY_S)[0].split(" ") + version = Consensus._search_re(string, RE_RELAY_V)[0] + + group_pr = Consensus._search_re(string, RE_RELAY_PR)[0] + protocols = dict() + for pair in group_pr.split(" "): + key, value = pair.split("=") + protocols[key] = Consensus._parse_protocols_vers(value) -def consume_routers(consensus, flavor='unflavored'): - """ - Consume router listing if present, then returns the remaining input to - be further processed and a set of routers (or None, if none present). - - Will consume the following fields: - - r - - m - - s - - v - - pr - - w - - p (unflavored only) - - a (unflavored only) - - :param str consensus: input to be processed - :param str flavor: consensus flavor ('unflavored' or 'microdesc') - - :returns: a tuple (remaining-input, headers-or-None) - """ - if flavor not in ['unflavored', 'microdesc']: - raise NotImplementedError( - 'Consensus flavor "{}" not supported.'.format(flavor)) - - # TODO: check if 'a' fields in microdesc consensus are still a thing - if flavor == 'unflavored': - whitelist = [b'r', b'm', b's', b'v', b'pr', b'w', b'p', b'a'] - elif flavor == 'microdesc': - whitelist = [b'r', b'm', b's', b'v', b'pr', b'w', b'a'] - - aliases = dict(m='micro-digest', pr='protocols', s='flags', v='version', - p='exit-policy', a='or-address') - - def end_of_field(line): - if b' ' not in line: - return True - keyword, _ = line.split(b' ', 1) - return keyword not in whitelist - - fields = [] - valid = False - while True: - consensus, header = scrap(consensus, end_of_field) - if header is None: - if not valid: - return consensus, None - break - - valid = True - if b' ' not in header: - continue + group_w = Consensus._search_re(string, RE_RELAY_W) + elems = iter(group_w) + w_dict = {k: int(v) for k, v in zip(elems, elems)} - try: - header = str(header, 'utf8') - except: - continue + relay = { + "nickname": group_r[0], + "identity": group_r[1], + "micro-digest": group_m[0], + "date": date_str, + "time": time_str, + "stamp": timestamp, + "address": group_r[8], + "dirport": int(group_r[10]), + "orport": int(group_r[9]), + "flags": flags, + "version": version, + "protocols": protocols, + "w": w_dict + } - keyword, content = header.split(' ', 1) - if keyword == 'm': - content = parse_base64(content) + return relay - if keyword == 's': - content = content.split(' ') - if keyword == 'pr': - content = parse_ranges(content) + @staticmethod + def _parse_relay_unflavored(string): - if keyword == 'w': - content = parse_params(content) + group_r = Consensus._search_re(string, RE_RELAY_R_U) + date_int = [int(x) for x in group_r[3:9]] + date_str = "{}-{}-{}".format(*group_r[3:6]) + time_str = "{}:{}:{}".format(*group_r[6:9]) + timestamp = datetime(*date_int, tzinfo=timezone.utc).timestamp() - if keyword == 'p': - policy_type, portlist = content.split(' ') - if not policy_type in ['accept', 'reject']: - raise RuntimeError('Unknown policy: {}'.format(policy_type)) + #group_a = Consensus._search_re(string, RE_RELAY_A) - portlist = parse_range_once(portlist, expand=False) - content = {'type': policy_type, 'PortList': portlist} + flags = Consensus._search_re(string, RE_RELAY_S)[0].split(" ") - if keyword == 'a': - address, port, guessed_type = parse_address(content) - content = [{'ip': address, 'port': port, 'type': guessed_type}] + version = Consensus._search_re(string, RE_RELAY_V)[0] - if keyword == 'r' and flavor == 'unflavored': - (nickname, identity, digest, date, time, address, orport, - dirport) = content.split(' ', 7) + group_pr = Consensus._search_re(string, RE_RELAY_PR)[0] + protocols = dict() + for pair in group_pr.split(" "): + key, value = pair.split("=") + protocols[key] = Consensus._parse_protocols_vers(value) - digest = parse_base64(digest) - identity = parse_base64(identity) - date, time, when = parse_time(' '.join([date, time])) + group_w = Consensus._search_re(string, RE_RELAY_W) + elems = iter(group_w) + w_dict = {k: int(v) for k, v in zip(elems, elems)} - content = dict(nickname=nickname, identity=identity, digest=digest, - date=date, time=time, stamp=when.timestamp(), address=address, - dirport=int(dirport), orport=int(orport)) + group_p = Consensus._search_re(string, RE_RELAY_P) - if not 0 <= content['dirport'] < 65536: - raise RuntimeError('Invalid dirport here: {}'.format(content)) - if not 0 < content['orport'] < 65536: - raise RuntimeError('Invalid orport here: {}'.format(content)) + relay = { + "nickname": group_r[0], + "identity": group_r[1], + "digest": group_r[2], + "date": date_str, + "time": time_str, + "stamp": timestamp, + "address": group_r[9], + "dirport": int(group_r[11]), + "orport": int(group_r[10]), + "flags": flags, + "version": version, + "protocols": protocols, + "w": w_dict, + "exit-policy": { + "type": group_p[0], + "PortList": Consensus._parse_relay_port_list(group_p[1]) + } + } - if keyword == 'r' and flavor == 'microdesc': - nickname, identity, date, time, address, orport, dirport = ( - content.split(' ', 6)) + return relay - identity = parse_base64(identity) - date, time, when = parse_time(date + ' ' + time) - content = dict(nickname=nickname, identity=identity, date=date, - time=time, stamp=when.timestamp(), address=address, - dirport=int(dirport), orport=int(orport)) + @staticmethod + def _parse_relays(string, flavor): - if not 0 <= content['dirport'] < 65536: - raise RuntimeError('Invalid dirport here: {}'.format(content)) - if not 0 < content['orport'] < 65536: - raise RuntimeError('Invalid orport here: {}'.format(content)) + relays = list() - if keyword != 'r' and fields[-1][0] == 'r': - if keyword in aliases: - keyword = aliases[keyword] + if flavor == Flavor.MICRO: + func = Consensus._parse_relay_micro + elif flavor == Flavor.UNFLAVORED: + func = Consensus._parse_relay_unflavored - if keyword == 'or-address' and keyword in fields[-1][1]: - content[0]['ignored'] = True - fields[-1][1]['or-address'] += content - continue + for relay_str in Consensus._findall_re(string, RE_RELAYS): + relay = func(relay_str) + relays.append(relay) - if not (keyword not in fields[-1][1]): - raise RuntimeError('Unexpected {} with: {}'.format(keyword, - fields[-1])) + return relays - fields[-1][1][keyword] = content - continue - fields.append((keyword, content)) + @staticmethod + def _parse_shared_rand(string, regex): + groups = Consensus._search_re(string, regex) + shared_rand = {"NumReveals": int(groups[0]), "Value": groups[1]} + return shared_rand - full_entries_count = len([v for k, v in fields if k == 'r']) - if not full_entries_count == len(fields): - raise RuntimeError('Invalid or corrupted entry?') - if full_entries_count == len(fields): - fields = [v for k, v in fields] + @staticmethod + def _parse_versions(string, regex): + versions = Consensus._search_re(string, regex)[0].split(",") + return versions - return consensus, fields + @staticmethod + def _parse_voting_delay(string): + groups = Consensus._search_re(string, RE_VOTING_DELAY) + voting_delay = {"vote": int(groups[0]), "dist": int(groups[1])} + return voting_delay -def consume_footer(consensus, flavor='unflavored'): - """ - Consume consensus footer if present, then returns the remaining input - to be further processed and a set of footers (or None, if none - present). - Will consume the following fields: - - directory-footer - - bandwidth-weights - - directory-signature + @staticmethod + def parse(consensus_raw, flavor): + """Parse a raw consensus.""" - :param str consensus: input to be processed - :param str flavor: consensus flavor ('unflavored' or 'microdesc') + raw = consensus_raw - :returns: a tuple (remaining-input, headers-or-None) - """ - if flavor not in ['unflavored', 'microdesc']: - raise NotImplementedError( - 'Consensus flavor "{}" not supported.'.format(flavor)) - - whitelist = [ - b'directory-footer', b'bandwidth-weights', b'directory-signature'] - - def end_of_field(line): - if b'directory-footer' == line: - return False - if b' ' not in line: - return True - keyword, _ = line.split(b' ', 1) - return keyword not in whitelist - - fields = dict() - valid = False - while True: - consensus, header = scrap(consensus, end_of_field) - if header is None: - return consensus, fields if valid else None - - valid = True - if b' ' not in header: - continue + if flavor == Flavor.UNFLAVORED: + flavor_str = "unflavored" + else: + flavor_str = "microdesc" + + network_status_version = { + "version": int( Consensus._search_re(raw, RE_NETWORK_STATUS_VERSION)[0]), + "flavor": flavor_str + } + + vote_status = Consensus._search_re(raw, RE_VOTE_STATUS)[0] + consensus_method = int(Consensus._search_re(raw, RE_CONSENSUS_METHOD)[0]) + valid_after = Consensus._parse_date(raw, RE_VALID_AFTER) + fresh_until = Consensus._parse_date(raw, RE_FRESH_UNTIL) + valid_until = Consensus._parse_date(raw, RE_VALID_UNTIL) + voting_delay = Consensus._parse_voting_delay(raw) + client_versions = Consensus._parse_versions(raw, RE_CLIENT_VERSIONS) + server_versions = Consensus._parse_versions(raw, RE_SERVER_VERSIONS) + known_flags = Consensus._search_re(raw, RE_KNOWN_FLAGS)[0].split(" ") + rec_client_proto = Consensus._parse_protocols(raw, RE_RECOMMENDED_CLIENT_PROTOCOLS) + rec_relay_proto = Consensus._parse_protocols(raw, RE_RECOMMENDED_RELAY_PROTOCOLS) + req_client_proto = Consensus._parse_protocols(raw, RE_REQUIRED_CLIENT_PROTOCOLS) + req_relay_proto = Consensus._parse_protocols(raw, RE_REQUIRED_RELAY_PROTOCOLS) + shared_rand_curr_value = Consensus._parse_shared_rand(raw, RE_SHARED_RAND_CURRENT_VALUE) + + headers = { + "network-status-version": network_status_version, + "vote-status": vote_status, + "consensus-method": consensus_method, + "valid-after": valid_after, + "fresh-until": fresh_until, + "valid-until": valid_until, + "voting-delay": voting_delay, + "client-versions": client_versions, + "server-versions": server_versions, + "known-flags": known_flags, + "recommended-client-protocols": rec_client_proto, + "recommended-relay-protocols": rec_relay_proto, + "required-client-protocols": req_client_proto, + "required-relay-protocols": req_relay_proto, + "shared-rand-current-value": shared_rand_curr_value + } try: - header = str(header, 'utf8') - except: - continue - - keyword, content = header.split(' ', 1) - if keyword == 'directory-footer' and not len(fields) == 0: - raise RuntimeError('Expect {} as first field!'.format(keyword)) - - if keyword == 'bandwidth-weights': - content = parse_params(content) - - if keyword == 'directory-signature': - content = content.split(' ', 2) - if len(content) == 3: - algorithm, identity, signing_key_digest = content - elif len(content) == 2: - algorithm = 'sha1' - identity, signing_key_digest = content + shared_rand_prev_value = Consensus._parse_shared_rand(raw, RE_SHARED_RAND_PREVIOUS_VALUE) + headers["shared-rand-previous-value"] = shared_rand_prev_value + except InvalidConsensus: + pass - content = { - 'Algorithm': algorithm, - 'identity': identity, - 'signing-key-digest': signing_key_digest} + dir_sources = list() - consensus, signature = scrap_signature(consensus) - if signature is not None: - signature = parse_base64(str(signature, 'utf8')) - content['signature'] = signature - - if keyword + 's' not in fields: - fields[keyword + 's'] = [] - fields[keyword + 's'].append(content) - continue - - fields[keyword] = content - return consensus, fields - - -def parse(consensus, flavor='unflavored'): - """ - Parse a raw consensus with the given flavor, then returns sanitized - entries as a python dictionary. - - :param str consensus: input to be processed - :param str flavor: consensus flavor ('unflavored' or 'microdesc') - - :returns: a python dictionary - """ - fields = dict(flavor=flavor) + for groups in Consensus._findall_re(raw, RE_DIR_SOURCE): + dir_source = { + "nickname": groups[0], + "identity": groups[1].lower(), + "hostname": groups[2], + "address": groups[3], + "dirport": int(groups[4]), + "orport": int(groups[5]), + "contact": groups[6], + "vote-digest": groups[7].lower() + } - consensus, http = consume_http(consensus) - if http is not None: - fields['http'] = http + dir_sources.append(dir_source) - consensus, headers = consume_headers(consensus, flavor) - if headers is not None: - fields['headers'] = headers + relays = Consensus._parse_relays(raw, flavor) - consensus, dir_sources = consume_dir_sources(consensus) - if dir_sources is not None: - fields['dir-sources'] = dir_sources + footer = Consensus._parse_footer(raw) - consensus, routers = consume_routers(consensus, flavor) - if routers is not None: - fields['routers'] = routers + consensus = { + "flavor": flavor_str, + "headers": headers, + "dir-sources": dir_sources, + "routers": relays, + "footer": footer + } - consensus, footer = consume_footer(consensus, flavor) - if footer is not None: - fields['footer'] = footer - - if not ('headers' in fields - and 'dir-sources' in fields - and 'routers' in fields - and 'footer' in fields): - raise RuntimeError('Missing entry: {}'.format(list(fields))) - - return fields, consensus - - -def extract_date(consensus, field): - """ - Retrieve the value from a date field as a datetime object. - """ - - pattern = re.compile('{} [^\n]+'.format(field)) - found = pattern.search(consensus) - - if found is None: - raise RuntimeError('Field {} not found in consensus.'.format(field)) - - date_s = consensus[found.start():found.end()] - date = datetime.datetime.strptime(date_s, '{} %Y-%m-%d %H:%M:%S'.format(field)) - date.replace(tzinfo=datetime.timezone.utc) - - return date + return consensus def extract_nodes_digests_unflavored(consensus_raw): @@ -769,7 +413,7 @@ def extract_nodes_digests_unflavored(consensus_raw): # We retrieve the third fields of the lines looking like that: #r VSIFskylab AD14gl4Llgnuz/Xk4FKXF3cuU8c 3VZwLdY0Et7vqUbqDdXg3WGGHCw 2020-01-12 23:47:04 104.218.63.73 443 80 - digests_raw = re.findall(r'^r [^ ]+ [^ ]+ ([^ ]+)', consensus_raw, re.MULTILINE) + digests_raw = RE_RELAY_DIGEST_UNF.findall(consensus_raw) digests_bytes = [b64decode(digest + '====') for digest in digests_raw] return digests_bytes @@ -780,58 +424,43 @@ def extract_nodes_digests_micro(consensus_raw): """ # We retrieve the third fields of the lines looking like that: #m v7E0VcMnwVepVUh+j193lrbqbWOg26g9hXOBwSYv32I - digests_raw = re.findall(r'^m ([^\n]+)', consensus_raw, re.MULTILINE) + digests_raw = RE_RELAY_DIGEST_MIC.findall(consensus_raw) digests_bytes = [digest for digest in digests_raw] return digests_bytes -def download_direct(hostname, port, flavor='microdesc'): +def download_direct(hostname, port, flavor=Flavor.MICRO): """Retrieve consensus via a direct HTTP connection. :param hostname: host name of the node from which to retrieve the consensus. :param port: port of the node from which to retrieve the consensus. :param flavor: flavour of the consensus to retrieve. """ - if flavor not in ['unflavored', 'microdesc']: - raise NotImplementedError( - 'Consensus flavor "{}" not supported.'.format(flavor)) - - endpoint = 'consensus-microdesc' if flavor == 'microdesc' else 'consensus' - uri = 'http://%s:%d/tor/status-vote/current/%s' % (hostname, port, endpoint) - - res = urllib.request.urlopen(uri) - cons = res.read() + cons_raw = download_raw(hostname, port, flavor) keys = lnn.keys.fetch_and_parse_keys(hostname, port) - if flavor != 'microdesc': - if not lnn.signature.verify(cons.decode('utf-8'), keys): - raise RuntimeError('Consensus Verification Failed') + if flavor == Flavor.UNFLAVORED: + if not lnn.signature.verify(cons_raw, keys): + raise InvalidConsensus("Invalid signature.") - consensus, remaining = parse(cons, flavor=flavor) + consensus = Consensus.parse(cons_raw, flavor=flavor) - if consensus is None or remaining is None or not len(remaining) == 0: - raise RuntimeError('Unable to parse downloaded consensus!') - return consensus, keys -def download_raw(hostname, port, flavor='unflavored'): +def download_raw(hostname, port, flavor=Flavor.UNFLAVORED): """Retrieve raw consensus via a direct HTTP connection. :param hostname: host name of the node from which to retrieve the consensus. :param port: port of the node from which to retrieve the consensus. :param flavor: flavour of the consensus to retrieve. """ - if flavor not in ['unflavored', 'microdesc']: - raise NotImplementedError( - 'Consensus flavor "{}" not supported.'.format(flavor)) - - endpoint = 'consensus-microdesc' if flavor == 'microdesc' else 'consensus' + endpoint = 'consensus-microdesc' if flavor == Flavor.MICRO else 'consensus' uri = 'http://%s:%d/tor/status-vote/current/%s' % (hostname, port, endpoint) res = urllib.request.urlopen(uri) - cons = res.read().decode('utf-8') + cons = res.read().decode('ASCII') return cons diff --git a/lightnion/descriptors.py b/lightnion/descriptors.py index e18c7b7..0eca7f5 100644 --- a/lightnion/descriptors.py +++ b/lightnion/descriptors.py @@ -1,356 +1,285 @@ +""" +Descriptors handlers. +""" + import base64 -import hashlib +import re +from datetime import datetime, timezone import logging import urllib.request +from stem.descriptor.server_descriptor import RelayDescriptor +from stem.descriptor.microdescriptor import Microdescriptor + import lightnion as lnn -from lightnion import consensus +from lightnion.consensus import Flavor -def compute_descriptor_digest(fields, descriptors, entry, flavor): - """ - (details of the parser – private API) +RE_ROUTERS_UNF = re.compile(r"^router ", re.M) +RE_ROUTERS_MIC = re.compile(r"^onion-key\n", re.M) - Plugs into our consumer to compute extra "digest" fields that expose - the (micro-)descriptor's (micro-)digest, enabling us to easily fetch - associated entries within a consensus. +RE_PEM = re.compile(r"""-----BEGIN [^-]+----- +([A-Za-z0-9+/=\n]+) +-----END [^-]+-----""") - :param list fields: "fields" accumulator used by the consumer - :param bytes descriptors: remaining input to be parsed by the consumer - :param bytes entry: last line being parsed by the consumer - :param str flavor: flavor used by the consumer +FLAVOR_STR_MIC = "microdesc" +FLAVOR_STR_UNF = "unflavored" - :returns: updated (or not) fields accumulator - """ +IDENTIFIERS_TYPES = ( + "ed25519", + "rsa1024" +) - if flavor == 'unflavored': - digest_name = 'digest' - pivot_field = 'router' - starts_hash = b'router ' - ends_hasher = b'router-signature' - base_offset = 1 - base_legacy = 0 - shalgorithm = hashlib.sha1 - # https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L602 - else: - digest_name = 'micro-digest' - pivot_field = 'onion-key' - starts_hash = b'onion-key' - ends_hasher = b'id ' - base_offset = 7 + 1 + 43 + 1 # 'ed25519 [identity]\n' - base_legacy = 7 + 1 + 27 + 1 # 'rsa1024 [identity]\n' - shalgorithm = hashlib.sha256 - # https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L3202 - - # 1. check if we're starting to parse a fresh entry before computing digest - if digest_name not in fields[-1] or ( - entry.startswith(starts_hash) and pivot_field in fields[-1]): - if pivot_field in fields[-1]: - fields.append(dict()) - - # 1.5 (extra sanity checks: double-check that we have what we need) - if not entry.startswith(starts_hash): - raise RuntimeError('Expecting {} to start the payload: {}'.format( - starts_hash, entry)) - if not ends_hasher in descriptors: - raise RuntimeError( - 'Expecting {} within: {}'.format(ends_hasher, descriptors)) - - try: - # 2. compute the offset to the ends what goes into the hash - sigoffset = descriptors.index(ends_hasher) - - # TODO: better support? - sigoffset += len(ends_hasher) + base_offset - if b'rsa1024' in descriptors[:sigoffset]: - sigoffset -= base_offset - sigoffset += base_legacy - - # 3. rebuild the original (including its first line being parsed) - full_desc = entry + b'\n' + descriptors[:sigoffset] - - # 4. compute the base64-encoded hash with the right algorithm - digest = base64.b64encode(shalgorithm(full_desc).digest()) - - # 5. strips the trailing '=' as specified - fields[-1][digest_name] = str(digest.rstrip(b'='), 'utf8') - except ValueError: - pass - - if not digest_name in fields[-1]: - raise RuntimeError('Was unable to generate proper sum.') - - return fields - -def consume_descriptors(descriptors, flavor='microdesc'): - if flavor not in ['microdesc', 'unflavored']: - raise NotImplementedError( - 'Consensus flavor "{}" not supported.'.format(flavor)) - - # TODO: check if family in microdesc are appropriate - if flavor == 'microdesc': - whitelist = [b'onion-key', b'ntor-onion-key', b'p', b'p6', b'id', - b'family'] - else: - whitelist = [b'router', b'identity-ed25519', b'master-key-ed25519', - b'platform', b'proto', b'published', b'fingerprint', b'uptime', - b'bandwidth', b'extra-info-digest', b'qkk', b'caches-extra-info', - b'onion-key', b'signing-key', b'onion-key-crosscert', - b'ntor-onion-key-crosscert', b'hidden-service-dir', b'contact', - b'ntor-onion-key', b'reject', b'accept', b'tunnelled-dir-server', - b'router-sig-ed25519', b'router-signature', b'ipv6-policy', - b'family', b'protocols', b'or-address', b'allow-single-hop-exits', - b'hibernating'] - aliases = {'p': 'policy', 'p6': 'ipv6-policy', 'id': 'identity'} - - def end_of_field(line): - if b' ' not in line: - line += b' ' - keyword, _ = line.split(b' ', 1) - return keyword not in whitelist - - fields = [dict()] - valid = False - while True: - descriptors, entry = consensus.scrap(descriptors, end_of_field) - if entry is None: - if not valid: - return descriptors, None - break - fields = compute_descriptor_digest(fields, descriptors, entry, flavor) - - valid = True - if b' ' not in entry: - entry += b' ' - - try: - entry = str(entry, 'utf8') - except: - continue - - keyword, content = entry.split(' ', 1) - if keyword == 'router': - nick, address, orport, socksport, dirport = content.split(' ', 4) - content = dict( - nickname=nick, - address=address, - orport=int(orport), - socksport=int(socksport), - dirport=int(dirport)) - - if keyword in ['platform', 'contact']: - pass # nothing to process - - if keyword in ['reject', 'accept']: - base = dict(type='exitpattern') - if 'policy' in fields[-1]: - base = fields[-1]['policy'] - if not base['type'] == 'exitpattern': - raise RuntimeError('Unknown policy: {}'.format(base)) - if 'rules' not in base: - base['rules'] = [] - - base['rules'].append(dict(type=keyword, pattern=content)) - fields[-1]['policy'] = base - continue - - if keyword == 'or-address': - base = [] - if 'or-address' in fields[-1]: - base = fields[-1]['or-address'] - - address, port, guess = consensus.parse_address(content) - content = [{'ip': address, 'port': port, 'type': guess}] - if len(base) > 0: - content[0]['ignored'] = True - - base += content - fields[-1]['or-address'] = base - continue - - if keyword == 'family': - content = content.split(' ') - - if keyword == 'proto': - content = consensus.parse_ranges(content) - - # The spec says 'New code should neither […] nor parse this line' - if keyword == 'protocols': - pass - - if keyword in ['allow-single-hop-exits', 'hibernating']: - content = True - - if keyword == 'published': - date, time, when = consensus.parse_time(content) - content = dict(date=date, time=time, stamp=when.timestamp()) - - if keyword == 'fingerprint': - content = consensus.parse_fingerprint(content) - - # Enrich 'router' with 'identity' fingerprint for convenience - if 'router' in fields[-1]: - identity = bytes.fromhex(content.replace(' ', '')) - identity = str(base64.b64encode(identity), 'utf8') - fields[-1]['router']['identity'] = identity.replace('=', '') - - if keyword == 'uptime': - content = int(content) - - if keyword == 'bandwidth': - avg, burst, observed = content.split(' ', 2) - content = dict( - avg=int(avg), burst=int(burst), observed=int(observed)) - - if keyword == 'extra-info-digest': - if ' ' in content: - sha1, sha256 = content.split(' ', 1) - sha256 = consensus.parse_base64(sha256) - content = dict(sha1=sha1, sha256=sha256) - else: - content = dict(sha1=content) - - if keyword in ['caches-extra-info', 'hidden-service-dir', - 'tunnelled-dir-server']: - content = True - - if keyword in ['onion-key', 'signing-key']: - if not content == '': - raise RuntimeError('Trailing content with {}: {}'.format( - keyword, content)) - - descriptors, pubkey = consensus.scrap_signature(descriptors, - fix=b'RSA PUBLIC KEY') - if pubkey is not None: - content = consensus.parse_base64(str(pubkey, 'utf8')) - - if keyword == 'onion-key-crosscert': - if not content == '': - raise RuntimeError('Trailing content with {}: {}'.format( - keyword, content)) - - descriptors, crosscrt = consensus.scrap_signature(descriptors, - fix=b'CROSSCERT') - if crosscrt is not None: - content = consensus.parse_base64(str(crosscrt, 'utf8')) - - if keyword == 'ntor-onion-key-crosscert': - bit = int(content) - - descriptors, edcert = consensus.scrap_signature(descriptors, - fix=b'ED25519 CERT') - if edcert is not None: - content = consensus.parse_base64(str(edcert, 'utf8')) - content = dict(bit=bit, cert=content) - - if keyword == 'ntor-onion-key': - content = consensus.parse_base64(content) - - if keyword in ['p', 'p6', 'ipv6-policy']: - policy_type, portlist = content.split(' ') - if not policy_type in ['accept', 'reject']: - raise RuntimeError('Unknown policy: {}'.format(policy_type)) - - portlist = consensus.parse_range_once(portlist, expand=False) - content = {'type': policy_type, 'PortList': portlist} - - if keyword == 'id': - id_type, data = content.split(' ') - if not id_type in ['rsa1024', 'ed25519']: - raise RuntimeError('Unknown id key type: {}'.format(id_type)) - - content = {'type': id_type, - 'master-key': consensus.parse_base64(data)} - - if keyword in ['router-sig-ed25519', 'router-signature']: - base = dict() - if 'router-signatures' in fields[-1]: - base = fields[-1]['router-signatures'] - - if keyword == 'router-sig-ed25519': - if 'router-signatures' in fields[-1]: - raise RuntimeError('Ed25519 must be first!') - if not 'identity' in fields[-1]: - raise RuntimeError('Need identity with {} here: {}'.format( - keyword, fields[-1])) - if not 'cert' in fields[-1]['identity']: - raise RuntimeError('Need cert. in identity: {}'.format( - fields[-1])) - base['ed25519'] = consensus.parse_base64(content) - - if keyword == 'router-signature': - descriptors, sig = consensus.scrap_signature(descriptors, - fix=b'SIGNATURE') - if sig is not None: - content = consensus.parse_base64(str(sig, 'utf8')) - base['rsa'] = content - - fields[-1]['router-signatures'] = base - continue - - if keyword in ['identity-ed25519', 'master-key-ed25519']: - base = dict() - if 'identity' in fields[-1]: - base = fields[-1]['identity'] - - if 'type' not in base: - base['type'] = 'ed25519' - if not base['type'] == 'ed25519': - raise RuntimeError('Invalid key type {} here:'.format(base)) - - if keyword == 'identity-ed25519': - if 'cert' in base: - raise RuntimeError('Extra cert. here: {}'.format(base)) - - descriptors, edcert = consensus.scrap_signature(descriptors, - fix=b'ED25519 CERT') - if edcert is not None: - base['cert'] = consensus.parse_base64(str(edcert, 'utf8')) - - if keyword == 'master-key-ed25519': - if 'master-key' in base: - raise RuntimeError('Extra master key: {}'.format(base)) - - base['master-key'] = consensus.parse_base64(content) - - # TODO: validation if both master-key & identity are present - fields[-1]['identity'] = base - continue - - if keyword in aliases: - keyword = aliases[keyword] - - if keyword in fields[-1]: - fields.append(dict()) - - fields[-1][keyword] = content - return descriptors, fields - - -def parse_descriptors(descriptors, flavor='microdesc'): - fields = dict(flavor=flavor) - nbdesc = descriptors.count(b'onion-key\n-----BEGIN') - - descriptors, http = consensus.consume_http(descriptors) - if http is not None: - fields['http'] = http - - descriptors, entries = consume_descriptors(descriptors, flavor) - if entries is None or len(entries) == 0: - entries = [] - fields['descriptors'] = entries - if not len(fields['descriptors']) == nbdesc: - raise RuntimeError( - 'Unexpected or corrupted descriptor? ({}/{} found)'.format( - len(fields['descriptors']), nbdesc)) +class InvalidDescriptor(Exception): + pass + + +class Descriptors: + + @staticmethod + def _search_re(string, regex): + # Convenience function to search for the first instance of the pattern. + match = regex.search(string) + if not match: + raise InvalidDescriptor("Invalid format.") + + groups = match.groups() + return groups + + + @staticmethod + def _findall_re(string, regex): + # Convenience function to search for all instances of the pattern. + groups = regex.findall(string) + if not groups: + raise InvalidDescriptor("Invalid format.") + + return groups - # Add flavor for convenience - for idx in range(len(fields['descriptors'])): - fields['descriptors'][idx]['flavor'] = flavor - if descriptors == b'\n': - descriptors = b'' - return fields, descriptors + @staticmethod + def _date_from_datetime(dt): + date_dict = { + "date": "{:04d}-{:02d}-{:02d}".format(dt.year, dt.month, dt.day), + "time": "{:02d}:{:02d}:{:02d}".format(dt.hour, dt.minute, dt.second), + "stamp": dt.replace(tzinfo=timezone.utc).timestamp() + } + return date_dict + + + @staticmethod + def _parse_exit_policy(policy): + rules = list() + for rule_obj in policy: + rule_l = str(rule_obj).split(" ") + rule = { + "type": rule_l[0], + "pattern": rule_l[1] + } + rules.append(rule) + + policy_dict = { + "type": "exitpattern", + "rules": rules + } + + return policy_dict + + + @staticmethod + def _parse_exit_policy_mic(policy): + + if not policy: + return None + + summary = policy.summary() + # something like 'reject 1-442, 444-1024' + + if summary == "reject 1-65535": + return None + + rules = list() + rule_type = summary[0:6] + ports_pairs = summary[7:].split(", ") + + for ports_pair in ports_pairs: + if "-" in ports_pair: + port_min, port_max = ports_pair.split("-") + else: + port_min = port_max = ports_pairs + + rules.append([int(port_min), int(port_max)]) + + policy_dict = { + "type": rule_type, + "PortList": rules + } + + return policy_dict + + + @staticmethod + def _parse_router_mic(string): + desc = Microdescriptor(string) + + identity = None + for identifier_type in IDENTIFIERS_TYPES: + if identifier_type in desc.identifiers: + identity = { + "type": identifier_type, + "master-key": desc.identifiers[identifier_type] + } + break + + if not identity: + raise InvalidDescriptor + + onion_key = Descriptors._search_re(desc.onion_key, RE_PEM)[0] + + microdescriptor = { + "micro-digest": desc.digest(), + "onion-key": onion_key.replace("\n", ""), + "ntor-onion-key": desc.ntor_onion_key, + "identity": identity, + "flavor": FLAVOR_STR_MIC + } + + policy = Descriptors._parse_exit_policy_mic(desc.exit_policy) + if policy: + microdescriptor["policy"] = policy + + policy = Descriptors._parse_exit_policy_mic(desc.exit_policy_v6) + if policy: + microdescriptor["ipv6-policy"] = policy + + return microdescriptor + + + @staticmethod + def _parse_router_unf(string): + desc = RelayDescriptor(string) + + router_id = base64.b64encode(bytes.fromhex(desc.fingerprint.replace(" ", ""))).replace(b"=", b"").replace(b"\n", b"") + + identity_cert = Descriptors._search_re(desc.ed25519_certificate, RE_PEM)[0].replace("\n", "") + + fingerprint = desc.fingerprint + fingerprint = " ".join([fingerprint[i:i+4] for i in range(0,len(fingerprint),4)]) + + onion_key = Descriptors._search_re(desc.onion_key, RE_PEM)[0].replace("\n", "") + signing_key = Descriptors._search_re(desc.signing_key, RE_PEM)[0].replace("\n", "") + onion_key_crosscert = Descriptors._search_re(desc.onion_key_crosscert, RE_PEM)[0].replace("\n", "") + ntor_onion_key_crosscert = Descriptors._search_re(desc.ntor_onion_key_crosscert, RE_PEM)[0].replace("\n", "") + rsa_signature = Descriptors._search_re(desc.signature, RE_PEM)[0].replace("\n", "") + + descriptor = { + "digest": desc.digest(hash_type='SHA1',encoding='BASE64'), + "router": { + "nickname": desc.nickname, + "address": desc.address, + "orport": desc.or_port, + "socksport": 0, + "dirport": desc.dir_port, + "identity": router_id.decode("ASCII") + }, + "identity": { + "type": "ed25519", + "cert": identity_cert, + "master-key": desc.ed25519_master_key + }, + "platform": desc.platform.decode("ASCII"), + "proto": desc.protocols, + "published": Descriptors._date_from_datetime(desc.published), + "fingerprint": fingerprint, + "uptime": desc.uptime, + "bandwidth": { + "avg": desc.average_bandwidth, + "burst": desc.burst_bandwidth, + "observed": desc.observed_bandwidth + }, + "extra-info-digest": { + "sha1": desc.extra_info_digest, + "sha256": desc.extra_info_sha256_digest + }, + "onion-key": onion_key, + "signing-key": signing_key, + "onion-key-crosscert": onion_key_crosscert, + "ntor-onion-key-crosscert": { + "bit": int(desc.ntor_onion_key_crosscert_sign), + "cert": ntor_onion_key_crosscert + }, + "hidden-service-dir": desc.is_hidden_service_dir, + "ntor-onion-key": desc.ntor_onion_key, + "tunnelled-dir-server": desc.allow_tunneled_dir_requests, + "router-signatures": { + "ed25519": desc.ed25519_signature, + "rsa": rsa_signature + }, + "flavor": FLAVOR_STR_UNF + } + + if desc.extra_info_cache: + descriptor["caches-extra-info"] = True + + if desc.exit_policy: + policy = Descriptors._parse_exit_policy(desc.exit_policy) + descriptor["policy"] = policy + + policy = Descriptors._parse_exit_policy_mic(desc.exit_policy_v6) + if policy: + descriptor["ipv6-policy"] = policy + + + if desc.contact: + contact = desc.contact.decode("ASCII") + + descriptor["contact"] = contact + + return descriptor + + + @staticmethod + def parse(descriptors_raw, flavor=Flavor.MICRO): + + # alias + raw = descriptors_raw + + if flavor == Flavor.MICRO: + flavor_str = FLAVOR_STR_MIC + router_func = Descriptors._parse_router_mic + routers_regex = RE_ROUTERS_MIC + elif flavor == Flavor.UNFLAVORED: + flavor_str = FLAVOR_STR_UNF + router_func = Descriptors._parse_router_unf + routers_regex = RE_ROUTERS_UNF + + routers = list() + + matches = routers_regex.finditer(descriptors_raw) + if not matches: + raise InvalidDescriptor("Invalid format.") + + match = next(matches) + + idx_0 = match.start() + + for match in matches: + idx_1 = match.start() + + router = router_func(raw[idx_0:idx_1]) + routers.append(router) + + idx_0 = idx_1 + + router = router_func(raw[idx_0:-1]) + routers.append(router) + + descriptors = { + "flavor": flavor_str, + "descriptors": routers + } + + return descriptors def batch_query(items, prefix, separator='-', fixed_max_length=4096-128): @@ -358,21 +287,29 @@ def batch_query(items, prefix, separator='-', fixed_max_length=4096-128): # https://github.com/plcp/tor-scripts/blob/master/torspec/dir-spec-4d0d42f.txt#L3392 query = '' + query_len = 0 + prefix_len = len(prefix) + sep_len = len(separator) + for item in items: - if len(item) + len(query) >= fixed_max_length: + item_len = len(item) + if query_len + item_len >= fixed_max_length: yield query query = '' + query_len = 0 - if len(query) == 0: - query += prefix + item - else: + if query: query += separator + item + query_len += item_len + sep_len + else: + query += prefix + item + query_len += item_len + prefix_len - if len(query) != 0: + if query: yield query -def filter_descriptors(descriptors, digests, flavor='unflavored'): +def filter_descriptors(descriptors, digests, flavor=Flavor.UNFLAVORED): """Filter out the invalid descriptors. :param descriptors: Descriptors to be filtered. :param digests: Digests from the consensus. @@ -383,7 +320,7 @@ def filter_descriptors(descriptors, digests, flavor='unflavored'): descriptors_d = dict() # Content depends on descriptor flavour. - if flavor == 'microdesc': + if flavor == Flavor.MICRO: for descriptor in descriptors: fingerprint = descriptor['micro-digest'] descriptor_digests.add(fingerprint) @@ -407,26 +344,19 @@ def filter_descriptors(descriptors, digests, flavor='unflavored'): return descriptors_valid -def download_direct(host, port, cons, flavor='unflavored'): - """Retrieve descriptor via a direct HTTP connection. - :param host: host from which to retrieve the descriptors. - :param port: port from which to retrieve the descriptors. - :param cons: consensus for which nodes a descriptor need to be retrieved. - """ +def download_direct(host, port, cons, flavor=Flavor.MICRO): - if flavor == 'microdesc': + if flavor == Flavor.MICRO: endpoint = '/tor/micro/d/' separator = '-' digests = [router['micro-digest'] for router in cons['routers']] - else: endpoint = '/tor/server/d/' separator = '+' digests = [base64.b64decode(router['digest'] + '====').hex() for router in cons['routers']] - descriptors = [] + descriptors = list() - # Retrieve descriptors not in the cache for query in batch_query(digests, endpoint, separator): uri = 'http://%s:%d%s' % (host, port, query) res = urllib.request.urlopen(uri) @@ -435,61 +365,28 @@ def download_direct(host, port, cons, flavor='unflavored'): raise RuntimeError('Unable to fetch descriptors.') # Rename parse to something sensible - new_batch, remaining = parse_descriptors(res.read(), flavor=flavor) - if new_batch is None or remaining is None or len(remaining) > 0: - raise RuntimeError('Unable to parse descriptors.') + new_batch = Descriptors.parse(res.read().decode("ASCII"), flavor=flavor) - if (len(new_batch['descriptors']) == 0): - raise RuntimeError('No descriptor listed. http={}.'.format(new_batch['http'])) + if not new_batch['descriptors']: + raise RuntimeError('No descriptors listed on {}:{}.'.format(host, port)) if new_batch is not None: descriptors += new_batch['descriptors'] descriptors = filter_descriptors(descriptors, digests, flavor=flavor) - if flavor == 'microdesc': + if flavor == Flavor.MICRO: return {d['micro-digest']: d for d in descriptors} else: return {d['digest']: d for d in descriptors} -def download_relay_descriptor(host='127.0.0.1', port=9051): - """Retrieve a relay's own descriptor. - """ - - uri = 'http://{}:{}/tor/server/authority'.format(host, port) - res = urllib.request.urlopen(uri) - - if res is None or res.getcode() != 200: - raise RuntimeError('Unable to fetch descriptors.') - - descriptors, _ = parse_descriptors(res.read(), flavor='unflavored') - - return descriptors['descriptors'][0] - - -def download_raw(host, port, cons, flavor='unflavored'): +def _download_raw_by_digests(host, port, digests, endpoint, separator): """Retrieve descriptor via a direct HTTP connection. - :param host: host from which to retrieve the descriptors. - :param port: port from which to retrieve the descriptors. - :param cons: consensus for which nodes a descriptor need to be retrieved. """ - - if flavor == 'microdesc': - endpoint = '/tor/micro/d/' - separator = '-' - digests = [router['micro-digest'] for router in cons['routers']] - - else: - endpoint = '/tor/server/d/' - separator = '+' - digests = [base64.b64decode(router['digest'] + '====').hex() for router in cons['routers']] - - - # Retrieve descriptors not in the cache desc = b"" for query in batch_query(digests, endpoint, separator): - uri = 'http://%s:%d%s' % (host, port, query) + uri = 'http://{}:{}{}'.format(host, port, query) res = urllib.request.urlopen(uri) if res is None or res.getcode() != 200: @@ -500,20 +397,6 @@ def download_raw(host, port, cons, flavor='unflavored'): return desc -def download_raw_by_digests_unflavored(host, port, digests_bytes): - """Retrieve descriptor via a direct HTTP connection. - :param host: host from which to retrieve the descriptors. - :param port: port from which to retrieve the descriptors. - :param digests: Digests (in a binary form) of the nodes for which a descriptor need to be retrieved. - """ - - digests = [digest.hex() for digest in digests_bytes] - endpoint = '/tor/server/d/' - separator = '+' - - return _download_raw_by_digests(host, port, digests, endpoint, separator) - - def download_raw_by_digests_micro(host, port, digests_bytes): """Retrieve descriptor via a direct HTTP connection. :param host: host from which to retrieve the descriptors. @@ -527,52 +410,31 @@ def download_raw_by_digests_micro(host, port, digests_bytes): return _download_raw_by_digests(host, port, digests, endpoint, separator) -def _download_raw_by_digests(host, port, digests, endpoint, separator): +def download_raw_by_digests_unflavored(host, port, digests_bytes): """Retrieve descriptor via a direct HTTP connection. + :param host: host from which to retrieve the descriptors. + :param port: port from which to retrieve the descriptors. + :param digests: Digests (in a binary form) of the nodes for which a descriptor need to be retrieved. """ - desc = b"" - for query in batch_query(digests, endpoint, separator): - uri = 'http://{}:{}{}'.format(host, port, query) - res = urllib.request.urlopen(uri) - - if res is None or res.getcode() != 200: - raise RuntimeError('Unable to fetch descriptors.') - - desc += res.read() - return desc - - -def download_authority(state): - state, answer = lnn.hop.directory_query(state, '/tor/server/authority') - if answer is None or len(answer) == 0: - return state, None - - result, remain = parse_descriptors(answer, flavor='unflavored') - if not (len(remain) == 0 - and result is not None - and len(result['descriptors']) == 1): - raise RuntimeError('Unable to parse authority descriptor.') + digests = [digest.hex() for digest in digests_bytes] + endpoint = '/tor/server/d/' + separator = '+' - return state, result['descriptors'][0] + return _download_raw_by_digests(host, port, digests, endpoint, separator) -def download_authority_direct(host, port): - """Retrieve authority. - :param host: host from which to retrieve the authority. - :param port: port from which to retrieve the authority. - :return: Authority. +def download_relay_descriptor(host='127.0.0.1', port=9051): + """Retrieve a relay's own descriptor. """ - uri = 'http://%s:%d/tor/server/authority' % (host, port) + uri = 'http://{}:{}/tor/server/authority'.format(host, port) res = urllib.request.urlopen(uri) if res is None or res.getcode() != 200: - return None + raise RuntimeError('Unable to fetch descriptors.') - result, remain = parse_descriptors(res.read(), flavor='unflavored') + descriptors = Descriptors.parse(res.read().decode("ASCII"), flavor=Flavor.UNFLAVORED) - if not (len(remain) == 0 and result is not None and len(result['descriptors']) == 1): - raise RuntimeError('Unable to parse authority descriptor.') + return descriptors['descriptors'][0] - return result['descriptors'][0] diff --git a/lightnion/keys.py b/lightnion/keys.py index a51b313..8e76868 100644 --- a/lightnion/keys.py +++ b/lightnion/keys.py @@ -1,21 +1,32 @@ +""" +Handle signing keys +""" + +import base64 +import hashlib import re import requests from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 from cryptography.hazmat.primitives.serialization import load_pem_public_key -PATTERN_FINGERPRINT = r'fingerprint ([0-9A-Fa-f]+)' - -PATTERN_KEY = r"""dir-signing-key +RE_FINGERPRINT = re.compile(r'fingerprint ([0-9A-Fa-f]+)') +RE_KEY = re.compile(r"""dir-signing-key (-----BEGIN RSA PUBLIC KEY----- [A-Za-z0-9+/=\n]+ -----END RSA PUBLIC KEY-----) -""" +""") +RE_SIGN = re.compile(r"""directory-signature ([0-9A-Fa-f]+) ([0-9A-Fa-f]+) +-----BEGIN SIGNATURE----- +([0-9A-Za-z+/=\n]+) +-----END SIGNATURE----- +""") -def fetch_and_parse_keys(host, port=None, tls=True): +def fetch_and_parse_keys(host, port=None, tls=False): """Convenience function to call getch_keys() then parse_keys() if needed.""" keys_raw = fetch_keys(host, port, tls) @@ -27,7 +38,7 @@ def fetch_and_parse_keys(host, port=None, tls=True): return keys -def fetch_keys(host, port=None, tls=True): +def fetch_keys(host, port=None, tls=False): """Retrieve the public signing keys from the host.""" protocol = 'https' if tls else 'http' path = "tor/keys/all" @@ -39,7 +50,7 @@ def fetch_keys(host, port=None, tls=True): res = requests.get(url) - if res.status_code == 200 + if res.status_code == 200: return res.text return None @@ -66,21 +77,18 @@ def extract_key_params(key_pem): def parse_keys(keys_raw): """Parse raw keys.""" - regex_fingerprint = re.compile(PATTERN_FINGERPRINT) - regex_key = re.compile(PATTERN_KEY) - keys = dict() for key_raw in keys_raw.split("dir-key-certificate-version "): # Extract fingerprint. - fingerprint_match = regex_fingerprint.search(key_raw) + fingerprint_match = RE_FINGERPRINT.search(key_raw) if fingerprint_match: fingerprint_groups = fingerprint_match.groups() fingerprint = fingerprint_groups[0] # Extract signing key in PEM. - key_match = regex_key.search(key_raw) + key_match = RE_KEY.search(key_raw) if key_match: key_groups = key_match.groups() key_pem = key_groups[0] @@ -91,3 +99,54 @@ def parse_keys(keys_raw): keys[fingerprint] = params return keys + + +def verify_key_integrity(key_pem, digest_hex): + """Verify the integrity of a key.""" + # Parse the PEM. + key = base64.b64decode(key_pem[30, -28]) + sha1 = hashlib.sha1(key).digest() + digest_b = bytes.fromhex(digest_hex) + + return sha1 == digest_b + + +def verify_consensus_signature(consensus_content, signature, key_pem): + """Verify the signature of the consensus.""" + + #public_key = load_pem_public_key(key_pem, backend=default_backend()) + + # TODO Dummy check for now. + return True + + +def verify_consensus_integrity(consensus, keys, min_valid_signatures=3): + """Verify the signature of the consensus with the keys.""" + + valid_signatures_num = 0 + + signatures = [(s.start(), *(s.groups())) for s in RE_SIGN.finditer(consensus)] + sign_num = len(signatures) + + cons_end = signatures[0][0] + + # The first "directory-signature " is included in the signature [sic]. + # So 20 extra characters are needed. + cons_content = consensus[:(cons_end + 20)] + + for _, fingerprint, digest_hex, signature_pem in signatures: + + # Verify the integrity of the key. + key_pem = keys.get(fingerprint).get('pem').encode("ASCII") + key_valid = verify_key_integrity(key_pem, digest_hex) + + if not key_valid: + continue + + cons_valid = verify_consensus_signature(cons_content, signature_pem, key_pem) + + if cons_valid: + valid_signatures_num += 1 + + return valid_signatures_num >= min_valid_signatures + diff --git a/lightnion/proxy/forward.py b/lightnion/proxy/forward.py index 365420f..b7d1889 100644 --- a/lightnion/proxy/forward.py +++ b/lightnion/proxy/forward.py @@ -17,6 +17,8 @@ import lightnion.proxy import lightnion.keys +from lightnion.consensus import Flavor + debug = True @@ -68,7 +70,7 @@ def __init__(self, slave_node, control_port, dir_port, controller, compute_path, self.consensus_init = False #self.consm = None - #self.descm = None + self.descm = None self.signing_keys = None #self.signing_keys_raw = None @@ -109,23 +111,23 @@ def retrieve_consensus(self, event=None): # retrieve consensus and descriptors if self.compute_path: - cons, sg_keys = lnn.consensus.download_direct(host, port, flavor='unflavored') - desc = lnn.descriptors.download_direct(host, port, cons) + cons, sg_keys = lnn.consensus.download_direct(host, port, flavor=Flavor.UNFLAVORED) + desc = lnn.descriptors.download_direct(host, port, cons, flavor=Flavor.UNFLAVORED) self.consensus = cons self.signing_keys = sg_keys self.descriptors = desc - #self.consm,sg_keysm = lnn.consensus.download_direct(self.slave_node[0], self.dir_port) - #self.descm = lnn.descriptors.download_direct(self.slave_node[0], self.dir_port, self.consm, flavor='microdesc') + self.consm, sg_keysm = lnn.consensus.download_direct(self.slave_node[0], self.dir_port, flavor=Flavor.MICRO) + self.descm = lnn.descriptors.download_direct(self.slave_node[0], self.dir_port, self.consm, flavor=Flavor.MICRO) - self.consensus_raw = lnn.consensus.download_raw(host, port, flavor='unflavored') + self.consensus_raw = lnn.consensus.download_raw(host, port, flavor=Flavor.UNFLAVORED) digests = lnn.consensus.extract_nodes_digests_unflavored(self.consensus_raw) self.descriptors_raw = lnn.descriptors.download_raw_by_digests_unflavored(host, port, digests) self.signing_keys = lnn.keys.fetch_and_parse_keys(host, port, tls=False) #self.signing_keys_raw = get_raw_signing_keys('%s:%d'%(host, port)) - self.mic_consensus_raw = lnn.consensus.download_raw(host, port, flavor='microdesc') + self.mic_consensus_raw = lnn.consensus.download_raw(host, port, flavor=Flavor.MICRO) digests = lnn.consensus.extract_nodes_digests_micro(self.mic_consensus_raw) self.mic_descriptors_raw = lnn.descriptors.download_raw_by_digests_micro(host, port, digests) From e5b1529652580300f0be9b534f117109c5c938b7 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 28 Apr 2020 17:40:43 +0200 Subject: [PATCH 24/30] Add tests for consensus and descriptors parsing. --- data/consensus_micro_parsed.txt | 830 + data/consensus_micro_raw.txt | 102 + data/consensus_parsed.txt | 902 + data/consensus_raw.txt | 102 + data/consensus_tor_raw.txt | 42798 ++++++++++++++++++++++++++++ data/descriptors_micro_parsed.txt | 175 + data/descriptors_micro_raw.txt | 74 + data/descriptors_parsed.txt | 872 + data/descriptors_raw.txt | 411 + tests/test_consensus.py | 35 + tests/test_descriptors.py | 35 + 11 files changed, 46336 insertions(+) create mode 100644 data/consensus_micro_parsed.txt create mode 100644 data/consensus_micro_raw.txt create mode 100644 data/consensus_parsed.txt create mode 100644 data/consensus_raw.txt create mode 100644 data/consensus_tor_raw.txt create mode 100644 data/descriptors_micro_parsed.txt create mode 100644 data/descriptors_micro_raw.txt create mode 100644 data/descriptors_parsed.txt create mode 100644 data/descriptors_raw.txt create mode 100644 tests/test_consensus.py create mode 100644 tests/test_descriptors.py diff --git a/data/consensus_micro_parsed.txt b/data/consensus_micro_parsed.txt new file mode 100644 index 0000000..0a4d445 --- /dev/null +++ b/data/consensus_micro_parsed.txt @@ -0,0 +1,830 @@ +{ + "flavor": "microdesc", + "headers": { + "network-status-version": { + "version": 3, + "flavor": "microdesc" + }, + "vote-status": "consensus", + "consensus-method": 28, + "valid-after": { + "date": "2020-04-23", + "time": "13:03:50", + "stamp": 1587647030.0 + }, + "fresh-until": { + "date": "2020-04-23", + "time": "13:04:00", + "stamp": 1587647040.0 + }, + "valid-until": { + "date": "2020-04-23", + "time": "13:04:10", + "stamp": 1587647050.0 + }, + "voting-delay": { + "vote": 2, + "dist": 2 + }, + "client-versions": [ + "" + ], + "server-versions": [ + "" + ], + "known-flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "NoEdConsensus", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "recommended-client-protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 4 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 2 + ] + }, + "recommended-relay-protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 4 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 2 + ] + }, + "required-client-protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 4 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 2 + ] + }, + "required-relay-protocols": { + "Cons": [ + 1 + ], + "Desc": [ + 1 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 3, + 4 + ], + "Microdesc": [ + 1 + ], + "Relay": [ + 1, + 2 + ] + }, + "shared-rand-previous-value": { + "NumReveals": 3, + "Value": "/2QHWbKWQJqYTGxPECy7+ksGKqcM4Bx4qKx3YKaZXUI=" + }, + "shared-rand-current-value": { + "NumReveals": 3, + "Value": "LSYbvpu2yBi8Ie+qZhu/nSZ82ORbVGIJUeCK0axx1gY=" + } + }, + "dir-sources": [ + { + "nickname": "test002a", + "identity": "12b3f62ed02c9b54816cebb06c5e259189220513", + "hostname": "127.0.0.1", + "address": "127.0.0.1", + "dirport": 7002, + "orport": 5002, + "contact": "auth2@test.test", + "vote-digest": "b6b5b2b4609d7969f6c4e8c39ac58a006130bbee" + }, + { + "nickname": "test001a", + "identity": "7e0219bb5a355b76a8e8adb17c772827bdadcd73", + "hostname": "127.0.0.1", + "address": "127.0.0.1", + "dirport": 7001, + "orport": 5001, + "contact": "auth1@test.test", + "vote-digest": "c2d0973074f7fca6b73d29123a0304b94a38b7d7" + }, + { + "nickname": "test000a", + "identity": "e459cc388963fe0c47b0c5c918b1166d1809a2d9", + "hostname": "127.0.0.1", + "address": "127.0.0.1", + "dirport": 7000, + "orport": 5000, + "contact": "auth0@test.test", + "vote-digest": "f8b88af1f50b15da61c77266fe3e81809d53f830" + } + ], + "routers": [ + { + "nickname": "test006r", + "identity": "DZZkh3UlCcgcxHqUEb2HozksADc", + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0, + "address": "127.0.0.1", + "dirport": 7006, + "orport": 5006, + "micro-digest": "vsIfsfWipqVVIP/sPw71/GVuqFBACo8isd0QE5IHWRA", + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 189, + "Unmeasured": 1 + } + }, + { + "nickname": "test004r", + "identity": "PE+93pE5LeQheWR29bZjhX3zqnQ", + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0, + "address": "127.0.0.1", + "dirport": 7004, + "orport": 5004, + "micro-digest": "r5w5OtvIDxowqug0biGBmqR6Fm2D0lukwOdAS+3f0nI", + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 174, + "Unmeasured": 1 + } + }, + { + "nickname": "test000a", + "identity": "S7wZlq4DvwY/2ZA/WrIzydmmRoY", + "date": "2020-04-23", + "time": "13:03:19", + "stamp": 1587646999.0, + "address": "127.0.0.1", + "dirport": 7000, + "orport": 5000, + "micro-digest": "sOncg9KObIVQCj2qbmTa166mzTNuYLq/78NnH4j9Rpg", + "flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 224, + "Unmeasured": 1 + } + }, + { + "nickname": "test003r", + "identity": "fyG+MaPfsktC+PscyWbZlnKXHJ4", + "date": "2020-04-23", + "time": "13:03:17", + "stamp": 1587646997.0, + "address": "127.0.0.1", + "dirport": 7003, + "orport": 5003, + "micro-digest": "apfWPB1RoS+VCxl84H7LPEvhTzaZPJo4pDT5ykzNcVw", + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 177, + "Unmeasured": 1 + } + }, + { + "nickname": "test002a", + "identity": "gwTBYQWI3XQvsEkcal8NUySwsVA", + "date": "2020-04-23", + "time": "13:03:19", + "stamp": 1587646999.0, + "address": "127.0.0.1", + "dirport": 7002, + "orport": 5002, + "micro-digest": "AxdJywx2p8PyFnLrIz/sSuEzqysJaSgQIV8Ar+MtZAk", + "flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 237, + "Unmeasured": 1 + } + }, + { + "nickname": "test007r", + "identity": "mXQh1rmHcqj+uqptfh158WA5bfo", + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0, + "address": "127.0.0.1", + "dirport": 7007, + "orport": 5007, + "micro-digest": "hXFJseLWgaqAea7Hpd5cBfEbTTISuFv92sTBLOJY6Mg", + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 189, + "Unmeasured": 1 + } + }, + { + "nickname": "test005r", + "identity": "nu8OBtyhPu7L2+p0cdzQSZc5hbA", + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0, + "address": "127.0.0.1", + "dirport": 7005, + "orport": 5005, + "micro-digest": "/oBdxYE6dEsNEuhT+eCKq5LbsJhz/5aE/CQlHeYQqy0", + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 189, + "Unmeasured": 1 + } + }, + { + "nickname": "test001a", + "identity": "/Vd+YTRcdGVeZ7R61X23NSUf634", + "date": "2020-04-23", + "time": "13:03:19", + "stamp": 1587646999.0, + "address": "127.0.0.1", + "dirport": 7001, + "orport": 5001, + "micro-digest": "CgFLrWqo2d17GIiSmHkos8ptM6hAXZsPpahMNsgRtuc", + "flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 159, + "Unmeasured": 1 + } + } + ], + "footer": { + "bandwidth-weights": { + "Wbd": 3333, + "Wbe": 0, + "Wbg": 0, + "Wbm": 10000, + "Wdb": 10000, + "Web": 10000, + "Wed": 3333, + "Wee": 10000, + "Weg": 3333, + "Wem": 10000, + "Wgb": 10000, + "Wgd": 3333, + "Wgg": 10000, + "Wgm": 10000, + "Wmb": 10000, + "Wmd": 3333, + "Wme": 0, + "Wmg": 0, + "Wmm": 10000 + }, + "directory-signatures": [ + { + "Algorithm": "sha256", + "identity": "12B3F62ED02C9B54816CEBB06C5E259189220513", + "signing-key-digest": "448B8141FECA90994DCDBE11A21FDAF2AF53D082", + "signature": "hC6pKTEp6qvpt2rym232DKtlwE+Um2m4X0aht60tXGpKfF6bjuLL5wacZHQP0d9ektNIJ0dQxSxzpeSvfHQS6wr3ptWuqz7IRIpycjjmaHW8J8r4An2eSJIl9JoZE1pjOSVG/vNXtJrLCcZTtnU//+dQh8sRW2JYGgPGxkc5HKvHBLbMiZfj5kAraTMojIcq84ZxuYuenmOPWtbHfzuGYc8N9ubGvXZDIwHC54/9eGtgwZJqEg2zzzBNIaQgHpwebNW4IkMftf0S4RjZ1hVcO328wd3shlvLG/70prKyW0mTVIZU+8FbFfsIo0HR9bpD2CaWYNvNoToCFnwGiGSecw==" + }, + { + "Algorithm": "sha256", + "identity": "7E0219BB5A355B76A8E8ADB17C772827BDADCD73", + "signing-key-digest": "2CA39E7AFCFC6422A80BF43DCD43A73872F86B87", + "signature": "aJ8Fq3xkSzJbSTOMQ8G3Y1YaC8fnyQFlq1woGbmeRLUArbBWkQHdS7rjjYBXSO4BSSB4xnLYKvqMvqvjGQ3g0zNXPegxQRSk99tpWgDkfdKcQyZw/2+XvLuDmsOfp7SCSEri41OV4oij+8pSqBkw8fEo4aXHQ8hdIfd5XnjEzM2t211JEolUO8tQjZ3dwNR8eHwL+6GOJYeP7uC+wpT14eUHTz1ztg///9yJl8pE30mCMwElKz5esyf1VUibVjEzQB2/y9COWHEm1Hx3anTGtwWmMI3+Dd6fbRFqGlmDZ3uIggIWTA2/yDHLvKzEEnSIHKuz9WvPG/5dg472sR32fA==" + }, + { + "Algorithm": "sha256", + "identity": "E459CC388963FE0C47B0C5C918B1166D1809A2D9", + "signing-key-digest": "FE1C48EDCC9F526DC7C40211D409F86BFFF35F40", + "signature": "v9/hw0lOQiEn7nzPIQoLTJqSn9t1NyFvpDDsB0I4zBwR021zIR3jQhdR5A1T6IJOLudW1l++I8oGPAxTB9GWdtndp5WN7f8TIGEtVypckI4GfD0obtx13q/UdZGTAFbPpX5wD9KUq+C0+DbfUJiG4iR/46SAw9dgqK2OBecVyjmE/4aI+io+6Sxp8TAbeQY2wlDJpTsosZwsYnugB1wRdgtjHUT+K+hMaqua6dTc9F93nIbk6Um08NuxkmisxrJZxjYy/lXO9XpNx9nQu4vfwP3R+XgpTcEu9VF6iov04Q4PRt/rpjln7yjRjU0JSMomCyrWXSoF0SPReEdKeF/gOQ==" + } + ] + } +} diff --git a/data/consensus_micro_raw.txt b/data/consensus_micro_raw.txt new file mode 100644 index 0000000..a379427 --- /dev/null +++ b/data/consensus_micro_raw.txt @@ -0,0 +1,102 @@ +network-status-version 3 microdesc +vote-status consensus +consensus-method 28 +valid-after 2020-04-23 13:03:50 +fresh-until 2020-04-23 13:04:00 +valid-until 2020-04-23 13:04:10 +voting-delay 2 2 +client-versions +server-versions +known-flags Authority Exit Fast Guard HSDir NoEdConsensus Running Stable V2Dir Valid +recommended-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +recommended-relay-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +required-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +required-relay-protocols Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=3-4 Microdesc=1 Relay=1-2 +shared-rand-previous-value 3 /2QHWbKWQJqYTGxPECy7+ksGKqcM4Bx4qKx3YKaZXUI= +shared-rand-current-value 3 LSYbvpu2yBi8Ie+qZhu/nSZ82ORbVGIJUeCK0axx1gY= +dir-source test002a 12B3F62ED02C9B54816CEBB06C5E259189220513 127.0.0.1 127.0.0.1 7002 5002 +contact auth2@test.test +vote-digest B6B5B2B4609D7969F6C4E8C39AC58A006130BBEE +dir-source test001a 7E0219BB5A355B76A8E8ADB17C772827BDADCD73 127.0.0.1 127.0.0.1 7001 5001 +contact auth1@test.test +vote-digest C2D0973074F7FCA6B73D29123A0304B94A38B7D7 +dir-source test000a E459CC388963FE0C47B0C5C918B1166D1809A2D9 127.0.0.1 127.0.0.1 7000 5000 +contact auth0@test.test +vote-digest F8B88AF1F50B15DA61C77266FE3E81809D53F830 +r test006r DZZkh3UlCcgcxHqUEb2HozksADc 2020-04-23 13:03:18 127.0.0.1 5006 7006 +m vsIfsfWipqVVIP/sPw71/GVuqFBACo8isd0QE5IHWRA +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=189 Unmeasured=1 +r test004r PE+93pE5LeQheWR29bZjhX3zqnQ 2020-04-23 13:03:18 127.0.0.1 5004 7004 +m r5w5OtvIDxowqug0biGBmqR6Fm2D0lukwOdAS+3f0nI +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=174 Unmeasured=1 +r test000a S7wZlq4DvwY/2ZA/WrIzydmmRoY 2020-04-23 13:03:19 127.0.0.1 5000 7000 +m sOncg9KObIVQCj2qbmTa166mzTNuYLq/78NnH4j9Rpg +s Authority Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=224 Unmeasured=1 +r test003r fyG+MaPfsktC+PscyWbZlnKXHJ4 2020-04-23 13:03:17 127.0.0.1 5003 7003 +m apfWPB1RoS+VCxl84H7LPEvhTzaZPJo4pDT5ykzNcVw +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=177 Unmeasured=1 +r test002a gwTBYQWI3XQvsEkcal8NUySwsVA 2020-04-23 13:03:19 127.0.0.1 5002 7002 +m AxdJywx2p8PyFnLrIz/sSuEzqysJaSgQIV8Ar+MtZAk +s Authority Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=237 Unmeasured=1 +r test007r mXQh1rmHcqj+uqptfh158WA5bfo 2020-04-23 13:03:18 127.0.0.1 5007 7007 +m hXFJseLWgaqAea7Hpd5cBfEbTTISuFv92sTBLOJY6Mg +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=189 Unmeasured=1 +r test005r nu8OBtyhPu7L2+p0cdzQSZc5hbA 2020-04-23 13:03:18 127.0.0.1 5005 7005 +m /oBdxYE6dEsNEuhT+eCKq5LbsJhz/5aE/CQlHeYQqy0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=189 Unmeasured=1 +r test001a /Vd+YTRcdGVeZ7R61X23NSUf634 2020-04-23 13:03:19 127.0.0.1 5001 7001 +m CgFLrWqo2d17GIiSmHkos8ptM6hAXZsPpahMNsgRtuc +s Authority Exit Fast Guard HSDir Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=159 Unmeasured=1 +directory-footer +bandwidth-weights Wbd=3333 Wbe=0 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=3333 Wee=10000 Weg=3333 Wem=10000 Wgb=10000 Wgd=3333 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=3333 Wme=0 Wmg=0 Wmm=10000 +directory-signature sha256 12B3F62ED02C9B54816CEBB06C5E259189220513 448B8141FECA90994DCDBE11A21FDAF2AF53D082 +-----BEGIN SIGNATURE----- +hC6pKTEp6qvpt2rym232DKtlwE+Um2m4X0aht60tXGpKfF6bjuLL5wacZHQP0d9e +ktNIJ0dQxSxzpeSvfHQS6wr3ptWuqz7IRIpycjjmaHW8J8r4An2eSJIl9JoZE1pj +OSVG/vNXtJrLCcZTtnU//+dQh8sRW2JYGgPGxkc5HKvHBLbMiZfj5kAraTMojIcq +84ZxuYuenmOPWtbHfzuGYc8N9ubGvXZDIwHC54/9eGtgwZJqEg2zzzBNIaQgHpwe +bNW4IkMftf0S4RjZ1hVcO328wd3shlvLG/70prKyW0mTVIZU+8FbFfsIo0HR9bpD +2CaWYNvNoToCFnwGiGSecw== +-----END SIGNATURE----- +directory-signature sha256 7E0219BB5A355B76A8E8ADB17C772827BDADCD73 2CA39E7AFCFC6422A80BF43DCD43A73872F86B87 +-----BEGIN SIGNATURE----- +aJ8Fq3xkSzJbSTOMQ8G3Y1YaC8fnyQFlq1woGbmeRLUArbBWkQHdS7rjjYBXSO4B +SSB4xnLYKvqMvqvjGQ3g0zNXPegxQRSk99tpWgDkfdKcQyZw/2+XvLuDmsOfp7SC +SEri41OV4oij+8pSqBkw8fEo4aXHQ8hdIfd5XnjEzM2t211JEolUO8tQjZ3dwNR8 +eHwL+6GOJYeP7uC+wpT14eUHTz1ztg///9yJl8pE30mCMwElKz5esyf1VUibVjEz +QB2/y9COWHEm1Hx3anTGtwWmMI3+Dd6fbRFqGlmDZ3uIggIWTA2/yDHLvKzEEnSI +HKuz9WvPG/5dg472sR32fA== +-----END SIGNATURE----- +directory-signature sha256 E459CC388963FE0C47B0C5C918B1166D1809A2D9 FE1C48EDCC9F526DC7C40211D409F86BFFF35F40 +-----BEGIN SIGNATURE----- +v9/hw0lOQiEn7nzPIQoLTJqSn9t1NyFvpDDsB0I4zBwR021zIR3jQhdR5A1T6IJO +LudW1l++I8oGPAxTB9GWdtndp5WN7f8TIGEtVypckI4GfD0obtx13q/UdZGTAFbP +pX5wD9KUq+C0+DbfUJiG4iR/46SAw9dgqK2OBecVyjmE/4aI+io+6Sxp8TAbeQY2 +wlDJpTsosZwsYnugB1wRdgtjHUT+K+hMaqua6dTc9F93nIbk6Um08NuxkmisxrJZ +xjYy/lXO9XpNx9nQu4vfwP3R+XgpTcEu9VF6iov04Q4PRt/rpjln7yjRjU0JSMom +CyrWXSoF0SPReEdKeF/gOQ== +-----END SIGNATURE----- diff --git a/data/consensus_parsed.txt b/data/consensus_parsed.txt new file mode 100644 index 0000000..0f645da --- /dev/null +++ b/data/consensus_parsed.txt @@ -0,0 +1,902 @@ +{ + "flavor": "unflavored", + "headers": { + "network-status-version": { + "version": 3, + "flavor": "unflavored" + }, + "vote-status": "consensus", + "consensus-method": 28, + "valid-after": { + "date": "2020-04-20", + "time": "07:36:50", + "stamp": 1587368210.0 + }, + "fresh-until": { + "date": "2020-04-20", + "time": "07:37:00", + "stamp": 1587368220.0 + }, + "valid-until": { + "date": "2020-04-20", + "time": "07:37:10", + "stamp": 1587368230.0 + }, + "voting-delay": { + "vote": 2, + "dist": 2 + }, + "client-versions": [ + "" + ], + "server-versions": [ + "" + ], + "known-flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "NoEdConsensus", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "recommended-client-protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 4 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 2 + ] + }, + "recommended-relay-protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 4 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 2 + ] + }, + "required-client-protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 4 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 2 + ] + }, + "required-relay-protocols": { + "Cons": [ + 1 + ], + "Desc": [ + 1 + ], + "DirCache": [ + 1 + ], + "HSDir": [ + 1 + ], + "HSIntro": [ + 3 + ], + "HSRend": [ + 1 + ], + "Link": [ + 3, + 4 + ], + "Microdesc": [ + 1 + ], + "Relay": [ + 1, + 2 + ] + }, + "shared-rand-previous-value": { + "NumReveals": 0, + "Value": "zxJao+gBmFMSezvz/VXkEWEQJD5b/z+7AXNCGoLFVW0=" + }, + "shared-rand-current-value": { + "NumReveals": 3, + "Value": "JmISyTQqJVDEYu65+XigBGZEoYdqlimCxnCBPquIcyc=" + } + }, + "dir-sources": [ + { + "nickname": "test002a", + "identity": "12b3f62ed02c9b54816cebb06c5e259189220513", + "hostname": "127.0.0.1", + "address": "127.0.0.1", + "dirport": 7002, + "orport": 5002, + "contact": "auth2@test.test", + "vote-digest": "c8c30c2f2462c7b5a232c4bd8e6e39df96ce6866" + }, + { + "nickname": "test001a", + "identity": "7e0219bb5a355b76a8e8adb17c772827bdadcd73", + "hostname": "127.0.0.1", + "address": "127.0.0.1", + "dirport": 7001, + "orport": 5001, + "contact": "auth1@test.test", + "vote-digest": "c97ec7a96a76ed366e5a30e49b5a8dabf4832f65" + }, + { + "nickname": "test000a", + "identity": "e459cc388963fe0c47b0c5c918b1166d1809a2d9", + "hostname": "127.0.0.1", + "address": "127.0.0.1", + "dirport": 7000, + "orport": 5000, + "contact": "auth0@test.test", + "vote-digest": "4eed924194cb5cc07fc7c450dfd98e30501161da" + } + ], + "routers": [ + { + "nickname": "test006r", + "identity": "DZZkh3UlCcgcxHqUEb2HozksADc", + "digest": "GW9HZ7kDARgbH8u31orhQDSS7+Y", + "date": "2020-04-20", + "time": "07:19:59", + "stamp": 1587367199.0, + "address": "127.0.0.1", + "dirport": 7006, + "orport": 5006, + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 189, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + }, + { + "nickname": "test004r", + "identity": "PE+93pE5LeQheWR29bZjhX3zqnQ", + "digest": "EtQKag0fzSSrarsZB0ZBbxGF7HA", + "date": "2020-04-20", + "time": "07:19:59", + "stamp": 1587367199.0, + "address": "127.0.0.1", + "dirport": 7004, + "orport": 5004, + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 174, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + }, + { + "nickname": "test000a", + "identity": "S7wZlq4DvwY/2ZA/WrIzydmmRoY", + "digest": "9UyBqUF6SN3HC5/i8QiTOG9nx0s", + "date": "2020-04-20", + "time": "07:31:01", + "stamp": 1587367861.0, + "address": "127.0.0.1", + "dirport": 7000, + "orport": 5000, + "flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 158, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "reject", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + }, + { + "nickname": "test003r", + "identity": "fyG+MaPfsktC+PscyWbZlnKXHJ4", + "digest": "xVYLJ490kxGxfbNn2Hvl/GpZJEM", + "date": "2020-04-20", + "time": "07:20:14", + "stamp": 1587367214.0, + "address": "127.0.0.1", + "dirport": 7003, + "orport": 5003, + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 177, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + }, + { + "nickname": "test002a", + "identity": "gwTBYQWI3XQvsEkcal8NUySwsVA", + "digest": "whpdrDjr77zJ6vpAp5HS+oNqeRQ", + "date": "2020-04-20", + "time": "07:31:01", + "stamp": 1587367861.0, + "address": "127.0.0.1", + "dirport": 7002, + "orport": 5002, + "flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 196, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "reject", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + }, + { + "nickname": "test007r", + "identity": "mXQh1rmHcqj+uqptfh158WA5bfo", + "digest": "VktXjhSji1mCsT/W/gBU9NvbYNk", + "date": "2020-04-20", + "time": "07:19:59", + "stamp": 1587367199.0, + "address": "127.0.0.1", + "dirport": 7007, + "orport": 5007, + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 189, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + }, + { + "nickname": "test005r", + "identity": "nu8OBtyhPu7L2+p0cdzQSZc5hbA", + "digest": "WQh2419G+nKtY0p6V8hmN3rS6fg", + "date": "2020-04-20", + "time": "07:20:22", + "stamp": 1587367222.0, + "address": "127.0.0.1", + "dirport": 7005, + "orport": 5005, + "flags": [ + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "Stable", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 189, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + }, + { + "nickname": "test001a", + "identity": "/Vd+YTRcdGVeZ7R61X23NSUf634", + "digest": "feX6QJWeiqOrPQweuMffQWuY3K8", + "date": "2020-04-20", + "time": "07:31:02", + "stamp": 1587367862.0, + "address": "127.0.0.1", + "dirport": 7001, + "orport": 5001, + "flags": [ + "Authority", + "Exit", + "Fast", + "Guard", + "HSDir", + "Running", + "V2Dir", + "Valid" + ], + "version": "Tor 0.3.5.10", + "protocols": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "w": { + "Bandwidth": 188, + "Unmeasured": 1 + }, + "exit-policy": { + "type": "reject", + "PortList": [ + [ + 1, + 65535 + ] + ] + } + } + ], + "footer": { + "bandwidth-weights": { + "Wbd": 3333, + "Wbe": 0, + "Wbg": 0, + "Wbm": 10000, + "Wdb": 10000, + "Web": 10000, + "Wed": 3333, + "Wee": 10000, + "Weg": 3333, + "Wem": 10000, + "Wgb": 10000, + "Wgd": 3333, + "Wgg": 10000, + "Wgm": 10000, + "Wmb": 10000, + "Wmd": 3333, + "Wme": 0, + "Wmg": 0, + "Wmm": 10000 + }, + "directory-signatures": [ + { + "Algorithm": "sha1", + "identity": "12B3F62ED02C9B54816CEBB06C5E259189220513", + "signing-key-digest": "448B8141FECA90994DCDBE11A21FDAF2AF53D082", + "signature": "aO5pbIg66t2w/jWgbZmhWrxuHIhv8Rae++ybBVWRtTTHZYdUUMgtfqQA9Cro/9qgeNHtZNBePapP6EWhQBKYzZxHEaRjhHJGlTYeJq1q2IxI3x6vSvabupLOnl3e++EPn0LR9IVUII1LmhsKp84ZpsbOuF8XoT1PfDsfcNhW898DmTGNuJ+R9P+rNOAvkKctAOjAYeNjiL4UH64iqOyA7MshB/oS1gmmmYhg5fBHhE8J24NNAcN32VEDoChwYYFHSj0uJiOv4vD09hHQxTimadEwNCl38hMbd/yLhBmlBi6jAKIAP71EJuaO3UkuK7DkQFj91kNmdyGYF9uIsxJ3iQ==" + }, + { + "Algorithm": "sha1", + "identity": "7E0219BB5A355B76A8E8ADB17C772827BDADCD73", + "signing-key-digest": "2CA39E7AFCFC6422A80BF43DCD43A73872F86B87", + "signature": "RWntGwBx/PUCkQChhrA41rPxfio6nel3nB4+7+3uQWOSm7HT60m5DN22ryQ14Qqsz0l/RK4GCwc1pXUBZvPnJ4wzW5ORcjgNaMi6KbRS6q+z0KT7yY+zF3cacY2GlBNVTWIV3FfggQth1AFTQRkHdOIW4ifQwQpernjozE08I/O3rlP19xtxpN06DqfpteSjFQhD+5xiSIclgkURCInVHCpbBl/KdGs/4LZ2JVciABDeYr3xpAcPYJ6u9CdFf5iAWFcsMO/oZ+9zmwj0qfqkEJhdHU4RX1DnECWWnBJU7wbAkGcagATEE/4aDRLdZSOktYFEJmyjbXuSI3r0B7uGwg==" + }, + { + "Algorithm": "sha1", + "identity": "E459CC388963FE0C47B0C5C918B1166D1809A2D9", + "signing-key-digest": "FE1C48EDCC9F526DC7C40211D409F86BFFF35F40", + "signature": "xUNpvtVSHnrwRMCYLUvjkN3kp0kmX3oxzEAcBXbcpYzdn757U5QefVBkq9ZC+6RsWHYE4tHsC5x2KW+GN1wnBkYyrTxSG1fG46sKpEYYSnEuCVa2nJpwMEl/EzsRT+20eZXIjj+FLKIrMrKV23k/LgbkN2fnvUpwGkWV7/RJ6a9MHGjWA/nO3hmNlF0mPLx+t3Z0Cao3PdiNOW/xVnQ6PKW1J3U4pWEe6DoQNzhSI+wYIF/kx2qv7K7fbPZ1RqUC5shNX2IZDkFcqVq1HoHpfzyLFaMY+JjWvUneQWucvMJOuLENCMLr79/elT23h2sHr3vPTIatzhTwSKXWLe92Yg==" + } + ] + } +} \ No newline at end of file diff --git a/data/consensus_raw.txt b/data/consensus_raw.txt new file mode 100644 index 0000000..70023d5 --- /dev/null +++ b/data/consensus_raw.txt @@ -0,0 +1,102 @@ +network-status-version 3 +vote-status consensus +consensus-method 28 +valid-after 2020-04-20 07:36:50 +fresh-until 2020-04-20 07:37:00 +valid-until 2020-04-20 07:37:10 +voting-delay 2 2 +client-versions +server-versions +known-flags Authority Exit Fast Guard HSDir NoEdConsensus Running Stable V2Dir Valid +recommended-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +recommended-relay-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +required-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +required-relay-protocols Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=3-4 Microdesc=1 Relay=1-2 +shared-rand-previous-value 0 zxJao+gBmFMSezvz/VXkEWEQJD5b/z+7AXNCGoLFVW0= +shared-rand-current-value 3 JmISyTQqJVDEYu65+XigBGZEoYdqlimCxnCBPquIcyc= +dir-source test002a 12B3F62ED02C9B54816CEBB06C5E259189220513 127.0.0.1 127.0.0.1 7002 5002 +contact auth2@test.test +vote-digest C8C30C2F2462C7B5A232C4BD8E6E39DF96CE6866 +dir-source test001a 7E0219BB5A355B76A8E8ADB17C772827BDADCD73 127.0.0.1 127.0.0.1 7001 5001 +contact auth1@test.test +vote-digest C97EC7A96A76ED366E5A30E49B5A8DABF4832F65 +dir-source test000a E459CC388963FE0C47B0C5C918B1166D1809A2D9 127.0.0.1 127.0.0.1 7000 5000 +contact auth0@test.test +vote-digest 4EED924194CB5CC07FC7C450DFD98E30501161DA +r test006r DZZkh3UlCcgcxHqUEb2HozksADc GW9HZ7kDARgbH8u31orhQDSS7+Y 2020-04-20 07:19:59 127.0.0.1 5006 7006 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=189 Unmeasured=1 +p accept 1-65535 +r test004r PE+93pE5LeQheWR29bZjhX3zqnQ EtQKag0fzSSrarsZB0ZBbxGF7HA 2020-04-20 07:19:59 127.0.0.1 5004 7004 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=174 Unmeasured=1 +p accept 1-65535 +r test000a S7wZlq4DvwY/2ZA/WrIzydmmRoY 9UyBqUF6SN3HC5/i8QiTOG9nx0s 2020-04-20 07:31:01 127.0.0.1 5000 7000 +s Authority Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=158 Unmeasured=1 +p reject 1-65535 +r test003r fyG+MaPfsktC+PscyWbZlnKXHJ4 xVYLJ490kxGxfbNn2Hvl/GpZJEM 2020-04-20 07:20:14 127.0.0.1 5003 7003 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=177 Unmeasured=1 +p accept 1-65535 +r test002a gwTBYQWI3XQvsEkcal8NUySwsVA whpdrDjr77zJ6vpAp5HS+oNqeRQ 2020-04-20 07:31:01 127.0.0.1 5002 7002 +s Authority Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=196 Unmeasured=1 +p reject 1-65535 +r test007r mXQh1rmHcqj+uqptfh158WA5bfo VktXjhSji1mCsT/W/gBU9NvbYNk 2020-04-20 07:19:59 127.0.0.1 5007 7007 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=189 Unmeasured=1 +p accept 1-65535 +r test005r nu8OBtyhPu7L2+p0cdzQSZc5hbA WQh2419G+nKtY0p6V8hmN3rS6fg 2020-04-20 07:20:22 127.0.0.1 5005 7005 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=189 Unmeasured=1 +p accept 1-65535 +r test001a /Vd+YTRcdGVeZ7R61X23NSUf634 feX6QJWeiqOrPQweuMffQWuY3K8 2020-04-20 07:31:02 127.0.0.1 5001 7001 +s Authority Exit Fast Guard HSDir Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=188 Unmeasured=1 +p reject 1-65535 +directory-footer +bandwidth-weights Wbd=3333 Wbe=0 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=3333 Wee=10000 Weg=3333 Wem=10000 Wgb=10000 Wgd=3333 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=3333 Wme=0 Wmg=0 Wmm=10000 +directory-signature 12B3F62ED02C9B54816CEBB06C5E259189220513 448B8141FECA90994DCDBE11A21FDAF2AF53D082 +-----BEGIN SIGNATURE----- +aO5pbIg66t2w/jWgbZmhWrxuHIhv8Rae++ybBVWRtTTHZYdUUMgtfqQA9Cro/9qg +eNHtZNBePapP6EWhQBKYzZxHEaRjhHJGlTYeJq1q2IxI3x6vSvabupLOnl3e++EP +n0LR9IVUII1LmhsKp84ZpsbOuF8XoT1PfDsfcNhW898DmTGNuJ+R9P+rNOAvkKct +AOjAYeNjiL4UH64iqOyA7MshB/oS1gmmmYhg5fBHhE8J24NNAcN32VEDoChwYYFH +Sj0uJiOv4vD09hHQxTimadEwNCl38hMbd/yLhBmlBi6jAKIAP71EJuaO3UkuK7Dk +QFj91kNmdyGYF9uIsxJ3iQ== +-----END SIGNATURE----- +directory-signature 7E0219BB5A355B76A8E8ADB17C772827BDADCD73 2CA39E7AFCFC6422A80BF43DCD43A73872F86B87 +-----BEGIN SIGNATURE----- +RWntGwBx/PUCkQChhrA41rPxfio6nel3nB4+7+3uQWOSm7HT60m5DN22ryQ14Qqs +z0l/RK4GCwc1pXUBZvPnJ4wzW5ORcjgNaMi6KbRS6q+z0KT7yY+zF3cacY2GlBNV +TWIV3FfggQth1AFTQRkHdOIW4ifQwQpernjozE08I/O3rlP19xtxpN06DqfpteSj +FQhD+5xiSIclgkURCInVHCpbBl/KdGs/4LZ2JVciABDeYr3xpAcPYJ6u9CdFf5iA +WFcsMO/oZ+9zmwj0qfqkEJhdHU4RX1DnECWWnBJU7wbAkGcagATEE/4aDRLdZSOk +tYFEJmyjbXuSI3r0B7uGwg== +-----END SIGNATURE----- +directory-signature E459CC388963FE0C47B0C5C918B1166D1809A2D9 FE1C48EDCC9F526DC7C40211D409F86BFFF35F40 +-----BEGIN SIGNATURE----- +xUNpvtVSHnrwRMCYLUvjkN3kp0kmX3oxzEAcBXbcpYzdn757U5QefVBkq9ZC+6Rs +WHYE4tHsC5x2KW+GN1wnBkYyrTxSG1fG46sKpEYYSnEuCVa2nJpwMEl/EzsRT+20 +eZXIjj+FLKIrMrKV23k/LgbkN2fnvUpwGkWV7/RJ6a9MHGjWA/nO3hmNlF0mPLx+ +t3Z0Cao3PdiNOW/xVnQ6PKW1J3U4pWEe6DoQNzhSI+wYIF/kx2qv7K7fbPZ1RqUC +5shNX2IZDkFcqVq1HoHpfzyLFaMY+JjWvUneQWucvMJOuLENCMLr79/elT23h2sH +r3vPTIatzhTwSKXWLe92Yg== +-----END SIGNATURE----- diff --git a/data/consensus_tor_raw.txt b/data/consensus_tor_raw.txt new file mode 100644 index 0000000..0a2e467 --- /dev/null +++ b/data/consensus_tor_raw.txt @@ -0,0 +1,42798 @@ +network-status-version 3 +vote-status consensus +consensus-method 29 +valid-after 2020-04-20 13:00:00 +fresh-until 2020-04-20 14:00:00 +valid-until 2020-04-20 16:00:00 +voting-delay 300 300 +client-versions 0.3.5.10,0.4.1.9,0.4.2.7,0.4.3.3-alpha,0.4.3.4-rc +server-versions 0.3.5.10,0.4.1.9,0.4.2.7,0.4.3.3-alpha,0.4.3.4-rc +known-flags Authority BadExit Exit Fast Guard HSDir NoEdConsensus Running Stable StaleDesc V2Dir Valid +recommended-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +recommended-relay-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +required-client-protocols Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=4 Microdesc=1-2 Relay=2 +required-relay-protocols Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=3-4 Microdesc=1 Relay=1-2 +params CircuitPriorityHalflifeMsec=30000 DoSCircuitCreationEnabled=1 DoSConnectionEnabled=1 DoSConnectionMaxConcurrentCount=50 DoSRefuseSingleHopClientRendezvous=1 NumDirectoryGuards=3 NumEntryGuards=1 NumNTorsPerTAP=100 Support022HiddenServices=0 UseNTorHandshake=1 UseOptimisticData=1 bwauthpid=1 cbttestfreq=10 hs_service_max_rdv_failures=1 hsdir_spread_store=4 pb_disablepct=0 sendme_emit_min_version=1 usecreatefast=0 +shared-rand-previous-value 9 qbQW58n0WTEkJNnM+gaaHe3GSSqUhiak4xIPCSADVps= +shared-rand-current-value 9 Vi5Qj732znJb4S0+3Z1Oet7+8buAGgi2Hz1LU9w8osM= +dir-source dannenberg 0232AF901C31A04EE9848595AF9BB7620D4C5B2E dannenberg.torauth.de 193.23.244.244 80 443 +contact Andreas Lehner +vote-digest 0656EAA70E9A2E20488D83DF3B777605AD322F14 +dir-source tor26 14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 86.59.21.38 86.59.21.38 80 443 +contact Peter Palfrader +vote-digest A032CB60EA5496DF5A1DCA02B2092739C9716C40 +dir-source longclaw 23D15D965BC35114467363C165C4F724B64B4F66 199.58.81.140 199.58.81.140 80 443 +contact Riseup Networks - 1nNzekuHGGzBYRzyjfjFEfeisNvxkn4RT +vote-digest C7D9E80F7CCD2B776626961E4F2AB21031359B07 +dir-source bastet 27102BC123E7AF1D4741AE047E160C91ADC76B21 204.13.164.118 204.13.164.118 80 443 +contact stefani 4096/F4B863AD6642E7EE +vote-digest 8485EBB33C29FDBB72F5C29AE92E99B21F1C6851 +dir-source maatuska 49015F787433103580E3B66A1707A00E60F2D15B 171.25.193.9 171.25.193.9 443 80 +contact 4096R/1E8BF34923291265 Linus Nordberg +vote-digest 967314BB3FE328964DAA267A00F1252A270C33E3 +dir-source moria1 D586D18309DED4CD6D57C18FDB97EFA96D330566 128.31.0.34 128.31.0.34 9131 9101 +contact 1024D/EB5A896A28988BF5 arma mit edu +vote-digest 686EDD65CA868C6D57A91EA428B30BA4458148F6 +dir-source dizum E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 45.66.33.45 45.66.33.45 80 443 +contact FD790065EBBD5E7AE6D039620D7F81CD19147711 Alex de Joode +vote-digest A38BC0B846CA0D5FA78A368A5495F68807BF1185 +dir-source gabelmoo ED03BB616EB2F60BEC80151114BB25CEF515B226 131.188.40.189 131.188.40.189 80 443 +contact 4096R/261C5FBE77285F88FB0C343266C8C2D7C5AA446D Sebastian Hahn - 12NbRAjAG5U3LLWETSF7fSTcdaz32Mu5CN +vote-digest 84A637BD62F9332361A0224861358A86A114CA16 +dir-source Faravahar EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 154.35.175.225 154.35.175.225 80 443 +contact 0x0B47D56D Sina Rabbani (inf0) +vote-digest E0FCC50340E79C95110284A8BD964FC799D419F5 +r reb00z AALMVwXahU5Odx8kCjhVZ/SjwT0 N18wbjN5Y6cr4Uq8uduK55Llfc4 2020-04-20 00:03:33 155.4.197.206 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3540 +p reject 1-65535 +r flageolet AAbeLnfjw+xeGCWwduUlf9IA7Qo 11fG9LpcmEL2b8fTNR4TLE+7bb8 2020-04-20 12:31:54 80.195.122.166 9090 9091 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r seele AAoQ1DAR6kkoo19hBAX5K0QztNw gu9JvDty7FJfMNkl/XpbaxULDr0 2020-04-20 04:53:45 67.174.243.193 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11 +p reject 1-65535 +r CalyxInstitute14 ABG9JIWtRdmE7EFZyI/AZuXjMA4 Vbihh2uENnISy65JDoTxy0jAQng 2020-04-20 04:26:24 162.247.74.201 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r 220VoltLive2 ABLiyQZzB7zWByF5wzs1Zl7MiCg HAmB8AYQUNIuU2+8QrtnWPDV/JI 2020-04-20 07:15:35 110.32.66.193 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=87 +p reject 1-65535 +r rotor25 ADQsDhVdRULlU5F4iy13nxRXjes WLicS0kjzs4bP+NfBvNb85Hvva0 2020-04-20 06:46:12 188.24.21.252 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3220 +p reject 1-65535 +r snap277 ADrjDGn2XsOdanMwLGUYewf2meY fRJWcovsMex0vnKuoXE1eY2F5Oo 2020-04-20 10:44:12 86.121.99.26 42351 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=187 +p reject 1-65535 +r ChapmanShoop ADvp/o0hvaKwH8l4unbdLUxHXt4 498oqpEt898B84ZWvA4LfqLKYLw 2020-04-19 22:02:59 157.245.189.45 443 80 +a [2604:a880:2:d1::173:b001]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8000 +p accept 53,80,443 +r xX0seamus0Xx ADv6G2zFy+/V0Agvj8mvKohoqPs JKuK0LnZZxyXZaFmPpo7on4RoJM 2020-04-20 01:03:13 188.214.132.49 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=45100 +p reject 1-65535 +r VSIFskylab AD14gl4Llgnuz/Xk4FKXF3cuU8c TSEvjjg9Nx/UchzU2/W7HvSVBps 2020-04-20 06:01:49 104.218.63.73 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6830 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r suspicioussytems AEHYeZkN7D0yZoi1fO7LLu6saII vGfBfbNtsne8u7BZlUEMwXALNhk 2020-04-20 10:35:29 5.9.142.238 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1680 +p reject 1-65535 +r helga AFnZKULbO4TlLrTYfp97GVz00AU wGQJPY5dwjyFokF/o20VEBC40Ic 2020-04-20 01:09:16 88.99.216.194 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r Athena AF7ZchP3JYZ+QiuNwEQzYbuyTjw dWF3Pk8mEdwWE5GwBbJIv6H24bA 2020-04-20 06:51:18 104.244.79.75 443 9030 +a [2605:6400:30:fb10:d07b:edfd:2c84:bb4a]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p reject 1-65535 +r comeandgo AHI68cQFJheb/uqxVQQ7V7zZwaw fOgifKkwVB5uFCGry0eFho6zipg 2020-04-20 04:20:16 61.239.100.129 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=502 +p reject 1-65535 +r Quintex13 AHe8unJE2z5qXtJ0boYXAGZoSIc CWymgAaFhAmIcFBEJ5IFEyaudVQ 2020-04-20 11:49:41 199.249.230.103 443 80 +a [2620:7:6001::103]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15100 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Relay5000 AIUFfBe9LhgJ4oSCXwb5TnL7QYw F9uVkEeexoY4zrBs6Ru4rFr9vmk 2020-04-20 08:29:23 148.251.75.247 4080 8000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=112000 +p reject 1-65535 +r Unnamed AIZhsnCbMuM50PlGGaN8536SNNc hf0XLYruzdUg3bebUKxoCDqR4fc 2020-04-20 12:35:28 167.114.92.56 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r baryon AJV5LMAHWPJFeVVWyVfCCj/34b4 JYxpHFkg/HhsQ3xN35+8GA6MQh0 2020-04-19 20:47:12 46.101.220.117 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=800 +p reject 1-65535 +r BlackBeluga AJYtLdC5vzpq8dXrIBEyOIrKFCQ PUR8+UvpL8Q92YnVqi6xS4wbWJw 2020-04-20 04:28:57 5.189.155.39 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=860 +p reject 1-65535 +r jactr AJhR35M3VLAN3odvzkCIzhtJQME E6r9F/hulmsCVjMG89MjDe6St+o 2020-04-19 23:08:14 84.40.112.70 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r snap277 AKqQFKpuORffpFGfRYCS8ZlGa0k ai7D0pUP2ncMZSWR6HF0IRww54I 2020-04-20 10:09:00 85.86.11.32 41507 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2000 +p reject 1-65535 +r mharelay ALV79hT37TBRBztdRSb/CyOvIXs 9DbptG/Znu1WksdUrOLJT4FqTHA 2020-04-19 21:42:24 158.174.145.139 9001 0 +a [2001:9b1:403c::1337]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28000 +p reject 1-65535 +r king ALxxozgJn5o4fDvzFKW9T7SKb7k IGpoOkwB+U73WZD3seAycO+silI 2020-04-20 05:51:44 51.89.213.81 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r effiorg1984 AMzmqE5tY6GkLhBYObyO1dSxZmk jaC/3iANjQJHS3S6E2JAJZKH1Fg 2020-04-19 23:06:38 89.236.112.100 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9730 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r dragonhoard AOFknmn/kdfwHnSl5i7xT32ZFeQ AFsk4kRB5s6XEtXg+Qref9cSgQs 2020-04-19 19:25:33 116.203.50.182 8080 8008 +a [2a01:4f8:1c1c:b16b::1]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r SemTempoIrmao AOid3vlEtC/WUvgMJIDV4g3xMZQ K9AVke41ewKV9RXtM9kDjgDsrP4 2020-04-20 07:23:02 193.234.225.67 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10600 +p reject 1-65535 +r king AO1a+PIkGzmbZniZOlhenJagvtE 3zKAHrZeZKJyv6Gsv+xMCW5Wz2g 2020-04-20 05:02:54 51.89.147.71 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7750 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MYLEXr2 AQt3KEVEEfSFzinUx5oUU0FRwsQ xB6lYgip3YH+TwJn3uhBHX9oKSA 2020-04-20 05:54:40 77.123.42.148 446 801 +a [2001:470:1f15:325:f66d:4ff:fee7:954c]:446 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1860 +p reject 1-65535 +r DigiGesTor1e1 ARG6m2BGaeY2/9W1A/OCpLetboA kR2xwbg6bn+EnctOm8cphEHuAqM 2020-04-20 00:17:35 176.10.104.240 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r motauri ARgbMb5YYMfWbaiPiK1SLAZHD9k S9TwH5N8XWWcN74MEq/16BQUkvU 2020-04-19 23:14:24 95.143.193.125 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=410 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5000-5750,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Bingamon ARodfXiXW7/Th67MOrbZXRgZlE8 p1qRFT+e3McbV3mSdaxR0K8VrLI 2020-04-20 04:13:04 103.70.57.184 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=153 +p reject 1-65535 +r biochemistmoscow ASgRXsTMNXheAF8L8v7ffs3E8Ds 2m0lWnUIZ67S9I5TBo70COlgVC0 2020-04-20 03:15:57 188.32.168.141 12630 12631 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1850 +p reject 1-65535 +r bang1 ATZpawJaxVA4R9c2/p89ZesnpZY dHXkVK7fr4smAxrTIt41wicyVWQ 2020-04-20 01:06:19 134.209.159.74 443 80 +a [2400:6180:100:d0::8bb:6001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=933 +p reject 1-65535 +r insist AUvQljY3O3jMKLpw42xxkOPeI2o C5Dp8xHBS/qM2sJ2s3O0loevl3M 2020-04-20 07:53:12 193.183.210.46 993 992 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18300 +p reject 1-65535 +r 8ac97a37 AU4kwM0h0rmCnoQdXsHTxBX4Zr8 L5YB2nAV1jA1yXmYPVpEvrCxqxE 2020-04-20 04:41:35 138.201.122.55 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=138000 +p reject 1-65535 +r marsmellow AU7iS8vaFg8jayVHpGObJ+MDoec lCTRGBjGpyLXu97lIRIU5wstLgQ 2020-04-20 04:45:50 62.251.89.74 9001 0 +a [2001:985:a751:1:428d:5cff:fe5f:7f92]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=254 +p reject 1-65535 +r Minducus AVGMBBeEPpcJsVs7AEvINM3mepI LLpz7T8m2fedu98CB1QrOXteNq8 2020-04-20 00:00:00 204.228.147.42 9001 0 +s Fast Running Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=371 +p reject 1-65535 +r Unnamed AVlYgY+gHPk36j9m/LgT2LOEDts 9bRJeI4PKP/RtsQtXMIkHc4Bm/U 2020-04-20 11:57:59 205.185.116.89 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4040 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r d0dak AWCT7kuumvRz/AyBGp0Q/aqco0s 7zFHPC4gQ6dvco9oPC1xiExwwSY 2020-04-20 09:13:14 62.65.106.163 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=914 +p reject 1-65535 +r noce AWZNQagfgXo+cUANa/1AlHqkCvs ovx/kA00AFtNaZDVOv2X2I60pao 2020-04-20 04:03:15 216.127.173.78 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4800 +p reject 1-65535 +r LastResort AXIqYNwOqmTXkFrWCjJCxgkec9E fPDUBdQzWNbu3ljQsRcJ7efWyaI 2020-04-20 07:25:48 185.112.146.155 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=250 +p reject 1-65535 +r CheenaTorExit1 AXKfEKgd3YqS13CyEzCC61bHXiY Uyx3Vw9SPvz9M8sICDw6hxDzpVg 2020-04-20 12:36:48 178.17.170.135 9001 9030 +a [2a00:1dc0:caff:3a::dcbe]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3880 +p reject 22,25,119,135-139,445,465,563,587,1214,4661-4666,5555,5984,6346-6429,6699,6881-6999 +r hedden AXOnqLqdMgQ2QbaXJtMqmt/ibRY OJdS34WawtWTElwHLNKbJMv6kbM 2020-04-19 23:53:59 93.174.93.133 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p accept 20-23,43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r k0nslNET15 AXteKKs1Wkneb6p7EjMtPPtf59Q Oi+uKV3t+swKL/2BbnTx01VZDKI 2020-04-19 19:52:59 198.12.66.116 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29900 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r Unnamed AZCP+2rU9ziXs9UKF8R+pHUUGmw 1lCzA8vLEoYOHUeCeE9JuY4jYbY 2020-04-20 12:38:33 199.195.248.240 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10600 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed AZgfCa8I6x7Gn5GzHYm2x2dXYgo guEfa3biwUhHyqXZ3MjbM6Czuy0 2020-04-20 07:23:11 54.36.112.244 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=640 +p reject 1-65535 +r Unnamed AZlHo+aYTF5PSCfjvqoJ9ldttvE 5eDPI63XG876BZj1gJiufC+gmW0 2020-04-20 11:15:06 151.80.194.90 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ProjectTokyo1 AZ4g41JIG9RaPOfWaRoQ+1MYUPs pvPbIH7PwJImVek2oxKlUgPWy78 2020-04-20 12:27:12 111.233.137.126 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=199 +p reject 1-65535 +r PyotrTorpotkinTwo AZ/rIs4Ey9BIm38kvgOFGLZPoiM XFeXUX4qrxlyJZYXsSoKT0X+eFk 2020-04-20 06:39:56 142.44.243.133 9001 9030 +a [2607:5300:201:3100::3e59]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9510 +p reject 1-65535 +r ForEdSnowden AaHRX5/GftBfopZv+IMGftUCzwg qDnF2ZOMHitp66IS/bORld1oRDQ 2020-04-20 09:58:50 51.15.133.16 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2500 +p reject 1-65535 +r snap277 AazsVV4byT7SFY10anLyO0p/tGg K+FCQYlTdU9RIo9rkreJOrToHig 2020-04-20 10:35:53 77.96.94.110 37403 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1010 +p reject 1-65535 +r rixtyminutes Aa4t4xQnbIL8zDYDocLzI45lRMk EFXyhRTrj5zzFl1iEDqr41squzM 2020-04-19 22:22:18 149.56.233.142 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21200 +p reject 1-65535 +r Hydra14 AbcMfEl/yGZ9teuCxA2PkhTWpIQ nDrDca0znS4aWykgPC3LrjKIvoQ 2020-04-19 22:56:31 51.15.225.216 9001 9030 +a [2001:bc8:47a4:1734::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 1-65535 +r da3dalus AcLfa9JAJazCA9c6J6tyTe0crd0 UD36gsaD8hnDESst6oiHYQ262PM 2020-04-20 08:59:11 79.143.191.62 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2520 +p reject 1-65535 +r idisdlagjnldf AcdCMB4o7RVNUpabn2acaBMiRms DRUsrjRkJxWt2A/8UN5QmudPaO8 2020-04-20 09:05:57 91.203.5.213 80 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r Unnamed AdcItBd93de58aQaMIHzMPuO8Dg 8W4zj2S+Y6i/1rpo97ulHGiD5VI 2020-04-20 00:23:51 185.243.112.87 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=321 +p reject 1-65535 +r king AeQfZ1deTSVRwwDlyaqCN6Bcjbk /bsfb2cGuob+ZEzvSyqRgY+JqRw 2020-04-20 08:40:25 51.75.175.31 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r aerona AeedEdrxsvUiztFfMwTDdlb5jH4 IKWmEWKwKKObs3r445gxBuJbRVg 2020-04-20 07:24:38 145.239.72.73 9001 9030 +a [2001:41d0:302:2200::1ac4]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21800 +p reject 1-65535 +r kr3pper4 AfS/j7Q1CmkPIh46g/UwN4Nv4BM PhSwh+0MftOYJ67HGb4VMVOzfBM 2020-04-20 12:31:17 83.79.221.148 9004 9034 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68000 +p reject 1-65535 +r Ubermensch Afc9vZtWwx49Oq65X4zx3rfZpy8 nvcVSaEyhNWfntW7/iV/lPPSwcM 2020-04-20 02:47:26 158.69.35.227 9001 9030 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r niftyentry77 Af3I6S0ygIR9hW2h+b/CtM0sLug fwgkS0J0EI7ICXDS5iP6phN7hVk 2020-04-20 10:51:23 185.220.101.217 10077 20077 +a [2a0b:f4c2:2::217]:10077 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19200 +p reject 1-65535 +r daskapital Af4hN8QuSAJQeh/ZewFYEW/Xiow HQFabk7/KmaV7OcTzFNac9Ae5to 2020-04-20 06:36:25 85.214.141.131 443 80 +a [2a01:238:438c:5200:1a03:ed1f:ae7e:e9fa]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r RS1Lselectel Af+chXHRwJ+o0qzOcn1VMP7BADg 5PyQZlyg6KepXbBQ3z9mP4vgQsI 2020-04-19 22:29:05 31.184.218.180 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4900 +p reject 1-65535 +r justasimplerelay AgW4UWKk3ArZAOBNOuUhmka8IKM p24FwMfUOgW6SwCnAB66ZVu4kb8 2020-04-20 10:16:55 54.37.16.59 9001 9030 +a [2001:41d0:801:2000::52]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8150 +p reject 1-65535 +r conquerorworm2 AglzN9hayRrMK15pHkRx9A9UqYk 6XuGS4bU3geyx2aDCBQO9GDre9M 2020-04-20 08:38:10 178.17.171.29 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11300 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r bauruine56 AhBHxRpXJU0mPduLknfKHChtYA4 /PsjFMztgN+dlOvtL9gaY5nUHWg 2020-04-20 00:10:13 94.198.98.21 443 80 +a [2a02:29e0:2:5::1c]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p reject 1-65535 +r tconionrelay Aj67xXvrf0VHOz3CqoEfs6q6RGY BMdtRWawW2hJi/AvmjkF0FWbqWo 2020-04-19 21:05:40 173.75.39.61 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9900 +p reject 1-65535 +r snap277 AlSchOTlVQbyuXlRBbXEuzzkHx4 Ur5flmMldVD1Dq2BS1iwPBUf6JM 2020-04-20 10:19:21 94.2.80.175 44417 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1650 +p reject 1-65535 +r nibbana AltmzrwHD8sFGdIGzwz0llwgyW4 qzEd90ayKAnw70+wkPE1sSSY8Zo 2020-04-20 01:37:00 185.100.85.61 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Anthemisto AmAfS9X6CBeX6eRmmOoTBioio70 ddUatgk8LQL3Ia2POmIjjEw8njo 2020-04-20 03:17:43 134.209.109.214 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=933 +p reject 1-65535 +r Assange029us AmSPLxNccpaiex9Z0q5O7CXZqHc BHYiJchEE/4RqJ+wgjo/6xQtWsU 2020-04-20 07:01:15 104.194.235.104 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r Endgame Am3XhmidJqTBuWq943l88BlB0nY 52GDyHZbuwOUf0fHTqfWZTzyNgg 2020-04-20 00:15:23 199.115.114.70 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=19200 +p reject 1-65535 +r KXDT8WM5QSBHZVS Am5T2aov8iIXshW1fkxLTvGW/NU YYcYZ2sL4uuzlece/dn3n74OWxM 2020-04-19 19:21:53 91.121.251.65 443 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18800 +p accept 80,443 +r zagreus AnQPRy0dpcG3dHXxiUD+efFa9Lg 5wPLh6lLTLp4T2xdznu/gLOVZgo 2020-04-20 03:24:28 81.169.222.158 9001 9030 +a [2a01:238:4224:8d00:f3a9:25e6:4cb6:f3d]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=382 +p reject 1-65535 +r niftyentry116 AnWM05jj+ELvgkeAeKquAnN3DbI 049h7CzP/HXYtS4h57UBKRJJOnU 2020-04-19 20:26:08 185.220.101.116 10116 20116 +a [2a0b:f4c2::116]:10116 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r zamazan4ik An3MqqCqwLP3kjjmDby+e1suS6w dVfA7icL8nV9R6OE+yyMXJPhszA 2020-04-20 06:50:06 194.158.216.103 9050 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r MrDetonia ApKIVb+teH+LNj8hhg0efRVuBlU La9ruKk7oy9Ui5Lf+Ye3buKVb4Y 2020-04-20 05:03:43 188.165.212.152 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29100 +p reject 1-65535 +r Ragnarok ApMP/rh5aNUYEB63kgLxw3ZgeNo hpMl5vqbh8ETddrlMUphDthyfEc 2020-04-20 11:54:07 176.107.187.151 9001 9002 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21200 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r SatoshiNakamoto AphcRyUWb0bpp23q+C/sxLfiGms a9kTfxn8QXdmkRgdyx8phZp4ekw 2020-04-20 04:39:39 87.247.111.222 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r pkswitchny Ap4QelnStP69BqYRUWe9bQSNnAo xW1Q5B+sad2jSVtM7u2F7nl+me8 2020-04-20 07:24:42 104.236.52.16 1747 1523 +a [2604:a880:800:10::63b:c00a]:7491 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=2120 +p reject 1-65535 +r Lorax AqKaL5WCEfm7WCEVMpbv/tkA7MY mPezH6X4lDrAUYyXJEWCmT6w5Rs 2020-04-19 19:32:39 2.56.99.215 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12800 +p reject 1-65535 +r TorRelay268SGP ArTp45e7GK3ShuQfaceEv4EY4nA kKml7ciyUNqxfc5Et5Vx9cjhzrw 2020-04-19 22:00:00 139.99.40.50 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=900 +p reject 1-65535 +r Unnamed AtWx9joN04OdnY5wVITsbi9fEIM 9MVvkWnwYvRw0L3/51ePO17eR6U 2020-04-20 04:59:53 126.65.143.106 1052 8080 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17 +p reject 1-65535 +r SixRelay12 AtdxTVyXRhYDHYopBexQHqbRDRM uFXZ+1Ij+IjmCyuAX4qik395ur0 2020-04-19 21:18:08 51.75.175.18 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3 +p reject 1-65535 +r ididnteditheconfig Au1PjbEfEwO6IbFqoc8qCkhUeso +u7WPgoQ0KHDidlUIDCB17Bg/TQ 2020-04-20 07:11:25 62.210.217.207 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4530 +p reject 1-65535 +r FOO Avli4Q83m0iTp1yfN4+yidljD3E KpC/ihMfW4+s0CxvI5WqeQSx3NY 2020-04-20 10:10:40 178.17.171.110 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r paladin AyW5HTwy06JMhj1d++0AVk+tXGQ BGQAYM3BjgbDKHRVhdPIiSERJX0 2020-04-20 10:52:07 81.17.16.147 9001 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed AzDVgn8yU6mK5q8w1WoPi+0cpYY ahOFKh9mYz9/FfLTkxMFE6YwmsA 2020-04-19 19:27:38 193.36.116.38 443 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=190 +p reject 1-65535 +r Nebuchadnezzar Azj59VER/o41cOfeEX7zr5mcwdc 9DUpCtqc3qUPNAiT5CqFSBIxtro 2020-04-20 07:26:22 185.225.17.3 443 80 +a [2a0a:c800:1:5::3]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r snap277 Azv2+4SsSwLXAQMuvJQBS/2WgNg anoJq0+WIBH5yUw/6qQRi1uh7wE 2020-04-19 22:26:44 188.243.60.249 41429 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=172 +p reject 1-65535 +r Hydra5 A0qksw933w/hg2Aup/glH/LPG6I AVogsJ2zwlZqv/D8XxWrpKOHxfI 2020-04-20 06:14:30 89.34.27.49 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p accept 53,80,443,1194 +r Venom13 A1OWJp9tAFA9F2XfNu0bIDoCjXQ M9j0AAT7zQkP5s7oUYwOBmzAO8g 2020-04-20 07:59:31 195.123.209.91 5091 5192 +a [2a02:27ac::4ed]:5091 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6800 +p reject 1-65535 +r asagudentor A2fh/6txasP0GM+3y7O9uUA82cs rzwDZFog5KAVIQrdaSBrBJP72Ac 2020-04-19 21:25:48 213.80.102.27 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10300 +p reject 1-65535 +r Unnamed A3e3axX7PPySwgAeGAoypKs43wM p+Me3YZj/089UqBpcvX7j5nbVM8 2020-04-20 09:30:37 62.212.72.243 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=12100 +p reject 1-65535 +r SLOG A3tsYNrU3zL9opv0WNXIyBaqjz4 LCRi/fHSEWz6ufVaBgHZFRvIuNg 2020-04-20 03:47:20 5.154.174.241 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p reject 1-65535 +r dike A3vNDr332589Vi2ifUY/D3jxSUs Y2WoRvK9lEsuaZWtuSYLdmzIiW0 2020-04-20 02:46:10 37.120.171.188 443 80 +a [2a03:4000:6:543b::443]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4990 +p reject 1-65535 +r turnt A4ww0q0FMUfJHvsSkVJ+1iHX0bE FoIPm95zsuFawBJPODwtFl7Fqsw 2020-04-20 07:09:12 82.221.131.71 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9660 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r HerbieStone A40y8RSK/D2M2gx0tG8WEzuWeMc y5JNi4rOTkJyzzH3MGtELBlzV8k 2020-04-19 22:31:41 85.195.252.93 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=233 +p reject 1-65535 +r ry4an A5ADwyDZmA4KdA8QehqcE8mcX+M TjxSwFPJclb+LUDw3akoCBMDmko 2020-04-20 11:09:50 45.79.159.52 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=700 +p reject 1-65535 +r operator A5EPKFoz82WDjsZu8sLvdU0EZ2A XOLVAlhG143T2vsU6d4jZdDNKC8 2020-04-20 12:24:15 148.251.237.219 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=120000 +p reject 1-65535 +r panopticon A5l6Co80sZBLb49C4HWoaJxLDFE JKz9/SLdV7DuIuz9uf49PxM5L7E 2020-04-20 03:05:52 69.230.150.191 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4810 +p reject 1-65535 +r unlobitophx0 A6L1nHQVlR8W718Pp6Jm5jZW3+Y XK8OtuaXdbdcfPQT7LUpQYRjlok 2020-04-20 07:36:03 216.21.9.65 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57 +p reject 1-65535 +r TLCOnion A6M8NFT8D5rGlm8S+khpmfWiKJY bNCGZl8gUjOz5+K1zJV1H2Rc7EQ 2020-04-20 06:33:46 96.66.15.147 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=870 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9332-9333,9418,9999-10000,11371,19294,19638,50002,64738 +r unrestrictedONE A7GyHXI3NRDh3v4uGTkyV2sVc2g GzcmcNkQC3fcTwvFbIMO3KCLovs 2020-04-20 06:50:15 178.175.148.148 9001 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5630 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Ichotolot61 A8MGnoFOKW6xh3brYbHst1Ttif4 WrLih4yee1D19GbtXjnMkpSSloQ 2020-04-20 11:58:22 81.7.10.193 993 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r SPARTACUS A8i2A66+wKxMH3PjsMyWoCoE2D0 WGRC/YQSg3DJguC/a6kRghxW9q0 2020-04-19 19:09:35 31.31.76.123 80 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4260 +p reject 1-65535 +r torgenerationX A8/5AGBGEIfTT/t7SFw60wFDd1w qizyKONWd3HyqlzGnf8hO6V5+yg 2020-04-19 22:12:39 54.38.187.54 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14800 +p reject 1-65535 +r itzme A9og/XHO0YjIt2UugZQcUGck26Y Q5v9CrDGWIEjI6aTHtOYhDyC7DI 2020-04-20 08:47:28 198.74.57.57 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82 +p reject 1-65535 +r krigernes A9wIHkQJYxAG78068Tr6rytVP/w Px6d2c7UvP+5QCAHRTc4L0fVJF8 2020-04-20 12:32:40 185.32.221.201 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r noipser A92dpOEU07/gYD6aDaJBlYi5xFs xT7UTNVXqlKjElqLkttqnv/vLe4 2020-04-20 00:23:10 84.241.82.211 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1680 +p reject 1-65535 +r chapterOne A+D07icnMWAXc/SOZCQNOoiWpeM rwcfqfG0jFaz/u7MqtoECA7IIJ8 2020-04-20 01:47:01 95.216.15.16 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22500 +p reject 1-65535 +r 4pyro2eu3org0 A+n35mnI+RHF7sPsCUUzFR+FdCA 0v5VKH29OUulBO/T2LuzjSAURpk 2020-04-20 08:00:01 217.155.40.118 9001 80 +a [2a02:8010:60a1:2013::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1700 +p reject 1-65535 +r Shockrealm A+593ZMdkrtXuBswOK58QKCKsjc V4Hkj4C8+1HNPT5hwhosnwAjFbs 2020-04-20 00:46:14 123.30.128.138 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=560 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Janky380201 A/JnZvFLC3tdIkYQg4B9MTQpo08 GVZQWYQ+nLlGhClRmK0rVxNC0y0 2020-04-20 12:42:41 5.196.71.24 9001 9030 +a [2001:41d0:e:418::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5610 +p reject 1-65535 +r arbitrium A/aKtWkVTEuZXn82UoMiB55IKbk wllbv9fE9Edtd02RRvVwvMw8KEI 2020-04-20 07:52:22 201.80.45.203 9001 9030 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r toastworld A/xcUtmkV38odi575kK7Wo8emAM 8Sbwr+F0uhKsUT54LoG03i0iMvg 2020-04-20 02:52:53 79.140.41.117 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1220 +p reject 1-65535 +r SCggHJTyWbtzDA9YZi A/+U2eUAHdIpC8Oxn6f1nOHjAnk fVsWxHlM3EiR1Am0+ejuw+rM0Pg 2020-04-20 11:27:58 78.142.175.70 443 0 +s Exit Running Stable Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r RichardFeynman BACF/+HojPSKsLWyqzkDV1jGXww KTFaCuOFU24ZvOY3nW6OcAX9WbE 2020-04-19 19:56:19 178.63.27.82 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=680 +p reject 1-65535 +r jkO BAlgXoNDVip5D/6EbLO9fARCn3A oiNl2Q5aCGL2i8jxAhtogMIAKsc 2020-04-20 11:31:16 158.69.204.36 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r Unnamed BAp0QjSaKskiM8JHDWxPK9Au3xU nRLS+m1H/xJQnn3PBUIhtr2/tLg 2020-04-20 01:54:54 216.218.134.12 9040 0 +a [2001:470:1f04:d9a::2]:9040 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4520 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1337,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,6880-6889,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9000,9418,9999-10000,11371,19294,19638,31337 +r EntitaetNull BBFTINEeJYPsP3+UStLUGfm4QQI rz9dtUTkG9l1REL7WyyoPkTDmXQ 2020-04-20 04:07:28 85.214.156.28 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38 +p reject 1-65535 +r QuintexAirVPN26 BBZGZAqzBup0sAGWboYWmwTMiNI w3l419kUUgBUw0oz2E4NVsqxXz8 2020-04-20 05:04:41 199.249.230.79 443 80 +a [2620:7:6001::ffff:c759:e64f]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r freedom BB4/zAJi5a8aouyJoTVljAfA2ak 44JBJ8W5Sby6YNKqlj0w6gzxfCw 2020-04-20 06:07:25 178.189.143.242 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1800 +p reject 1-65535 +r ecuasterces BCvN8tNteu4HDghtrUtX8nsvEUM Zn7y/ud6bkVkJ3swjGUT7LzJ2lE 2020-04-19 20:29:14 73.170.195.217 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=205 +p reject 1-65535 +r hacktheplanet BDGZ0sQeZAQwt3OIuA1ELTeb2OI UPDGBTvJzkk68Bt8FNUl8YlLmns 2020-04-20 06:24:36 51.15.128.2 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=20000 +p reject 1-65535 +r Hydra2 BEPZjAxE0+DmI4eQNF21Yk20Gyg 5bpW7bdpTMt/ow9zAM3SwMennKI 2020-04-20 12:35:09 89.34.27.59 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14800 +p accept 53,80,443,1194 +r rabukel BEtrje8qqMU6xnZA3AD9Je5nPPY +wE30yQPwjVTzv8y07rsz7vViag 2020-04-20 02:10:40 77.11.32.181 9001 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 +p reject 1-65535 +r goddisignz BGV4KW1qVZzzN5Yw88dsHHitCkc MtkwXCjzg/rA0WooPyjSgzfqpWo 2020-04-20 01:48:18 88.130.7.152 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=392 +p reject 1-65535 +r Zwiebelmett BG8tWahfrmk2dqh1M3F8V0NiYcI kKQM7EUckNE6rKDx1doNmLw0HVc 2020-04-20 11:35:53 95.217.99.142 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29100 +p reject 1-65535 +r hviv117 BIUCego0nUVNl49sHOzdKeoXdpo AiVixI67qR1tte786AvlArrJeh0 2020-04-20 11:41:19 192.42.116.17 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r snap277 BJ740vNknyLmtAk3+meitz9I7IY pmZlQWt4krcSaTGasNi+ISKcmxM 2020-04-19 21:18:44 84.124.50.151 33205 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4300 +p reject 1-65535 +r darknebula BKKKYvJ9nEpg+e0MQmTpi5iMZaM dbCK6E/rgu9kdO+WzRomUD5KkmY 2020-04-19 22:48:58 163.172.169.253 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24300 +p reject 1-65535 +r torgwthem BLfpcFgPIb6Lq/DMmiPSy/wiIpU dB9HANV3XYzOXSoYHfCun72u4pc 2020-04-20 08:31:13 212.17.102.77 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=150 +p reject 1-65535 +r aaron0x10c BMNGi+JHQDR8vMAFNMlA28vKvII OTDBxLVGtC7YSa2Qalbg5Ejhu/4 2020-04-19 22:23:45 51.158.187.110 443 9030 +a [2001:bc8:1824:421::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26400 +p reject 1-65535 +r snap277 BMe6KM2ELvolpzDfP2jBP8JGfc4 nvXzSY0LA/SQM98aHerEURQr/Rk 2020-04-20 12:29:47 178.36.49.211 46835 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r Assange024us BNnOqNd4q6EwsBT3WMK8rdMdoF4 v/vw9YZf3/tJCq4vIRI+WfhPmwU 2020-04-20 01:09:05 64.94.212.135 9001 9011 +a [2602:fe90:604:1b::2330:38db]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p reject 1-65535 +r birdsarenotreal BN/cbH1OoY5K/MxCRJCTgAF0Pe4 mEdV2MOBeUpb9HvgGawK+CTorPk 2020-04-20 08:23:35 67.186.247.178 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r takei BN/gR6zfemYgrKeC+vxe8a5/R1Q baB4fjffppfVroTsTRrMy6z7rBM 2020-04-20 11:21:29 46.22.212.230 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28300 +p reject 1-65535 +r rofltor08 BOO1kl619mxuyBCj13AuDKP51ec zmQTjEsYSrffVQ2WVPkszntTHrI 2020-04-20 09:44:30 95.216.136.46 9001 0 +a [2a01:4f9:c010:2e::1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r thorius BOdijTg73nAirajv33NwGRLHUOM 4LVK/KGzZWKrmXLJSRNj6alMhVA 2020-04-20 11:37:23 185.248.160.214 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r dorinne BO5eGyMSfSajb3HGaBDYiwuAu5E gZwIub9B4rTCto9xZsPjGOkE310 2020-04-19 21:15:13 91.213.233.138 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2560 +p reject 1-65535 +r Unnamed BPDUf97e7WO4HHrl3saf5gHrlD0 9uEzDpnlFl2PJ8h5hzT4BiXKwMQ 2020-04-20 04:34:19 82.102.20.254 31315 27876 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=160 +p reject 1-65535 +r FalkensteinTor02 BRL+a+nMoO0TMVLmQBCy+6FB6xA yxl7P40u1+OosYwQ9zwqN1fVrFg 2020-04-19 19:20:03 5.9.43.211 9001 0 +a [2a01:4f8:161:32c7::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=44000 +p reject 1-65535 +r AccessNow007 BRYIXWysQO1M3O/fxcz2sA3mHe0 Ee5cVBgkL+EMtDHpTRkJ/rx+c6E 2020-04-20 10:32:13 176.10.99.207 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19800 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r fiedlerRelay20 BRahpYNoJfWISNR7kfR8tZO1jVQ AA8foigJv5bk/3xE2M6jYnhWHOo 2020-04-20 10:10:41 185.183.159.99 9030 0 +a [2a03:4000:1d:8ee::3]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4110 +p reject 1-65535 +r RedRelay BR0oWPiv4daWZxtUxP6qZ0vk8lI X0KxFQPkXgxMFPinG1dXSRjTSJ8 2020-04-20 10:01:40 173.212.198.197 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r b0fh BR5JRiRNCiIaZ2/56ld/yQpXP0g gRmspezNLI8ox+RLtHdiuLDZ7ms 2020-04-20 12:07:50 78.46.99.170 9001 9030 +a [2a01:4f8:120:93d0::2]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r opix BSmeOPJm/0r7uvZ7RQK3Es4owzk Ca7ZVcxYFaUkSrgI1oPFIsC53lw 2020-04-20 03:27:04 95.26.115.190 44040 44041 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r king BTQo110opD9kPQq7DtnIYFmAXzg MTgwecnfwNPzk0+841by3Ri9S8E 2020-04-20 05:13:30 51.89.200.106 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14700 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r vasilievsky BTScDzXFY1pwiIgAT4sCKTHovuY gYqnb7lKG7Qb+XMYA7EaQBadN10 2020-04-20 01:37:31 37.120.146.88 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p reject 1-65535 +r torproxy02 BTYOlVxMTFHLoUDf3fyL3irPYkQ 5AL7kkPqn7ReWUBY+HrEfmME6gM 2020-04-19 20:52:09 195.254.134.194 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p accept 20-21,43,53,80,443,873,989-990,992,1194,1293,4321,5222-5223,5228,11371,64738 +r relay2 BTyEc3Oi+CEGNw27AWteihTakQE aUuBzGZPIxKbaE3pH/Xau11t0o4 2020-04-20 00:43:16 23.157.160.195 443 9001 +a [2602:fe2e:2:2:18:11ff:febd:583d]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12200 +p reject 1-65535 +r Taste BT+FYy6RbvV0EwCWhutGkPHZkLI eNF1+znWwVmaCa8c4KwuuwGiiZ4 2020-04-20 06:31:31 155.4.70.10 80 9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16200 +p reject 1-65535 +r Ephemeral BUDYcK1Obye2it8/gJ+SXnANGC0 Tw1TqmmPZVyjQG1n128TTS1cf7o 2020-04-20 10:41:02 51.158.178.34 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31000 +p reject 1-65535 +r niftyguard33 BUiIRRGlHuoIzUZLAW5Pk+n4EHI sc0JAQ+kvwsz+wRTIV2mENVOYOU 2020-04-20 12:45:37 185.220.101.242 1242 2242 +a [2a0b:f4c2:2::242]:1242 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11800 +p reject 1-65535 +r extrastarch BUmVB9qLOBNw4IWKeEw6/hPckn8 q0JCsYOR9sZ/DslBQPQ9nQ1kqXs 2020-04-19 20:01:50 178.162.199.66 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=69600 +p reject 1-65535 +r verax1 BVo8qiWCuHRIMBNn7NWQXROO8Ek BDzKeVsa650NcemQelJfYwpBo84 2020-04-19 21:29:42 104.236.46.10 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=88 +p reject 1-65535 +r dinuccio BVsVWkSpaEkdce7xHTtq44CC9vw DWrSc1+Jo7aB5DEtrvaVn9tygb8 2020-04-19 20:29:05 46.38.48.225 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2070 +p reject 1-65535 +r smell BV0c2CY7QMEq5n2EyfoY26HfVnc +8TRpY7mWicV+Htxd4icbujoEgw 2020-04-20 02:03:01 137.74.153.3 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9520 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Unnamed BWgal2eDTZ7am9/k4Vob1zxP388 d/a8Pn2vfboEOWoGpkZbGb8/tfs 2020-04-20 00:02:40 109.236.83.11 46810 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p reject 1-65535 +r Unnamed BWmTrBAoqkg2IFXAFhEI5p0UiyI VYd3HvgwNgVAfQKds0X3neIqJww 2020-04-20 10:12:39 104.244.75.51 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r powerghost BWvWLrbPZCQbOhMFae3Pbqcl6lw YF1EsA1651MIIq+J3GbWm4BKd4w 2020-04-20 11:12:29 90.50.190.214 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r snap277 BX3Fu690qM/ManpsF4Wikx59ygo aTEaYsSO4C7cBhYRwCVAO/cCdNw 2020-04-20 09:07:23 109.78.221.230 38497 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r cauldwell BZIIQYqF2upTcCf1SvnbigGv84E mMxkNS0grq8sPcomcI/ehH3PSb4 2020-04-19 22:48:14 159.89.174.9 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1360 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed BZdurJG8Z6bAYoR27iTawcw3ihA evHdvEP/VgYXAOGmD9fmJO4lBq8 2020-04-20 02:53:50 110.175.109.121 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120 +p reject 1-65535 +r black BZnRdKDFEhJgl5WItwy1SDvlMe4 p9fFUCOo915bxlrsaBxmzEJj0Vs 2020-04-20 04:27:39 80.210.66.216 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=993 +p reject 1-65535 +r lpf3 BbRRwFYv3iMwevqE/Wo3ZS5hUjM UD25f/SX9Y7ogvUgjZj3r3z2JWQ 2020-04-20 12:30:29 95.154.194.31 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44000 +p reject 1-65535 +r snap277 BbwWiubyJgYjTbocB2Y4dO71jAU yc05yGhH5XGoRkNjlBpk1pFh22I 2020-04-20 03:53:46 109.28.116.250 37519 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r Unnamed Bb7Hf0DexyxXy8090wQ56Fm45Ss cbtIT8rN4bjoACMKxzIeHHa2w4c 2020-04-20 01:32:15 81.20.143.138 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r montrose BcOD3IE8RktxMlaXIr5SQ6n/c1w zmSw7aw9C19EpTaVjeOu/SaYwag 2020-04-20 11:12:38 160.119.249.24 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=331 +p accept 20-21,43,53,389,554,873,902-904,989-992,1194,1293,3690,4321,5190,5222-5223,5228,8008,8232-8233,8332-8333,8888,9418,11371,19294,64738 +r OpenBSDRelay BdxdvvtlG8ApRtsyhvhdsbXSw9Y jK8srJ+Pw3JJnu9C1mm/4GgHWto 2020-04-20 07:15:48 71.19.148.12 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=320 +p reject 1-65535 +r 0x3d069 Bd27dKq28Z4AMYhwKx5U8jA10GQ LY557UgSeIJt3knSdcCp47rAz74 2020-04-20 01:54:28 37.48.120.47 2195 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=372 +p reject 1-65535 +r niftyguard15 BfW7ddoAc2HOA3cDkwM9TVKDbYo mu0JKdgv2jxUPhswke4mWd+1y2o 2020-04-20 12:44:55 185.220.101.224 1224 2224 +a [2a0b:f4c2:2::224]:1224 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16100 +p accept 80,443 +r HelpCensoredOnes Bf+jnXHaEW92aepO5ToLrqMVun8 QVfBbrF3iAMMWQ11Otirosbd60Y 2020-04-20 06:06:25 85.93.218.204 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13200 +p reject 25,119,135-139,445,465,587,1214,4661-4666,5060,6346-6429,6699,6881-6999 +r newsvendor BhNwrkHBCEspEOsFIsiy2xwsuW4 vB/8SOo0Nr6wveHWulrZKbU9VM0 2020-04-19 20:30:10 49.50.107.221 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=650 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r bauruine66 BjvTv4wRBhfnygnJbA7cAnAynws iG5A5kZXFVCTQ4ztLwrh0deDKJc 2020-04-19 22:33:58 94.198.98.21 3443 8888 +a [2a02:29e0:2:5::1c]:3443 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p reject 1-65535 +r bruins BkMtG1p8EyBxYm0YbX8aQpxbvtk BJh9mRulWNdtB8u1Tu1Ix1jdAY8 2020-04-20 09:03:22 85.25.44.141 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,11371,19294,19638,50002,64738 +r Hydra1 BkfD+DUrv6DVehw+Dc9n/D4HPSw 4sMFno8owVVgD4n5PF9lSA9+6us 2020-04-19 22:01:19 185.165.168.168 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p accept 53,80,443,1194 +r TheYOSH Bk0YPTTey4T3LEM1sMJNHolGqbo l93lBeWH1BngQR2AZ2U+ROlz2PE 2020-04-20 02:46:42 85.149.71.50 9001 0 +a [2001:470:1f0a:716::2]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=160 +p reject 1-65535 +r SanitaryLandslide Bk08TMG4VIObCXn+HC8Fq6t/nWg MNd0XUQpZXFBnlljkLBqTfXfWzE 2020-04-19 21:58:38 104.244.73.126 443 80 +a [2605:6400:30:fa6b::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9300 +p reject 22,25,110,119,135-139,143,194,220,445,465,563,587,993-995,1214,2525-2526,4661-4666,6346-6429,6657,6660-6670,6679,6697,6699,6881-7005,7070,8000-8004,9000-9001,9998-9999 +r snap278 Bk/ERWmOxvR9dbsbQdK/PP4x2Ts d1pC5K5UcOhE/qUG+f0sQJ7EroQ 2020-04-19 19:16:11 80.87.222.19 55181 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4290 +p reject 1-65535 +r FreifunkIbbenbueren Bmc11D+0dvpkV4xdgp4XbfU+WgA ZBrykO0OE/uZX93uhig5N1PHxjU 2020-04-20 03:12:28 92.252.108.79 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5020 +p reject 1-65535 +r rubberbeardc BmmOThVV+4MDLgue+Amyc6958lc YLJoVyozEcvFzhaLVbdSd9otnr4 2020-04-20 01:47:52 71.127.52.172 1043 8383 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5690 +p reject 1-65535 +r niftyflorescaverat BnffCwXs2i70XybDMycxBDu4mrg ZPyZMTdSNVEsldKJ1/SvNk6jn60 2020-04-19 22:24:07 137.74.19.201 80 443 +a [2001:41d0:203:1c74::567:f3f2]:80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41100 +p reject 1-65535 +r snap277 Bn251uOD6BKoExMwn4TVhbLT+8w 7oHMn03f6Fh0/Pz3/ZYiJQJ5l4U 2020-04-20 11:51:45 109.218.63.199 44141 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r TorRelayOfRio2 Bn7PGYI4vRSwz+JImUdaU6lOFOw VG0k9bh4w0pUi/AX2X+ZEpjCcXA 2020-04-20 06:31:56 83.212.103.129 38513 9030 +a [2001:648:2ffc:1225:a800:3ff:fedb:b40b]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3360 +p reject 1-65535 +r paradeiser BoBOY4PulOg8lFPzmx5STCctbYQ SQ4te0UOl8vRfPEkA9BHBPY7f9s 2020-04-20 02:16:39 109.70.100.7 443 80 +a [2a03:e600:100::7]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=87600 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r garlic Bp362oxl3qK5sichYK9eV5WPmpc i5qdEYOdxJeNuiWMnK5pzmYFiKw 2020-04-20 12:03:06 157.22.22.254 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2750 +p reject 1-65535 +r Unnamed Bp5zLslndO1WCdSAPXsRMOM4sOs XLcqajbYqjr+7+HxLmHfHyNho8E 2020-04-20 12:03:44 94.19.14.183 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r snap277 BqXM5GSJwZX8lpoUyY+f8pVSdvs FCFBuOyLDEdwS5RROde4bqtCi+s 2020-04-19 23:52:42 96.60.4.11 46665 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=524 +p reject 1-65535 +r deprofundisclamavi BqtuhT6Nkp+dYOOkHvT5e3z2/aQ hvSwxZLwy8gwkcFlcwHC4KR0GHQ 2020-04-20 03:01:13 176.114.248.47 9001 9030 +a [2001:470:59a3::1]:9001 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r heaney Bqv8UT+nHH7kI9zGq/gPa0ovwaw OUAlUHJHHEjayFUKnLEE2ZdX+q4 2020-04-20 03:07:18 93.115.241.194 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=890 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r KlausTor02 BrCih7SFKIUk7XYd+vqq0uSomSs IVmXX4WOtP2i76FYQ/bu21lg8A8 2020-04-20 05:52:57 195.201.27.159 9001 9030 +a [2a01:4f8:1c0c:53ae::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p reject 1-65535 +r BungeeNet2 BrMI9UtKd510swU2lkGCoJwIq48 qXX9JYe1L26U77p1ymN6XfFex4M 2020-04-20 00:11:17 51.161.43.236 443 80 +a [2001:470:1d:3b0:0:1:ac:ce55]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p reject 1-65535 +r FueledByCofe Brfy0G+MvsJLbyg/X2Lo/gA/iXI PdxiS12/mvMZ76dqk1LDkp2iIUc 2020-04-20 07:03:11 78.46.76.235 9001 9030 +a [2a01:4f8:120:3286::c0fe]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4880 +p reject 1-65535 +r r Brvqpvc3WaF5XrRh050qoWjzBdE z3/cgvLUvrw9uW+oi5LRl900OFs 2020-04-20 03:41:16 77.68.94.106 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=53800 +p reject 1-65535 +r 666Name666 BsTmgLAplsNomK1DVtt0aYZfUAo qn9QWrLCdGxFHgNQ/SyktsRSttI 2020-04-20 12:01:48 67.183.149.202 54817 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120 +p reject 1-65535 +r COSMOPOLIS BtD7nGhg6Nf7meoxCgFnB6+qcc4 z3p81NB+NTT3mtKm9cGmYIk/3lg 2020-04-19 20:09:06 154.57.3.214 9001 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r Unnamed Btd+RhyYFCQ9osYUVUTVuztGtS4 yXpJxw3YFfQnTZhVt6flB11VaSs 2020-04-20 06:21:28 54.36.112.234 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=350 +p reject 1-65535 +r blackbox Bt2TxWFzV49REzAs9C5VUJexpdM beDem+VlDZ3BnNmyXrainUEHD3g 2020-04-20 11:28:25 77.191.212.9 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=388 +p reject 1-65535 +r wien BuclJrvgQMUcWt+6oHrdmuteH6E BElHPfnIg2EQ5dTRyij5zf9V5OU 2020-04-19 23:36:35 94.23.247.42 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39000 +p reject 1-65535 +r niftybeshaba BuwsFmnlqBHZZA4HztV4baUMVzc sY96dpQ7Cba9SI6h04FyaKdpviU 2020-04-20 08:52:48 185.220.100.245 9000 9001 +a [2a0b:f4c0:16c:10::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47800 +p reject 25 +r cypher BvAr5smoF6HJo0At4ACcvg7pLWE E+56U0MxEVyOMS5g2aFSgiaYcW4 2020-04-19 20:20:09 136.243.147.28 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=561 +p reject 1-65535 +r pisaco Bv07cAWhdDWX7WsKDkJOqn83Qn0 OiKKLgtSw/lY1sPEb7ruwg8JkZ4 2020-04-20 06:57:09 144.202.51.172 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=2140 +p reject 1-65535 +r 1blupowered BwIppMws/7JOtmcpin216NEetwE 2+McYgAE81OA67io1uSKohGEND0 2020-04-20 12:15:32 178.254.36.73 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=76300 +p reject 1-65535 +r thorgodofhunger BwQGL7mlpWWTYaC49CuItkGaG0Q FvMhzr+JkeYEmNTtia2yEdFqqlg 2020-04-20 10:49:00 94.130.10.251 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=195 +p reject 1-65535 +r pr1v4cyple4s3 Bw8QJuZa1vXl3d1gSJfamIV8474 Tk4QbEhkh/a+ShR6zleWRlQuERI 2020-04-20 02:39:54 93.71.133.31 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=160 +p reject 1-65535 +r LaTlayuda BxKIshgnEeUoQkgTcEjg+7+zYjM 9N+0M9HiFwPsD3k4yQIeN8Fty7A 2020-04-19 22:02:04 91.121.147.65 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=175 +p reject 1-65535 +r StreamsofLifeSpa Bx3AEE98YwEj4hbbpnQXZEMMZzA aofEwv7Z3+XjeBtqze/+/IlR2Dc 2020-04-20 08:06:54 51.83.237.59 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7340 +p reject 1-65535 +r 69cd8fad5fe7 By2+n9w2oc9j6r46J8GWru2XOGo MpgtYDBY6UVcJDgnewtdrSKsOXo 2020-04-20 08:12:51 51.81.254.20 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r jaures B0WFewYze380NjVgiXWXKp7BSQE OlluUPZdyKgkPWanKNaH1BXfTbQ 2020-04-19 23:15:08 193.234.15.56 443 80 +a [2a00:1c20:4089:1234:cd49:b58a:9ebe:67ec]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7770 +p reject 1-65535 +r snap277 B0wU3d+4s76S1O+qTqPbDNK/0Ko nM2aIuiGu2e5SozYSx7bfYRo8e0 2020-04-20 12:22:18 90.49.107.61 42835 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r snap277 B3ZsQ7tMsRFot23FNt60vRfibh8 unO0UYq7akOJq41c7bB+bYscMr4 2020-04-19 22:31:28 93.41.239.209 37343 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2550 +p reject 1-65535 +r snap278 B3g0oCVhRGcjEpYxRFWWZDjzMhU zG94cJvbfE5b4l4or6ybEFVqNpw 2020-04-19 19:57:50 83.251.221.54 36595 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1260 +p reject 1-65535 +r SingularET B5BaDYrRwTTTA2hyFAsdset2F3I Fgi2UBg6+DzLWrI4cwnlHWczCf4 2020-04-20 09:33:46 185.212.149.111 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3100 +p reject 1-65535 +r mistersixt2 B54RfguAhIRkbKdxX1L2/8gx748 +TD7mogU+bztKtXSZUOcbgnXWN4 2020-04-20 04:03:32 85.10.203.71 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=217 +p reject 1-65535 +r birdyExit B6imYWS4dSqeBtRKq2IZ2J1sEPY 63nsvy4zcS6sG45vOjazAdQC9MQ 2020-04-19 20:11:10 45.76.115.159 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r homeplanet B7j8W2ZxnDVfq/hLT14BMeEn3wE PeJS/ENqaGKi0PYgvjuXycAsuLc 2020-04-20 10:23:25 85.91.153.163 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r WolfClay B8PrvkHfn+hVHfaWQv66cOlU3A8 A9u2NC2lvPNHVx8LkvXjyW2gl14 2020-04-20 03:10:04 185.177.151.42 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4940 +p reject 1-65535 +r MooTheCow B8U21zKFDjq7tRF2+8+eefwsbno g2YDXtOLM84Me0ZNoiEKnqbc2P4 2020-04-20 01:13:59 93.228.163.64 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=518 +p reject 1-65535 +r Pansy B8fP45WMgD+RNzDZgM4kCU17wqE 8K5+B1FF5n2qwHjyzJIYXQbz0dQ 2020-04-19 19:49:50 147.87.116.196 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=83200 +p reject 1-65535 +r tdz B8g2flt9F4uJlXhXi/wRH7Td8uo N8CL9NRFM/FmrwWff6uoUaQJ9U0 2020-04-20 06:44:29 51.15.85.13 3158 3159 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120 +p reject 1-65535 +r Casper03 B81HbZzBNsIHZGS4Ob8XaNFu3BU JpX3hajTo1AcaoeOn5TzwlmcPjQ 2020-04-19 21:16:52 109.238.2.40 995 110 +a [2a00:c70:1:109:238:2:40:bad]:995 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2680 +p reject 1-65535 +r dedicated2trump B830uEF4ZcyNRfYWFdeDEcGPu/A IEBQtW7gvusCEq45wHk3vD4wlpk 2020-04-20 04:09:58 205.185.114.206 443 9030 +a [2605:6400:20:7ca:657b:598:6942:c737]:9001 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3110 +p reject 25,465,587,6660-6667,6697 +r Unnamed B/UJbhgjrXN+dQfeNTO18WtZTXQ 1honPpjt24UPgeg8tEjyEmnaKMk 2020-04-20 10:30:40 104.244.73.178 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r LiCi01 B/nxO8s+H2EX+yEZBRJ69B5y4Ic EA1lTNBuGB+6OSj/2sxoFWIYFQE 2020-04-20 01:04:24 216.150.65.94 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1360 +p reject 1-65535 +r AEtherC0r3 CAu/mxRFSXb96tGtYgoEOI9aIfg 5HwVxmkA9Dx/XCFidvHiSALAr/g 2020-04-20 04:43:08 83.212.102.114 29950 25751 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1960 +p reject 1-65535 +r TheGreatKing CCTXx/sRfVxqwBWB/XmOZww3yAQ 4/LhpqCc+D0gpGLnvp1q1UAKNHI 2020-04-20 12:26:24 80.66.135.123 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6210 +p reject 1-65535 +r TorScale CCX9uWrpkgN7b9I8DcSvtqHTgEs HFgSS1ouSFJ9tcDlVwzv6ddHYN4 2020-04-20 09:37:25 51.15.86.162 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=66000 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r StrangeLady CDC9OuTrEZTTAiyZXfmbzP8WtsE cK3NIPsBqhPX5isYkGtARh1hXBA 2020-04-20 11:24:49 79.141.160.40 9011 0 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=680 +p reject 1-65535 +r psamathi CDM0paK54S72BvbXZFsLEdPefzU 6AS21p4dMgNaIwmMoaNuf2LUqmc 2020-04-20 04:33:42 67.205.177.119 443 80 +s Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r pengy CDlMSHPIpxvp9TWT+bStaUv825A PA1VNxs2CEMWfc8SU7IG9sCVxE4 2020-04-19 19:23:44 185.56.171.94 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3550 +p accept 21,23,80,443,3389,5222,6660-6667,6697,8080,8443 +r NAKAM CDxSBRFA24r3cL1Ax8iIPv/0yvM Ft4xU+xBIa8qiOn5C0MzIc5r1m4 2020-04-20 03:54:02 212.227.165.251 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2420 +p reject 1-65535 +r Unnamed CECZCfRkc5Qvcz4Sa3jynTiNYPU G8IouS32w6qaQ13RG/7JtftRAAg 2020-04-20 10:36:22 144.172.71.182 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r GreetingsFromNL033 CEkqntGu9ixW14OkLoJ7wiApKxk rZqGioYwive8KssLoVlnpO4VurA 2020-04-20 00:41:22 51.15.90.174 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=11400 +p reject 1-65535 +r OTO CGArrLYEE58HyVMN/CQ0VMSLl0k lOTvS3fL4hkTUCczlr6krWx7qAE 2020-04-19 20:55:14 80.143.158.22 7777 7788 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4090 +p reject 1-65535 +r MYCROFTsOtherChild CGH0lm4ZnAup2x2QTbS8hDUI8Sw eBfRLjwd2OAbf5i/XzqJ7w43VqM 2020-04-20 05:52:18 98.193.69.56 32323 32326 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=158 +p reject 1-65535 +r snap277 CGN7rYfR4EcqEGUYON/BzJXDMis lpS/e6WTpAHlKP9w1GCVHzp/C6o 2020-04-20 01:24:45 193.169.81.146 34743 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1710 +p reject 1-65535 +r Belgarath4TOR1 CGnqUDN3xwJmm8dd16WQlGWN+gg jVmU/jIK1jG1JoDpZ9k4kNM4aks 2020-04-20 04:07:52 83.253.14.119 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3490 +p reject 1-65535 +r tor4freeworld CHODWym1H1Bxj4XWIyRugHSgG+8 qchjTxkrskV5i8dfj9S8R0b55p8 2020-04-20 04:00:00 144.217.16.175 9001 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8020 +p reject 1-65535 +r Grexit CHQGqBdw+zSWc08+YpuKeiB8usM r9NK/+96ii7q4nkEgSO3r3ZY7sk 2020-04-20 11:28:31 185.4.135.135 636 990 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24400 +p accept 80,443,554,873,1194,1723,1755,3690,5228,8082,8232-8233,8332-8333,11371,19294,50002 +r 8lyWARGTU4wesrfy8i CIJECHQDSvvi+/FkY6KQ8yeOJPc qkCmxXJtOzRS+IJSOy3cUICjdGg 2020-04-20 08:31:33 176.58.121.159 9001 9030 +a [2a01:7e00::f03c:91ff:fe70:e0b8]:9099 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=358 +p reject 1-65535 +r Unnamed CIpiN+7Yft6w4eOtCkpBn5Y/B4c MIKKTb4EUbBSRLAHasI4r6hz+eM 2020-04-19 21:06:47 176.9.40.67 9001 0 +a [2a01:4f8:173:402:267c:d656:b84c:abd6]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=100000 +p reject 1-65535 +r 0xAligaTOR CI011j6s+T+jo8ldD+KLXSakGNI OEIfs+HMmzYddCVgTQbRjtV5dp4 2020-04-20 10:23:02 37.24.226.249 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r enfewuzeh CMbu12yJOLc4MWo0qikjxDLsBbE heaze12Yl4iYepm0IbLkzVgqbps 2020-04-20 02:52:41 92.219.124.31 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=798 +p reject 1-65535 +r AutonomyCube CMpFlgiHOAXriMzV7wF1JHrWYRg aZ6mVafy+K/XTGuS7xSqGQhsBvQ 2020-04-20 04:36:46 213.215.202.234 8151 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5660 +p reject 1-65535 +r DigiGesTor4e4 CM49v9qifbbARKZ3r2jXI1wq/IU kYAeu6L09YUuVPVmBDtzZePwcbY 2020-04-20 07:37:05 195.176.3.20 8443 8080 +a [2001:620:20d0::20]:8443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r ivitor COlTCzmfenGTYGZYazGmaHcGZFg hssd8I3XQxBCiXL9aeoD3eknqI4 2020-04-19 21:34:20 84.83.117.215 110 143 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=910 +p reject 1-65535 +r FalkensteinTor01 CPBqDdr6v5om/LLjkqFDX54EghY UExRwGQtIqbGUqfHxo+FigkLN90 2020-04-19 19:26:31 195.201.168.111 9001 0 +a [2a01:4f8:13a:1082::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=71000 +p reject 1-65535 +r neartAurora CPRpK2CGJkD2iLhoJrZvMN6nq3M FeteMqhpjtcsw7NftsfxkZuTfvg 2020-04-19 23:57:51 51.15.182.104 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22300 +p reject 1-65535 +r relay CQkv8SCp/Z3BrqyJm1w8/sumwnk NyW9MUFX5u3ub6P9N5wQY3eTQIw 2020-04-20 00:43:25 23.157.160.138 443 9001 +a [2602:fe2e:1:9:a4:fdff:fea2:d22d]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p reject 1-65535 +r RadioMineOver CQ2cFtwaGpQC55ReOJ3URbsjm+0 saxRx32OyoIhY8Dke2NjS4mtIwI 2020-04-20 06:44:32 199.247.21.157 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=591 +p reject 1-65535 +r vampire CRhyAsDXMnk+KuJV2n006O0E34s bX2lmG5Ott4tX3t0goyTQKzazUg 2020-04-20 12:04:09 185.132.133.29 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r Merlin CRuzjYpkEBSmUqNqiCep4w7uqII JrILSLPwGcGIvNFMJg3fOm9+Ga4 2020-04-20 08:14:54 54.37.16.241 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20800 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Unnamed CSrkR9zN+Dgs8NtuOPMZYanHqq4 39NfPrMaAi2xsQap9cfIYYRRlEc 2020-04-20 12:17:55 199.195.252.245 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SevenLayers CTW6kXj547UMmd1T9yOGX8Ikz6g /phfdjxfiaX/IIo88RSVRWe1WmY 2020-04-19 20:56:08 192.124.250.83 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16900 +p reject 1-65535 +r SarDust CU6NAgh/1sUWKU7hklfYt4A49Bc DI0cQQ/oQyUM23VT5YMZq9MbG9g 2020-04-20 09:28:07 185.205.210.133 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2600 +p reject 1-65535 +r hunter CVzEW/MbYNpH7TR/kkYUdfXIGR8 v9f8GUJZqZ7UO97SYkhrBAfsu1A 2020-04-20 10:36:10 137.226.59.108 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r RecycledElectrons CWTu7zrvhEL1EPimE3Ble8bg4Jg Kh2qku+Hl9YE67wCHiDuuLcd4cs 2020-04-19 20:36:19 95.215.44.167 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26200 +p reject 1-65535 +r panickychess CWyd502dwu+EWlnZYvMDBUrSCAA ZUvWgpCGIolR7EMM7QTt8w6ntVY 2020-04-20 12:36:15 198.199.96.39 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=1900 +p reject 1-65535 +r BananaBoat44 CW3MC+i56hH6fgFG0MUHkCvaeZI r5XiRynAB4dr3IVpaMcWbvOeMCo 2020-04-20 10:17:59 75.110.46.136 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=838 +p reject 1-65535 +r snap277 CXQ571WMtnCUAaUFcUpYm1N6HZc wuD96piwvhwYxdnZ7Qm5llFGfqc 2020-04-20 12:37:19 91.160.36.33 45689 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5280 +p reject 1-65535 +r snap277 CXtQgCZPPAyoozb4AzfY4gJrKs0 S+Z6zrkkjvCll089E1sb/o5V7Os 2020-04-20 04:18:57 189.4.104.111 34141 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=239 +p reject 1-65535 +r PsychiCToRRelay CYkHNJwRkMStrbRIK1H1yfx4nHg bYgfXMe+Q+PKEq+/6FYaP4TWJDo 2020-04-20 10:11:49 80.127.151.162 9001 9030 +a [2001:980:a167:1620::3]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41500 +p reject 1-65535 +r tourette CY2c91aNJ6goj6S7OBmpmRMxXW4 /vPntadXbXUKnrcOpBPDJZKk+YM 2020-04-20 00:33:09 217.224.230.67 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=166 +p reject 1-65535 +r Anankke CZDg9PLBJ73am2cmQA+sB39sg7A ylyzyts4XA+RoToTzcOGBKSFgOI 2020-04-20 07:59:35 38.39.233.117 14514 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8130 +p accept 20-21,43,53,79-81,83,85-86,88,90,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1043,1103,1113,1194,1220,1293,1500,1533,1677,1723,1755,1863,1883,2082-2083,2086-2087,2095-2096,2102-2104,3690,4070,4321,4643,5004,5050,5190,5222-5223,5228,5287,5675,6880,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8502,8601-8602,8888,9418,11371,19294,19638,50002,64738 +r Unnamed CaHana0mpOxBEcqMRxucV2aJP4Y ZkuLUJ6ff/jX+41kFpwUhDNM/wA 2020-04-20 11:40:54 142.44.156.159 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Deepsky CacOOW3pP1TUVBu7Dsjisjdh808 D0apXeJPiJGhhzgyguf8emG/fO8 2020-04-20 09:33:33 77.68.88.20 443 9030 +a [2a00:da00:1800:81b1::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=100000 +p reject 1-65535 +r bahabugger CbF9HKDoXZrDTYuqf6rb4I73iR0 K/k/HLUu1I0vBkEzptVSSNgwXPY 2020-04-20 12:31:51 27.255.77.69 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6 +p reject 1-65535 +r OONITestHelper CcKqMSrg3d9MXlfLG+JBWKVAhZA wZxs8k/lyTkDqAjTV21PTRBYU9g 2020-04-19 18:59:29 37.218.242.217 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5470 +p reject 1-65535 +r cadory CdBSS2gEzjfbVZGmkAUadfhM5h4 vgXzmjTvmp9KbQF6OdRYmuHlOgo 2020-04-20 02:23:07 83.135.78.14 19002 4445 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=421 +p reject 1-65535 +r snap277 CdO4qZ+38B43gv8FCrfaFIhMTy8 q27cyOo2NEnZM61CxnxCjpq+4DI 2020-04-20 06:46:10 82.193.100.148 39233 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r snap277 Cdc92456AucE12S7z62+AJAZo00 kwTtJ+grFf8DSCKMnLAu4vqLO7U 2020-04-20 09:36:05 85.2.90.164 32999 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r Taliban Cdjvx8IEjWDktyQ5aO7RLTe9Bqo 1T2Jcw3K9HEOPdTDkNvTdfIpSf8 2020-04-20 09:36:11 5.230.23.199 9001 0 +a [2a00:12d8:7001::6c58:f35d]:9001 +s Fast Running Stable Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=560 +p reject 1-65535 +r spercalifragilistic CeMt+l7B3bBrySbGYXxCBDir11A mPTzHxs7LsHc4m0s6lzDMpNGNHA 2020-04-20 05:00:15 194.167.46.177 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p reject 1-65535 +r Unnamed CeQXuBWDTDdvkqA4sDGIlaE5Tns GtHXsT7E8KGqHWiGj33EAL0VYuo 2020-04-20 07:33:18 108.160.176.91 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11200 +p reject 1-65535 +r BASIS CfMGdFLY0dr9M9BSSkHb9SldNHI jBfnysPh3V6zYWT4KzxJxYgTtHc 2020-04-20 03:08:24 45.125.65.118 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p accept 20-23,43,53,79-81,88,110,143,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Hermes CfZOAPNMiPYEFj8k03vq+SRXAuo vWCGOgYP+cgX3YqruKHNI7oC1k4 2020-04-19 19:59:47 108.39.229.147 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8450 +p reject 1-65535 +r Unnamed CfnkAK5RALFdkhIB5yY3tpC5G0c 0kNcAtycJBx4Bgs/i9fDZq9bYq4 2020-04-20 10:31:21 111.90.145.126 21989 4110 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=207 +p reject 1-65535 +r El CgBx6I+HbkSx3OhI/a0RXmWVTKo 4eXT0XPFUk9BiJcjV0i8D3cxtgo 2020-04-20 06:24:57 179.25.158.252 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=66 +p reject 1-65535 +r portnoy CgwB3QBE5wMY2ePaXxJaCQacV8E O8QfUGCirVzeMOzrgrMsJLKHb6U 2020-04-20 05:40:22 185.198.26.149 9001 0 +a [2a04:bdc7:100:16::ab2d]:9040 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5840 +p reject 1-65535 +r snap277 ChLoNBXO+HlqBanRNZ5cftNWgL4 wom74fvXilQInKo8chuqq0mwT4A 2020-04-19 22:12:16 80.98.96.182 43433 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1330 +p reject 1-65535 +r pusith CheNMCk28gmvPad8zE48TV2+Eek u6w2zJq4GImPpyX3G/CD+Hc5N9U 2020-04-20 02:07:29 178.63.172.14 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r RoundRobin13 Ch8yKkAyppZLc/T2DVghuZuLHeE J1C2wUQ4RJBIoBCprihcoEzzFC0 2020-04-20 00:03:09 91.106.131.90 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p reject 1-65535 +r Unnamed CiFRwEkrihf9A+1AWYYnpwJ645s gfjFFrz8lGAzN1Y8pqjh3bpxFiM 2020-04-20 00:21:14 63.227.116.162 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r blinkybox Ck7RP1Y0EIfXkBjAU5DPKik6/c8 4QUYw5zSdgeG2CcCJwURSNr9ZaE 2020-04-20 06:24:36 128.199.149.82 443 0 +s Exit Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r niftyguard19 Ck7Ux0AgdAqQTzqZNgMLekxhcLs Q3YRdwm1MitkLMtpZlz78BTUpio 2020-04-20 12:45:01 185.220.101.228 1228 2228 +a [2a0b:f4c2:2::228]:1228 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p accept 80,443 +r FlashEel ClAA5f8pd+DSNrn1tHWQ2IiElN8 j6CzWDr96iaBWpRNxlPxur7cnXE 2020-04-20 05:00:44 130.61.125.241 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6400 +p reject 1-65535 +r niftyDinosaur ClaYW73bX9H6qMkTPHEVlhqmw3A jEavlhGHnPCLtU3xrlcLIrASVGk 2020-04-20 09:10:54 178.17.171.225 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21500 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Faultycode CliwXUA6JmPrVhJPjHqrDKv6oRU qglZl2WlX7ViY9N6W6rqbUhSvS8 2020-04-20 02:03:25 85.209.50.72 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4190 +p reject 1-65535 +r Sturmvogel Clks6KU67N+RMNNyRcZGCyOHKN8 JKERyc3IPi4VKXcwMcdc41ZkhDQ 2020-04-19 21:04:12 176.15.224.56 443 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4440 +p reject 1-65535 +r arighttosurf CmABseOp9TZb08KYi9abuOrXEok kv4UZ0plNTB5UL4YNKBiNOuxZyE 2020-04-20 09:28:28 82.161.50.30 9002 9031 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r cameloid125 CmPblO9eJEbToTA86g65x6jsdhU iZ5SVwL1E5XU3kHJuvQE1uWU1FU 2020-04-20 02:37:07 159.89.205.184 2443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=799 +p reject 1-65535 +r FalkensteinTor02 CnIIuJA90/9c36IYo4I69JjOac4 5Mqh6Spg7k3RsuypKRDYpItBuUg 2020-04-19 19:19:56 5.9.44.29 9001 0 +a [2a01:4f8:161:32c7::2]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=48000 +p reject 1-65535 +r cbd98f06c5b7 Cou0ona7CxATNxSQgPtQsC5jhTM aIw92ox008Bf0id+OmhU75HnDxE 2020-04-20 09:03:24 51.81.254.24 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r torpedo Cpdxcj2N4uAVcYMD3Mi82Ir8Ygo s9ytVDC0nQQ6y3550fKSQ8xXnXg 2020-04-19 20:39:28 81.221.212.72 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=322 +p reject 1-65535 +r torwell1984 CpqiwFJvHJF0YlbZQEneVKdwTEg TN9d0KEb5rOrmBqpECUNAi+qTk0 2020-04-20 09:06:38 146.115.133.179 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=151 +p reject 1-65535 +r fiedlerRelay07 CqOfQysud4ysBvgNpEl1OFNHzdk F5H24yRSrjoETGXhQr8HkgC5fkE 2020-04-20 10:07:50 185.233.107.110 9001 0 +a [2a03:4000:24:829::2]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3600 +p reject 1-65535 +r merrall CrBfxjz5rHBwwdibsaEYnDGeGpI hQyP6v1Ge6OCSl2uJz5Sd8DZpYI 2020-04-20 03:36:11 185.227.82.56 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6790 +p reject 1-65535 +r relay6524284254271 CrtjzICd6JoKcam6h1HEq1wtw8M y5nKgRRfW0sAWFwabsuMUnpcDG0 2020-04-20 03:02:29 185.255.132.94 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Unnamed Cr02L3wM40weHWBqnYM3/YwP0SA 4SaUwqYAGs9dO5Qk9TfuJRm0QBo 2020-04-19 19:46:18 88.198.61.241 32273 2718 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1270 +p reject 1-65535 +r kalashnikov Cr4xUX/bkYL65ASCHkMsh09dHQU HE8IyIBTb6PhbYRTbOvTLC0KFMk 2020-04-19 22:30:19 31.13.195.39 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p accept 20-23,79-81,88,443,8000,8008,8080,8888 +r clicker1 CsTE2Lyo2nuua+P+qHRC5yQ1PL8 WghbolGLyi8UE0diHa+sOargxwc 2020-04-20 10:09:36 94.16.116.137 443 80 +a [2a03:4000:29:91:2549:9:f370:a1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3190 +p reject 1-65535 +r ritirong CtOxat8+7T5ZYvqUTNUBNS55CBQ GVwSTQxhZdfMKStubDz6/ix5N0U 2020-04-20 02:27:41 46.165.250.224 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p reject 1-65535 +r riuriu CtXcPEfK02LlaC9/vV4uKLLUmJk y5bPJQGqp1m1JnvycjiMWHnQ7ds 2020-04-20 10:23:41 37.187.16.175 8090 8091 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5750 +p reject 1-65535 +r snap277 CtrTWy3kfKxGp+YkPPiPtmbNggc uy5tcKoLHhak7YzSqifb2r00/Rc 2020-04-20 10:57:20 2.7.229.242 41969 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2140 +p reject 1-65535 +r Unnamed CvkChdaz7MUqv6PLMUBN9vr5MTQ Sg1IohajDvQU1gly7CKFI42BVeM 2020-04-20 07:15:17 37.191.198.135 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p reject 1-65535 +r ieditedtheconfig CwecfBqMpLRGVMbpmd2AsYS+N30 /UfCz7fC2yKYZ59GP0PdB9QnRe8 2020-04-20 00:00:00 134.209.83.57 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r StarAppsMR01 Cxm7/cSYzOojAnsde9jiASG5XmA bA7yRRGk0z9/KtugsHTN1zJqsVs 2020-04-19 19:17:37 185.181.160.216 9001 9030 +a [2001:1600:4:8:f816:3eff:fe0d:b974]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74800 +p reject 1-65535 +r colosimo CyURC6NHOm3ASrWKOg1eTWkioOA dQcoaSS/+rHLnviiimbZDUIhAzw 2020-04-20 08:55:42 109.236.90.209 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98000 +p accept 20-21,43,79,81,88,194,543-544,563,706,749,873,902-904,981,1194,1220,1293,1500,1723,1863,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8087-8088,8443,8888,9418,9999-10000,19638 +r Unnamed CyhfUnlixNUKjNVU7aQoq+TVwFQ V19mB71GPpRIgBEIKk/5Bo7cuvg 2020-04-20 08:31:56 218.110.147.186 443 80 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r voxstueckscheisse CyjHKoLUzgFgFtq5jQd8mX9SSqE v77xhcBQZ7Mljr+hvhpndtGakKw 2020-04-20 07:06:37 195.123.227.107 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3190 +p reject 1-65535 +r OnionLover227 CzLYARN+brwdzAE1GidOGDnPPnQ +zOU6clX6uU6WBUObgpj/WjaVHg 2020-04-20 10:09:43 84.197.135.154 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1490 +p reject 1-65535 +r ozora CzQ824k0cp3JGxyte9LQX3BekOA APXVWx/31yq0YT9hHtxL2zIphME 2020-04-20 03:23:48 89.40.181.107 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r niftyboglemming CzyMKysaHKRCm5ZJ9TO+tNdHCuo mJ44qicn6iJ0m7phF6MbmfEf3S4 2020-04-20 04:13:58 185.220.101.133 1133 2133 +a [2a0b:f4c2:1::133]:1133 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49100 +p reject 22,25 +r Ranlvor C0U3WizoBl6KZJ1SzDXznRKHRag Z8V95wkOUpXGrw5qX2Y7JxzeJ1M 2020-04-20 11:45:53 95.216.27.105 9001 9030 +a [2a01:4f9:2a:1b96:2::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6930 +p reject 1-65535 +r TORro C1VZQNN9yElyiEHAspAHThob3Kg sXuZhC+xJ42M+JkFc0VFwafG+UI 2020-04-20 03:46:05 188.138.75.101 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67400 +p reject 1-65535 +r ULayerSwartz C1ipXlOf+mwFwBD1wdo1+4A446g dXDxn9tM5qBGs3PztJ4kuJyp4Lk 2020-04-19 19:33:43 199.195.250.184 443 80 +a [2605:6400:10:4f7:fbbd:d07f:bbb6:4da7]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r CalyxInstitute08 C15ecP/qnH+f/RO44WkWpgjz6es XEFYPFnZTC/bqQ3HB3WocXoP9wI 2020-04-20 02:08:42 162.247.74.216 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r itcanhappenhere C4I1AtNOFZh79qirRVe2ABALDsU riB/wJexgaNpCZkQQgxYpNQnm8c 2020-04-19 21:11:01 82.221.141.96 9001 0 +s Exit Running V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5 +p reject 25,465,587 +r Fission04 C4Qctw+e0f0DIsK6LrDYBCDYfPo v7oipQ5jf1EPCWMqhb1vlFs2lHg 2020-04-19 19:25:49 149.56.94.219 443 80 +a [2001:470:b14a::7]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p reject 1-65535 +r tdxchg C6MKPRG3P5XRRHzJs1vl8GgdWhw sIlHpLEJQNLSBbjTxIKYn9grdDQ 2020-04-20 09:39:04 5.199.133.193 9001 0 +a [2001:4ba0:fffa:5d::93]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45 +p reject 1-65535 +r Albis C63ZUQRAyb86co8stjCDb/mBQrI S0idQgqaGBCfxlacSRIchDhrYCo 2020-04-19 21:47:13 138.59.18.106 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=893 +p reject 1-65535 +r makhno C77pDIFPnf0hNYkMog/NN8aVumQ 4zHQaOCZWd+EjNI92wf9z5Bs+Eg 2020-04-20 06:28:44 209.222.4.174 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=716 +p reject 1-65535 +r bullman C8MUKByDFn8kx8/NaN4GmwKpI0U +j0MQA5eN6zXBVjrz4thlVnFFhQ 2020-04-20 00:22:28 88.86.102.163 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r artikel5ev1 C8i6Msw8sPWY4MknePfAlG37zpE 2R3hE7J/iGibjAjQ2SGjAals+hk 2020-04-19 20:23:41 87.118.116.90 443 9030 +a [2001:1b60:3:221:3132:102:0:1]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r bigdaddyny C8zzZMTuczi26SDmPpUZIshfkfc t5W6Dkh3la+KMkAKdIMftB2yosM 2020-04-20 05:17:40 74.111.25.177 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8780 +p reject 1-65535 +r quark C9dExGdP+2DNHypuh3sC975FWLU zbBLTEl89xNxxtiP/GHb6fcNNmc 2020-04-19 22:52:23 178.63.68.78 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23 +p reject 1-65535 +r 0x766c6164 C/YG3oNtTHlMr/fKeHIPjIdmCZg eLZzq9OmRQhH1s1au/1lEyX9cpI 2020-04-19 23:19:32 5.14.156.124 9002 9031 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1740 +p reject 1-65535 +r armik1 DAOIvFUteskD9JOQpAJE/T//RKI wQnKxi2ai6Y7v5xw/BsIcgwpllM 2020-04-19 23:02:30 95.24.136.153 443 0 +a [2a03:e2c0:bd9::2]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r libel DAOfNcLkDctxzYoH6Xx/13h9QtY c8RjJS2D3JbqD+tYLYyJQHACu54 2020-04-19 23:52:49 5.200.21.144 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17400 +p reject 1-65535 +r 5GRelay DAlEXQK0n6Jr/YgdZV1sjKCiVyA bEGwfdwVtnFoGNIBRnSqaWNk41o 2020-04-20 00:50:38 3.17.117.250 13275 0 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r BassBeatsMelody DCXRzoO3VMSlocP8HCHiVa7F12Q anTvx5Hnc4OQcNWPqs4WwckDHtk 2020-04-20 11:00:08 185.82.203.209 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4840 +p reject 1-65535 +r torrelay182365 DCeBAR1hzLAJRZtRFY2mMouj2zs SWHpitK54Hw+inMAiVh7Pblx9+E 2020-04-19 22:45:28 149.56.228.36 9002 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6840 +p reject 1-65535 +r tryingOut DDPKgp2kGMmyapOIlUc7x5PPjOQ M7cUUWu0NCaeWthLpqLIytqQh1w 2020-04-20 01:57:19 84.30.75.164 443 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46 +p reject 1-65535 +r rem023 DDWZB57yHEmUrW3ekfcqSPFuipg EAh/cXa014f83Iz0w/i49Q64JyY 2020-04-19 21:15:27 217.78.28.37 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r HORUS1 DD1eGePHW1Bcis0m+J3KLflwVT4 226ElkiLyWGznh55rz27DiBYGM8 2020-04-20 08:20:51 95.217.42.7 1066 1067 +a [2a01:4f9:2a:2e8d::53]:1066 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57300 +p reject 1-65535 +r Freebird32 DEdbpNOqPCibcW+VlUytYW5QxOU IfLLHy9HdHmaDVdElfHh8eMcjEA 2020-04-20 04:45:16 81.7.18.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14300 +p reject 1-65535 +r king DFjApW010utpb2NNeR4GfEVCWSw KZ6rgTcuP4Gtbo7rATXa7yd9rPQ 2020-04-20 05:18:29 51.89.213.87 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17400 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Halo3Valhalla DGhCzPg23gjv6gvWwUca40Y7m3E LknULT90sgKbMtsPV174ZZ2Kv8o 2020-04-19 23:02:10 23.129.64.186 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8900 +p accept 1-65535 +r comeandgo DGnaeXPE8dJvuOjczNg77BJpZFo Dq9gd+obOl9SY7r/yvRAwmf6Zug 2020-04-20 11:10:23 111.90.141.158 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1050 +p reject 1-65535 +r lamomieauguste DGylgVNAD6B36rsUdz42/WG/DXU 31TmELKRUNObL68j6C8kzpreB8s 2020-04-20 03:20:14 81.17.19.58 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 20-21,23,53,143,194,220,389,543-544,554,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,8074,8080,8082,9418,9999-10000,11371,19294,19638,50002,64738 +r aSmallRelay DG02VXY7Gjpg/EITXNYHZa/pU7o Jm/cH+QX+gYBs8G18Dq0AmE7XQo 2020-04-20 04:48:56 116.202.238.106 9001 0 +a [2a01:4f8:241:3cd4::2]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2220 +p reject 1-65535 +r anontaxi DIQztrkuLxx0Tzz75JrafL7+6/o 3Mv1r+gVFV5I1SCOuzTTNdNfV8I 2020-04-20 00:05:14 163.172.47.34 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r Animus DIin7yFqxFfL2so/Vy9/Vii+1lA JtiEbKELvgzwnDD2Cqxs+jng3I8 2020-04-20 01:22:36 195.13.50.212 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=320 +p reject 1-65535 +r doppelganger DIpJ/mK3x97WS3xqlB71JA5PP3Q iz90yW71iUcqMomgR/3+X3l9Z4o 2020-04-20 12:19:16 95.217.5.88 9101 0 +a [2a01:4f9:c010:54f8::1]:9101 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9000 +p reject 1-65535 +r pzodisoe3 DJCnfEtPW4zCmUjjqsV7l0Rw9Po 0wllrR1R7FYLJx9RpiSpH0c6Who 2020-04-20 09:07:54 37.59.36.94 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=183 +p reject 1-65535 +r torstreiktnet DJNVnW1+lbQVYUJDRbCxdvvmbwA qPtn45g9rGO01SJYPwHs+xSr00Q 2020-04-20 11:33:15 78.47.226.12 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9700 +p reject 1-65535 +r nsaPwned DJs8aGQhxajCC6oNc2nNkp9DoXQ hREF8nK0G9BzNgCN8An+4rf+qWs 2020-04-20 04:17:20 80.244.243.158 1337 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2360 +p reject 1-65535 +r mgvx DK//5HDoivFW1nULYWmVs3kPJO8 blaIR4uYLR9Q0HLzzo/1b4Y35zc 2020-04-20 07:29:42 86.123.52.188 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=599 +p reject 1-65535 +r 998ff4256e18c5cb DLQNEhd8urq4dlK7/ACn5vRDTT4 p/YqRuNbGaRAZfQJXm2QXisJ9ls 2020-04-20 03:54:42 185.41.154.232 9001 9030 +a [2a03:75c0:27:a9c2::1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r LunarMerlin DMGOQuXsrf52hizi63GJ76F6Ef0 b3qR8mctRIwI7q3F+mYq+5hSto4 2020-04-20 01:21:31 78.69.12.229 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p reject 1-65535 +r yeicob DNYjRtG1yxZI3akH+Biw3+p1Log eSOFtvE5S0aAtIafjiXgwJg+Pls 2020-04-20 07:12:05 51.161.33.20 443 0 +a [2607:5300:205:200::1abb]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9440 +p reject 1-65535 +r UnivUtah3 DN1g5AFevyw7XTKiucyP5smKXDM 43o36ABitU1t8Couke2XnDLPPPE 2020-04-20 05:32:34 155.98.5.6 9100 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3100 +p reject 1-65535 +r Route66 DOO3Pd/5L/ZlOpx/kAOjK7bCNk0 k6Na0ssUD1jjErvkjaVuoUUjc1A 2020-04-20 07:07:50 88.91.112.118 80 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5220 +p reject 1-65535 +r snap277 DOiCyw3pmwHVWPUZXKs2vzEdkLw TFoWKEUnrOj3t2LNuZm+WK406aM 2020-04-20 12:13:23 76.31.163.117 43617 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=491 +p reject 1-65535 +r torpidsFRonline4 DPjz5lkPRdULcPL32mYF7KbNQI8 XMOm/zMrC2BNvbnZti3Go3xGBq4 2020-04-20 06:06:18 163.172.25.118 22 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23500 +p reject 1-65535 +r mef DPw8AT48SVh4Q3lhBsXjrQk/Vf4 t6xlpTcTO9kI19B/g52fQ1GLFzs 2020-04-20 11:44:32 94.23.248.158 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74 +p reject 1-65535 +r tornadonode DQVK9zNOffO0tLg4ww1iG/EXNh4 Zcid/QCjUUBI+KjTfJyoiPsyEgA 2020-04-20 02:11:34 79.218.173.165 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=324 +p reject 1-65535 +r sellerie DRLY5y3tme4xuwxXeJNSvtDO7v8 QAU+wunZ8TXmWNfim84tsvUmfNc 2020-04-19 20:17:12 109.70.100.10 443 80 +a [2a03:e600:100::a]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79200 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r locke DRP++xUJAxAK8vnlKlhS7BBagX4 21zp7wFxvaJnHjzLTYmB1Hr2qdw 2020-04-19 23:42:23 46.188.6.64 9002 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7140 +p reject 1-65535 +r oniongroundrr DSQqSqDWFlVFjuFaVEGuyevI1zU akkAS594pBBJYYT6jvleBe9pYJk 2020-04-20 09:14:55 184.54.75.212 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2300 +p reject 1-65535 +r DigiGesTor4e3 DS3iQq2g7XcyXjruOp2MXNB8LPM KhTcCJVYQ4y9BAwk61FydluB9RU 2020-04-20 07:34:08 195.176.3.20 443 80 +a [2001:620:20d0::20]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Unnamed DTWkV74DBPJlYxDJDHdGlaN3Oms 8WhuXZZVve/2Ax2FQ5pmdYgpVxg 2020-04-20 06:37:36 51.79.86.180 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 25,119,135-139,445,1214,4661-4666,6346-6429,6699,6881-6999 +r cavative DUObCCMD2Fz0CIthMutQUaL3ISI JUqooiHfkFK2cMAGHKvNOLgHMCM 2020-04-19 22:58:23 139.59.85.24 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=628 +p reject 1-65535 +r Dampfsonderzug DUoa5tlPXvKfe30V2JPVDBf0+5Y UEHUxqC2Y3ioQ7sp3d3FwPYppqs 2020-04-20 06:29:46 78.47.159.96 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=20000 +p reject 1-65535 +r RWCrelay DWF0xxIb6/xXd3UPmdte2l1AzaQ MJFqs2VinQJQv58B3fxWZ4koYqQ 2020-04-19 21:15:08 185.230.125.38 22409 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4 +p reject 1-65535 +r martina DW4lvYxUAXjDCe4qhMenRJY2DW4 HByx/5bL4fm6G4XpZyVUfOXIJWU 2020-04-19 22:08:45 193.234.225.62 443 80 +a [2a00:dcc0:dead:ba3e::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7330 +p reject 1-65535 +r lara DXxpVR+RhttYm98AhYMUrBNqM9o QX9zau1I3xQqhwvjn8GCBLhDnhk 2020-04-20 06:22:32 46.4.217.100 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45000 +p reject 1-65535 +r smell DXx4OBdOccmVg/YVBs+7Ut1S7MQ An8Ij+Al8e2fk2awZ0kIaBFMEqk 2020-04-20 02:03:06 137.74.153.7 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r LooseMoose DYO4pZN/aTjHTzJsIcIZWfOV6CU aNyUw6qjIHwepRq1ZsXH/SFpCwc 2020-04-20 08:05:40 206.174.115.140 9001 9020 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r granby DYUCuNmaxcbOo219v/DH8vusDtk sL8x3bUi186wDhoYrwgNtcHEDqU 2020-04-19 23:13:33 212.69.166.122 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20400 +p reject 1-65535 +r Starlight DYh3OS8v9a2NjlvEOAh/Au+XuQQ sZ0bdt13AGt5e13wqKyf6qKUcr4 2020-04-19 23:29:04 1.43.247.217 9001 9002 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=125 +p reject 1-65535 +r notani2pnode DZn4m7uSv1VX+NP4ldshinKHEIk I5YTJSGGkr3zn+7ZQgXg2Jmdy5c 2020-04-20 06:01:43 46.105.121.228 9100 9993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38000 +p reject 1-65535 +r avdjusko DdBO8LCBu/3jCC1OzIpj/QAi/K8 mJMUGMd8BX4cCVcw7EWabDjAw78 2020-04-20 08:16:17 141.255.161.167 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13200 +p reject 1-65535 +r Andrewlev77 DdWfmDZlFxhFLMYvMSgZ+YoURnw i4dPRgX36ZDnBnzQ4d0oiwD/2S8 2020-04-20 12:03:22 87.162.164.237 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1080 +p reject 1-65535 +r humanscent DdwZDUWmxFL2gUQIKE3ffagXUAY 63P9/awd8aV8x0rpJcd3WWxZHeo 2020-04-20 11:47:12 45.55.34.252 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=919 +p reject 1-65535 +r RelayName DihGfhDrZvfnY4r2iHc+lPPy5tc uskbpgFLo0GPtwfIq5Ck246YY94 2020-04-20 02:55:11 31.169.6.86 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=232 +p reject 1-65535 +r BringMeToLife Din0car0xjp435Qn5L42eUKk8GQ 4x+miWRpySzS+mg0rTAngIEAF5c 2020-04-19 23:01:18 96.230.76.104 80 110 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5460 +p reject 1-65535 +r Nako Di7sElpqyNXr9ds2t3aj2lUQ56A 1tmN2Gsel5SZaWK77avK88duF5k 2020-04-20 04:59:06 51.158.79.198 9001 9030 +a [2001:bc8:47a0:1807::1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r pcfreak DkUqMOfgV0QHFnjgoFm920aJMM0 dp+b5R+NAKjNi6qpsMMTzTDeXJA 2020-04-20 01:11:08 83.228.93.76 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 +p reject 1-65535 +r weizenbaum DlUiy09542wLsmO6vIYc/GhpKa4 jm63jPRLgWQ62HBfwQ2reea6/Jw 2020-04-20 05:17:00 62.102.148.68 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50300 +p reject 25 +r artlogic Dl1zBGblu2dbyXBMN02+fhnwYWU bM/iTdJVNKcqTBKF67M4tGm68XM 2020-04-19 21:58:18 165.227.34.240 9001 9030 +a [2604:a880:cad:d0::6805:f001]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3780 +p reject 1-65535 +r bee2 DnLpNZMIQGn3IED0+4IPpRCxnRo 634771RmM/rH2neaKI+X+7NTOms 2020-04-20 06:59:16 62.219.3.48 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2400 +p reject 119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Kladuin Do20nVv1/K/6Qzp4/uNBeUGdHE4 QPmTvqr/x/pNBkZasx7SWn5l5gI 2020-04-20 06:23:45 51.15.228.222 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=820 +p reject 1-65535 +r k0nslNET1889 Do/UNoCDvXgXpC8+zt6G3+PDWVg Spmc7zGjZ0eJMa/8WF2es7wSqc8 2020-04-19 19:32:35 199.195.249.82 443 80 +a [2605:6400:10:163:8592:98c1:1d47:7cf8]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p accept 1-65535 +r HorpickSneeker DpEpz1aNSdFaCjDgyqlArhmKNUc xhxZP5uvVJ644XcD3wpQGI+yYA4 2020-04-19 23:29:39 206.40.118.229 443 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r ua321 DpK/ArPBGw3RgwGg3hsWSgVG428 tuxN/+JeNMImaGIxld2Jxpj7Z5E 2020-04-20 10:02:40 185.222.202.12 9002 9030 +a [2a0c:b807:8000:c93a:ff51:90ac:0:3013]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r alexandrro DqunoqQpUTazD39O4vOMzJ1HS14 rHJO94pPbOI9VaMWDYcdMPvq1tk 2020-04-20 07:39:52 95.215.46.168 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3300 +p reject 1-65535 +r OmegaRelay2 Dq0AAOAbBzroixtKDmOmuUB7olU e0YokgsDsWs+NbzfYkgaEHviy48 2020-04-20 05:26:57 203.129.27.87 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=251 +p reject 1-65535 +r Enimal DrBzQO8tFgj8FvYmjh2gxTLrPRE Aos5GPOz3ko2J1GMh1h5JYZ5HEI 2020-04-20 10:29:00 213.32.90.15 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r TOR2DFNrelB DtDqMkyTHPQctScr+x0BWz1Xcqk m8zWmRWYnJmVHW9V61dYYWkNIk0 2020-04-19 21:49:03 217.182.196.68 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=71000 +p reject 1-65535 +r Hermes DtTKio5s4tKNbSOyCBWuOYJkb8s 91mpnbHkQGQ9Go2y/+QzMnDVtt4 2020-04-20 00:22:53 104.244.72.115 443 80 +a [2605:6400:30:f858:2704:73e1:7085:12ef]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45000 +p reject 25,465,587 +r coi DuIIKrV6r5GSd2hbJ5KS4UZbzk8 9gqI806Zs5VirmWAsY39s+iHT34 2020-04-19 19:54:22 192.81.223.177 9001 0 +s Exit Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19 +p accept 80,443,6660-6667 +r 67c213d7b5a2 DvLff4sgn3FgRjYEo/InykW9uuE +VRorkYAWLMsHB9ut0p7yx7g1eY 2020-04-20 08:20:16 51.81.253.205 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14200 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Torsti Dv8YVWnsGA9wJ8BgxctxJytfjEQ acW2QTkaWWIYC6bJAieQXVkfyfY 2020-04-20 04:00:29 188.68.34.96 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 1-65535 +r itsover DwJ5z/ZAjX0RC7QuaT+mT6YGy6c vFOT9aEtssDywR2/vhsSgAC4tSw 2020-04-20 06:36:57 185.82.126.215 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1720 +p reject 1-65535 +r anonymous DwtPrTBLlp6D/xjR79F/BBOwXfs OWO1CYgl9XMc8blV3dmOgFKyzYE 2020-04-20 09:28:25 46.101.145.137 9010 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=701 +p reject 1-65535 +r panspectron2020 DxlBPmnbZQfv3eyURMhuBXTW9HE wh6PhjiXEkhGLLi4Tjp3D1pWwaM 2020-04-20 09:09:49 91.64.93.37 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1640 +p reject 1-65535 +r tranquility Dy2gSNt/sbEJ8I12K/+lIeJcDIo xxVkfSkhay2lDAB660Mnj/1NXX4 2020-04-20 07:39:32 174.136.98.130 9001 0 +a [2607:f2f8:a2c0::74:6f:72]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r oddskate DzQmtqFZSNTpEGRNsG0Nhwrznp4 V4NzcCyg0dbh2v5dOJxe/JVCrkM 2020-04-19 19:03:50 45.77.72.85 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=1390 +p reject 1-65535 +r snap277 Dzo/NHeEdmTJuwImXPsWU52oCu4 o3oTr55/z2PlIbMuXtpXEmrgJsQ 2020-04-20 06:13:52 37.144.238.27 32893 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=668 +p reject 1-65535 +r Qazwsxedcrfv Dzsby0LA5ojUpFiH7912K40vCPk j0JP6SY7mJAw7bZ2INim1FYqIeM 2020-04-20 11:17:26 47.152.207.89 9001 9030 +a [2001:470:f00d:1:e139:a2df:f3b:e56f]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5000 +p reject 1-65535 +r Nozel09 D0gOJP5b6pK3l8852cJ5rc9eb7k syLmO01thbW9f7QMK2zesArupi4 2020-04-20 06:34:52 51.158.22.87 9001 9031 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17500 +p reject 1-65535 +r partain D1LpZS+WrR1QCsBiNQoUmQLBKLk kSxL+8Ag1zBr9B0wv6XPymMRJ8g 2020-04-19 19:11:33 188.214.129.21 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22300 +p reject 1-65535 +r pilvi D2oEJ2y5XQQq7o0ot0WHj4J9IQ0 MrrdQ2mMaDRMow3WIW3TG9NY9hM 2020-04-20 08:42:32 85.23.41.52 9011 9041 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r wansabai D2qHGsArj/fjBWKBKYkMxngETkM wtEjgcgpCM96aiwOEkICsfWG8EQ 2020-04-20 03:07:50 138.197.202.35 9001 80 +a [2604:a880:2:d0::503:1001]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3600 +p reject 1-65535 +r jaures3 D25cpL9VZdmqn93KFlr8alMFdj0 t5qiPcb7TuAedtgr98Tx36Uc1iE 2020-04-20 01:15:15 193.234.15.60 443 80 +a [2a00:1c20:4089:1234:67bc:79f3:61c0:6e49]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5070 +p reject 1-65535 +r mrshuTor01 D4Xm2w5KO2/d98lFLJtdCJsRl50 j79XnfkZk0oPQBIHxs7+YUb+CqQ 2020-04-20 08:03:12 31.31.73.222 9002 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10800 +p reject 1-65535 +r signorbusi D4mRLmpMSorOQ8WP+Lg8opm/908 yGPiyA5EV7rcgVONtkk6V101juc 2020-04-20 05:33:54 81.6.40.141 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=100000 +p reject 1-65535 +r nordiques D4qWfOyT3lWQ36nZM5+V6wTS7sU lJ+7FUlDhmhxqzE9mrJks0WR4xA 2020-04-19 23:31:15 144.217.255.89 443 80 +a [2607:5300:203:1259::]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48000 +p reject 25 +r slalix D5d7TW6+7NV4rIOKX93IG2NgYKc rPH0a8vvHlsDJza2HJmrbTux16o 2020-04-20 09:18:33 51.15.105.214 443 80 +a [2001:bc8:4700:2500::90f]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15700 +p reject 1-65535 +r patimkin D62oAbFQJhEJ3R9JK7EM45yDp4I 9l7ZRwTWjxf8hI9ng33vTggthkI 2020-04-19 20:32:39 188.119.151.108 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r ParisTOR D67Qt9PQCcoTpXqISc/qwUVvr0c nH2MGUbcMbKOdq0Y182wcqnvQ4w 2020-04-20 05:20:14 82.67.205.48 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2910 +p reject 1-65535 +r niftyhazelmouse D7Ltq5nRCitwg3DmJTI8duuJX6I tsCXOJOXCQrfDAFuYr85G2pWbFw 2020-04-19 22:13:54 185.220.101.146 1146 2146 +a [2a0b:f4c2:1::146]:1146 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p reject 22,25 +r WaywardHound D7fCKOkm7VIo7CjMZuYM3ITHHrc wNbByTbyc9CZnjwekYhlZiIEEVg 2020-04-19 19:05:16 208.113.133.247 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r AcidBurn D7s8Yattk+EKveaeuMzGBRiovzo VWbbPy7jD9qQrHwySbUHIHXXrqs 2020-04-19 22:59:08 23.129.64.204 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5350 +p accept 1-65535 +r mentor D8EvK33Q6Ukw+bPN0yEwiZZlKVc 48WP5leJkZoomp443iaguTe/KUk 2020-04-20 07:08:40 72.14.177.164 9001 0 +a [2600:3c00::19:ffff]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=66 +p reject 1-65535 +r BaBaBooey D8q7jG5BLmDLhi/hmmQZGmnrlOw pNpYNJFNn7QArw5j2n5AOCdTaU4 2020-04-20 00:27:06 108.62.211.205 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=45900 +p reject 1-65535 +r king D+ALjHro4sg8MVtgu7wC1Uo1aGo cMgGDuccUfa56t7OCreCEc5ZNqY 2020-04-20 04:52:43 51.89.147.73 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8640 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r jannis D+3r6DwfLePWZzh2u6FDPM8K3lE 9sx06yNDWJr4jVVrVV3AZ7uqctI 2020-04-20 01:57:57 31.31.74.47 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p accept 43,88,110,143,194,220,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r politkovskaja D/IzyNeKF7jbfIJX0uBc1ap8a4g TYgP1RfWiE6hfyh1BEmeuLeHvWs 2020-04-19 19:06:28 77.247.181.165 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47000 +p reject 25 +r 0x616e6f6e D/nnFHjps1IW2S9zpUlphT611Ok 9grdYS5wf91GrT9MmA31gviI79c 2020-04-20 04:45:33 94.140.114.62 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6800 +p reject 1-65535 +r alphagremlin D/n4glAfsdYQUi32qtbnXJX48rg PxM7u+v9jrshKTVtFZdvDS82mJQ 2020-04-19 21:10:48 78.107.239.253 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1800 +p reject 1-65535 +r Unnamed EABcuYRs3Pfx8iz3mGLV1llyBHg NERVZ/OFjdS0Myeg3LRVtG0X0Lg 2020-04-19 19:36:58 198.50.128.225 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8590 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r mirabbit EAGV4HmnYXUVh+MaCR0uIgbzXDo 5MwWlZmakOacL6bCjTDMD7j3RQk 2020-04-20 05:44:04 5.135.187.5 443 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9840 +p reject 1-65535 +r LovePeaceFreedom EA0jal/T2AMywTcoyeFSeMOuLlw 2sKP7sZr7NX0ERyu17Gm3nQMv/0 2020-04-20 05:24:15 172.104.147.72 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=745 +p reject 1-65535 +r cryzrelay04 EBwYiGswuyOzbLqtFZJhGIhS4RI 2gaL+23i0ZGy+oWgdzIYLni+5HQ 2020-04-20 06:50:20 82.149.227.123 9001 8443 +a [2a01:440:108:11:82:149:227:123]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8700 +p reject 1-65535 +r smell ECLOKqtvvrYtf/pwRA19zmkpYLA pVKOoxG0j+KyNvMkTelxQeREV70 2020-04-20 02:03:53 137.74.153.8 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9430 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r doofenschmirtz ECMeCPGcA9Wi/jqtA9hjq94ggbw sR9V+UlrRjLgk7fzNz549UzdBjM 2020-04-20 04:33:14 173.249.2.224 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r Uva ECOUA6fBmS12+0XiC4npjvzmnaQ VE1k55UiVXzVxrvk7fv0Ir2EGB4 2020-04-19 19:33:43 147.87.116.29 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37800 +p reject 1-65535 +r torchy ECr/9CqOzjEPI7gJYwk70a1epcQ I/JAka5E56VMpIhvAWH4UiX/YsQ 2020-04-20 01:25:00 93.219.41.158 9002 9031 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=322 +p reject 1-65535 +r max7 EC6hSSEfSQwSLKzEBU8bxqhQPrQ C0jVPtPrqQ3osMbp0bpWfvlvkK8 2020-04-19 19:17:06 93.170.246.217 1294 1295 +s Fast Running V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80 +p reject 1-65535 +r RelayStation EDM2FloNLvytNgUzmEOgp3ELi5I OeR9Vf4CbqpKVaXnxivRgPOQF74 2020-04-19 19:11:51 85.195.235.248 9001 9030 +a [2a02:168:a403:13:5054:ff:fe21:7c4c]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=52700 +p reject 1-65535 +r Matrix EEF7mJB10Egchoc1GqlhGOzGivM UatjjRO31+3aKkM4ULdX9Ydl3go 2020-04-20 09:50:41 178.27.147.64 9001 0 +s Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24 +p reject 1-65535 +r king EEiZnRbZ8lhabkCq1ctH5WGOvI0 7n4CbrHdsZYUW1mSQUO6AQQRyoM 2020-04-20 04:24:26 51.89.213.92 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r vger258 EE3BWs+mnPlPiejtD2zbLSmCNNI 0sxIz26D5ljUfKvp0Ez3seAYWVk 2020-04-19 21:13:17 163.172.152.22 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42800 +p reject 1-65535 +r KenRelay3 EE7dBcCCx/vAkzhdR99ku9Pogi8 W0id9qx79oJ3jWL9MLCoQDbObVw 2020-04-19 19:34:58 3.9.60.181 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9370 +p reject 1-65535 +r niftywabbit EGRM89f1VfEP4o6x1SARH1b+cYA v4qwwSJc61/TqC6txhVWwkydFfM 2020-04-20 10:54:05 185.220.101.199 1199 2199 +a [2a0b:f4c2:2::199]:1199 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=51000 +p reject 25 +r PoochySloochy EHnmKPxrACVlasAk8tmXXEQUmM0 Jjh9+91jSLd8nnOE0p1XLv2I35I 2020-04-20 08:19:54 51.15.185.201 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=100000 +p reject 1-65535 +r Unnamed EIQVKcOkYxwWLsTcsBOQ9Emg0rI DJpg51Gy2zcfGIuBwa7ciG3fbqU 2020-04-20 12:14:34 93.186.170.7 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=55300 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r niftyhedgehog EIQgC0QCHTCOpCU/JWeUZxsdCZo dHF8m7q/+2JtWADeGVtzuwGoEUI 2020-04-19 20:26:18 185.220.101.1 10001 20001 +a [2a0b:f4c2::1]:10001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32300 +p reject 22,25 +r a47u26ufdzq EIy9qowtCpTwJGkWdq2iCxyibYQ RQED+qDb5sxjsZ64pUWT0ZoTDfg 2020-04-20 09:16:36 172.104.74.190 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=143 +p reject 1-65535 +r Unnamed EJbXHC6kWmjk06N1yuWQ+/NJ3qs 6njS1yh1DTFS+hCRjwNCJAb+2tY 2020-04-20 10:44:55 51.158.76.119 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=650 +p reject 1-65535 +r chaoxrelay EJmYPixcPs2tC31aq9Ksa/LLv3A 8IHYpESd3OGRDIBaiW0rzv89AQs 2020-04-20 11:53:52 46.4.122.173 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r bewilderbeest EJzgCarDWgjjYjvMU4v4noB5yqQ 67RxFgoe311ZlEA0G5pcaFhILwE 2020-04-20 07:30:54 71.19.149.21 8421 8422 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=480 +p reject 1-65535 +r rpitor EKHiJaVuAvZgEb6jzVHZ9pTSKRM V5kUKBcHLpVrauxLe8rktrUd810 2020-04-20 07:26:04 162.237.207.53 9001 9030 +a [2600:1700:131:c1:ec99:43ff:fe4e:f310]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r eridanus EKXvzNL7nBpKwg+3eaXbEbWJV6c kbflTTdBipJw5WmtEnrDipTh//w 2020-04-20 10:00:30 213.239.218.195 9001 0 +a [2a01:4f8:a0:72c1::5:fa]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p reject 1-65535 +r MuddyMouse EKnB7DvMhcIJdn43TZOmz/XyLKI lk5/U+EPQCbrXy1o7H4ROTl/LvU 2020-04-20 04:52:15 94.156.128.10 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=59 +p reject 1-65535 +r pnwtor EMPM+jlAH6/kJvVKEpcOcJTe1xU OLFLtlrzwnJY3CbMC12VDzdUEmA 2020-04-20 00:50:18 63.225.175.196 8081 8080 +s Running Stable V2Dir Valid +v Tor 0.2.9.15 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=25 +p reject 1-65535 +r vaal EMcX0Xf/i3K58LWPa5c47rYGojM ex6ib5i1cSWcMC5jhjLtI9ihJ5E 2020-04-20 11:48:10 66.175.217.78 8526 8986 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=420 +p reject 1-65535 +r Torminator EMpa4mCeufGampa+SytEZ/OVbbY bVJ54mJ2NOaoWJ0wsqYctHTjwKU 2020-04-19 21:29:26 80.208.231.152 9001 0 +a [2a02:7b40:50d0:e798::1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4010 +p reject 1-65535 +r tor2oeoe801 EMqFnEKaF+/3BMxT0AgJQBSNWdo rJ1yo2w04ihfZgubSO6jXtqDLv8 2020-04-20 09:53:30 193.182.61.9 443 80 +a [2a0a:3507:1:2999::b060]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15400 +p reject 1-65535 +r christianbro EOHKehg/bHF96usHA/BUUcjOXU8 zhypJ1n4T/52tZGmiEW3+nLG5K0 2020-04-20 07:23:15 178.32.221.207 6069 6070 +a [2001:41d0:8:e0cf::]:6069 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=8300 +p reject 1-65535 +r Unnamed EOnW+VGhyd8FWSK4rtiQIgoLwTw YsN39lJ2UTuwW5yjQI5tOgW6JSg 2020-04-20 01:29:33 218.45.67.146 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r cryptonaut EPZQRTP6WFTz6HfVjObcB6TfW1E 13IcpX/U7DIHFC384zPZpNB3BhA 2020-04-19 23:25:05 213.195.105.125 9001 0 +s Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23 +p reject 1-65535 +r tondro EPuPb6XIkqmUJkB9/cokhoMDBAg e0HSUQUsNEZFmtYe8aE2/hVoNUc 2020-04-20 04:51:56 91.109.21.148 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p accept 119,563,8332-8333,9375,18333,50002 +r snap277 EQ0fGyvddwsaZ1Dz2Y3+/E2tbc4 +eGqYYP1DePGLO5Rfs8M25UOBSs 2020-04-20 12:02:58 78.123.14.102 33379 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r zerodivided ERmonnKdtlg5+yMqHg+GabCuhN8 hd7k9k+cjO5SvLM1KcB69PRK36w 2020-04-20 05:52:00 80.241.220.57 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6070 +p reject 1-65535 +r lpcomsat1 ES4ZQvozFXfPoUAK9PSZ3dJc+Ys fLqlT4IqeVVH3639PBTrssEmMV4 2020-04-20 08:53:20 209.141.40.201 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6500 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r parasol ETFDRpAhiCw6S4LwhPgSWwjuRx4 wpKJfyVFuW0St9+Szez9hMX5g0c 2020-04-19 20:22:08 93.177.67.71 8080 9030 +a [2a03:4000:38:559::2]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r 5fd833ab ETGE+YVa7LHZvzIwoHQI7Cdnpis Uin395E8Q2iMn70W0tChodyy5O4 2020-04-20 10:10:43 95.216.51.171 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16900 +p reject 1-65535 +r mpfusion ETNj++swjIpriXmBLFsmzRIUNEE S3pHwnN4xjVmJNtJq/OWdLtYoLU 2020-04-20 10:25:22 93.215.152.116 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1790 +p reject 1-65535 +r giovanna ETerH4TsLVLfsZFXF/FP8aEOs5I 0SXqK7njxKLjNe37+XyX/EWxh5g 2020-04-20 09:18:22 185.227.68.78 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p accept 20-21,1723,3128,3389,3690,4321,6660-6669,6679,6697,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed EUHjabVNXJ9eAUHslmvkyHhUibw vcdcHINlKCsvcj2Hi2DfSACoxJE 2020-04-20 07:27:30 217.87.65.220 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5 +p reject 1-65535 +r afoosrelay EUWjnsDOGINOZ9J5njxdh0U8XvI A4jgmNCfMqmCerUngfRWB2UYdKc 2020-04-20 11:27:16 116.203.44.87 9001 9030 +a [2a01:4f8:1c1c:924d::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p reject 1-65535 +r Machiavelli EU+xRRE6jVOBjwupNj37yB3IRH8 OR4ZpCefqkjLAquBiDchgsi07zQ 2020-04-19 22:06:55 167.71.150.11 3389 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r frs03dp8023 EWDZWWoyhhjAEFRsFmQHRBxIPTY uY0FW1T7i/5vBBQbF84PUWwCX50 2020-04-20 12:36:27 172.94.53.204 8023 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=66 +p reject 20-25 +r Unnamed EXmF3A8fmKSoYt527VygB7ZcFKw F7g6e8AYW1RDI3nV3SFtlW2w5lU 2020-04-20 10:25:17 23.227.199.103 9001 0 +s Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23 +p reject 1-65535 +r Unnamed EYjcVJ/fXoBU4f6MeJpjLNGHL34 64FxW44B06+jFh6KdJUMACHqnhI 2020-04-20 01:27:56 51.75.143.150 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=17400 +p reject 1-65535 +r UniqUser EZ5Waz10dliQjqAPM29OFYrpeq0 f5O30x9UH2taBWV0H+ButHhjTQ4 2020-04-20 04:24:15 212.51.153.16 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=902 +p reject 1-65535 +r ru20101315 EaqZt2tGUzNEHjAA9HeZXHBJm5I mksmhlWEWra/H5EaXcPEabEZTh0 2020-04-19 21:48:27 185.246.182.197 9333 0 +s Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67 +p reject 1-65535 +r jonasbebe2 EavbTQuUTxhqiYVgy4LHBDmVfco Z3VP7JjxIT99qgtvT1+nPHvGdrQ 2020-04-20 05:27:56 178.63.18.223 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Unnamed EcPRShFmrt7W0kejLeZFH2yVIjo 6Zpl3VMVASnmWt9K8CcsOl8DmqA 2020-04-19 19:08:57 51.75.153.19 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11800 +p reject 1-65535 +r mekansm EclSnJ0GcVRervgN/iCa2Xe86Qg w5k4Emey5BPfbNLqQEi1OszF2Lk 2020-04-20 01:18:03 95.91.3.85 9999 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r gGDHjdcC6zAlM8k08lX Ed8AF6Q68fCIJc1dlzKX+BqwD/M uAqJIDd5GPFhuPASC7vIh4fgsKg 2020-04-20 11:48:54 37.120.174.249 443 80 +a [2a03:4000:6:724c:df98:15f9:b34d:443]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p reject 1-65535 +r hopertor EfCW3iGZ6IEv/GufouWxxHQ5nv0 RM1gm1RDBCePCXXINOxpqm4R7LM 2020-04-20 02:48:29 176.165.28.165 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4440 +p reject 1-65535 +r sleven7 EfrABcTgeTPfkpKmdUNaMdqo+eE cn6EQQMKrw/ppOfCC5cHm7pdovA 2020-04-20 10:31:47 151.236.221.44 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r AgrippaRelay EgYmB3eLVMIhWmhgbHw7Ad186PI dVkaw7KuIOy8dTHlxUPvJ3TA3hA 2020-04-19 22:01:00 88.99.76.10 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=270 +p reject 1-65535 +r MasterOfDisaster Eg+J0QL5ZkfSJYFms7tQy/zvIOM s85g3zQWacKmGseE4xkQbP/wgtI 2020-04-20 10:27:13 167.86.94.107 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ccrelaycc EhGsG7uKGvfLqGvOhomqMUa4ZCM 5i3LmCVQeeRJEC6I97ncSjtLM0E 2020-04-20 06:00:52 95.85.8.226 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1850 +p reject 1-65535 +r TeleMishka002 Eh7MinvYgYI9rqPAhY1R/fGbGZA 0Bi3CehQFu7FwowHX3uGre1B0zM 2020-04-20 04:00:00 157.245.184.13 9001 0 +s Exit Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=770 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r MattWillNameLater EigRGm1K/GGe06cAeaOgtnhHakM JI/TmYTkJUHecu9MxTQp+QC0zaQ 2020-04-20 04:51:19 23.129.64.188 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7300 +p accept 1-65535 +r FermentationLabs2 EjV1kpSAIkMKj+dtMS/6jFWExag X89gtM7ybztEwaMgysR6eHwz/O0 2020-04-20 06:37:30 99.150.229.21 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r snap277 Ej1S4+TI6yv6Fi/Ac7Mh7ieyOe4 BBl9b+mUySusd0Dmufyi4BJoZw4 2020-04-20 07:11:54 90.110.75.214 36297 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r PI01 EkplJ0YxugK2qg3t7RRNX99r3DU PfbGK5bryZaeFKZqwMW2fwdsRMM 2020-04-20 03:30:14 94.16.133.124 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1510 +p reject 1-65535 +r snap277 ElT+K2jTclhj0oMpVYGr1Vltu58 dQ4HHDW9c00I6VRJMc/sunKxwJc 2020-04-20 06:22:56 109.13.138.29 38197 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3430 +p reject 1-65535 +r Unnamed EljQqdlVgrdmb8Cvbpp5gQmpop0 yE2oYv9GA8M0cFWRNrcPznhtoAY 2020-04-19 21:55:09 165.227.161.62 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=733 +p reject 1-65535 +r Bathtub Em5Di2khiC/Bfx/DKqxhcwBWGTg bChDgxkj6mR0kjX4NJv2tKCucRY 2020-04-20 12:55:42 212.74.233.19 9003 9033 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1650 +p reject 1-65535 +r Stuttgart0711 EnDjz7r7X8zov9Nwzcmuowwj/VU RyuSYYR+Q/mC6TOwRndAFnIeA/8 2020-04-20 06:41:10 46.223.38.135 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2110 +p reject 1-65535 +r Wy8L EnDznvTTsu6Hkn8tfORNfUFzWao n5DfNcVGAcRufw2Ish9Zc5DaMlE 2020-04-20 09:34:19 51.158.154.122 9001 0 +a [2001:bc8:1600:4:208:a2ff:fe0c:67d0]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r CoudroX EniHv1tp7++g3Ef8dnE14Kyq/Z8 omY98f7G/oV88BVz/v+F7tjysR8 2020-04-20 12:33:09 2.57.236.215 9100 9101 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r heteigenwijsje EoPr3uwrnXRfHn++g0B2VbmE/WY /YFLEXRSa4ELHo1bC1TlcuSuYx4 2020-04-20 05:26:51 80.127.116.96 9001 8080 +a [2001:985:7aa4::2]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,563,587,636,706,749,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6696,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r amedias Eo0WUIZ2WY3Ix0Zcxah6M4IIRmw QSDfwYO90pxXc7TJ82Nx4eynD4s 2020-04-19 19:05:10 95.120.214.163 10001 10030 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p reject 1-65535 +r FalkensteinTor03 Eo/G2Pv3UxIcVmL+4wnM1Htkums khCk1uv/TlTjqbrf/Yx6jCc3VQQ 2020-04-19 19:22:11 144.76.236.27 9001 0 +a [2a01:4f8:201:120d::2]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=56000 +p reject 1-65535 +r papillondesetoiles EpP0mbddBBuihYHJoHI8vJ0TOXM q5Lf5Y0tMiyOEXbsnQJ62n0+pVM 2020-04-20 12:30:02 176.151.246.91 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=838 +p reject 1-65535 +r mdfnet1 Eq0w5dJapn9Rl4DiER5hGkVf3Ik OgAftSnvGBcpHDWYYR7Y3TO2Xr4 2020-04-20 05:28:29 193.11.114.43 9001 9030 +a [2001:6b0:30:1000::99]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18500 +p reject 1-65535 +r angeltest32 ErGldp04/0fPaMIjXhvaMV30API 7NrWtCqXfiL3WcWwbnwgUxxp7tA 2020-04-19 19:57:11 185.99.2.178 443 9030 +a [2a00:8620:201:215::9cb2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4790 +p reject 1-65535 +r hotelbloedel ErabClMkly/zIaAy08ESi5D+wO4 PgEW85W/S+6mY7OTuvVaU9FTxaY 2020-04-20 01:45:03 81.141.176.111 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5120 +p reject 1-65535 +r yesno ErbFs0sDmI2GpIuI95IhV6rY/9c MBjf2x6qZ0iUrICAnl4tdbxUSCE 2020-04-20 07:21:19 185.125.33.58 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7730 +p reject 1-65535 +r zzzttt Eri93XJZirfANcEdWNVwXWgWdm4 L8NH0VPNlFf6M1f2uaEoEzZEarA 2020-04-19 19:48:43 89.34.27.61 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6110 +p reject 1-65535 +r dangelo EsK6BATIa7mVvJ5y14MDQ6q5YXw 1R+OS1TAs183w5m65zl9DwcyXZQ 2020-04-20 08:45:10 185.234.72.43 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=786 +p reject 1-65535 +r ATZv5 Es9ttNrhBiBtbGsJmI6GXAUJhDs ZNZ9jrPqOq81Su96hBaphib2sT0 2020-04-20 04:41:29 159.69.114.110 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61800 +p reject 1-65535 +r Unnamed Es+E09LjC7l5m/wOHd39qNNa8Ac cMF42dAwJv0rmvrvMQHui+WCisY 2020-04-20 11:24:48 5.135.178.184 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5310 +p reject 1-65535 +r TOR2DFNrelA EtVS6K96orcbIYtbv2pf76bya6A 4wUqhNKgdrYx1/kIGXTsIigpqko 2020-04-20 10:51:57 217.182.196.67 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=88000 +p reject 1-65535 +r TorRelayMPC EtnaU59HpVkf1T2Supvd+IiWiew 10mva8VOxc8bPKXmOBFkcY1Axvo 2020-04-20 09:52:50 151.80.44.177 49001 49030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=1020 +p reject 1-65535 +r Trumper Et/J0YUpeZOdkxf1eoV8gLxzFl4 5+xwBAXAACpW3k1tiNm4UH9a+r0 2020-04-20 01:54:17 87.147.184.154 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2140 +p reject 1-65535 +r Unnamed EuvILuY4eRXXuD5YA2n5cCJqTY0 KTpeYF7TkO7wwYccYQhXtvcNF7Q 2020-04-20 10:51:51 100.8.164.39 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31 +p reject 1-65535 +r floberelay2 EvTD2xyP4cSf6YSwI2TPsZRqi7k BY4BM6kzy5h6lXT+BOLcnKKnA3A 2020-04-20 03:33:36 172.103.164.206 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=590 +p reject 1-65535 +r ridcully EviHmN1Lm/slppeNqD8ILvHVBRo Yoxgw8WLdwDlmllK+gJQ+XLt+9A 2020-04-20 07:00:00 188.40.99.69 9001 0 +a [2a01:4f8:221:1901::12]:9001 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r TeivosRelay EvjlgxDPB+s/Lpqtb3i81QZdOTA 77GCXPBPA4ZQ3inPDQ3qTvLsasc 2020-04-20 08:59:17 94.71.182.40 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=74 +p reject 1-65535 +r thanatosCZ Ev1iTuc87zcTfJDTiyQGpm9o+qI MZJWamvpEJdMhOyO/hZ/p3OLMBA 2020-04-20 09:06:56 37.157.195.87 443 8030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p reject 1-65535 +r funkturm Ew5p6PeD3vJW51f6eBVLfcKjng4 Eq9uaLGliNRiTYt5sOQPEEB5PNc 2020-04-19 20:37:51 185.72.247.145 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3700 +p reject 1-65535 +r Unnamed Ew7W9m4jOabAL2SSdihXxuSlByU DFW7722fhjRWxQlyA3nED1z3l4k 2020-04-19 22:23:41 85.226.195.172 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1290 +p reject 1-65535 +r JassMischer ExNc+W9K1Es31FTNGF0vWITvkBk ezfaMBUoo2QJyZCav0/d5xa8pDw 2020-04-20 02:04:43 212.51.151.250 9001 9030 +a [2a02:168:5214::15]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=952 +p reject 1-65535 +r apollo ExwuRvR94nSFffVcdWFhqjKgjX0 zRrVTCoDpkAUIZ3SIeY/Dv57t7Q 2020-04-19 23:11:34 66.42.242.13 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r CCrelay1337 Ex+8ij1LRN6bJYrcWGdAgrHgbSw vGs3Bi73jR6qipfW3pcnIMPv2Hk 2020-04-20 00:43:29 188.40.238.144 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20400 +p reject 1-65535 +r Unnamed EyLZDqbtqFs6hWbywE8tjFx8HvE mcLuisTXsKI13Jw6tUInmeQWMwg 2020-04-19 19:30:53 176.126.242.49 443 80 +a [2a04:ad80:1:8a::31]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14300 +p reject 1-65535 +r angeltest27test EyPTTC+krg7E7qmFPzRkaT70KOc 43O99VJOkxAEyuSisj9q/wkEQvU 2020-04-19 23:10:10 92.223.109.71 443 9030 +a [2a03:90c0:b5::38]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3610 +p reject 1-65535 +r Unnamed EzfABTxG8W9jREJgKfWIcAF7JPk yNPYdPAdx/ZGKlj9j7bEzG78RGI 2020-04-19 23:35:42 198.199.112.121 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r artemisw EziJq3B5GZpDcMh8x6XL/+7G3oQ MXzpBIJCDdESAc3w4J4ds9DQIsw 2020-04-20 04:02:25 24.187.175.14 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=250 +p reject 1-65535 +r torreymcilroy Ez9G5Fkpnh3L6RUlw1Op2yXEdNs 99KEYgKBE3FpiWjLf1cHdZ5o9mE 2020-04-20 05:47:15 45.56.77.230 9001 9030 +a [2600:3c00::f03c:91ff:fed7:c81c]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r DFRI8 E0tJ0CEsiQZPl3jl6P2ee8NG88k x7BEN/yaVMU66a81vtLGBnKUJpI 2020-04-20 06:34:06 171.25.193.234 443 80 +a [2001:67c:289c:2::234]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21300 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r bauruine11 E1V0SK0WMr8IB1fC/3dpuyPfHfM En8Q5uKe9dXx8oLgqc+Q3qnKmcU 2020-04-20 02:59:51 144.76.71.91 8443 8080 +a [2a01:4f8:191:8484::1337]:8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=111000 +p reject 1-65535 +r niftyjubilex E18qizL1g4RfKw4TPv2EwlAmdhs At2fqKlk/l6thTsWzi/10DuzESs 2020-04-20 08:51:08 185.220.100.248 9100 9101 +a [2a0b:f4c0:16c:5::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46900 +p reject 25 +r BurnerMeetsTOR E4irQDlvV+2Vu2A25lBM6OD2Irg I2d2gOJROkan3/wg/hBp2VSYorc 2020-04-20 11:31:13 84.160.68.224 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=302 +p reject 1-65535 +r sennovakatido E4uV+aEOi+umsUKtrHMxdlxhrOQ TPqmgQsgKa/zdSg6VO5QF3/4kr0 2020-04-19 22:03:10 88.91.29.249 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p reject 1-65535 +r GoodfellowTorRelay E47UfuIVbmSS/eC2EzjZc8lxfzI HS6DsjJkhI+rvcCRxOlDRkoBjoY 2020-04-20 03:26:21 92.222.180.10 9001 9030 +a [2001:41d0:401:3100::7d36]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 20-21,43,53,110,143,220,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r KS0120141125 E5fbEGSS8ck3HMuoWdr2hD/ie6Y 6lNVjMlU4rGsjDuxswsgiOpZkfc 2020-04-20 09:28:33 37.187.97.31 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r voluntaryism E6Y+wkKpfnNVFFYBqvcNmek82jw 8wimavWUweqcGZZJSfdduEkO+Ic 2020-04-20 12:13:12 37.19.127.104 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=98 +p reject 1-65535 +r mkg20001Relay E69oQJNFSHJlvGT5+f4FD6Pn/WM t9FFKyr0dnFr4DOJcDSJy/BzXkM 2020-04-20 02:28:31 91.22.153.63 9001 9030 +s Running V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=99 +p reject 1-65535 +r jodope E7EyIjDp0Qwp+K5jHaZYrlw8e6Y qnk8om7Q2sf8kPfA+fkQrgL8IQo 2020-04-19 20:28:02 144.91.104.242 9001 9030 +a [2a02:c207:3004:5908::1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18100 +p reject 1-65535 +r TORtitan E7I1THTM4pgVtOH2kvLw6Gx/E90 MUji6M/SmHVNqZ1zyaqxol9bSDE 2020-04-20 12:34:35 172.241.140.26 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30200 +p reject 1-65535 +r snap277 E8ocHH9+MpQyDu9MAbjY8sWX91U QV5O1h6vGpyU/vkE3AnqiJzBJ3Q 2020-04-20 07:08:17 90.93.38.108 35683 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2390 +p reject 1-65535 +r UenoStation52 E+4OFMaidRYzE4J3wUQ6TDfdVdQ wa4qv+/lUGSgeb9gbOXiqxrRXp0 2020-04-20 04:08:43 51.89.143.152 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2440 +p reject 1-65535 +r darky1 E/JNX8YOmdNTWmh2HC1iIwNIT5M 2R8emld7eu4bDPAhfg5Ph3zGf/A 2020-04-19 19:32:00 51.15.46.15 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21800 +p reject 1-65535 +r CanopoIT E/fq5zHKRgCVGYaSHgjsq5sdKvY JDbWPpEXK2i9WLqrugfiF2WEj9I 2020-04-19 21:35:21 37.9.231.195 443 80 +a [2001:4b78:2006:ffc3::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17100 +p accept 5222-5223,6660-6669,6679,6697,8082,8332-8333,9999,11371,50002,64738 +r ApexOne E/gOZBelP1vQF+zIheJZirLaMrE +wcUIXTmCIcdMD96RyQuy3zCwbU 2020-04-20 07:40:26 88.202.230.112 9001 9030 +a [2a02:2498:6d7b:7001:216:3eff:feb6:d2c1]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r AnonFrance00 E/zg9uM8vOJC96koYSPZTXeNf0A 7j8ZD0YTAZDzwDHXLzm4Le9SpcM 2020-04-20 11:56:31 52.143.157.92 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r rortor6 FAjaXDEP7s5258+I+2jssosi1Nw /w9pw9s1n5ATbnLzVssCFRhM8s4 2020-04-20 12:32:16 172.105.204.32 9001 9030 +a [2400:8902::f03c:91ff:fe8d:e505]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=350 +p reject 1-65535 +r Redu FAjqur9zN+ArOr1U+PX0xIxaEyY j2xeG0K6xeIbYLEd6andbf2Fqy8 2020-04-19 21:40:10 62.171.145.59 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34900 +p reject 1-65535 +r snap277 FBQf0B72hHU/erO+AIHTVe4U9WQ 94ys3V8bSNJBUvvVCDzSNYlOYRY 2020-04-20 12:03:26 196.188.192.92 43399 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r Cosworth03 FCQAC4bfZ9H7/2hbIEBzu5WRzv0 Qs2EhAieu62aU7+RC5LUypDCn18 2020-04-20 12:27:10 54.38.52.101 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r lagarennePIrelay FD9aPvhL8ajoKZjKJh2ciJwkcSc nzw4utRo49JrxjP35DistRAefjA 2020-04-19 19:22:41 91.173.202.195 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1090 +p reject 1-65535 +r NotFBI FEsZRkHTl8PBt8R44r9sIfx7ZRw 9XUznTgUOYbfRLcT/KgkLC4DUk8 2020-04-19 20:24:30 80.186.168.9 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=911 +p reject 1-65535 +r cycasctornodeerl FHshoYB/jHzLwmpNstAuL3pA4dA bmmbo4qfjuEG3HP1G8qBijcQmw0 2020-04-20 04:31:14 79.239.62.2 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1580 +p reject 1-65535 +r Unnamed FISHxuvgTrIklggMIHlsUbBg9hE CD1bb6E9Ni9W/DKy7FTiBU4WSeg 2020-04-20 10:11:27 37.191.196.246 38443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13200 +p reject 1-65535 +r niftywoodmouse FId8Y4Sp55P0IsjR3aRHyspPfEs qMKBWjH+GZQy3XCdLSMDMV23OQI 2020-04-19 20:27:24 185.220.101.31 10031 20031 +a [2a0b:f4c2::31]:10031 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41700 +p reject 22,25 +r iriseden FInthtYUsksCs1Us1T7pxhinxr0 kYtSImNVQFyOB5yiQjSajq/j/xU 2020-04-20 08:11:46 163.172.125.41 9001 80 +a [2001:bc8:32d7:307::351]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r draco59 FL8YOgY+HcZa3ansMBm0dTX/nn0 Z9MqQYp1e0HrTIZxwwxsgz7j6G4 2020-04-20 07:44:29 62.171.145.37 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r hp FM8EAJ/+gUSDkfP6Ym6dLxFL3lQ u2QYN6HaKWhYLrK1QKuzmi4QsBg 2020-04-20 11:31:20 104.244.74.57 9001 80 +a [2605:6400:30:f625:20:20:0:2]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9000 +p reject 25,465,587,6660-6667,6697 +r OONITestHelper FNL9xqvc0aJ8oy0TqixoVm0egiM CXn3YLxqx37LmgJSQj9u61XvvHk 2020-04-20 05:29:11 37.218.241.28 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2200 +p reject 1-65535 +r acT0r FNV97fCkVUotIa1TzMxD4xFYxzM suh+vnMuXkOUhQiqk+RTIP8nMt8 2020-04-20 12:19:34 136.243.39.185 8443 4080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=89800 +p reject 1-65535 +r Assange012us FOctTaELZjU+WD8m7gSsDVY+p+8 8JdNVU0NZpMr5nsMgl6UXgl71lM 2020-04-20 02:48:29 147.135.114.98 9001 9011 +a [2604:2dc0:101:200::6c]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9280 +p reject 1-65535 +r PatsyPide FPk+bJTVcywhKHfWpoCu10el0rw Y7gP7mld/WRpFBBiB8Sat4Q7/qA 2020-04-20 03:16:03 83.135.69.146 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2430 +p reject 1-65535 +r max5571 FQHkMMIej2PrTfFMXKzzz8YwdRo 8iHd5sX1/75pXrecXMHJQIg6bYE 2020-04-19 21:09:32 94.130.27.193 8080 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r tor01hueedv FRz8NsNCNEP2jAVj4xMhrVqvnio fSBHOH+IeH2NWxUjPLkt8m1inDA 2020-04-20 12:32:38 78.46.60.40 12801 12830 +a [2a01:4f8:201:4101::40]:12801 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4500 +p reject 1-65535 +r PiTorBox FR5j0p6eeBst9ZOz1+KA7uqf6S4 9/pcQPNFdXHVvnl0XZgMyThm3oA 2020-04-20 07:41:49 90.112.45.184 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=380 +p reject 1-65535 +r casaholiday FSPFAql1S2tCzKXrQCqDPP8OQC0 c81Lk0A0/zMwWod4cZKuW7Jpz0U 2020-04-20 08:26:57 209.90.224.5 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=106 +p reject 1-65535 +r funbox4torrelayipv4 FSQmF/wQSWENlZMetWEwuOQeQ3g hQSZjqiv+4BuGPplIiX6+ifJxWA 2020-04-20 08:39:14 84.132.157.225 9001 9002 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p reject 1-65535 +r snap277 FSW+U8SH8E8ctvXg/c0o3Ty8MC0 CoDnLb0r1mQIAN3lH9mMcfuGeug 2020-04-20 09:19:54 81.241.2.86 38189 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2400 +p reject 1-65535 +r thueringenhosting FSlo4uqL7q6hd4EcFiWPzvkWqU4 He2LXnWs0DmYXt09kg85MWoJwxI 2020-04-20 12:03:32 87.148.122.126 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r tspio FTKjYXLHABKxBX+7+v4nNO2/Sjs NxxKPLtMRjaG6mtaaXfg54e/MXA 2020-04-20 02:56:39 77.81.247.72 993 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p accept 22-23,43,53,79-81,110,143,194,220,443,531,873,981,989-995,1194,2086-2087,3128,3690,4321,5222-5223,5228,6660-6669,6679,6697,8008,8080,8888,9418,11371,19294 +r Unnamed FTli+g8qBYqX03sDlgc3fuZ+WIU 4F2hBmGT0s1vuEdYysU2kUzYfGk 2020-04-20 11:35:10 185.227.68.82 58380 37756 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=140 +p reject 1-65535 +r COMPUthings FT7Wj6mrt1lDknRcfSLDITNWEhk vyndqzaFvsS7fwuzKAslpP5oAFA 2020-04-20 08:06:36 62.235.194.119 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=216 +p reject 1-65535 +r TugaOnionMR6 FT8lchezu+aqt1b5JA9Ao9cSY8E XhB3IcEY5Nf3YnbVOkBg5kvFGek 2020-04-20 06:55:21 62.171.177.98 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=42000 +p reject 1-65535 +r HANNIBAL FUFcLEQMxvAKfOxOhEcw9t7GFTs k7PvaT4crN9o0MnCZ6f75lma+vc 2020-04-20 04:45:27 195.88.74.178 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=437 +p reject 1-65535 +r rackhamsaltair FUg4k2mSRnJLgTXMbwh3Z+qJotM cfc+NRpjWa+TZent3wAdaeJkqao 2020-04-20 09:11:48 37.187.21.49 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1250 +p reject 1-65535 +r smell FVANgkel7i/8CuW1OdGwm29vkVU Bd7j4QD7Fp/iThk17dQuPNpyJAg 2020-04-20 00:30:29 209.141.42.231 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Illuminati FVcs0+USDY1ZMnKNnltGBMsUCdw NCyxmMKjoAVlMxvW/jgh3kSkosM 2020-04-20 05:07:21 87.118.110.27 443 80 +a [2001:1b60:2:1:3935:104:0:1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25800 +p accept 20-21,23,43,53,79-81,88,194,220,389,443,464,531,543-544,554,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Quintex18 FV1vV0JfFsBiTXd3dkHk6xtHxvA mqstiFoRJ7jEN2X5nR9aii/GTHM 2020-04-20 10:53:33 199.249.230.108 443 80 +a [2620:7:6001::108]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16300 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r WillyJamesRelay FWh90DAmU8lyshQ7He51L2Kgr4M oz8ZvZ3Zvhlv/veLF5GRzfMo+y0 2020-04-20 06:50:57 178.17.170.194 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5700 +p reject 1-65535 +r Bundesgebaermutter FYQalspcEXGYWpVlv3zd/iv46R4 4sEOtvkvY82wA4OzPS+W8ixNdAY 2020-04-20 03:27:22 178.6.191.234 8080 0 +s Running V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 1-65535 +r bakunin3 FYWBgnA03vG6sfwkjRgBZUUuU9M GYEyfeX2VQ4kre4n38fbcJ4D5Tw 2020-04-20 01:15:08 193.234.15.61 443 80 +a [2a00:1c20:4089:1234:2712:a3d0:666b:88a6]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5340 +p reject 1-65535 +r RToRpi FY1BG1HTE0VtRe9m0JlYWXbM3W8 ORpusKRY1+J7ZtGcShdpQQjbyhw 2020-04-20 07:53:04 213.152.161.40 13526 52817 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r raspberryITA FY1teGAg+BqDlQak/DHfmZdhNsY 6/cpPJB/IxWQujLONKrf3ZDUOg0 2020-04-20 11:43:19 2.225.231.92 9030 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2020 +p reject 1-65535 +r rex FaLq4GgUkaXvLVRUCmh4MH51lrc 4bTghB8mFHMFNooQpTkf+BB4evs 2020-04-20 04:54:17 145.239.82.231 9001 0 +s Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r snap277 FafPiL9SPsMSyXBqfljhdoGH4J0 Cxi/XydmfO4jsDdAu/9oIRZ73Uc 2020-04-20 05:29:06 84.120.194.173 39443 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2310 +p reject 1-65535 +r 5b82I0IfxsHI7ekh Fa5v/g4kWoINT3TqZLTDBO5VXB0 rsC/Y71lOb4bSireHgR5IhTrIoE 2020-04-20 02:01:11 87.122.102.237 8443 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1080 +p reject 1-65535 +r rofltor07 Fb4XyZ+s4kRw1Ar3gtapxpKrNtY Wqudn7SP04nETmlseyp7+/KXxiw 2020-04-20 12:06:50 51.15.78.0 9001 9030 +a [2001:bc8:1824:c4b::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19700 +p reject 1-65535 +r bosses1 FcPzmyc3J7au9El1xeb4+jQcL0s X1Twsavh+4KvjKCZer+h2GOCDNo 2020-04-20 07:08:35 104.57.231.27 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7300 +p reject 1-65535 +r snap278 Fcc9xdxiCYpJugmKJUppBPg+7gs hIDJaN/24gAkrJwhpo0Hn3Bb1ac 2020-04-20 05:48:49 77.232.150.186 36371 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=953 +p reject 1-65535 +r HardKitty FcvXUI3cuoFpdVZXh9OEA7sy1Aw dYu2LHiLKV7NsT9uJc1Hki3/u+A 2020-04-19 19:47:40 210.215.135.2 9001 9930 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=100 +p reject 1-65535 +r nortor1 Fdgy7qxnjsfusnsPZeDVC3SkO1s me2w0lc21kTf5jblVLBndFgYk3Q 2020-04-20 03:27:54 217.170.204.126 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16300 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Schneier FeW7pJA2IDo2DwBmLpOhfZQwAlo 6PkjtEG2QmGw93p4DWaH/VGUU4o 2020-04-20 09:37:05 80.127.152.4 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=430 +p reject 1-65535 +r peci1tornode Fe/nJp+z+L57bl74Rx7WoEeZsCA PvorPDG7ai110LQLW9rygwhfUiM 2020-04-20 11:35:31 80.250.4.18 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p reject 1-65535 +r spider Ff7kI9/4r54uCBlZsMYyYHLGDaE LsfJqR1uZv3m1KaTRARSQgxnhbA 2020-04-19 19:05:59 192.119.108.114 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4740 +p reject 1-65535 +r theRack FgHJBhkAsgU/98t0vU7AUgKK9SU X3ObDvDfb7IA9xTdWEr0cE0u1j4 2020-04-20 06:22:16 81.4.103.214 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=57 +p reject 1-65535 +r FGERTOR FglHbX1jN8eoBckavWH5JuxYzjs GHzEdAx7tfR8WXKixl7mv1Iuc1I 2020-04-20 09:15:26 87.121.52.41 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5750 +p accept 20-22,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r eden FgtYBaeB2TOQ1KKuBeqcW0OOeWc Mqq3fuuDNYBwxCFoiSbmbKBhYuQ 2020-04-19 20:16:23 162.200.149.221 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8300 +p reject 1-65535 +r LiuXiaobo FhenArMDIMN6XJ+jz7c3oq+pGY0 o/gu6rsy5AHcZ/WMH2v4BfFx3RA 2020-04-20 10:06:57 82.118.21.59 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6600 +p accept 53,80,443 +r snap277 Fh7EVu+c+lr5WGV73TwkI1lV/Xg Npeo9wXNCNTadb+FiOW/OkjENTo 2020-04-20 09:53:24 81.245.68.200 33051 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r BucketOfBits FjJMiRMr4U8Z4T/W6zIm/Frj8Fk RIvKkPgWOJKaH8jJG27QfnBL844 2020-04-19 21:58:28 142.54.162.114 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16100 +p reject 1-65535 +r Piratenpartei01 FjMD8Fg6GRcyYhQ3m9GrLShgRuo DhHfX4xLkC9lW82Os1xaQy+4kU8 2020-04-20 03:05:31 185.233.106.34 9001 9030 +a [2a03:4000:24:591:a8a0:aaff:fe05:20e9]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23600 +p reject 1-65535 +r dockernode FkKV1VopAmHTF4GU3rNqsAPlrKw tNlsB0NRMNRRKCrTHs5+2ByPDfY 2020-04-20 01:13:29 2.206.63.213 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1690 +p reject 1-65535 +r KienjochDE2 FlUyv1saNN9g10N1QJ1jLW+++D8 Cydzt3p8ajX3OM7aLMfNI6UEhBA 2020-04-20 08:58:18 178.254.18.151 443 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5500 +p reject 1-65535 +r Unnamed FljZ/SVAmf+qoCwiPskShiYB4WA eBL7VrlISHAcM+Jn/wE5bgaokOI 2020-04-20 04:46:44 176.9.144.162 30052 7042 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=990 +p reject 1-65535 +r toraway FlpOhDE2nyRvdL+D7rUVtLHSNMc AV6T4rIdGX6SAxjypE+nIoXaNZ0 2020-04-19 23:06:33 24.190.194.186 9001 0 +s Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22 +p reject 1-65535 +r Torshammer3 FmcqiDOL0BGxyq2JQPvLCb0gqI4 hZZsteWy2X10LN6nQVD/QniKKLs 2020-04-20 11:07:03 108.6.181.168 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r torproxy03 FmmFqEIwtfmnjJcHNq6US0E5MNc 7XPTPrVE7muZTL/OVKHVrBs7sUw 2020-04-19 19:22:28 193.169.145.194 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 20-21,43,53,80,443,873,989-990,992,1194,1293,4321,5222-5223,5228,11371,64738 +r guidemenow FoJPiF1ytPp6UJDgjYd+VAS8IU0 OEODqpJv73LrQv+iEkRIgACr/MA 2020-04-20 04:22:20 62.216.54.29 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p reject 1-65535 +r Unnamed FoSzCuKt03Hl06iz8orKTOnKLgA oGzERVXoVIOONOU0keeAZzKqMIw 2020-04-20 02:48:17 185.86.150.133 443 80 +a [2a02:7aa0:1619::94eb:3758]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24200 +p reject 1-65535 +r Oook FoZEEruZaQfkaWHV5+gy5BihvaA z/Hx+RPk4ArUPD/hup5ElBUP99A 2020-04-20 04:48:33 51.178.54.218 993 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=780 +p reject 1-65535 +r TorRelayFr FobLutYkCEN+VqV2lX5wht/tjT8 8xFB++06amLhTXWBgB8NI518sEQ 2020-04-20 00:30:36 109.9.187.181 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=281 +p reject 1-65535 +r gratinee Fofs6m0g5izzcbqNU7leaHiPmME Fv0RDVB3Kz+xIL6RnBSrg3aWwTs 2020-04-19 19:28:14 173.213.108.116 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4700 +p reject 1-65535 +r amorphis FpCXYIXw3V8IImci3eAfhgbqfEg UHszJTbgw9qcuacl5pdvnPAw3ww 2020-04-19 19:09:23 178.83.129.40 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r bradburn FpU1zEx1/3nG1UjUFyAGTuT+YdI WAEymPrAA6J76oBN96VjRK06OKU 2020-04-19 20:52:16 62.210.125.130 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=64000 +p reject 1-65535 +r Unnamed Fp02p1EI2dd7QiyJ76eDz7xmK/g UBRls04lxXW+AWxZR0bU09Ue9ZU 2020-04-20 00:25:11 93.72.79.64 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=743 +p reject 1-65535 +r torreyporrey Fq4nBLeUxsABPH5HrxHcq6gIoLk zTImyqqogAEMj/e0Rpb4JKq3dH4 2020-04-20 09:40:00 69.164.222.151 9001 9030 +a [2600:3c03::f03c:91ff:fe4c:1fd0]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r M5 FrsKKMeedwDnPAaMaPM2brVSQk0 g963XR5LhxqUe7QQ4Z+ZNd0+Rmc 2020-04-20 06:45:14 71.19.144.184 9001 9030 +a [2605:2700:0:2::4713:90b8]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4740 +p reject 1-65535 +r 0x616e6f6e FtDkUvzl5sKMhvxtFMP56pDowIU csGPz4Ezl1sfgJ7MwBWqLQWBQ8U 2020-04-20 04:37:38 178.175.148.165 443 80 +a [2a00:1dc0:caff:153::d2c7]:443 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2990 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r 456c Ftt4RZuEX05yhAXraU4ykp4rMYo ElthpHb8bALtvNULVYPcYx2xdfA 2020-04-19 20:31:07 91.213.8.89 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=411 +p reject 1-65535 +r zm Fu72xQgHlDI+NnQC0qjtysmbRXU Cb/iPq7egJCBZl7eDAl2/nf/UAY 2020-04-20 10:57:34 144.76.30.167 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r RelayTheFuckOutOfIt FvUPJyhYH+XKesMfUGbc6GU/mWw LPTFY1Hf9ID0AmDxazjawWv4mDE 2020-04-19 21:06:12 51.15.113.25 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r crmh FvaF70qzWxP7z84GwycK3kmP7bM hLWFgt8Oc5WlCD1Qq5QVxW5/TEE 2020-04-20 03:22:08 80.208.211.96 9001 8080 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=919 +p reject 1-65535 +r bluesnake Fvfp6T1sxGk5KtC6Ago/NZ35g0U 1qH4018KR9mzc4ADvAbajV46WhE 2020-04-20 04:24:11 213.114.157.212 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p reject 1-65535 +r brmlab FvhGm4SPnctFkLzFzqXySYC9yAY D+tHR11L6YXvVs5LzgR0SRvRLM4 2020-04-19 20:15:25 91.146.121.3 80 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=224 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r estrellaobscura FvnXhBt+D0b0kdlO6ufkAVKXSUo WTJuudO8wIWKz15dXYsyVWRzZ2Q 2020-04-20 11:03:03 173.73.35.139 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21 +p reject 1-65535 +r firstNode Fv1+XWe3BU7k5/3fBK+0ghbKZAo RqmL7w98YtVhnQRx2etYkyEbPBc 2020-04-20 11:54:56 82.165.115.166 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24400 +p reject 1-65535 +r snap277 Fw6QLNVGIiEkMCMMs7pd9BPIGjg rBzBkoTWDORlLnOwi0ZLwSJFi58 2020-04-20 08:46:50 212.198.134.123 35581 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=160 +p reject 1-65535 +r bella9 Fw7xnA+gSR386m4fsJQWcLgFBuE q+TyH7dOA4mwNOQkT8hjIaivKRk 2020-04-20 08:54:49 94.199.173.217 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=789 +p reject 1-65535 +r austria123456 Fxlb8PHUELhPvKnqscse2XR852E 2Owz7uhgI9e8DKlQBkFVjhLJjFw 2020-04-20 11:00:00 144.208.193.246 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=270 +p reject 1-65535 +r Unnamed FyN1GFST2dYkiwHPloOlQJ0BaPo +Sty0hMri/icu12sEcE1AOnVaU0 2020-04-20 12:40:02 108.2.139.164 9099 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18 +p reject 1-65535 +r bwRelay FzPVeqFtLp5aRI2mB/yl+pieT00 d3OBFVlv74r4kM0UhgF417gq/tU 2020-04-20 12:11:51 192.99.42.34 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p reject 1-65535 +r blueberryTORnode2 Fz4SBsI4jaKMBpmyPq2ui7eWmW0 xxHpjwcg0C+SPCKgFPSzAoRPfkI 2020-04-20 11:59:11 188.166.93.208 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=480 +p reject 1-65535 +r Unnamed Fz66H6yllxhJmugCMYfl+V6L8cc +gdRRbF5vtnY43Vc4pR6goJr/qI 2020-04-20 01:55:14 37.187.122.101 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5510 +p reject 1-65535 +r Unnamed F0II40aBKuBgbmKPW0AV8Jfo7Sg 6QNdyBwe2IBmDTdE5XGIw4b++aw 2020-04-20 11:39:57 51.89.114.178 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed F0PAzIJRcFZrIOUv8W3E9G53j3k x0daOJrAWCc+VGaGpkhe4fLp/28 2020-04-20 00:01:31 185.14.30.137 9001 8080 +a [2a02:27ab:0:2::d8]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r blackPanther F0YJl+ZsR/gFqDS+k8wU7A3GCOo W86mp5Jd0S0xVOngfmPiJqQ21DI 2020-04-19 22:42:25 213.183.56.140 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=520 +p reject 1-65535 +r Tordubreizh F1XMzNWJuB0qyo263kiAZU/t07E LN6c5ptj7HMTpr4I4/dGiAMVtD8 2020-04-19 21:52:33 92.139.56.67 9001 9030 +a [2a01:cb08:8de7:6300:dea6:32ff:fe16:477b]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r ShrubberyGreen F2qTclP2opY5ksJ6mP/k7I4cK1A ZN3PVtdbRpWMGVQNbM3tR60dOZI 2020-04-19 23:59:13 69.250.241.88 19001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=269 +p reject 1-65535 +r Unnamed F2/WhtCDSOn8XgFL0LZomc7zTxM PczmhM9dSxn7xJYdxuIA6h19sIw 2020-04-20 07:00:58 103.230.142.10 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=780 +p reject 1-65535 +r snap277 F3oNZtxkQrBublf2hBGPE/PhmBc Pzve/C7HWQolw0o9vu2sq294HRM 2020-04-20 05:21:57 119.155.58.210 45553 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r Genideb F3qnYOf3ayWc8mAj15MYiujcmm4 Z0zy0M1OylrVHPOGrDIa3Y3Sshg 2020-04-20 07:09:33 178.74.103.183 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=698 +p reject 1-65535 +r nonanet07 F4bq9rvFVSuZF+1NlGWGl3KhXmw UpDheO13Or5SChLWteWLmhC1LPg 2020-04-19 21:02:29 209.141.38.43 443 80 +a [2605:6400:20:13f1::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1640 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r baikinman285 F4nmXV3oNl7lsKasliEE8/TSNZ0 ll4/3daWf7uo9NceuZ6f9WZZfQ4 2020-04-20 09:45:25 36.55.231.145 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.3.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p reject 1-65535 +r BlickWinkel2 F5IfTABXWfB+fS2AB7aZmTiKquA DMW0fss3ID9ZvWXl8oKhzIKNxSM 2020-04-20 11:58:56 139.99.96.212 443 80 +a [2402:1f00:8000:800::850]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=660 +p reject 1-65535 +r Aarsdala F6unNFctuxBQzzgA8N0UW65+2ac XZBnstxNErviVbig/d2r3r0ueV0 2020-04-20 01:24:27 185.109.91.126 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r BoneColdSteve F64oLrqzcQCzyHV4AOT6YfEb0oQ zx6jOz4MGdjxbPGXdYwdpiuu2Ys 2020-04-19 21:52:29 47.152.35.153 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r AntecsTor F7GFglY4nsB9TErh+SpWSTDHntQ K9VqoYpaESWnkGS5fvJH657lWiQ 2020-04-20 06:39:15 5.189.143.178 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=162 +p reject 1-65535 +r snap277 F74G3zZHRrgF86epeFOgZAEM0y0 tpXbP+m4t9ptH8+7lJsuD4Sn8Oc 2020-04-20 12:37:56 71.63.154.38 43173 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=290 +p reject 1-65535 +r casalserugo F8EdIhTLopJYF2WlFNyMzU49hIs py+LNf2+11WIo+SP+KALusZnY5c 2020-04-19 21:21:15 37.187.180.112 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6210 +p reject 1-65535 +r UnseenUniversity F8KfoL8cyeJQB8cCloNXYWLE5og d0mXBIxD7HYmgzhVbcje7TtEAzA 2020-04-20 09:49:21 93.211.235.226 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=373 +p reject 1-65535 +r elguaposghost F8xNJeM5k9ARzabmiAZDX//S5sc 6kWENyybH47YJLdD8s3zhLcvIBk 2020-04-20 08:53:34 99.164.87.33 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=579 +p reject 1-65535 +r ddxor F+lY8F4mmNU226ARknUMiyPz+WQ hl+2rl+5dR+dMB/0+ckIRolTBdY 2020-04-20 10:03:45 139.162.232.42 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=840 +p reject 1-65535 +r voisocial GATAaiZvDaJt9YzVWeAcL3w/xCo TJj9MctCBwRjfaU01MtxjRkEUVM 2020-04-19 22:00:00 92.42.136.105 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 1-65535 +r Hydra12 GApbzAGGbgnk0im2wITNHjx1Y28 crFc56aJEHtSSqg673m/0yF9ABc 2020-04-19 23:27:22 89.34.27.149 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p accept 53,80,443,1194 +r wisdomavoidance GBRm2IMqmz3tbuuYjPNKyXF9lFQ B8A6g89V3JBXW6nXtwA4liNZ/Hc 2020-04-20 00:13:13 66.44.22.166 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33 +p reject 1-65535 +r Dozer GB3GDIJOtWJ2H62t/7fx4YwZ6Wo WmshkrMHrAW6viqx+E0QJHvvNkc 2020-04-20 06:13:51 87.122.248.39 39001 39030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r cybertwink GDyMZyfiE3ryeLOFCtXZwjBLmMk d5xDPKAMrksDDWBTmCbYChOf1C4 2020-04-19 22:58:01 23.129.64.201 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6590 +p accept 1-65535 +r SchulteTorRelay001 GEHLlgEogGFRth/G2Hr76amLmdc aSMUx/KPP2bZz5i0ycFe/IcWh4Y 2020-04-20 04:22:31 66.70.211.20 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r xmtx GFBYW+m8ofgNCgUZCclOSdHEntM fI4yzuihR1YS8vPkOsOvg5Yh1b8 2020-04-20 08:11:01 78.194.158.141 9001 9030 +a [2a01:e34:ec29:e8d0:224:1dff:fe11:170f]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14700 +p reject 1-65535 +r FoobarFritz GFLYSwNBhF8r3CzLxnPp1CMHoRE dB6R25e5Cf5Y8y1L8AKr8vPBRp0 2020-04-20 08:52:39 84.174.131.205 9001 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15900 +p reject 1-65535 +r DFRI5 GFZjt8End/BSssLSPXojnY2oig8 Mt+Qie3NDK5hQzWTg9RZgYySVeU 2020-04-19 22:37:05 171.25.193.25 443 80 +a [2001:67c:289c::25]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25600 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r BoingBoing GF8qV7DEYgWCYCdhCX0X24FlT3A vGY+xmVF8HYu18KjcpUL5JxhAVA 2020-04-19 19:30:50 204.11.50.131 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4620 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r smell GGLda+r+zvHFRC5TYoafJoUzzU8 drUYEFY9SqJWlqIwZPBeJ3f4CAc 2020-04-19 22:22:57 45.9.148.213 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7600 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Unnamed GGVJPeurlc5OV8THuejFB1VmvQ0 XSUn9NW8yj10EYHj6s9bR5cQtRM 2020-04-20 07:31:53 185.8.177.152 46265 41963 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=150 +p reject 1-65535 +r TorOrDie4privacyNET GGcd5QksZ4g7+yRQwyZ7kmGL7GY lmSgOQpytgVxB64AD1NiDeAHg1Y 2020-04-20 11:01:29 37.157.254.114 9002 9031 +a [2001:4ba0:ffff:1ce::3]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p reject 1-65535 +r king GH+KRygbsPpSIPKrCT+xXS4Ex+c +nBI+bIcNrRbzsdHPk3tJ8llS8c 2020-04-20 08:33:11 51.75.175.26 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Sunworld GIME+W991vljpVimqyzfw5q7mjY hKKDYdqwB4IWDOXA5lG7sLR/d/k 2020-04-20 00:02:18 210.140.10.35 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TOPAS GIZzzzk3RCUXMBgA84O+U9ShdzI gompXkoB8z9lm00Ake5JEEv2nqc 2020-04-19 23:26:28 83.135.64.130 9001 9002 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1090 +p reject 1-65535 +r ididnteditheconfig GKP2TupJa/aXVUqrJgju6gUNseo l8kBz14Pr6BSBFxZasehkXi4/o4 2020-04-19 21:00:56 78.90.198.72 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5350 +p reject 1-65535 +r 3cce3a91f6a625 GLFgzV4iv8NFrue6hLfqRb9Ff8o gz+iu8k210PIwEAswfv/EQoobXE 2020-04-19 20:27:36 5.132.38.231 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43100 +p reject 1-65535 +r Carson GLstsSoLzBnqjk9Ng1orMfmWahw B9w7zUHgMoiKMIamf/XbUf3aGwQ 2020-04-19 20:33:04 172.107.201.134 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p accept 20-21,79,88,110,143,194,220,389,464,531,543-544,554,563,636,706,749,853,873,902-904,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Fractalia GMWF4VPfvMQUuCWf55lLpSC1628 2TdCn6T3faJ0ziftow4w0Z2pLCY 2020-04-20 00:15:48 45.77.196.39 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=291 +p reject 1-65535 +r FreeAssange GMozmtDDPqsDXx2GlRjz0tiLq8A 9HeIzZrpsz5VkcIgRhxUzFgnA58 2020-04-20 11:03:53 14.200.110.106 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=119 +p reject 1-65535 +r GermanCraft3 GMqeoJm7mGHjVNKm/0kzen6BwvM 1GUHp04NqqE3M6nZ7YxiEYxHjrI 2020-04-20 08:56:20 159.69.2.239 443 0 +a [2a01:4f8:1c1c:af5::1]:443 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19500 +p reject 1-65535 +r tormb3 GNjVjTd+GZ57PZ0ePo52HZHKn0k F0RnewQwmSGWjxkOoJuaBvc7L98 2020-04-19 21:09:30 18.130.166.169 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=600 +p reject 1-65535 +r millet GN9sBTsSH1HQYawi207sbsOOVBo lazC6paYnCWHPddunrnrwHeC6Nw 2020-04-19 20:34:45 220.130.54.175 9001 9030 +a [2001:b030:8315:ff02::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=283 +p reject 1-65535 +r snap277 GOFvwIPCKA71Yb+L1nFks0Ns+Io 9RSDP7lQEwL6PDdVb9U6A8pofHg 2020-04-20 11:31:07 81.232.24.84 44241 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1360 +p reject 1-65535 +r C3WEyeOfSauron GOpq+jYJoLJHUvv0EaLareJ94Sk zqdJGxuARRRVmCu+lHQfbzkPWdg 2020-04-20 06:22:44 37.252.188.180 443 80 +a [2a00:63c1:d:180::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r sweettearummy GO7p2FU7oBcaeWfOuWNmhk7w5VI Vw/nsLmPxdft1ayIzkQPXnfov0s 2020-04-19 22:03:35 8.26.21.143 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r homez GPNK5lZ/X7CBxDU9Xtpc7hVYEMQ aSKbQlHFDYlO2MNnYScoxRpRZAs 2020-04-20 08:05:56 188.165.192.152 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22500 +p reject 1-65535 +r NervousPayne001 GPuudQZgdgFcknLujH+j3fVXTOE 91zm09/W7VoBVbTSdYcKL2V1GMU 2020-04-20 12:21:44 109.241.167.138 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3060 +p reject 1-65535 +r 3158e4013328 GQRRHrKteGOhMj6lzhFYI/bZ40Y lrSQ4k81uvijKU2Bx1fI2XmW+90 2020-04-20 08:24:15 51.81.253.192 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r okolnir GRCfrg6e42b/lOxqR3w7M+eY0YE AAV8mdf+4LlBWnWcjUb4Eh2SvPY 2020-04-20 09:25:34 185.185.69.212 143 110 +a [2a0a:2b41:14e:3063::]:143 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1640 +p reject 1-65535 +r Assange032ru GRL00wf46Oe+vtV3y6kUnUK77eQ +oEgTqycrFEUZCJgxSqFvPIrLBE 2020-04-19 20:06:50 45.129.3.116 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6950 +p reject 1-65535 +r operaTor GTQ1qhF7Dt0njfwHpEKAeGvuoo0 AihbR6LRJOmS6ueBUXFP8dUZfaQ 2020-04-20 00:10:18 24.27.75.137 8443 8444 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=490 +p reject 1-65535 +r Aerodynamik04 GTjrrLsae/qIjZYjyQBhEw5juz8 7uE6MBoChZlzSO93EYshXwTFRcY 2020-04-20 10:26:28 149.56.141.138 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r SatoshiNakamoto GTnMG0EpiknAaEh4gT3tXNGp7pg HB9SNsKP3cG/OvddrxUVWHacULw 2020-04-20 07:27:17 51.68.139.151 9001 81 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Thrones GUTzpHPLd7Er2049FZY6JN9Y5Oc CP6NUXq4T1NA1zrkS8VDEe18QZY 2020-04-20 09:53:33 146.185.189.197 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p reject 1-65535 +r snap277 GUebkg/oVIBWydVGcNw0VSDvOM0 EncJWfRDOPYmOdismVCnif5iW6o 2020-04-20 12:18:06 41.76.158.106 42237 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r kree GU7XQAVt11FAyC/uss3ZCZ9gKE0 rjXzp3y4wnb9ZMgpqcXjMVK3o0I 2020-04-19 20:39:50 85.248.227.165 9003 445 +a [2a00:1298:8011:212::165]:9005 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60500 +p reject 22,25 +r artikel5ev3b GVcS6W/RwbGNFNCenk56ZBbiOyw Y7p+CBwg78SYUPh4jDvxtQQ+fvE 2020-04-19 20:13:40 87.118.122.51 443 9030 +a [2001:1b60:3:239:1003:106:0:1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5230 +p accept 43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r hovaNet GVomo5DEKhzp+nfS/cJftlrifUU xXYLvp9f9EWgKwdjieGBy7wGaHk 2020-04-20 11:02:18 96.232.195.28 9002 9032 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r snap277 GYm9fdOW/3M5itsEEwTQEgAZZag W3h4f20+sxow2+yfs/yIIMZ7jKU 2020-04-20 12:48:10 86.193.126.68 40087 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1240 +p reject 1-65535 +r MakeTorGreatAgain GY8S4t775r7rw4sv7dYVrss42no arYnBDPg1fvxmzG/C1iR2rCJ7a0 2020-04-20 01:12:16 212.227.200.133 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=52700 +p reject 1-65535 +r snap277 GY/x1aaKNuvBiKO9tOIkVeMfI3s ZMCnULsCD+ysDaBppEdAhUpuyrs 2020-04-20 11:46:54 71.125.56.44 46251 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6080 +p reject 1-65535 +r 15soEiRelay GZpL7MGYiPnjB6vBnrQxLquyzw8 l1ZQaqYsqx0XXw6EQB+26o0BxwA 2020-04-20 09:05:12 78.35.204.113 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3100 +p reject 1-65535 +r NonsenseInc GasCAlFhmo4l9fql6luQE1NA+os 88VoAIqXksEDL0SbkUyXqnoBU3c 2020-04-20 02:26:08 77.191.165.232 9933 3399 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1010 +p reject 1-65535 +r nodvrelay21 GcOAgSSbwg9PQEAYYD2xGgoK2KA M1aq8nH6+FlIjO/sRNFGUarHFOU 2020-04-19 19:20:51 45.62.246.185 9001 9000 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3940 +p reject 1-65535 +r Unnamed GccIfYiD2jerSZZtIWM8EBBGPA0 d1ADP532kALGI2oLc+7QtcXSXZg 2020-04-20 11:16:14 46.105.191.83 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r mosaik Gck4KEmBHCN6iiH2b0IuBWt9vS8 3tadYp78t8LFWu5iS+MhflAM+34 2020-04-19 19:11:50 188.194.60.85 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=862 +p reject 1-65535 +r TouchMyData GeEK8VEWCRZeGTMKxJzP7OYBjkg 6XLEdf+cx5Z0SPq7mBt7RxssNCI 2020-04-20 11:37:23 67.166.175.144 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5040 +p reject 1-65535 +r FlyMeToTheMoon GevqlTKXuoM3Y/qsGXWI/vKm/Jo 5xx+WZNVrbvue34s58ec+mft5FY 2020-04-19 21:17:00 81.11.234.72 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=90 +p reject 1-65535 +r EmiIbarazaki GfTZYCibH3XkDaD900+BWWRL8tU W0Am+a6zGDqKJRejekzWmlmg2sM 2020-04-20 09:35:01 178.62.79.227 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=970 +p reject 1-65535 +r Noaccess GfkDE7LA6wPvw0dwbyc16Bh22EY VXSMhmuGQyuWl8gxu3AImwk3vyU 2020-04-20 05:54:17 80.219.136.62 9030 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=724 +p reject 1-65535 +r Unnamed Gf/wTEtESKmT9ckIyZcEiB3NR2c 7P+XqOsZMT8JNMEGBv9rD3b7gxs 2020-04-19 22:52:58 87.103.241.202 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=395 +p reject 1-65535 +r Avalon2 GgArbhY9UC8jOBORcY4RpWiXZAM LbRKXfIN6vbyQN1nR/3uDGT0xxQ 2020-04-20 07:20:18 62.141.51.90 1443 8050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14200 +p reject 1-65535 +r ABCVG GgIKQU2Ksl9UQVyMHnWlViqd2aY wnapvIEkQOMPOjf23oIx4r9s0DA 2020-04-20 04:55:51 37.187.103.54 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8950 +p reject 1-65535 +r lepton GicPLyobraBc1BCadNz4tjBnaLA AC0U/jvdXVjIf5lU44Gvs7SdF/8 2020-04-20 02:15:54 108.48.172.138 8001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6020 +p reject 1-65535 +r MYTORExit01 Gi7uRkp9pQCoaaunpbx3LP4ZhTQ 0hDcznlJhqZ1QRETHaNWqGizxFY 2020-04-20 02:39:28 103.75.190.11 9001 0 +s Exit Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r AutoNoMe GjrBG/hc44bhmGP1zfd2m6MOSgY BCkRwcrPIOcb4o/WezzU2LWHQy8 2020-04-20 09:28:43 185.212.149.125 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8700 +p reject 1-65535 +r moomoomeadows Gj7SOE5/kpYWntA77tU2zdHz3EQ F1QbmGsXHroJ0RhoI5oDmsjvBt8 2020-04-19 20:27:57 82.4.83.111 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23 +p reject 1-65535 +r Unnamed GkNYi74SOeqJbdBsItqyDAxeaO8 RHjiVjJDFn2mmTDED6fA8mVJ4uY 2020-04-19 22:09:49 185.113.140.178 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3200 +p reject 1-65535 +r clicker2 GkjKzDD8BkJxA86zjEEyhzGH59s +th8FGPq0xEuvBAbX9q6UAdbuNI 2020-04-19 21:09:21 94.16.116.137 993 9001 +a [2a03:4000:29:91:2549:9:f370:a1]:993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r just746436456 GlLh6pXqHAXmo7ZDqprB6H/HlvM uSsYUs5oQ90kV4+64D7bhsYhEGk 2020-04-20 11:03:34 37.221.195.19 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2670 +p reject 1-65535 +r newnet5555 GmatX3y940wL3YSdKICc+YGJOyw yYZCcLEL+LXUkuKVuiqPrENlCRg 2020-04-20 07:03:46 209.59.175.188 5555 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r IceMaiden GmzUp4vFpPGc8vJ8SrMuRMiyB2k zNeXHUYLTkrDS1Oi5ZsnwdvUCpg 2020-04-20 04:19:34 82.221.105.198 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r Unnamed GnbteijLcB0t4VbLXJApurBa1TQ E4sa5+8B1FY90yveFBggJiH1zC0 2020-04-20 03:18:56 185.246.128.163 57898 54094 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=250 +p reject 1-65535 +r angeltest28 GnolFqlh8oOPf5R4aogRvoL5z/4 Oi4tepImONsyGnkVpmiusRCXKSg 2020-04-19 19:19:41 31.207.89.49 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r TorOrDie4privacyNET GqwZ2JL4SRCrlMRQkiQaujz8TIk aLmW1n3C3djKmiOqbsQVYDyqBMo 2020-04-20 11:01:40 91.194.84.89 9001 9030 +a [2001:4ba0:ffff:1ce::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64000 +p reject 1-65535 +r Unnamed Gq0BX02IVBOivODlgVkRaQEjbEk Ik1IsWdLiDd0GITeg1N5O1g7bvY 2020-04-19 21:30:55 51.75.143.145 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=15400 +p reject 1-65535 +r marsvillsvin Gr1IQS8UWpPHDfZkoqMaGEAe1ms jAM4IrNio/SE6qk4HQtNTxie9iw 2020-04-20 01:15:27 51.174.15.18 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2960 +p reject 1-65535 +r FOO Gr2fzXfa0MF8xB+0oId7jUVBfj0 P97zenNBAngFczjUdhDTRYizZxk 2020-04-20 11:42:19 178.175.148.25 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=12800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 GsVdTRLHu2XHG8uo5jm2OLUwmbQ vcNbUGYbFoxb/LgteJ4jqkR61qY 2020-04-20 05:44:54 124.197.63.133 39901 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=161 +p reject 1-65535 +r 948794crazy GsstAFGRtri+LibAIesLoWR6WrM D7zcSD6zMS8HS/aT8JqXhMKlyFs 2020-04-20 05:14:18 128.199.213.157 9001 0 +s Exit Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=376 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed Gs8GZoRLiwrKo6Dp1DUIdcIXsc0 kQiiznyVogl493nYd6lAct9TCa0 2020-04-20 09:23:22 139.30.255.200 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=73400 +p reject 1-65535 +r PoopyTheChinchilla GtTCfNxmgKape2V8puJ5OmN2ZF0 GbMHo8lB+gbRDYW9G8OwdXTOuC4 2020-04-20 05:18:04 95.109.122.52 143 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r Cygorg Gt2TQTRPwLRZ1Gel5DUbuaPKFqo xQfNV/h9861LPWJu4RphNrY++Ag 2020-04-20 08:24:36 93.104.244.179 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1420 +p reject 1-65535 +r Ichotolot60 GuA57gsR23nktLKcup91KGSgJZ4 Nu55chBchrKSi84HONu5k9Bw9o8 2020-04-20 12:06:56 81.7.14.253 443 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4340 +p reject 1-65535 +r Yossarian GuGAJQ2AppIHfto1zI5zh6n98iA 1iS1QEEhppveGAt7KnSsraTR+4o 2020-04-20 00:25:40 97.107.139.28 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1550 +p reject 1-65535 +r Quintex36 GulJln+Cu+dTSj1rp3p+vhztQ2k 9n3MSwPurK06QlhbFLpUi/0vf6M 2020-04-19 22:39:51 199.249.230.85 443 80 +a [2620:7:6001::ffff:c759:e655]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17800 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r pato Gu0VcdX6c4WsPCX7Pob0nnBqvZk awCgmCiEcT7Cz7nGHn4tfDBdlDw 2020-04-20 08:54:15 84.74.203.146 7444 9031 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=520 +p reject 1-65535 +r BlackBox Gv9Z+bJXnXgoTvcXOhg/NAhtS1Y gDqP76oaK71PyO2UzGDToNIxz5w 2020-04-20 00:46:36 217.182.76.66 9001 9030 +a [2001:41d0:601:1100::1646]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p reject 1-65535 +r myNiceRela6898y GweeLo4kZb99LGMo5nCpgspf6UI GAVaLsPVE2dREzrpeZBoc5hda4Y 2020-04-19 19:42:11 78.47.63.216 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68400 +p reject 1-65535 +r Banana GzChfHfmMrPaY94/KhgFmocqUt8 5fi7WfaqipodtJdGXIom1LMakDQ 2020-04-20 10:08:14 177.148.220.33 9001 9030 +s Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r IronKangaroo GzWPEhC+HmDr0y6wc1bDYucMsoo Yt5Cr8NRPKrU2k6Z8/Wnvsyd3eI 2020-04-19 20:06:15 95.216.164.6 443 0 +a [2a01:4f9:c010:18b0::1]:443 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28000 +p reject 1-65535 +r TheBestRelayNick3 Gz5I115/fmHRubviS6FaOLRUOA0 k1j1/+v1aD89x3YveWovHeoSvAk 2020-04-20 09:15:24 74.14.203.222 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18200 +p reject 1-65535 +r mamafisch G1T8aJenf1vQBtDbBpcXNeZSfR4 fDUCASTU2dOByDk95PU/afhRmz0 2020-04-19 19:25:07 148.251.155.108 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1130 +p reject 1-65535 +r slalix G1yaot+WqOZgPU76I4r+RUqDzM8 vW9G8wYwNYooVOkYiUp6aZuAyP4 2020-04-20 00:48:06 104.244.79.131 8443 8080 +a [2605:6400:30:fd6f::4]:8443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6220 +p reject 1-65535 +r snap277 G1/O6bDgGvBsc4UbB8YmgnSYv7g ed+TxkogZcC/QeVihoMcdEl7E8E 2020-04-20 08:56:47 179.110.49.241 37359 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=433 +p reject 1-65535 +r niftywabbit13 G2BbJ1EnmxUsoJjtdrHrzJrcojk oA5XRQN+zB4Rn0Ac9FE35bVmeIs 2020-04-20 10:53:08 185.220.101.243 10243 20243 +a [2a0b:f4c2:2::243]:10243 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24200 +p reject 25 +r Kolobok3D G2NBT7rh2ZiaZFO5ZMJvdgYGmDY Z8R670xxx+HCJr7PmoLfRbUcNhk 2020-04-20 00:34:10 91.77.161.90 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=334 +p reject 1-65535 +r snap277 G2ouDLZEfzjDtyGdexCHdwvgZUs w84u5WKYKHMF9fxGD42PmzIrEbU 2020-04-20 10:30:26 75.160.57.14 33916 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r ryanfragdev G2s3uuJgfitsgWhaI1Vut8+5lhw zDDBnTCAZiYD1kEDgkCQdi0JlgY 2020-04-20 03:49:45 144.217.87.28 9001 0 +a [2607:5300:201:3100::24c0]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=673 +p reject 1-65535 +r YesIdidTheConfig G20vqNS4e1zY4q6N1aSp3GpptFs bwtECgAPm9adpv4fCYeheHHLhKs 2020-04-20 04:30:55 157.161.57.70 9001 9030 +a [2001:4060:dead:babe:20f:b5ff:fe1d:6879]:9001 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1 +p reject 1-65535 +r schkorski G4GIFw8K15mKfQS9XOn2EosDLI4 ucpp476O7XEFYtwveG3u/OCqm7w 2020-04-20 01:58:28 91.203.146.126 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3570 +p accept 23,43,53,79,81,88,194,464-465,543-544,563,587,706,749,873,902-904,981,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r torproxy04 G4+u39QoxUap3MnsFeE8BVAiLUQ gkagaNGEy/EPw2gwS8ioDCzjASk 2020-04-20 06:26:27 193.169.145.202 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13300 +p accept 20-21,43,53,80,443,873,989-990,992,1194,1293,4321,5222-5223,5228,11371,64738 +r shitbox G5G4a2cxemNjb+OKvmxOcBorGpk BB5DcbXPS2+8VCdgWbZoh68ehQ0 2020-04-20 08:16:22 76.72.171.41 9001 9030 +a [2607:2200:0:3902:1a03:73ff:fe0f:1465]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20900 +p reject 1-65535 +r niftyguard36 G5I1ZWUD6A6RPpyaE5rYnTbi3/0 ktDbLDPo1iZ7S/nUrEeT2s/5aqQ 2020-04-20 12:44:40 185.220.101.245 1245 2245 +a [2a0b:f4c2:2::245]:1245 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p reject 1-65535 +r kouettng G5WeB98MM8HpVsjY+kFatS8Hb7c NrFz5AvsrWCqKvX5ej2eXiGjHuI 2020-04-19 23:37:50 163.172.27.62 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7900 +p reject 1-65535 +r ieditheconfig G5bthB6lUoGAKJIcxrUUZV87bm8 I5QdUAj5LizvefnJaijtsNNFe5o 2020-04-20 09:34:21 196.12.37.68 80 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r sqrrm G5wmwdqxkOrT6623CRTglJrcJYg rwoIn9+SAo8O3jXq9iDb2HhZcME 2020-04-20 05:54:55 185.25.50.199 9000 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r CalyxInstitute07 G5+s8l4X0m4wfqfPp9RVsUSwMuU AYvPgilEmjbc8aBrF28VC09HAiE 2020-04-19 23:21:46 82.94.251.227 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19100 +p accept 43,53,88,110,143,194,220,389,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Assange017md G6L5Q2wAGKS1JiXQcbcvZIUit0g +IDjNYpYLSNMF8uO/lujTAZStF0 2020-04-19 19:33:16 176.123.4.64 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p reject 1-65535 +r ggggg2 G7mLb268thbQvZSF6ktvp6dQHXQ 69VnqXzx7IpYLnM/UP2Mah1Rl2M 2020-04-19 22:52:03 46.4.174.52 443 0 +a [2a01:4f8:222:26c1:46:4:174:52]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7200 +p reject 1-65535 +r lecirque G71xa0lz2W5XDTNKV3aXi/9+Dl0 qu3QUwnix1pHG0SsbXdXrVP5JV8 2020-04-20 00:59:52 151.237.185.134 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2950 +p accept 993-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r cerberus G9OxlRQgvwz5+Xm5J2wFSesDiSw WReBsezz28x64+5c5FNOIaVf0Co 2020-04-20 12:11:08 217.170.205.113 80 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p reject 1-65535 +r DigiGesTor3e3 G9vpwPcDTmeJqb977YK+IEXw9bc uzbdV+eQHghS/mGFDXB+AzSL4gQ 2020-04-20 09:42:56 94.230.208.148 443 80 +a [2a02:418:6017::148]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33500 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r snap277 G94vGQzFNItQWw7sxeTNq7opaWQ 3ewWMoknVim5oB9ZJIn//pn31pk 2020-04-20 12:44:12 46.118.71.133 34331 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1290 +p reject 1-65535 +r VotezCommuniste G+3ekpYMQGuUmECGQH3njcozMDY jcgVxkxRndEGDMf7y/h2NfMIbGI 2020-04-20 01:36:44 80.241.217.52 110 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3000 +p reject 1-65535 +r AnonymousNamespace G/w4MTNdBZqAvTDWW2LXpyXJUdc DYxLvOybBp/tLAtgYfGoOsh+XK0 2020-04-20 12:09:33 92.245.194.234 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4 +p accept 53,465,993,5222,8333,9735 +r Valyria HAQ7BFexZcFIMCAFqfswkK7UPiI D7n02QQUVvL/Ad+40TTQbkTN34o 2020-04-20 03:19:05 194.99.23.167 443 80 +a [2a09:cd41:f:4267::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p reject 1-65535 +r dupa HATlPsHt9DlUCKbgGqBHfMgUGyk YDEFE0NtifX6+J+NV6urHGlRnjE 2020-04-19 19:08:42 51.83.76.139 9060 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4110 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r FreedomFries2 HAc2zzdEo7h8LSJpuL0ziMfmBVI rTh7o2d3c1VDUo926r0HKFn5Kt4 2020-04-19 20:14:42 94.130.246.106 9001 9030 +a [2a01:4f8:10b:3344:106::106]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120000 +p reject 1-65535 +r SpongeBob HA0K8/8FzLuktu0mIZakxadhAuY pavQFlV3CAfmZHxlT/iv2hO5t70 2020-04-19 18:54:28 104.244.76.13 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56600 +p reject 22,25,119,135-139,445,465,563,587,1214,4661-4666,6346-6429,6660-6667,6697,6699,6881-6999 +r ProtocolSeven HBX9I0yTtlvgyWwZ97d0+tozlWk aAkqgBid+0RtJQd1Q7VzvAQboOI 2020-04-20 04:12:57 162.219.230.139 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p reject 1-65535 +r jpfnzov2 HBwnW46fjQgkQk3fq8pIi6JHVrA F7HkgFGn0FIEc9pVC0WQlwF9WbQ 2020-04-20 10:37:04 95.165.143.112 2115 2116 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r AlekseyNKrylov HCSiZpx+DWKyFXuV9W7QDuMHyFw LH9D8jd5iARIwb/TtkbwXBAbzK0 2020-04-20 09:01:25 144.76.58.23 9001 8080 +a [2a01:4f8:191:6205:2000::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r LongsideOutbck HCZUccqrIPHT77u21mSOBg5/dcQ oILXKLwCHdwOyvz/5b3THj1XBco 2020-04-20 10:31:18 207.148.99.160 9001 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=400 +p reject 1-65535 +r niepokorny HC8JKaSo2WYdg+cP3pa2EEDsoU0 oIIB9Q5Iws6+IAffnRV7OlDA4/Q 2020-04-20 03:59:21 37.187.118.34 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9620 +p reject 1-65535 +r Assange020ca HDxK7wNtEgLuxiMijrpftxkx4qM RQrWUSAFtqP5BPsNxTi1R1CxbKg 2020-04-20 12:40:51 162.250.191.15 9001 9011 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6130 +p reject 1-65535 +r VrijHeid HEFHveMe1lcV/hzwiFcOFFv0aqE JAOSW1qBRQr2eAPAcjUU6c6yWCc 2020-04-20 02:06:55 94.142.244.16 443 80 +a [2a02:898:169:803f:ac0d:485b:397b:88a2]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4660 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r scottsmith HFW168buMc8ZieOs1NpPuLZLwjE +aOghWvn8GAEt0poI7MSGNMkHYU 2020-04-20 01:04:19 173.255.250.126 9001 0 +a [2600:3c01:e000:b4::8000:0]:9001 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1500 +p reject 1-65535 +r ILoveMyBMW HHDCqn83cs4HxO9rGKbjMBUDcu4 59bSFQkSiYwDYebLE0JT2xoZeZM 2020-04-20 08:36:06 145.239.85.208 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16500 +p reject 1-65535 +r blablabla HHIVvAEj3aI73tD50oSdOtgBg8s a43eeDxR6WHiU5ZI9NqzotGDTo0 2020-04-20 01:28:00 148.251.201.50 80 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=60000 +p reject 1-65535 +r RegnalOrton HHbhMrl+8KA4dGR95lunSDRpwns y+OmrL9RvjsJLuvgGxb6b3TyfkA 2020-04-20 01:53:47 87.181.46.200 9001 0 +s Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44 +p reject 1-65535 +r idideditheconfig HHgWvHk2vZVTIr2UAoVbKIzjyTY c2Qv524dXXzw9qzIl+UIvPqYjd4 2020-04-20 12:04:32 188.227.201.133 443 0 +s Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r Unnamed HHnVpHMhRxSnYcCkDdLVsDH36YA e/zigWWaj1uliR5TQgwXqCvoauw 2020-04-20 07:23:24 37.191.198.94 38443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9860 +p reject 1-65535 +r BabyOnion HH1xolgd55xc/E7R/3XVvjDwG7c AUA7OiZlAXKKotzrJtBGXYRFJU0 2020-04-20 07:51:50 51.15.243.22 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p reject 1-65535 +r TheRock HITIkZiRHQyJYqplw+TmUwB1OW4 /N+HMxBcVWVwpjVUj0oCQ5ZJjwQ 2020-04-20 00:15:55 188.151.223.105 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6930 +p reject 1-65535 +r lpf2 HIs8PYvHBYg7d5nJFbL+Hg/rAG8 QKugH9RHy03PZ57MvkvX7EQEC48 2020-04-20 12:37:13 78.129.180.16 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57500 +p reject 1-65535 +r uname HIv+F5S6Qs3EX4xR3xDnD6f78YI Yp/OwMZDxjhOBvBj6lJMmu+Cl7Q 2020-04-20 11:06:35 86.57.149.14 1443 9130 +s Fast Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=3180 +p reject 1-65535 +r firstTryFFS HJ3+RFUlGsk+OmKPk78rmswJVtY jSjDcaZf4xy9g2b9e67lf+DgL6E 2020-04-20 04:05:04 89.12.239.137 15001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=887 +p reject 1-65535 +r Kalabint HKbjTnYqtVUPuyVKfHvYdPFVBxA U82GEDT4tfVS0oMSZFF4Z/LsXBs 2020-04-20 10:21:53 5.172.130.139 6699 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=734 +p reject 1-65535 +r Unnamed HKb6FQVD2pX5awmzcgDmU5hmSzU 8jaus+iySdBWgF4ZnxmbtsEBV8k 2020-04-20 05:46:19 185.163.46.87 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r snap277 HKubYKuzWcQTzUiTmb+BFBZGOyY OGhDDZn773ey0zN7YyYDqRICbrI 2020-04-20 12:15:50 81.51.66.93 46823 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r kleinbus HLbbaYxJll08daCbjZ6/3Q47VgM ENmUhG6HWoVV8y1jqNp9qijYRrg 2020-04-20 06:18:57 85.25.210.168 8443 8080 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=86600 +p reject 1-65535 +r hochrheinsecure HL/cq9kBKwZHH/ho/gK2vMATNSA ZX8CTR0yV6xjuk1fzvvR3m/LRUY 2020-04-20 06:37:42 91.89.26.64 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1700 +p reject 1-65535 +r theia1 HNF8sgIGPFHH2tO6zvh+zoHCNQ8 5v3n0k4SzLf9yaovv7UjrP9L/ko 2020-04-19 22:57:54 50.7.74.171 9001 9030 +a [2001:49f0:d002:2::51]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6700 +p reject 1-65535 +r Piratenpartei00 HNSPTtDxgh/78ZQIAqE+79TCdQI c/8klczVC9SZT68TVnnLox7b/6g 2020-04-19 23:50:50 176.9.40.131 443 80 +a [2a01:4f8:150:518e::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=109000 +p reject 1-65535 +r drkhsh HNy0j2TiHVrK/iRxkS4udvYA7fo 0LHx2RPfiCDEbnrRZGENXhfvUq4 2020-04-20 10:26:23 5.9.21.240 9001 9030 +a [2a01:4f8:161:e2::4]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35000 +p reject 1-65535 +r FOO HOq+SvJBhErUPfRvoj25LoHytPo Xo205WAqCc/Tc2JYRVdR8dlrfFc 2020-04-19 18:20:25 178.175.148.36 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=12500 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tower HQT/kgzoBM41f+YsZlkBxXi8JtY P6OakAbBl0LpNJYsNCqjkeoC/28 2020-04-20 09:08:24 89.238.75.64 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11700 +p reject 1-65535 +r Unnamed HSXHst08C9VVJtz5Wxdeo+ldkoY l1iouf1gYcrpEKyAor9PAQU1iEA 2020-04-20 11:45:12 54.36.112.237 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=995 +p reject 1-65535 +r criticalmass HTF0M4oRMaU+CYRD524RA83tANw udToI91lr1zKNVvMq+UgvywNlg0 2020-04-19 21:30:07 185.220.102.4 443 0 +a [2a0b:f4c1::4]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ButaryEntry1 HTYaLxyuT91aheE8FovnB1oQBSQ zJq/Q3WNA6uBTrEcipXb0Mjr+jg 2020-04-20 12:24:29 193.31.27.93 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31800 +p reject 1-65535 +r Kostiks HUGY57w6ijcarRpWtWcI6qJWoRw 8kpHyZwvq0c0uhL9YYo56fb8BVw 2020-04-19 23:25:28 78.85.145.227 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2400 +p reject 1-65535 +r isbear HVT3zLfHoYXuiqVhbAed2SPrV/I SzQAY8Kqu+NZz5Cnp5bh0Hve40w 2020-04-19 21:31:54 176.36.117.185 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14800 +p reject 1-65535 +r 3tudK4Nde8iQ HVogpHdxuAmVcR4gGVoh7LFz4cI 8TG8b6QADnSs3BSpmhofIqZ45D4 2020-04-19 23:27:14 84.217.182.244 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7510 +p reject 1-65535 +r Unnamed HWkf6epVQh9oi0mKGK1ebB+zKLk x/VawLdTMss9fgVOCOr2JlCwIw8 2020-04-20 10:27:07 91.219.236.48 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3280 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed HYEnIhm2edURkwSZrYKGvNj2xEU KXYZ0IHE2Fpjo+O5zCW52yqC3rM 2020-04-19 23:07:34 37.191.202.95 44100 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12800 +p reject 1-65535 +r niftylagurus HYmoEL34RSK2A2A09JmnZu8pTbE BvnHazE/KvT5t/Ksi2fZ93Vtryg 2020-04-19 20:25:30 185.220.101.7 10007 20007 +a [2a0b:f4c2::7]:10007 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31100 +p reject 22,25 +r boxendotspace HY7VTqnfLUZVitAJbdXZ3Sl/E6g IWSF4Cukx3P9f7sJjKZW9Z1ADCo 2020-04-20 02:38:35 193.182.111.182 80 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3630 +p reject 1-65535 +r docker0b2b2401a8 HZY/CnK4/yHs0rJmbXDnBAvt6rY PBGrKt8G6kcLZ64KTJd5WM2OME4 2020-04-20 08:32:25 176.57.79.249 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5270 +p reject 1-65535 +r TORoid HZ1dgoG0gG3NDTvRgKs4itHpcGU sC/opxk/KQHNaZb3pVnnLJi0Dek 2020-04-20 12:28:27 84.236.15.19 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5700 +p reject 1-65535 +r 43b8107fbea0 HZ9Bk6CA/QjKDsYNPniV5Nr8GbE kZcIDyU60Ol4CQfrnrITdd/XKxU 2020-04-20 08:08:09 51.81.254.17 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r PlanExAU HaGDayzELUiJAfCLRKb0UtZ+FDU bY5zxo/FjIj/yAQN44Rtn3CM8KM 2020-04-19 22:21:02 121.208.145.39 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r king HaSRzEIyzF9wXyLo9TO2PcP0rco 0HvFDK+0M4IEXOYsFjXWHT+kV4g 2020-04-20 05:34:56 51.89.200.108 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r fenrir HajW4BCSsglo+Z1oYcXVG4AltRE jym0xLDG8MkcNZEmQCHk2/upnuQ 2020-04-20 01:09:13 139.59.58.109 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=748 +p reject 1-65535 +r AnonSydney00 HbEtYYxj5V5JfUjphkLkasG50QQ oSG9ajTN1DU6AkguHlcGK4niHNI 2020-04-20 02:54:46 13.72.231.121 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=149 +p reject 1-65535 +r Quintex14 HbJd9Z2qAbW+PTzriv7RFZQOvos g2HVyWndIh+xu8LjZ59jd+RXD9M 2020-04-20 11:50:42 199.249.230.104 443 80 +a [2620:7:6001::104]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20700 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r hviv128 HbrMMUhvxnD71AP66Hc0LsaW1Zg A9IkGcfGBYa3uGUBylMqn6cpGjc 2020-04-20 10:40:45 192.42.116.28 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r kraghtorn HcF8SlKkWLXIseeRV/hmVpYhDhA 1SP3mK7eftpeiVDUMpKMQUuAaP0 2020-04-20 05:31:14 51.15.47.17 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38000 +p reject 1-65535 +r eiais HcblKtuf5DRs78BcaRbYuPf2bRw Ki6PAZ6PrEgfoUbYMm2oFKaWI3U 2020-04-20 00:31:10 23.129.64.194 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8110 +p accept 1-65535 +r ubeenhazed Hc+DYwX7lTuqoZ1L3/6dLKyAV9Q h1WwtOw3dkFLNV40LBE/mAWMiKM 2020-04-20 07:10:06 95.112.34.223 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4900 +p reject 1-65535 +r BriSSett HdhYjmnMC5zB9kiJ1mKG/2+h2S0 3YIhtBvk00piR5hzCNG/xTztXoM 2020-04-19 23:47:20 172.107.92.18 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=403 +p accept 23,53,79-81,88,194,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,991-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r HorrorPicture HecFBMbpuyI+LsT61FxowHpq6fs Uup8CWSB2WNzDxY+bAciPbFOf5k 2020-04-20 09:47:27 195.122.181.242 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r Marsu HejoEkDSDZdVspqK6hMb4s1Tf7g 5/7fSkIAdE5R4I8foi5RxmtHyvU 2020-04-20 02:02:58 164.68.108.59 9443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6810 +p reject 1-65535 +r TORKeFFORG HfsRNQiGWO6dTZsnK+FeJhdq0FI s9wI86/8U/hBTvynjfMyT1rFH3I 2020-04-20 09:47:41 45.154.255.44 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3333,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Goliath HgPYHJdE3g48nebm+98d+drqWvw VsiniF9yEAf3qRfElw+5B7c5ycI 2020-04-20 00:21:17 185.107.83.1 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=59000 +p reject 1-65535 +r pellidos Hhp8kTRjc4O+ZTxBlzmVoinYFZU AIoR13U+mUPjTUCz2VX5gF+thMg 2020-04-20 09:22:52 51.83.37.40 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=49900 +p reject 1-65535 +r nodvrelay29 Hh2OvFcQfbVSkVQqIAEfZBR+IEQ 4EphEdzQPplC0P80/RrY6xJgS+c 2020-04-20 06:28:15 45.62.229.238 9001 9000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2310 +p reject 1-65535 +r snap277 HimqAX4D2RH2JM+J9P00GUU1hC8 FaXigR99dJe6FylVV11lvLG+JVU 2020-04-20 09:33:28 186.53.181.195 38489 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=100 +p reject 1-65535 +r snap277 Hi15PL/Z+vuwbAOfaT9H2jnHBTo 4YNTTzwvHrfflRR9TOO+8BIQl4I 2020-04-20 12:19:38 148.3.186.171 34441 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1570 +p reject 1-65535 +r goodRelayPleaseWork Hi2wPRH0kXDAXa7fCMYVt9/3QLU cMpS9tcqWgv1fT206lKTL4uCKXs 2020-04-20 08:27:48 75.58.45.109 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2020 +p reject 1-65535 +r F0F8 Hk9AzOyO5y2x6J09P8RehzzaITQ zzDvJXbtdt3falLuasn1PD4S6to 2020-04-20 06:49:33 90.242.247.180 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=877 +p reject 1-65535 +r Quintex43 HlE23cUvrhIZII8Ka62wumJYfuY xhBtb/kMSIr11RNRuADd8gbJuYY 2020-04-20 06:47:14 199.249.230.66 443 80 +a [2620:7:6001::ffff:c759:e642]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r hazeltine HlYYwHnXTPmuDFNw3kxuGv1cCzk 3olWkaKcU4WaqM/WKKCZANaOzRM 2020-04-20 04:44:41 62.113.216.173 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8700 +p reject 1-65535 +r Blankenship HmPCztO23c0QeLKk8QyKSL0sMaA 9PDoS6P4sCsJU368WOoHOHJupKc 2020-04-20 06:35:56 13.124.18.130 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=160 +p reject 1-65535 +r DedicatedToSnowden HnF6x4HwLh7oRYf98QEsj9DG+2k NrW91mNaj9Ta8O7UQlDYFrU4PZI 2020-04-20 03:56:48 104.244.76.189 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79000 +p reject 25,465,587 +r Unnamed HnQW0M83pmYbATD1TG6+8HHjbE0 bCNKffGG5HUEjot2L7EGYS8hkI4 2020-04-19 23:29:15 64.137.183.142 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5200 +p reject 1-65535 +r cebolitos HnveAxUaq3ectK/q7qUlNv+qlAA EPVCAUG156/bVkBj+TKvTiKzfFw 2020-04-19 20:54:05 143.106.73.35 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=292 +p reject 1-65535 +r Unnamed HoUVjTHMczMG0ro7VRwOiKumYsY PiYXzE3Nd4kAkJ+K9WcNEcbtvf8 2020-04-20 07:57:15 159.89.156.215 9001 9030 +a [2604:a880:2:d0::2059:6001]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r MindZeroFive HpNn2tnfHTVC1mtKsySZ1bm2aRs FOzmgCzsSjc7Zqa4xnIU3hhHYsc 2020-04-20 07:40:22 81.174.231.18 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130 +p reject 1-65535 +r snap277 HpS0BPKHr1qo6UPKVhRtbFwFcCo RtWs5tTR9dURLepAaaeTujyD/Vo 2020-04-20 10:44:55 92.144.189.91 42647 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r Ailuuchequai Hr/HM8zZUvf3YW67p7xrjm8vDLw xyMGILLSUbg4wbrOjZwQOE/aqn0 2020-04-19 23:36:37 94.130.58.99 9001 9030 +a [2a01:4f8:c0c:2613::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5990 +p reject 1-65535 +r JakeDidNothingWrong Hs1zuTbLbms81kfMIE8QjZ3yyfc VS7bPKG4HIh2U6GEYCiYdc1fL1E 2020-04-20 05:16:59 91.219.237.229 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2400 +p reject 1-65535 +r etin Ht42GYhluXwi2U2U5Al8i+ljwz8 AWt+7vl6EyHB0gziauKKwtoIjWY 2020-04-19 22:09:55 109.68.191.159 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3930 +p reject 1-65535 +r W4LS3R Ht5gjF4ZDIaCovgnZk51hBYQRnA sX3g7JJtP15vC9kwSKfBJLZ8uio 2020-04-20 10:15:59 91.214.169.69 8092 8094 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r QuackQuack HuFROfOJ/aJEACOWB8tMC+XdjHY qw5yGgt/Zc4hLOieX7jKSG4p6t4 2020-04-20 00:15:08 160.202.162.186 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Tor4VPS HufPYb03T2VgbIeOit8NzYpmD8Y EWO4uGy4nIvTw6w7FSg7NO1vBxg 2020-04-19 20:53:45 51.15.75.80 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=37200 +p reject 1-65535 +r ohschitt HuiCEm+M9hPGfcJUFTMNjPMozbo H4GHodwWt5suILCl4sAlHOP/mjw 2020-04-20 02:01:26 198.98.51.156 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3110 +p reject 1-65535 +r initramfs HuolEUcYCP0mMi9k1paayxiTZEg nuqc8poQVmqpaLM+kIENXd/Z0xY 2020-04-20 03:11:09 59.115.118.15 9001 9030 +a [2001:b011:4006:1b62::11]:9001 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r nonanet00 Hv6E+dvuVZz0F3T1M2Iv+kTA2YU GWGj9O1PxAWrW66ffQtidnwzjk8 2020-04-20 09:01:11 209.141.39.98 443 80 +a [2605:6400:20:8da::1]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4360 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Sepiidae Hv8nBNGb9FMFu8ylPitZo9F6buM PIaB/Gs0z0k44E2CWtj1tuNWh6Y 2020-04-19 20:59:43 71.238.214.21 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=273 +p reject 1-65535 +r kumakuma HwNyFf9/5HEL/QUHrs4zw6fLYnc 7fWOJPH5XVlqyfyK4kQRk+FNbdQ 2020-04-20 04:38:01 139.162.81.156 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=147 +p reject 1-65535 +r Unnamed Hwy/n53h43L5abox0tIU88pd3s0 pURxbJ63faiN2hyp1JcQq95moks 2020-04-20 11:34:01 37.122.208.220 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=780 +p reject 1-65535 +r mrTrololol Hw7lDdtglSgcqWvsgv81e2e6x/Q iTTdZPbN4FUToOzUl1LaZ3DAcEI 2020-04-20 04:00:00 46.109.122.122 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p reject 1-65535 +r plutoa HyB3vwHK8j+BnUiSqJiDGWq6hCo EF15OMidtLD5j0MpfaeDMC2ytHQ 2020-04-19 22:37:17 37.235.48.247 7654 7653 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=573 +p reject 1-65535 +r BobsHouseRO06 HyJs2Cd9osKNFTZOiNWW+fzO2Ys EA36YaHZ6xK3DhRDByUiKFliQ+8 2020-04-20 12:12:53 45.14.148.98 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9160 +p reject 22,25,109-110,119,143,465,563,587,2710,6881-6889,6969-6970,55000 +r snap277 HzdkTFuYEPq5TWELYM+GRtKkPB8 CHI6byl4Z6bm8w4Uh9hTo7VNwAI 2020-04-20 12:09:57 109.11.141.73 37817 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=322 +p reject 1-65535 +r Unnamed H0EFxojoNaVq89ZseHZ3tXJA/6I waagTb33T5XLHluNhlsKpApJX+E 2020-04-19 20:10:56 149.202.190.14 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=18400 +p reject 1-65535 +r VSIFviking1 H0Gl76aUQq1JY1B0gzlFUjp9IUU VHsrJSGMvF+9Q3/9lt5J+Eo51R8 2020-04-20 06:01:49 104.218.63.75 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3700 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r king H0UmCGV2tp8cc1sW4d2EWki1kTI yLQDaD77I/WauKhO6Q6PX++inOo 2020-04-20 05:37:03 51.89.200.111 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap278 H09kVMTZ7KZf2s7y+Ov8nBKJCNU jCmshJx5/DDFWpt56to9dZsqfN0 2020-04-20 06:14:31 5.204.185.149 36889 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r CulNoir H1CViff3C2mjhxmiAUUc9LcPicY EK9N/CUb8IyV0qUACfjta2UXvZU 2020-04-19 19:09:00 149.56.185.56 8001 8030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=114 +p reject 1-65535 +r Ninjaipservers3 H10AKX0bn8wJzN5iyhBD42IfqXM G5OTaRfrfFi/IBKn3A3sdIYAQhw 2020-04-20 10:01:12 185.222.202.107 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4800 +p reject 1-65535 +r Perlman H2Fu+ufUVpYENy75YM4nvMiQYKQ aaBCBK6nJe1vFRw/1vmKrD1JH6k 2020-04-19 21:36:54 45.76.86.86 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=361 +p reject 1-65535 +r dao H2q9CG9AuJCjPJPMRgbuaLMclVY GUCc4JXa3MqY+rMbBildI39NO7E 2020-04-20 10:04:18 199.184.246.250 443 80 +a [2620:124:1009:1::171]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6490 +p reject 1-65535 +r FreeBSD H3aPOe36RFwU4Y6RWwztfhTkUM8 vtghCwrn/xA4MZRcS5jYV7hsflY 2020-04-19 20:20:19 195.40.181.34 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12700 +p reject 1-65535 +r ballers1 H3ct2T2iCmdF4zS6/8e5dlh2uxE seNCC8+y/BIeuBUOwoZks/ZznME 2020-04-20 07:08:10 104.57.231.26 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p reject 1-65535 +r Toreto H3qtrr1hQdzqMg/oIdws+OfkS4E OKZ51vYcQ4LOFEGTfMgwvAtG83s 2020-04-20 07:07:02 79.143.186.17 143 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=364 +p accept 6660-6667 +r jealousstreet H6BWVBvQsRryKYjXhg4n1Q9JmM0 MijeJz7ZokeTQnyQJ8GakUTeHPU 2020-04-19 18:56:52 45.63.83.146 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=2000 +p reject 1-65535 +r Unnamed H6RLxRvyQW0+RMmq1zL3sUwNHAU oWJ9iOB2xddjbFgFDcehv8rlALc 2020-04-20 11:41:23 89.102.209.34 9005 9006 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2220 +p reject 1-65535 +r ffly H7M1aWa7CwB+QVZkR1IScx1WI6w ELh3NViLLa+j0d2ISc7+azsZsvk 2020-04-20 02:12:16 85.197.11.110 443 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=864 +p reject 1-65535 +r snap277 H7mlaGa+yHJb20sANRTOcIe3Rek xBWgShw3o/D6CjtI8VNfKL2xMfQ 2020-04-20 06:09:27 109.29.51.232 37433 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r cimmeria H7rnI/gYaEfjDqHAPMo9QIHU4vk inlCDZE1ejTA2+ZRDDcueEnEOYM 2020-04-20 00:00:40 91.219.239.92 443 80 +a [2001:4c48:2:8400::5bdb:ef5c]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=913 +p reject 1-65535 +r yv3r3nd5yi1k H76wAdm+0L9fz8ZXIlquBlrJ7NI GOZrRBQPSz5cLghFYg2MEJjtt3Q 2020-04-20 00:29:25 86.21.160.245 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=650 +p reject 1-65535 +r TugaonionMR4 H9bc+TuWYPzd6UBQGf7UBoFVnqg 0eGFaH+WyCgQHRFdURA0Vj6hyg4 2020-04-20 10:34:07 37.187.3.92 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9520 +p reject 1-65535 +r serana H+cdD4j7iV95zgeuIil4WxILH7A +Aaw7c3rn6BVgLaI/MHaV9OaA6A 2020-04-20 04:53:19 104.225.219.232 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2190 +p reject 1-65535 +r deckard H+nw+Zn7cvSvsNG5I5t46VGcEfc TmUqKes6O5ZGtOIU9khZUZaxyfk 2020-04-20 01:12:10 87.16.211.203 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r TorNodeAP H/oiL5zixvzfqBElING37lriyN8 UUwkctg+nAo1n6lRKb/FZwUDCUY 2020-04-20 01:16:54 87.231.48.99 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=93 +p reject 1-65535 +r DarkRelay IARzt5dOjXi3Wyjb1sIY2joLgFk mp7C7D7QQ2PSeCH6FBBp9ktjYIg 2020-04-20 12:04:34 93.73.41.238 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1010 +p reject 1-65535 +r freiundwunderbar IBo461SEoUB0NhJXU6MWyB71Bng nomaXTvv8S8GUz/GNvTVl8LlTXI 2020-04-19 18:56:16 146.0.40.126 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=34400 +p reject 1-65535 +r Unnamed ICK8s3RT3BaObLe02tEZrAcvLe4 nriad2AZzlMTAZexese+GyRqYCU 2020-04-20 00:59:00 185.80.222.158 80 443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1560 +p reject 1-65535 +r Bernard IDYYZiU72xoHHX6tN0ThhwT85vE FQFMyj7Ng00TambuA1Ow7P3+IBg 2020-04-20 04:19:05 45.92.238.246 6666 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=330 +p reject 1-65535 +r lunaTor IDemVoxXcaXY/1xk/BgZJH5v7ns eNOHPzHHfOq81HQuqhNyphHYdr0 2020-04-20 06:49:41 66.146.193.33 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p accept 53,80,443,6660-6667 +r thedoctor IDhtmjK+y+YCN14BX8cBF5VWU/E mzVFKgpxzon68Ta5HLNfy1ixU5c 2020-04-19 20:45:28 192.44.30.40 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r heHuffedAndHePuffed IELyqaILkvEYRF6TOs8plD2iPvY 3sYSYCk70lL9joAaHZvIQdb/gyI 2020-04-19 20:06:38 69.28.82.48 10001 30303 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=225 +p reject 1-65535 +r scaletor IEYsul2kwtljVn0X0LcklxgRSmg jlU4/MujXlQgZxiPCoiiot4Z/0s 2020-04-20 00:02:08 212.47.229.2 9001 9030 +a [2001:bc8:47ac:23a::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29800 +p reject 1-65535 +r SXbqvQix9zBHtEnBY3R IEZfPf1396yV8xpNNXJvttgvDmc h9VpA323O+GlO05TB2DklZAZNpI 2020-04-20 09:28:22 178.78.213.214 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r PinwenTorRelay IEdZnwHpDO51i0swS/ztS8hl7Nk UT3C3jYZVmqGTmXdlkSSpGILLXs 2020-04-19 22:06:54 45.156.22.24 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r ragnardanneskjold IErTccInouFX4C6fODqp9oClEkY L/16VChoWMBI4V5u6pjJptRnL6g 2020-04-19 19:52:04 178.79.148.186 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p accept 18081 +r HaveHeart IE39KixqDcH6Dqy0lSGOC2YXBP0 b9nSHL0IhgnCcJrFsigY8U3No/c 2020-04-20 04:50:48 77.247.181.164 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=71000 +p reject 25 +r ccc2 IE7MT/j5OGLoL6GcU7W8mLGvYEY +95jjRkk9j+jKBPOq6Q2YqDap4Y 2020-04-19 20:02:35 54.37.207.84 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p reject 1-65535 +r SilverOne IFsbtofkHbvaxKItcRt7XK2sbzE Bqme1Akzt8tJucEBJP2hb0u0Ln4 2020-04-20 08:24:38 216.229.34.70 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48 +p reject 1-65535 +r RazorsEdge IF7SwwmZnw8YdnoezNOEtYAHC6k l2SXOi0C7r++3KgvlBc/mKynTl0 2020-04-20 08:25:59 209.250.2.254 443 80 +a [2001:470:1f19:c2::9090:1]:9090 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3300 +p reject 1-65535 +r kawaii IGa/bi/LuvRPngvNcX5IVtLlNf4 cvzK5I1V5FwYU5MmeKcluwwwftY 2020-04-20 00:52:41 13.48.137.162 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=770 +p reject 1-65535 +r summerfield IHHudbUfSijdecH2kM1w2KONuTM XxOc7L6djXMfcIE1Nn1O8z1OxGY 2020-04-19 19:52:09 185.189.112.162 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p reject 1-65535 +r biggie IHY1n8O+tqtNDybFQZcSowzehdA IF6aUyCykuM5blrQ5nJyRLFLoy0 2020-04-20 05:06:39 104.223.45.150 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8300 +p reject 1-65535 +r CAUSTiC IHa6DJpwSguKvqlRHtG6OTlEqFo kz3bp3kmJFEIfL/urcW0RC0GHFs 2020-04-20 03:48:34 103.119.112.61 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14700 +p reject 1-65535 +r edenDelroth IHqzYjPGhKiMVJrPdmqNJoy095Y U1g4nWA7Dk9tkZI/sLSSFbdlpfc 2020-04-20 10:02:05 172.105.199.155 143 0 +a [2400:8902::f03c:91ff:feaf:723b]:143 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=420 +p reject 1-65535 +r jfred IIACpYWOpm9MK0eWe6GIopArnVg kqC+2pNoPljJ1siSTRp8ylvjnuw 2020-04-20 07:56:02 50.116.56.48 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=909 +p reject 1-65535 +r Unnamed IIP7taZ9sV+KvwyDGVlO6fvmXa8 imbqo6y/zuWRBCU0+YeiqoFcOvM 2020-04-19 21:04:18 172.86.144.15 443 80 +a [2001:19f0:1604:3ede::3:f]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3570 +p reject 1-65535 +r norisknofun II2QDQ4ZM4wpDK4gbNe8FP5pgq8 wPMJdlFJMvXYThYgFsWtvEzZE70 2020-04-20 01:19:28 81.169.253.27 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r Unnamed II6WXmldZKRlO6whGd7MpLMX6j0 AAOAnVSKZAxeiQGe9kiKELfDDe0 2020-04-19 19:59:33 167.114.89.205 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r freja IJa8/ruVoRNPOfz4zrB2/0GitIs Hmc/ZqPOvzscENuwqaRMwP3kRwk 2020-04-19 21:48:10 194.88.143.66 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14800 +p accept 20,43,53,79,81,88,110,143,194,220,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8087-8088,8443,8888,9418,9999-10000,19638 +r cvbnet IJdNKOtmjmidQlYEbg4yA0N1oKI /vXs3Nq5A4DWXQouB9kfji04nQs 2020-04-20 10:14:13 46.38.236.250 9001 9030 +a [2a03:4000:2:ba4:88e9:eff:fe89:3637]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r somerecuer IJ+jGJuKeEKO6UHZ8QxGwDTePsI ZOmVCWolRwnPFzhWs0EA/PbjMVE 2020-04-20 10:53:18 207.246.94.103 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=2350 +p reject 1-65535 +r FuckingRelayMe IMgxuFaIPwr7YFKRdZXWAi1SsZk sBhFbiSEeWe+emr8m4aYIg5IWqE 2020-04-19 19:31:14 188.250.74.215 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7870 +p reject 1-65535 +r Unnamed IMojNtUotcXhKIYGGjkM51UkAB4 4XITOpFpRbvvV88qm5Q9WiO65cM 2020-04-20 06:26:35 209.97.173.48 19091 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=554 +p reject 1-65535 +r dude2019 IM5+nEmnSGYeZsdHxuIQnO6qVwU dBQescg0r2RqDACCyeDLfJtPH0Q 2020-04-19 19:39:39 194.59.206.54 9001 9030 +a [2a03:4000:34:3f9:4db:c3ff:fe7c:13a3]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18900 +p reject 1-65535 +r marunga INKhhqQS6kM9m60v29e0izayCzQ WgsLFhBJqgHeGei51FWJKcLMWXs 2020-04-20 01:46:19 125.212.217.197 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=129 +p reject 1-65535 +r hopeforabetterworld IODdOtJmGV9GIOgzS0z39Ro/IQ0 JvVJZ8/ZzuRHjylLFv3fHtZ9nbQ 2020-04-20 09:24:50 188.68.45.72 483 0 +a [2a03:4000:1d:46d::483]:483 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p reject 1-65535 +r redquasarxyz IOOfFTyLUrmw9uEAN76/oKCNDWM ARe4KvaLTvQinccZBFmCM/awFKQ 2020-04-19 23:16:49 172.105.168.144 9001 0 +a [2400:8907::f03c:92ff:fe9b:f9fe]:9001 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=104 +p reject 1-65535 +r NotTomHolland IOOwleiEO7JwCdjbbk4JLOnbYDI 0kyGhkCHr077O93qiyA392rLiSs 2020-04-20 11:31:21 173.249.60.101 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r ULayerKlein IOeltbo9y55vSbnQ8+ueIO/H6mM 1zQf43H+KO8vUgt6xjfn0GBxuxQ 2020-04-20 03:34:18 198.98.48.30 443 80 +a [2605:6400:10:668:6e3e:3ce6:28b0:f2da]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r MrRelay IQAB7oqOCGmDo71I8Nk2mWRRycs zGx95R0ula2tyjQxrudmigdqd34 2020-04-20 03:09:18 185.225.17.60 443 0 +a [2a0a:c800:1:5::2e]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7640 +p reject 1-65535 +r endurcissent IQFMig2YBrhTID7xE3vS4g5p1dc 2Le18byzmmtwAKz0Zb46WOSeCcM 2020-04-19 21:07:56 172.104.76.242 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=660 +p reject 1-65535 +r mamadu IQTo6+XgCWm+gP+h38xYM6xDDXk j3zx0Ls+Z0XzmXFNLHMSK2LGnQU 2020-04-20 00:39:16 85.195.238.100 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r Unnamed IQZEmcpT/ZLf8J26E1ODmm0BIPw MBfrxDAJqzXql6frj3zacB/WRrk 2020-04-20 01:09:24 46.166.163.76 443 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5730 +p reject 1-65535 +r ModernisePollutnt IQwPEc3kraX4PQiMWolxDjG9yd0 QYchco8ubsORb2g8oYP9iOOzk5g 2020-04-19 21:22:06 47.254.25.107 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1920 +p reject 1-65535 +r bmwanon784717819 IRMQzQnsKQUFwfJAGK5TMAdkEqA K6XfTnO3/uTIZ6gXqaGxUYpcdaw 2020-04-19 21:29:12 78.47.178.19 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17800 +p reject 1-65535 +r fallout IRT6mgU6QpDMdss8IBF68bJEFb8 dg+diZx+1S+ofmAjs3btYoqwDQM 2020-04-20 10:51:58 81.17.16.150 9001 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nighthawk IRnlpLX0IBZb9d8ZpaKPRhD/0QM nkQlfhGoBd1gvgsH8b5zECg74Oc 2020-04-20 12:04:50 78.47.36.20 9001 9030 +a [2a01:4f8:1c0c:603f::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 1-65535 +r Lavaronn IR8DPPmSzBQZxXvleRVvw0UzvVE 2Dymr1n7mH05TzEBhE5v5CoQhyw 2020-04-20 10:24:29 92.232.175.224 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r 0 ISOcwxOiiz5s7kjZSb93h0cbFRk /G2Kf3BRgy5P+3DCTWf2w2RPamg 2020-04-19 19:51:25 185.163.45.29 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6860 +p reject 1-65535 +r notorious3 ISm+mEUW9aZEmDbx+jbUKh4ZG00 hStvtnVKhq015oTJQXIdfw9lyJQ 2020-04-19 22:07:27 207.148.8.210 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r tamanegi ITEPSAZqTKresr/TJPCzj44USNY X/sHJs+5ul2j4lkFJsIFsLLXI9c 2020-04-20 01:52:19 212.89.225.242 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17000 +p reject 1-65535 +r nl2xtracodews IT8rSrCe5v+MohuASy4b2INQiNM HsSZBZQR/FsqMRYscjO9EykKGKw 2020-04-20 12:18:59 51.15.42.172 9001 9030 +a [2001:bc8:1820:a23::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=30900 +p reject 1-65535 +r otac IVFyL8iTKen6QESPqHW5tFmQHmY CN5copdFTHT/kMNG/Yt8gbtLAbM 2020-04-20 07:37:25 87.120.36.212 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4000 +p reject 1-65535 +r RBN1 IVVVCmlfqezKng9nwCzsUDFp15Y oyD8jIu0llq4B7zQg33Z+TSNpxc 2020-04-20 02:09:24 68.183.66.229 443 80 +s Fast Running V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2800 +p reject 1-65535 +r Assange013us IVYWUn+5ftW+C/jSFmvbRO62qEA senKHP97NQ4XJzkdvYosWGrd7lk 2020-04-20 08:02:15 94.26.73.162 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r Unnamed IVl9lCTHRgoWEZ+i2A0LsPe7TMA GnTvGNPxSRNkPbcLKnnTIMn0cuI 2020-04-20 12:56:20 31.220.4.133 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=191 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tkContrex IWAoMqAJSZay3ktfpveOkw2YTGE mSznpgEdkumYKm6g9JGW8davohw 2020-04-20 09:42:59 91.121.2.157 9092 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=20000 +p reject 1-65535 +r NoGodsNoMastersUA IXub5w3GAvbZKRMuoqnfYLrtjOA 0JC6kOdgBls9UZ+bO4NiINUscV8 2020-04-20 06:10:52 217.12.210.210 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7260 +p reject 1-65535 +r detonator IX9dfYs/Rkjr17CBueCpV11J1Vs SOkGxE16mRmUMGDsg1VvTTyQwMo 2020-04-20 04:03:20 51.89.149.208 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13200 +p reject 1-65535 +r king IYyPINeQ8xjLk1j9pXRiWw7y3Ao +wCo+42d62L4cQuKWbInPrptKro 2020-04-20 08:25:04 51.89.200.120 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r FaerieOnion IaXVjAQr+clRHheTDC/4t1aWmfk l5s5sYJ5HI6jlIE01IHrWQTjh4U 2020-04-20 12:45:21 119.17.158.221 15151 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=150 +p reject 1-65535 +r Assange013us2 Iaxu8VyGZBzmI7igjWQUS8rBSuw csP2kk/mt2UYkjWnLWCAgbiarZQ 2020-04-20 08:02:15 94.26.73.162 9201 9211 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p reject 1-65535 +r snap277 IbD3k9W/qXexcoAmLE83zQ2fTfc wvJZeKMh5B9MxM9fh/qhbstXec4 2020-04-20 11:54:09 95.44.180.215 37621 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=34 +p reject 1-65535 +r relay IbVF7gnaTt7zmfjuClzZO96YdcY 5iaFLeYTdjMFAD5U7TazJ3sg96A 2020-04-20 10:09:07 125.205.45.73 443 0 +s Running Stable Valid +v Tor 0.4.2.4-rc-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4 +p reject 1-65535 +r Unnamed IbVQcsAPRSKFdlX7sPPiXXWlNXs ouYrG7D+nMYp0o5GjR3ytEOLoiw 2020-04-19 21:26:41 109.107.35.154 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=760 +p reject 1-65535 +r smell IcNtH6IAecYQHFWpkzG6KYESSQE 1doU8D8DQdgV02jZG2ZA0ePJWhQ 2020-04-20 01:21:51 205.185.115.70 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r cebolin02fr1a IdoVbBor6nq4idJ/mILFoyXtGCE QRB9MGast4qWktv2pfuAjZyqMUY 2020-04-20 01:32:54 51.15.143.49 9001 9030 +a [2001:bc8:604:82f::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33200 +p reject 1-65535 +r Enterprise Ieshdt/XNkqONwWr9RjogDYkJfw Wr+Uglhf/OzYls5GZXE/QvOWp9s 2020-04-19 23:43:21 163.172.184.243 443 80 +a [2001:bc8:47a8:2415::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=41300 +p reject 1-65535 +r snap277 IfFn5fAYa6DKoI2HzIVO3smSsDc 5oAdqHQrl3xQTqW9zD2iuaftG8s 2020-04-20 09:41:28 109.129.222.94 46501 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1550 +p reject 1-65535 +r Zalax IfL27ASZCX/vAHVNEKA+IPWu8SA K1s+hvpIxzbCs+28X5k0CrAMm8Q 2020-04-19 23:54:02 51.178.122.233 9050 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35500 +p reject 1-65535 +r Unnamed IfxL+ELsS09mvRJASm2MUH3FNCM HdLtYQQfB0cCqcxhiv9wPwcgYiM 2020-04-20 07:45:32 163.172.176.21 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=1230 +p reject 1-65535 +r fwioetwg4utghw4ignc Ig5hH21IohA89Ryrhdse1UMeRWA wncwaeawRU71NRJbEWwziYd/1Cg 2020-04-19 22:52:38 157.65.61.9 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=280 +p reject 1-65535 +r ne0 IhVG2uhrADE5sTvW9q4bS0K1nfg gfRLijgy1eNC6ACjNaSaE4z3x9Q 2020-04-19 21:51:13 176.9.114.252 4080 4443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=91000 +p reject 1-65535 +r amsnl Ihd6BAXSjVql0MNbXF81Jlvm1iQ QT+sC8RaldgD4lRIn6A0e6xIkx0 2020-04-19 20:04:58 195.123.217.153 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=928 +p accept 43,53,79-81,443,531,873,981,8008,8080-8082,8888 +r malechick Ih6Xa1RuYASKAZUCUDmbhTTU5Lc Jrqn7FraQFmNazKBMXj8Fj/0e08 2020-04-20 03:26:02 37.187.122.8 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6700 +p reject 1-65535 +r Unnamed Ih8DWjMKxCMaLj2QHxyxFIPBn2Y Szi0ripjsP/M1ldOOznx4ayju8c 2020-04-19 22:13:45 130.193.15.49 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16100 +p reject 1-65535 +r Kodachrome Ii7y198p/U3Jq/WUSc/u5UWqz+M 1KCcF35hCHMvgrHTsfU7rYTDDNQ 2020-04-20 12:12:44 217.123.216.103 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r raspitor Ii+niyWD95YKt7u9BkOLvfrTO7Q ICyWyzDnQjH9YowL9y9CUDEcg4c 2020-04-19 21:06:08 213.140.92.199 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=210 +p reject 1-65535 +r artikel5ev7 IkBKPofy1/4vxjWf3nG23C1ucw8 QL0P9o+qfIZS/2Y5ecdbkqJOUTk 2020-04-19 20:35:53 185.84.81.240 443 9030 +a [2a02:248:2:41dc:5054:ff:fe80:10f]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2110 +p reject 1-65535 +r Unnamed IkTKw6mMHPM+B5nBvecQ7uCWrII yfYqO7GpXLnHaZvfMUyuD5Qp/uw 2020-04-20 06:38:30 51.79.53.146 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 25 +r nasiOne Ikw90d/28RIZYEhw1IlTJJ7jwm8 Ci6qI4IdCkeT2rp/Km91vD0MLYw 2020-04-20 10:32:45 212.51.134.4 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r Manureva IlqOo2ffMHNDPgqEXd2ibSNX5MY zYsrZR5QcI17wBZM868fVJBh0EI 2020-04-20 09:30:40 82.64.243.112 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r Assange021us ImWDaOWqB1rqrMGQda3BlnCncWU o89ZUg+u5w+PvPdh56pma7xSWGQ 2020-04-20 07:45:57 107.174.244.102 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3030 +p reject 1-65535 +r Unnamed ImdZYrdUZqgdhRfr58WIXNNSqYA S5dneSnzwr1gsjG2uDn4a0kPhiU 2020-04-20 10:10:34 45.76.43.42 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r lucinda Im2eXBAgkYRdD+qrBHFIeqPFyKc dwt4VJeQ+C62Kja1Lr1vcTdOKxc 2020-04-20 04:07:14 163.172.53.100 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=449 +p reject 1-65535 +r Zenobia Ina/iDR9A+uqFt2fY1wK4uOXKnw Ofzv/OExKIunxnvJZ/oT9ylHL7A 2020-04-20 04:20:35 147.87.116.199 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p reject 1-65535 +r fruitybooty IndblT5mIVFUnBFMuO5fvby9rQI sZge19PFCeHNkRLQnk7kS0Hoe5I 2020-04-20 10:47:40 88.198.35.188 9030 9993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=75200 +p reject 1-65535 +r PataquetsDockerTor InvEkn6leQmiNV4wiLjeiy6sQ9U y30pKjCZq4odYPv7ZncFQcpwdBc 2020-04-20 10:59:53 188.40.81.198 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=27000 +p reject 1-65535 +r cyanexit Ip2GXXrAhNMOX1AWzlqMIXQPdPQ Q7zMHm/hkNKmXZFCwtcwN+jAVs4 2020-04-20 00:31:07 51.38.233.93 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22900 +p accept 53,80,443 +r Seccom03 Iqa+mNIBsQHDJmFzmWe/Te0S75Y nkhFYxijg5sJOCP1fyEMO7HL/NQ 2020-04-20 00:34:47 54.39.176.60 443 80 +a [2607:5300:201:2100::b8]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14100 +p reject 1-65535 +r Pombero Irb1SHantv4mwedGQqWEfKfURFE f8YmpE74/+5MeLo0ODDp4WYjPgc 2020-04-20 11:32:00 84.194.130.155 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3630 +p reject 1-65535 +r Fastnet IrzQ39FIIJyYYMf4mQerTe6XSgg /hcRRpJoOseaysrQ53Dum/BZckk 2020-04-19 19:41:53 95.216.115.85 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24100 +p reject 1-65535 +r Pegase ItIxS8UUaJCo5cGciE2WwMv+qiQ LQmF+OHbSH+N9Egq5aHEsCiFWik 2020-04-20 06:01:14 80.67.167.81 9001 9030 +a [2a0b:cbc0:1100:1::1f]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p reject 1-65535 +r 1804m1 IuHR20cjoXTnE7G/QHPawcJTUbM geMwsUGXgYLA0mBX8v4mqM/hDCw 2020-04-20 07:33:52 198.211.103.103 443 80 +a [2604:a880:400:d0::1516:c001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r Unnamed Iub72413tMD6AX1sX5tFvs3Lz/g YHX/wIljzjUb/RZa7t/Wuwz3PQI 2020-04-20 00:42:03 82.251.74.105 23353 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39000 +p reject 1-65535 +r hydrogenuine Iul1k1unfqWaKOoaqDh/kGA0/L4 DE5ozRTsHkuB7j+dRu91p8cCbGM 2020-04-19 22:30:21 172.104.208.190 443 80 +a [2600:3c03:e000:19f:0:11:11:11]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9010 +p reject 1-65535 +r MakeSecure IvdOF2+ANJnU+A2c59MliDqMDkU eACndd8x9s4cpLYrbQ+0MO+rsfE 2020-04-20 11:04:16 83.96.213.63 443 0 +s Exit Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SouthernFreedom IwUzfTiM6rWB7TuTCOJu7U+KMPA RxDfPoP5hzfYdixDtySW5urFt4s 2020-04-20 02:45:13 72.187.245.134 32987 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=725 +p reject 1-65535 +r niij01 IwqLKouoYSENm0upd0WuwhepQgc uTMXsNQn9YaA5g9LcAjfV52yFV0 2020-04-19 23:03:59 163.172.176.167 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r CBTorPi IxGsL6h40AWLs3a6OBI9gc7jhAI gFr/rzHjFY95jcMFGT4+9sThAqg 2020-04-20 01:48:23 210.54.88.208 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=166 +p reject 1-65535 +r Unnamed IxwAzTc8XajluomIMwBQa8lYgdk Qm/9gmhU0Z7ENXY+tAYa59m8yug 2020-04-20 10:24:53 178.17.170.164 443 80 +a [2a00:1dc0:cafe::f290:7489]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4220 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Bael IzHeXS6a5qNjV05OQB2kLQZ8HS0 aSVZhC3ywdTC/0y9ABe/zWRPBtc 2020-04-20 00:17:51 200.98.161.148 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49 +p accept 22,43,53,80-81,443,636,853,873,989-990,993,995,1194,1723,3690,5900,8080,8082,8332-8333,9418,11371,50002 +r snap277 IzsuWhom9AehyD6NVT6H/8D1paU hYfKflx//xNAFH70Z354Oht74I4 2020-04-20 10:58:26 78.244.194.160 32875 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=279 +p reject 1-65535 +r AuroraBorealis Iz7Z2TlctbkGMGOpgO9XTpkyEnw BUZCtwWJzpORq/XY5ecAQe4TJGc 2020-04-20 11:38:14 178.17.170.226 9001 9030 +a [2a00:1dc0:caff:183::95bd]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7100 +p reject 1-65535 +r Ceres I01nDqp5Twkve9dY1dKqf04/++M +INTZC8PasaK1cG50yL7wzAFYbk 2020-04-19 20:35:40 80.67.167.82 9001 9030 +a [2a0b:cbc0:1100:1::21]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7490 +p reject 1-65535 +r Tor4eefeeyoh I1jQyB3CMVO1bjYqSaPPAH5YNcg 9jU8gUhThP3+VocZuutMGZks33U 2020-04-20 05:26:55 5.164.219.245 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=3300 +p reject 1-65535 +r UenoStation54 I100RCNqvCj0Euk4FPa3gyANRjA v772vZkXiIcvxghzOyYRwOP8J0I 2020-04-20 05:59:05 51.15.249.81 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23400 +p reject 1-65535 +r Nightosphere I2Ba3hYpjKFSzGLwx1k7PrV70PQ bd7CjdXrbLPwi0xU2D+wCdKj8qU 2020-04-20 03:08:45 79.242.148.62 9005 9003 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r Eutaxy I3f0FawkvGzgHB4A4fXoUK8oQC0 5vSb/88aDCy0nr/NDKxZWvzwygk 2020-04-19 19:07:35 67.249.138.113 9250 9251 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=264 +p reject 1-65535 +r Rondoletia I3q4KZEJLNbU+trOEinoQAjjddk sYJ8Cq/khzctoMPNfsFYsfozioo 2020-04-19 19:49:53 147.87.116.61 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58300 +p reject 1-65535 +r ProtoAES256 I3+QXnRIUM/jtRCMkRL9/OjcBdY 7Z7+X9G/aUO2jRHe5pDeNz/DBZw 2020-04-20 08:29:48 104.207.146.208 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=220 +p reject 1-65535 +r SkyLights I5F7s/OZS8YfDJ160ZsGn54VDSY UhiBG+XxfS2uOEjEIoae5waK3R8 2020-04-20 06:56:30 67.215.255.140 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=140 +p accept 80,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033 +r FamGuyFunnyMoments I5i3/Wycl6IP3X5jfL2tF11bdh8 cia783K4RBJLdaad7/ON94hTChI 2020-04-20 07:23:23 188.240.210.50 42069 42070 +a [2a04:9dc0:c1:7::e9d:4eee]:42069 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=850 +p reject 1-65535 +r shallotandredwine I5ouDwm4/qVRcnSGUZBAWYoCJ3g Ag/7p3LGqb4AFAEb2UV9OCOf03w 2020-04-19 21:09:54 37.187.21.153 9001 0 +a [2001:41d0:a:1599::705]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1220 +p reject 1-65535 +r k0nslNET1488 I543OxCOBJErOvjDLpn/DtxJKmg e5x8iVzwR0jZuWY4t63S5L/uwYg 2020-04-19 19:29:31 198.98.53.61 443 80 +a [2605:6400:1:fed5:22:f80c:3ee8:9e1f]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12800 +p accept 1-65535 +r p4r7154n I6AiBYlIhnZZ5ppSgqxONnsqz70 qGmUCnoz3Ibd9uJe5XhbGwV6gXY 2020-04-20 11:23:53 99.131.45.143 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7920 +p reject 1-65535 +r xenon I6LY3fdh81zGO99l5gS3an4vaXE tfixFtrpnghQFnQ/ZS5QuPjjBoQ 2020-04-20 10:07:38 217.160.59.39 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45300 +p reject 1-65535 +r fr33as1n5p33ch I6S03cIXABU+0b1YU4Owx8Y241M kEfEuCY+Bb3VHeS0Sm7FjMScIew 2020-04-20 01:04:34 212.51.137.248 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=683 +p reject 1-65535 +r marschiertor I6qMYewyXB+bJEOmT1chyNEHTgw VbC8Dq6Bx4st8H8ckmEoyv7tUWo 2020-04-20 03:19:26 134.130.181.43 9001 9030 +a [2a00:8a60:e011:e1:94b3:e439:2197:4433]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28600 +p reject 1-65535 +r apostate I61rFlE32VfAmqD3o+57Bc7EqPI VNoQpZT7CRFPwVWoZEXXZXI+YYE 2020-04-20 09:45:30 51.15.62.130 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6300 +p reject 1-65535 +r GaoZhisheng I7PvQnHjinROI6zENF5Wy9tCoaU /wWjToe4Tl/sSlxD4Ji17IBcB8A 2020-04-20 12:15:52 89.221.214.122 444 81 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r TRUMP2020 I7sSvWiVK/49a/Tv0BDbZNl1ywI votIT3RCQzMujmcWpHQmo+uXDXE 2020-04-19 19:05:30 199.195.251.226 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 21-25,119,135-139,445,465,563,4661-4666,6346-6429,6660-6667,6697,6699,6881-6999 +r Relay01 I8GMgBDqyD7IUaObJeR1rIKo74o E8EHcwF0xHY/AxeLUS5LslXgr3g 2020-04-20 03:12:45 187.63.100.24 9001 9030 +a [2804:538:0:1::24]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=180 +p reject 1-65535 +r esko I9wpXXcdUdqYEAjRuXAqA8ZEiNg O/CH9HLOAYFxuVreN4hxsPG3VrU 2020-04-19 20:27:59 188.127.197.42 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r freebsdrelay I98NYhMdS09przhSYdm2CmmB13M yIDBt2pOkUAR2RO/zF8erQizMUs 2020-04-20 15:31:48 131.150.192.182 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=925 +p reject 1-65535 +r FR1sevpsNET I+fu+dGg/YB5kha5cO52J+8FC7c 9DqzT1TKUzxSDJWYH9YThsnhV24 2020-04-20 05:12:08 193.70.73.242 50102 0 +a [2001:41d0:1:777c:200:c0a8:6606:0]:50102 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3760 +p reject 1-65535 +r cannellini I/U0tHndWh3HsY5Dw5FOQhL+414 a+q0IqDaKjvwq9/a8xytBveECxs 2020-04-20 05:29:29 185.65.135.166 20240 28912 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p reject 1-65535 +r Node102 JBny8e/5qrcDwcyViqc93t9ngqo H4itBZXTw11XiiQq6o/lL1lgaxg 2020-04-19 23:22:37 93.196.81.87 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r niftywabbit14 JDUtMBlr7+W7KaUJI/eaKARSdhE t1RzvYa+xsRr4bxuhekFUMwdnQU 2020-04-19 22:15:47 185.220.101.154 13154 14154 +a [2a0b:f4c2:1::154]:10154 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24500 +p accept 80,443 +r king JFAMTnt7UEGsekyn4pR982kOAgU 1dqDaMWIkCCRsvqjGa7T7S3GUD4 2020-04-20 08:37:07 51.75.175.27 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r chydenius JFktsc2gZs3KQfZAPO1mGDnN4iM 6lLe8lRVQEe11mqaxVtj8Rwb9IQ 2020-04-20 00:18:00 37.228.129.2 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6410 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r atacama JGRFbCh+cVg6bq38+ClZcitulv8 PmxOwGVGK57tHVJqn6VR0hHJj+g 2020-04-20 12:00:00 85.119.82.142 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5340 +p accept 706,853,873 +r flowjob03 JHWE30mPX5mYbAYnYPMOFCP1dxQ Npa+shjXowkssa1LFfQo3Kq5/M0 2020-04-20 06:49:11 152.89.105.84 9001 9030 +a [2a03:4000:39:3a4:343f:dff:feb9:4da1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46100 +p reject 1-65535 +r Unnamed JI4xIEsQy9kLAjB2q+eg8D7hp4E wTHItUlsHUvf1AY5vJa660yIWf8 2020-04-19 22:13:34 155.138.143.28 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13400 +p reject 1-65535 +r Unnamed JJMblZev/lApu9uKraU038OMZAc gWuQC0KTeOGR7EnAp2rtHASFlvU 2020-04-20 02:14:37 172.104.170.82 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=239 +p reject 1-65535 +r dragonhoard JKF6TB+owhCKzeO+aBsHMThL86U ttbkUUlEA4ASudF2bFAYhevdqF4 2020-04-19 19:25:40 159.69.21.196 8080 8008 +a [2a01:4f8:1c1c:2e49::1]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25400 +p reject 1-65535 +r fury JK8WA8300Rjh966/aAwYvaXo95M BHF0SJA/Whn97CbXmuHVYvWnpy0 2020-04-20 06:57:45 51.15.73.97 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11300 +p reject 1-65535 +r spechttor2 JLHfgHaDMpkLqPEjC6QdldgtUr0 Lp0iWV2ZkSCONgRFjxEc2j7r9JA 2020-04-20 02:29:39 81.7.10.86 443 0 +a [2a02:180:a:61::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p reject 1-65535 +r bennytorbot JLg0IxdJImc7sa9Ds4lCkF8c4wA aHC1VPeSORFNvtKR/MqLIR0lwYU 2020-04-20 10:13:38 204.83.204.143 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31 +p reject 1-65535 +r Tor4iesongev JL2j5h6YVgcHJAVQL4vCbm4MZDM C3egfHGk08ihnGsDP40WTphqt7U 2020-04-20 07:14:10 71.127.179.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=7250 +p reject 1-65535 +r Unnamed JMDcPzmbC6bZIU4ydkvbFv+sVHY 0Y7+ir4jB4yhed7PnASBtMF/EOY 2020-04-20 08:40:40 194.124.33.248 36851 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=17500 +p reject 1-65535 +r bakunin JNBJGiraq1LBdiX7ySbYRHeuoyI MpuZc4VwFPBnChGzl2kVj4ri/mg 2020-04-20 01:15:08 193.234.15.57 443 80 +a [2a00:1c20:4089:1234:7825:2c5d:1ecd:c66f]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p reject 1-65535 +r niftymastomys JOHGQSGDlyv9dtg4rATR7SYXQ9M dyjczRp2LSbedMkEAeq9+bCDZ3o 2020-04-19 22:25:22 54.38.73.16 80 443 +a [2001:41d0:800:1b3e:1:1:158:2f44]:80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56000 +p reject 1-65535 +r bastet JOLxORIdQ5TFS1vMNos7QRhXxBM nAKYMiRztZ+GvB+pSxJgmbV+BDc 2020-04-19 20:17:10 204.13.164.118 443 80 +a [2620:13:4000:6000::1000:118]:443 +s Authority Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r rmdck JOVE/gdGqTcBn9qUM+co/igECk4 IN7DuGrxZIs8qmiRjMpQ6kqJZms 2020-04-19 20:02:28 92.158.70.4 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=402 +p reject 1-65535 +r niftymouse JOkZVdlprqHYBBPGT+EG+uf9Lqk 1flLBBQWzinH8TTp9g/O+V6LwK4 2020-04-19 20:26:39 185.220.101.10 10010 20010 +a [2a0b:f4c2::10]:10010 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35400 +p reject 22,25 +r cosimaniehaus JPl/mMReR1RlW+ZnmQSXY9rumc4 nRevqtEujxMPgPFsidfbzmuAI8A 2020-04-19 21:40:36 136.243.4.139 8008 8081 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.1-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=69000 +p reject 1-65535 +r LeslieRelay1 JQfmqXrFLcCfpRnTE0AVbuxials gf1uapUIeE8zc6KTlTQnCw8MqfM 2020-04-20 12:12:34 193.218.118.50 9001 9030 +a [2a0f:e586:f:f::50]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1870 +p reject 1-65535 +r Unnamed JQhpjO4nruYOL9Ja/aTiKr9FPSo G0mDzuB1YC0Fn6lJxKzZpzYUwLI 2020-04-20 11:48:49 128.199.146.186 9001 9030 +a [2400:6180:0:d0::50b:9001]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=570 +p reject 1-65535 +r smell JSIk9ym12+8yJRbA2cH5NcUjglU 7Jlm+U/+v12HE+K/xMLItPWJ+kQ 2020-04-19 22:23:22 45.9.148.219 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11900 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r corsair626 JTUFCa6dI3Nocc/MLPgL+cmqXTY 5i1Punfmj/13A3Vl7ozgdWUBros 2020-04-20 11:28:34 79.111.15.131 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3700 +p reject 1-65535 +r snap277 JThbCXVkrm6vHzONm5iqQfH6KVk Ir8YPvQzP5+7nJhP3qp/WZd1S5k 2020-04-20 12:19:55 90.78.122.14 34457 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2 +p reject 1-65535 +r snap277 JUEIo82GsSi54gJfttB0ogFbNdg UtU55amF+kG7Xr8xKPRyZQ22JoI 2020-04-20 09:08:46 109.171.11.233 37813 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1060 +p reject 1-65535 +r kukks JUO8rfy6K1reg/uTGUtenUWBBTI 3GpqV7idLN4iNG7mI55YeR89BmQ 2020-04-19 20:52:40 91.205.175.156 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r Unnamed JU/0gL9WQpKUYFMv9ZvOFd8QcOs Sj4pEM6o7GWLC/ONAzowuAn1dEw 2020-04-20 11:17:54 185.113.140.20 37899 46906 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=196 +p reject 1-65535 +r niftyrabbitrat JVJuYbi8IrZi49SlBQQCHMPZhz0 TqIWxYpJbMN/LA6Ly0evgP5RFd8 2020-04-19 20:26:55 185.220.101.19 10019 20019 +a [2a0b:f4c2::19]:10019 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59000 +p reject 22,25 +r Leodagan JVz4zGgTdEnevUQ3l6s9hR4wZbI oIA8L8zUXK6S32d4w8ivBRBjvfY 2020-04-19 23:36:34 178.17.174.196 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3500 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r galapagospadda JWLUY9FcPDg1FOfWEXYFBzrEedk cg+gsN0SA7hZ0kzd8jJ1GE65afw 2020-04-20 07:30:44 213.66.107.250 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=278 +p reject 1-65535 +r willcarey JXL73aRWfaZudoSpo8W05KVLuzc sXm1ZcbaTjU4Q/AA4r51VC0ouHg 2020-04-19 20:25:38 139.59.0.6 9001 0 +s Fast Running Stable Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=631 +p reject 1-65535 +r pitorbyjens JXNkjUVh7w6lX5JP8/QvbguVxdo HC/i85tGUWr2CKLh9iP88dUXX4s 2020-04-20 04:13:14 77.179.31.49 29035 29040 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3470 +p reject 1-65535 +r TotorBE1 JZkPxU1yaMkUFwoRjuTudQJUUdo W/Pdyh/KKGAP51z1jjdH1MpIXrE 2020-04-20 02:20:05 137.74.32.25 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50800 +p reject 1-65535 +r 8e55c66ff8a8 JaP9nf/d3ITFm6USPJFqLX4YZeU ZUE4qc0Bosu76t465ULZbn68HRc 2020-04-20 08:07:02 51.81.254.2 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11600 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r darrieux JbaU6pX4JfFWxdrlYHszdehsDE4 Ei/vEsgl7Kb29dIqajyW/uXBPkU 2020-04-20 02:07:13 153.92.126.234 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9100 +p reject 1-65535 +r freudianpopsicle JbtRgt5o2m/BvuLIpjRUNpWH6V8 Xn7YjC6YdURHzLxs6huhVmZFSfo 2020-04-20 05:45:32 142.93.135.71 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r bumblebee93ed JbximMduuTmPau/nEXq2v6CfEeo wF6DCGu3Zvk8+fVpibesplTj5Xg 2020-04-20 04:20:03 139.59.85.141 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=608 +p accept 20-23,53,79-81,88,110,143,194,220,389,443,531,554,587,636,749,873,902-904,981,989-990,992-995,1194,1220,1293,2082-2083,2086-2087,2102-2104,3128,3690,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8888,9418,11371,19294,50002,64738 +r lapin JeB4zR5TenQYMYFo9+GZDvKhYMg LsldqvgHVCxCSClmc+kr9rffVfA 2020-04-20 11:22:45 195.154.161.5 9999 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31900 +p reject 1-65535 +r hkt001 JfSSR2RvH5ycSzEheuAEMIsnE1k JyTNjCvWsZ9QmsV/qmuXu6SDTKA 2020-04-20 08:50:06 103.35.74.74 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=539 +p accept 20-21,43,53,79-81,88,110,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1293,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,3128,3389,3690,4321,5190,5222-5223,5228,5900,8008,8080,8082,8443,8888,9418,11371,19294,64738 +r snap277 JfqzG7f3dOgCNgrTYQm00jc7pT4 7qprewYL74h0luiPJ9d/1mi6l1I 2020-04-20 11:37:47 84.62.255.196 37583 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=750 +p reject 1-65535 +r trooper JguGoEy+3mBfGDYkwvyjzoH9JKE nKdc+alwA3dIpMcGAe+7mOQAGXM 2020-04-20 05:40:35 31.31.72.24 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2220 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,11371,19294,19638,50002,64738 +r mramazoni Jg5RNkXLCZ9Ugo47BqwxFP1gP94 eRP6bH88dsfL4dJV+twS+0YNyrQ 2020-04-19 19:09:40 95.67.90.202 443 8080 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=669 +p reject 1-65535 +r Unnamed JhRQvPS9WiCOyogr5M++3c0dFx8 x42kQtKrfdtUMdR6BBTRjkXa7JA 2020-04-19 20:00:48 45.12.206.106 34513 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=18100 +p reject 1-65535 +r Q JiIK6hiLjQ5Hu1QeGmFus61wKV8 q5G9cSac9OxGaXfUMypk1Px7Q90 2020-04-20 07:04:27 78.47.221.71 3451 3480 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r bikerduderelay Ji3SbjcdwCov+wunso/OGrcHmbo W8BS2P/2ob8QOLoeUipb61Xqvd4 2020-04-19 23:46:32 176.10.223.50 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r anonymous30012 JjQdIW0e2qp++DEtoNGbMJgBsuI yvERfmWebJmB9HHxdtFXAHOzNk8 2020-04-20 04:13:38 83.135.238.77 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3690 +p reject 1-65535 +r shenanigans JjyEWNxYkJSYY8Ahlq/OaOl719I 3/M7aVeOsCSF+GG5tVZoHwPR8bw 2020-04-20 08:22:16 71.39.169.105 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=85 +p reject 1-65535 +r khjmklykyu JkDsGmEbJ6sFDWB5Y3L73S+QR4k IeC4AiXW3x73MrWthb4OVKNjz44 2020-04-20 09:17:21 94.158.244.26 443 80 +a [2a0a:c802:0:1::1a]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6220 +p accept 20-23,43,53,80-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,981,989-990,992-993,995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Magmarowzee JkEHMh5NjqavR6XY5piU/24/Z8k nWHYkAHd1SVmykeP1iK7ysBGsjA 2020-04-19 23:33:00 139.59.19.222 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=410 +p reject 1-65535 +r Unnamed Jkm7l2z9pKENVfKM92xrXte+fp8 JkktG7THyX6BOKgtIiYudWnqUfw 2020-04-20 10:32:00 104.244.75.173 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r hatcheck JlmsqhQLaEXjjxibQICBe5gZ65o H7XgrVdG7jAPH8+yAU8mACfHrqs 2020-04-20 07:36:13 94.156.175.120 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p reject 1-65535 +r p14nd4sark Jm8sXOOoL3NXcosQKYiCbjjZjxc ggzSWD0ZVzi7o7t5/6PAefo2UYE 2020-04-19 19:57:37 207.153.17.244 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r NSAGOV JnWSY5SNBD8mBBOb3ZPvTzzyIoY R85GRDOcDAz0BKDTENMUSStf79I 2020-04-20 09:25:40 78.55.240.245 443 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=846 +p reject 1-65535 +r whynot Jn+h7PG7fghXtKrP/WEIGnoMTa8 zBbRad0orN7FF8g/8VOKSXinuO4 2020-04-19 23:39:50 118.211.154.56 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=178 +p reject 1-65535 +r TJM JoUyonKtwD2X+WBmJ4nmKWasgsA wgMIV+Y2MNOZD16gj9KNbT0tylI 2020-04-20 08:51:29 107.175.147.73 9001 0 +s Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r torrelay01hacklabor JpCJdV4x5KVtBkwjidk7+N+WYN4 hRwDQufk4Nxl5tQu9Ha+LyjVwGM 2020-04-20 00:20:48 213.254.32.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r torzpi222 JqzToe/su2lc6N8ut2nbkkKWTGw wPPS7YtENi4qXNTZqt3zZsGbzlo 2020-04-20 03:19:54 130.204.161.3 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=800 +p accept 20-22,43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ageinghacker Jq08HBjxzSs1ejP6dlKpBtsTqMw yv+Th9Bw8nbem5NEejDQcY4RITg 2020-04-20 08:30:30 82.221.139.190 9001 0 +s Exit Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2 +p accept 1-65535 +r CastleBlack JrCaTJ9qnUgV20bro2JqDtjXHo8 BVJcB/AQgw87vzWJEc5f+3POCe8 2020-04-20 07:46:33 116.203.82.167 9001 9030 +a [2a01:4f8:c2c:25b2::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p reject 1-65535 +r philotes JrK75nFJlzqm9jH9CeKjTnMlOrQ 5VMnhYu53pakjrHgj0vrLAiLN78 2020-04-20 09:12:19 94.16.118.250 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18300 +p reject 1-65535 +r seegurke JrWaTpDvcSlKRCYQZ/JHWl3Oxto etVoMfVnwi0W+sW1kGAKmIzjpJ8 2020-04-20 01:12:41 84.139.42.34 9001 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=810 +p reject 1-65535 +r artikel5ev4 JsKPKbYR303iOs9dncHrSJXvXos dwkhXe55uhdJO5HKnnzZa2yEttE 2020-04-20 02:01:04 87.118.116.103 443 9030 +a [2001:1b60:3:221:4134:101:0:1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34600 +p accept 43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r sasoom JsQ/tErKrtt6T38fH07JMFuHhRM LewU1Wkpzv7jm1ZBNk4KBditqxo 2020-04-19 19:51:51 70.89.115.157 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r snap277 Js0wmm1RhxJN8sX74Y3+8wC4u/8 a+MQJR7uSL+Jq18hBGARwKy/hbk 2020-04-20 05:26:20 128.72.96.23 33094 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1030 +p reject 1-65535 +r ViscaCatalunya Js5HYsxpYLmnJSdW4SsqAMIoDQg UaZssZKVHxFPaSf+ZsLkZPBPuEE 2020-04-20 10:23:18 81.37.42.80 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=95 +p reject 1-65535 +r torexitteffalump Jth7ji6BbN3EEF8U9Tyw/eKTQyA 003CKAOca7O+yZdN2DOX6BzyMaE 2020-04-19 22:18:27 50.116.37.141 443 0 +s Exit Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,8332-8333,9418,11371,64738 +r ksp96 JwP9nVapuoAkoEbNtlsbgLihiA4 PMW+cLyehsexvgSj/ZVrOfgGp6E 2020-04-19 23:20:09 34.71.56.77 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r florian Jwg17kmmCQBlp1Vac0xBT45fA/4 fksmQNvEbDpH/EASl4iBAZG5HOw 2020-04-19 19:19:33 5.135.152.143 4444 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r Unnamed Jwh3+0ACFLJONX/weXXz3mtVIJM +ApcRhasfLhp1N/csO3JItbGBFI 2020-04-20 10:38:28 91.219.236.168 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2080 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r toloso Jwk0pPe2aao4fy1HX755PQNpRUc SR/gRmU6/JoJpJDhM7HpWOInZIo 2020-04-20 07:56:35 212.7.217.52 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r Unnamed Jwois3/ZS/44G5giBs/fPEwsZww 2uG9D1xH680LlN0JOW/zpwRASCY 2020-04-20 10:00:01 84.198.112.154 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=680 +p reject 1-65535 +r TheMind JyitJkKElE293f4Mbb5laoWpNgI XavMYvTiP925SViJ+tpgdIg0RAo 2020-04-20 11:14:06 138.59.18.105 88 999 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p reject 1-65535 +r bsdtorbrokencode J1GhjSlm25qVX64L19dDG54v7KQ lolBpEWb/nWmG9nJdjIE1DvN6SM 2020-04-19 23:45:37 108.197.232.51 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2950 +p reject 1-65535 +r moeph J1ffvs/3tbAmgPXOCEpE/bwIsZY 1uaoPlD/VnNTb5qlNUWW3tCOOCo 2020-04-19 23:03:01 139.162.117.43 9001 9080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=472 +p reject 1-65535 +r Unnamed J16kJWJiRxO4uJqPFVd5bF8qoks bF1cn4kxavAFhayOnhu7p61QP88 2020-04-20 04:36:29 149.56.99.85 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p reject 25 +r 4f9e6fe80a32 J2N9Uk6W4rlrkYhJWOxHd7NxvMQ jjDAFe2bXdPcb5sQf1VMlfzlWuQ 2020-04-20 08:13:21 51.81.254.22 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16200 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r async102 J2QaKxHMHdB7+tG78X0jnf4FBts NmWGfde/0lcRvxPwXQzIDzUkhNs 2020-04-20 01:16:03 68.142.39.64 443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32 +p reject 1-65535 +r wintermute J26tYRnDJ5MMC40+NwvxY++wJEs KcAG5C0pbQm8jJYOo4fBMrDi8ok 2020-04-19 19:05:41 188.166.87.136 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=800 +p reject 1-65535 +r snap277 J3QoVtqohYtyY0FvZnGtlqEndNo j8SFA7z81X5ZrR4dTg7offGZgpk 2020-04-20 12:25:54 90.43.22.207 37241 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r preecher J3nbO3oO7DLzl5Ljk8qhNIR7v2w 3soVEcu6/GG384gnJkngH8lISn0 2020-04-19 19:58:34 51.77.158.218 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21300 +p reject 1-65535 +r puma J4XEpl/prcXHXnnwsDTs3jcA+CA +MUYF0iqhdiNQbQQypfSlyQ8avc 2020-04-19 23:02:20 185.100.87.244 9000 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19400 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Yani J6Wg7nLPBQ+fCgkuKw5/+kBlN80 /jzIItXxPh/WF9kzfaattzn8QGY 2020-04-19 19:17:16 37.97.185.116 9999 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=520 +p reject 1-65535 +r tordebain J65sanN750b2ShMSbOAXZVvARxU aYvKJ2ZhwNy23IHO0jN2s1Fg5as 2020-04-19 23:35:57 95.216.212.220 443 80 +a [2a01:4f9:c010:491e::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3430 +p reject 1-65535 +r DacMonalds J8Ya4I692LJreJksdkfYkCaengM 6t+GLk17vnD4LQMZQX6ohbjsO/E 2020-04-20 10:36:54 94.63.75.74 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r Hydra3 J9Alea1fPjKJXZnDjkgtHcbLrl4 ukQLndnGxfFU3Cd+Oukdumytp30 2020-04-20 03:08:34 178.17.174.232 9001 9030 +a [2a00:1dc0:caff:111::785b]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4260 +p accept 53,80,443,1194 +r REDPILLsuppository J9CXAjnnBPQYjee/HwCNOGtZpXY kH4xQVd1wk4ZOuGg/7QhyAPLZbw 2020-04-20 11:04:09 139.59.36.149 443 80 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=45 +p reject 1-65535 +r Unnamed J9LQCQDBklJWelCnwOa3SFQFogc Ue4H1oC4muQUFkbaxWkhjUOYkTo 2020-04-20 05:06:15 167.86.93.74 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=19600 +p reject 1-65535 +r PeachEm J9Zov7ODnYxuNhk//D303W15tRM qHTHpsGbgRjF1rzmK9TsWrGcAxE 2020-04-20 05:24:23 51.161.11.228 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12900 +p reject 1-65535 +r Unnamed J+aq19rSLWQGvo1OfMuiM7KMqY4 WD9Jissalbgxm8yhXZJmrC5kuJQ 2020-04-19 20:04:10 167.114.89.201 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10400 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 J+vm0JLMr0/6ut1taUr8QeCg8fQ 5RPCFi3+GmqAS5b9OzksPeWfoB4 2020-04-20 12:30:16 87.222.93.243 37841 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r deepspace9 J+wBjIB9+k9Goh1pzUU10fMMe10 fkG6tmLO+gOUdda64am2yuDvP7c 2020-04-19 22:41:00 79.140.41.118 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=948 +p reject 1-65535 +r spe J+5IVNA/gfrqOISkQwO+AN7u5VU /TaIFnJUuqigz4Xuro6r3Kxq5uM 2020-04-20 00:48:32 80.112.144.249 9001 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5690 +p reject 1-65535 +r WhatsGoingOn J/ODNFPEAG3x4hxr9i5PzY6Z3vI /sYLE83/QsC7DVrjxjb/YKb2FsQ 2020-04-19 20:37:32 66.70.207.168 10001 10030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=420 +p reject 1-65535 +r alternativlos KAkHEKvkM6RwIfIiCLPsJFqRKQA wyerfzO+AgGGDPB6jF/cEMDBum0 2020-04-20 00:08:22 213.136.94.10 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2810 +p reject 1-65535 +r CerealKiller KA7CwRCPWPOZQsh0CwZlcC3AXkM EsjWH6hKeZlZTWjYsgynmbC/JfM 2020-04-19 23:00:05 23.129.64.208 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p accept 1-65535 +r Unnamed KBojLYy5Vdqw20lCKK9kGVsVebI 7hGWVvx3sXKDRnLr7VIMCLDZKTI 2020-04-20 10:59:44 31.18.177.147 9002 9031 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=984 +p reject 1-65535 +r niftywoodlandvole KDMSuySfy2Yzp8fh6CQUYQAOYAQ FIqXapLsRjMgZsi6+WjWZPpG1TE 2020-04-20 12:07:03 185.220.101.134 20000 20001 +a [2a0b:f4c2:1::134]:21365 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41000 +p reject 1-65535 +r Unnamed KFBWSgugCxolMiuvO3y/OzoYfpA 72+P+9H0nMdze796LsVJRl4kaw8 2020-04-20 06:30:19 185.183.107.38 65093 41001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=120 +p reject 1-65535 +r 3230613567394501 KFsxlSVt6mbH9YwFlrF9kjeIBWw 64RufzGExiD33ufGbY2IkRDXKfU 2020-04-20 10:38:38 5.2.79.179 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2670 +p accept 80,443,8080,8443 +r ratatata KG8i9dGYqyDFDGW5SgO1LK5YiUY XyBUtn9e8RNMFvAHdZIsfD+Lr+A 2020-04-19 21:59:41 217.20.130.72 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6730 +p reject 1-65535 +r Unnamed KHlGRnjU210tLkGXUbex6kXQ4FU dOYLZ5Oz/KOHV9xwoclT0S1ijj0 2020-04-19 23:09:06 99.166.172.244 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=169 +p reject 1-65535 +r Tortule KHqapFHOYxtkAxQ08aZicH9E5jo 1yCW3NQBA83tCWiWdGKBGYa5d/Q 2020-04-20 12:19:47 109.136.135.193 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6 +p reject 1-65535 +r Beet KH4QQd/DoD4WUKYa31gOoca/Nkk ug/OOcQJKqeF95QJwpvBcxNGTbw 2020-04-20 07:34:09 46.19.141.85 8100 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22500 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r investigator KIwQD/plaTjCPzIgfK8NqTLs0kc caUxoj+XglKsBTzUDIX5YSkEfag 2020-04-20 10:24:57 138.201.19.5 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110000 +p reject 1-65535 +r derdave KI16jqRxtdljW2qKwIF2TjzTl5g rRGPxKZ7zCcVBms91D2ttTExfmg 2020-04-20 02:01:01 62.210.109.48 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=575 +p reject 1-65535 +r Pleiv KI2i8n4wvHP8ioQ2dpbJ32tMG5A NUg58ea0Fx/5vM3RdgSOElyU46o 2020-04-20 04:46:25 195.154.133.124 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13800 +p reject 1-65535 +r intothetylerzone KJIHNgiYWXfe0z+YqfonqcR8i2E uecGHmaA1q01VOGpMxUFRZzs5k0 2020-04-20 02:25:32 198.58.107.53 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=600 +p accept 22,80,443,465,993-995,5222,6660-6697 +r PixelBullyRelay KJ+VX6BL0iTxje2dR2ZSlwX73Eg qKGM/EDhAOOd9ZoRur5bO3xSUQw 2020-04-19 22:49:18 82.35.159.254 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=405 +p reject 1-65535 +r niftyentry108 KKTGTDQSDgdXAbBBXXSQbsaH8h8 XXZC1aO4OOLRuUUydpqufeoXlc0 2020-04-19 20:25:55 185.220.101.108 10108 20108 +a [2a0b:f4c2::108]:10108 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p reject 1-65535 +r th00ht KLOdZ70Y0TaU3gNnnqSoZOtpd+k Fr4Aa8LEpLjA1vLuhP/49Z3M/tY 2020-04-20 02:02:07 83.97.80.89 9051 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5500 +p reject 1-65535 +r king KLyc3VLY2BeGK0k3sR+CUbiWp3E 0VO5Ibu2HjxLssYtumCcHJJ8yrM 2020-04-20 05:51:49 51.89.200.99 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ayb KMUs27eNpGEk2mLsHWeWaJ5xkhA VGtFYtKsLSPysvIwObVFpvzMGgY 2020-04-19 20:29:00 88.198.70.137 9090 9091 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=728 +p reject 1-65535 +r Unnamed KN8c5AjS4LpVYYjoHsdJnfkLWDo hDWsC05JvwmxcRHB+TEypHswYd4 2020-04-20 11:31:23 185.108.129.78 443 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5260 +p reject 1-65535 +r niftycottonmouse KPTzkvjxnj+94JYW2duBQ6Hi3dM DvUZNEMTyDmEm4gXtnPXkt46Jzw 2020-04-19 22:15:27 185.220.101.137 1137 2137 +a [2a0b:f4c2:1::137]:1137 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56900 +p reject 22,25 +r bb24d2d87e39 KPmkuAzUWh82gLu6unhXLGuXZUk CyMMv1OrRvYNanDZett0VI2VLwE 2020-04-20 07:16:19 51.81.254.27 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8130 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed KP3MI36DxO+DN2M225YNEdSfp1Y Mu3Iu7wVdCk/ojMWA0ZPaUGkp5I 2020-04-19 23:05:20 109.92.182.91 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=210 +p reject 1-65535 +r MediumSlesmn KTXg8DtxvkT28mX++XboELqtb04 74Q+o35pLLqYC5OQrzHkiDcdxyo 2020-04-19 18:59:11 144.202.63.243 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15700 +p reject 1-65535 +r glittershy KTalOU0toUv0c1Ra7HZ1wMh7hZ4 +H1nGLnJZHqqu8xTVSwW1P0Ae6M 2020-04-19 19:22:41 74.96.242.116 9001 9030 +a [2001:470:8:79b:1::beef]:9001 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7310 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r treebark KUgRowVTDdgGMcKuD0h1OoNmmKA Rhzw351a1jjR5R7qgHmwzSY2nYU 2020-04-19 19:17:53 208.113.134.18 9001 0 +a [2607:f298:5:101d:f816:3eff:fe4d:3e77]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11 +p reject 1-65535 +r karbtor KUibPNaf5qmpzt3312WAebsXoLM +mc4zQr+VIBDwztnvObOneOlpdE 2020-04-20 04:21:04 185.47.222.34 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=121 +p reject 1-65535 +r Eliise03 KUtM3qh4uo/i5wiuevZD+t0RDw4 AhLuxP/JWV2PhS6reN7QIkQkKXc 2020-04-20 12:04:15 185.195.237.25 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r 84197ae125b4 KV18jLcnL6k124pp3AqQP3EpGbk f4KAiJG/pyP3ShF78VHexj+R1W8 2020-04-20 08:14:05 51.81.253.214 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7960 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r iiyatsu KV8Fq1HLftR6xtbmaQuBiDrR9+o 4FCoXeOonX6slJ1XvbksPm2Dkmo 2020-04-20 05:55:41 159.65.16.134 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=550 +p reject 1-65535 +r angeltest6 KV8b2JlaEuzHfgUMz27GQVcnOek gTj4uE8BL2cIDWZbjJ7loHq1qxk 2020-04-20 04:33:39 185.61.149.67 443 9030 +a [2a02:7aa0:43::827a:763d]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31000 +p reject 1-65535 +r nodvrelay16 KWgPLJtiyZdxh1vnrxYel/6eKco DdukE6xO7/PGbnTh50SwRqVnDxs 2020-04-19 19:16:34 45.62.212.103 9001 9000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3410 +p reject 1-65535 +r hlin KWqaLJYkm8XYyozxlu9eP8yASI4 E4iq9ewuI2Td1ISIDI4UPOBMzcc 2020-04-20 09:33:06 88.198.36.122 465 993 +a [2a01:4f8:a0:23a1::122]:465 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5300 +p reject 1-65535 +r soltor0 KWsheP10KrNasgya3wTV39PUB+s sOVzXTg9OhmVDipVUk+ygiqhcxA 2020-04-19 21:35:10 206.55.74.0 443 80 +s BadExit Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=520 +p reject 1-65535 +r snap277 KXnIwRg2cc+2N2AO6hG2+lmeBLo BTWHJ/CTl12f9JUqalQYn1F+0hU 2020-04-20 09:17:03 109.129.169.1 36621 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=855 +p reject 1-65535 +r mirrorfdroidorg KZTNRBezu2m8HrK7mSavKt2lLsY RWJzT8N0zKVLJoz8yTkX+8sqsmU 2020-04-20 01:37:21 37.218.242.145 8443 0 +a [2a00:c6c0:0:151:3::145]:8443 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=230 +p reject 1-65535 +r Unnamed KZiVXIClxVdalgICr84NffYz9u8 QKNJKCHmEjWkNp8EWGaNlZ4WvKc 2020-04-20 09:01:51 188.195.3.98 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=858 +p reject 1-65535 +r BorrisvCorbyn KaORRK0UEkJDbQeQH3qLkfdRamY HaEktkuBzqBmYswakITdK1dJxik 2020-04-19 20:59:56 176.31.116.155 8443 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42000 +p reject 1-65535 +r bassblitzed KaccgkdnCJNnMq/KvijIlcE/3HY Y8aYra5fScGoXxfDVsrxO/9ii24 2020-04-20 11:02:40 75.3.204.124 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p reject 1-65535 +r jenniJosh KaqqY85F7pT3jwaH5YsawzS2Erk 9V+6c+oeCRAFaYkArfpGIi1f6vY 2020-04-20 12:11:23 196.12.37.70 9002 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8 +p reject 1-65535 +r mrTrololol KbHBZgZ60zkimJSS9zvNPm4GZ8o VWZCFZUI8OjsguDdcXh2sQWKqVw 2020-04-19 21:00:00 94.177.171.20 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5440 +p reject 1-65535 +r Leon KbH5U2WoxFI9CqnILVBQiEKLpQ8 9wUh0bZkSRyKm8AbwUp3XdRM6hs 2020-04-20 02:17:30 74.208.88.58 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6130 +p reject 1-65535 +r neximon KbH/RgKeIdYMnFROIuhFPMRh730 UHm40hQNjMPnEeAjTwaZJAAAHSQ 2020-04-20 04:12:39 103.253.41.111 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r corona Kd3SXIOD/aVZ1ODoj4IKuIwmISo jv7pz8u9uSlvJJj/WSgzM1cxU4k 2020-04-20 00:45:17 116.203.234.246 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13900 +p reject 1-65535 +r DKRelay Kd5+4IZtT0NArgz9cq3DUZ9lRho Y/xQkzw2/Y0LnI0jyI5uVIAcmTo 2020-04-20 01:53:34 116.48.109.89 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=590 +p reject 1-65535 +r darmon KfpRHmejGhqHSqv7K2JK0SKuTtQ 3/uJgmeH8OSXOyGIZkdopOY4fvU 2020-04-19 23:07:00 138.201.143.186 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22000 +p reject 1-65535 +r Unnamed KfuOBYparzIl0IjqEFnSMoAYQeQ 1sqXl7ZBwa2JbcfiW8U/MEP48Sc 2020-04-20 06:29:52 134.249.119.130 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1310 +p reject 1-65535 +r snap277 KggKdJI845+SxcMUf5N8+No6o44 feMLGYs4Gjndj4/lO4JAws6nnk4 2020-04-19 22:27:00 79.92.138.106 42191 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8 +p reject 1-65535 +r king Kg1WHcN6VWQCetLew0AeowDjytQ NMORQy6d+cw21PsmxLpaR2NdaTQ 2020-04-20 04:19:14 51.89.147.65 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r HassoBarks Kg+tPKehkMQ9jteJZye9Qm6MLvo jvCaUO6Po2vsNKTCZijDx192Q9Y 2020-04-20 09:43:38 217.160.13.173 6574 6547 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2990 +p reject 1-65535 +r hellokitty KiAi04aJTTyzQ4dSl3wnp69Quvo j1rRRhC55UpjHdCwzls+Cy3OK48 2020-04-20 10:52:35 203.186.69.98 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=810 +p reject 1-65535 +r niftyneochoerus KiMaXKevkQKbdHVRHX0W34XskiE D6HpvS6GRknFSHX0VkMyya5GfKQ 2020-04-19 20:26:39 185.220.101.12 10012 20012 +a [2a0b:f4c2::12]:10012 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42300 +p reject 22,25 +r askatasuna64 KiTgt/fWS4CNcPvpLmQcnW/Zmz0 ILf+THUQQa64MUZs1467NKxZcw0 2020-04-19 23:56:24 163.172.41.228 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6900 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r BreakingB4d Kik+TDXOv9GhUUddFQ90LoUgntQ qJOn8nn1pDOS8kpiJRsz0qYdzZc 2020-04-20 04:21:06 185.229.109.155 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1790 +p reject 1-65535 +r stewwerter007 Kimc9HPd1GjRkBkXEiSwUDPCFX8 FrX1VTm0C6Uw91Ahi7agFi7M9NQ 2020-04-20 09:31:17 188.136.78.234 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=88 +p reject 1-65535 +r Angband KjYAWoEci0IPOA1nxKnWMGVfCQA 126Ony11JV14ZT/k9ZzudXzGY4U 2020-04-20 02:34:34 178.17.171.102 9001 9030 +a [2a00:1dc0:caff:138::94d2]:9001 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4430 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Unnamed Kk7MOXB9oErsLbK98nchdgdtv/0 Uj/luD1UJr+m1EXN5i/WKndDyMg 2020-04-20 05:31:49 95.213.150.194 30069 14945 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=822 +p reject 1-65535 +r Challenger KldGv/MqNjzTqtBRlsDxDnFDu7Y aingZCUJwI//KRtI2S9DnIQZtu0 2020-04-20 07:46:08 54.38.36.44 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p reject 1-65535 +r neurostar KmIaQP8wgfYSlG/fuNx4G86FmgU FzjHghyyhZd3TqMhcKeF5YPTnkM 2020-04-20 02:17:56 116.203.88.24 9001 9030 +a [2a01:4f8:c2c:7a40::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=17400 +p reject 1-65535 +r BLEPTOR2 Kmb29lDIt1cZ8xnjjwfgpSJ3zTY /vA1XOg1B2HgGpRaTwLCgVytO9k 2020-04-20 06:13:13 5.135.232.46 9001 9030 +a [2001:41d0:2:8042:0:6:1:0]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9980 +p reject 1-65535 +r ZankleRotaryEngine Km56v0P5eWrUoT3ysgR/kOcpGl8 wTUcmtWxnGCzkGvd9nYEv4AfSH0 2020-04-20 09:53:17 24.52.242.153 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=450 +p reject 1-65535 +r edsnow1 KpvAzV2jt/mFSgka824qcFK0FNs qRiTbYOLdaJtwGqSd7C51FV7AuM 2020-04-19 21:59:27 91.168.166.18 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13100 +p reject 1-65535 +r setsun KqX1mPmhgS8BzZnjtZu4c2LtdDg hGHmEF6sWay7bactKd0lxQhQipQ 2020-04-19 21:33:58 144.76.200.80 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=92000 +p reject 1-65535 +r snap277 KqaPrRcE2E4u9k4qaORPoXyyPsk kwjnCAL51TLI+KUAJpBNDt+8R9s 2020-04-20 06:27:55 109.87.55.221 37707 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=914 +p reject 1-65535 +r SleepJeep2 KrcIu8LVLHg/n8gh98qOUaLPupg 2a5fxeYRRdJ268vXfbmZbSKUa98 2020-04-20 05:48:04 31.220.2.134 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54700 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r kellogs Krn/zGYY+7yXPEV/xr5ehiCmD9w /4ie5kKp2u0+49FzXpuKHD0mSHU 2020-04-20 06:47:13 51.75.65.10 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7160 +p reject 1-65535 +r zshjumper KroTRfyZdRUjcvQtBqGn3MhwwvU 1GuNQr+WqEZwPv/yKYK+cfHfRBY 2020-04-19 23:03:09 188.143.77.14 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r foreach KrqRhi/QImNy8GPJS4w3UT7Iprc GGa0a8mv4LdKiTtWrANUXmtS1zQ 2020-04-20 07:45:21 104.207.149.101 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=77 +p reject 1-65535 +r vienttorrelay KrqSiUX37B6d0QWmKNXAVgnbW20 t6K66qxON5lbJDYFxcjIFfary+w 2020-04-20 12:35:55 51.15.91.217 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r KienjochRO Ks7A60+ScpuMoiyGhUWGa5UpQxw MJTMDcXP2Vf5oNzb4A6iKgvGrk8 2020-04-20 00:20:26 89.34.27.24 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4100 +p reject 1-65535 +r Unnamed KtIt3jR5C74Z+00R3cu/3EXvFqY anNy05mwESF9L5DtYoaH7WKtiow 2020-04-19 21:02:18 185.65.205.98 9090 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r Unnamed KtgvOWTTJbP+L/dOmA+wBjdO8ZA BBJVKTdN1nhSMe1G9/vUf0zL3yM 2020-04-19 22:44:25 91.134.147.134 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21000 +p reject 1-65535 +r Tuca Kuwb1jS806QlHcAEVYs+nF0cBaI aq3r0zAXRW0fy6l+9H9vr6049sU 2020-04-20 08:39:44 193.148.69.128 3030 4921 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3430 +p reject 1-65535 +r nodvrelay32 KvlDUpuqfOyTknHySpMYkqrXCcM lrRtAo021UlP0ioH9cTa4BH0Imw 2020-04-20 12:32:25 45.62.235.25 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=730 +p reject 1-65535 +r calu Kv/7RNk7LwZqaFP6GZ+3vq88U9M BrP4OFlIysyu0WLs116lBMLkrqU 2020-04-20 00:29:23 92.243.6.46 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=521 +p reject 1-65535 +r Idatha Kxuyp5bHDX3llv+foMukjxKZTEw uOIYNMMhSryMZra4Sbp5lqmqVKQ 2020-04-20 07:05:42 91.228.52.186 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=191 +p reject 1-65535 +r snap277 Kx1K4TGS6F3+Tikx1NqwlOA1018 nJS9EEz9o/4y6VXJSRRNvHo7rRQ 2020-04-19 21:32:44 24.20.165.214 46159 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=289 +p reject 1-65535 +r FOO Ky1hS4IqadeRn3/4B5u/wg9Mtrc M6cKiDDRa4Ra/z7kLZwPtFKYRJc 2020-04-20 05:17:29 178.175.148.42 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=10400 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MrTerence KzH7gn1M6nNLn3jBYTfP1viuu3s 9nXfN1ID/5cY/yG7nC1beS90gBI 2020-04-20 00:33:38 185.165.168.229 8443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p accept 22,80,389,443,2222,3389,5000,5222,8080 +r RunningOnFumes4 KzQJntK8WYxHRclshz/XOkRWRr0 zOGgBfvSumhgsdXQHGfCCocH6K8 2020-04-20 11:01:28 185.82.219.109 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=752 +p accept 53,80,443 +r xmppse K0wMGJBv7jepNoFb67X46xhs5FU ad7H3vzub7CaVNJyVzahzwXs3BU 2020-04-20 02:21:25 94.254.86.22 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=564 +p reject 1-65535 +r snap277 K0yNwPSgeQq3LSajGblNMofqRM0 Sh7NE+dLTeHp5ahd15h+syt8zfM 2020-04-20 01:25:26 74.210.249.117 37945 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=740 +p reject 1-65535 +r thealgorithm K1EZMgXQkcyAuQTWVyH/jcvlHJY +bPuZ9lKKP1vFHPYYZC7Mkkl84U 2020-04-20 03:47:02 77.109.191.140 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13300 +p reject 25,119,135-139,445,1214,4661-4666,6346-6429,6699,6881-6999 +r Konditional K15QJTakNv422ixodfTHfzWTs38 V/oOzs7R9ooPZ8+9Saoq2jvU6to 2020-04-20 05:17:21 50.7.116.58 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4300 +p reject 1-65535 +r nitrohorse K17SgaOZ4fwcfAlk80mxKhdd3gc ozdUYQ9DgKZ7tN3GmB/xjq4jVWU 2020-04-19 22:58:09 23.129.64.212 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7030 +p accept 1-65535 +r ididedittheconfig K2Ll72pbcyRD1prI6JNpnZww4B4 s/FB2usKHMK0zc4l+o0J+G1hems 2020-04-20 03:57:47 3.92.225.220 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.3.1-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r SNAFU K2kZsCs36l6lZ2BnCdJ7UhLyTQk b7qn301V4HNHK/YF7U75DC75U4w 2020-04-20 03:40:38 87.98.185.5 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r crivit1955 K29vBBQEZOUxgLlA7uxXu3JWsQ0 KMYoyUFhZXYq1OqavDBJyBvJMQs 2020-04-20 05:42:36 81.100.16.81 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=407 +p reject 1-65535 +r lobRelay K3B2BlyBd/Lal8vIQwfOuyE0Bv0 UxauokYU/qKFP2Sv5QtKP131sqM 2020-04-20 05:39:37 213.209.221.53 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4620 +p reject 1-65535 +r nortor3 K3apFMrzsSHRTviigyfK7hJ5lKQ pQgPHuVCw1PcgMaAGxs8qwV5yx4 2020-04-19 19:48:06 217.170.206.138 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tauro K4iq0uYB5W5eroK+w4qrDKbvIoM lDNUvdPkoY2Kx7G+AUMzWfuh4ZI 2020-04-19 22:26:55 189.84.21.44 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=200 +p accept 20-23,43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r torbogenpi K45kKBH/b2EGAPJwOrWeQvuaAMs L4w/vCoSNCS3404T9z7mxIxr2T0 2020-04-20 03:13:11 37.138.225.163 9002 9031 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=279 +p reject 1-65535 +r LaserSystem K5T++WjJlJ/S8Q6xVJOElLL1BSc Ypm7fyojLzGxhpM2k9R1fEwXAME 2020-04-20 05:17:23 134.249.231.207 8080 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4820 +p reject 1-65535 +r fuckthefuckingfuck K5k8EXeCGzQN6QMnF4NM8q2EKRY mmx6/xj5Bg1NCNphTxTu+LUvsaw 2020-04-20 02:13:47 91.5.200.76 9001 0 +s Fast Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=338 +p reject 1-65535 +r storm K6LI6WslkOEHKuzivbXEiSG/hRA we13QlB+VlM+0gWeB92hv/9isxQ 2020-04-20 08:43:29 138.201.250.33 9011 9012 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37300 +p reject 1-65535 +r parittya K6ZlV+heu+N7+3YN0pRDRothjiY vmoiDo0PS8UPVPWTkATK0ard8T4 2020-04-20 06:03:11 80.98.57.24 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2180 +p reject 1-65535 +r Unnamed K6jvjndm9Hr/eDXk09IzNTtnUyY 6sSPS+gyH/KzuDmduvCoj7tNEMs 2020-04-20 05:32:13 91.219.237.154 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=246 +p reject 1-65535 +r finTor K68JLoZnwAyj2WhsdtjsPMa8fFs 8R5Mg/Oe91XDe2Mzv5Y1QPDgFoM 2020-04-20 04:08:25 95.217.15.125 443 0 +a [2a01:4f9:c010:607c::1]:443 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r snap277 K7KTIhLoswxike9OfHWlpMlBoos 5t489oAoEKCJfgFyYAJInl4oupc 2020-04-20 12:11:09 92.52.130.147 43296 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r AlanTuring K7hdxb08bw2BpPK1iCF2xr9+z1o 36X+5I//QWSPyExSE9cYzdg/AFU 2020-04-20 04:57:53 5.181.50.99 443 80 +a [2a03:4000:3f:16c:3851:6bff:fe07:bd2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 1-65535 +r carpetor2 K7m+J7BhUvXnV1u54wUKM9iaC2c VRroQKQCgOOeCJuC8vPkUg0rqMo 2020-04-20 11:18:05 79.199.149.96 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25 +p reject 1-65535 +r MoisTorRelayNr2 K8yJMxOiEOILCSvKo/xVxaOJkk8 CMt4ilS/dH6v7wsk6ycKJDnEnP8 2020-04-19 22:36:17 80.127.103.214 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1500 +p reject 1-65535 +r atomator K83dIAamAAuNX21jx9bSAOQ/ixs C9KnQ9WkN94P4OYzOvN+weoKOm8 2020-04-20 04:11:57 51.15.187.209 443 80 +a [2001:bc8:272a::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13200 +p reject 1-65535 +r fiedlerRelay01 K88b/LcUc7eNRLzRjIU49AbeMM0 RBWqyGrIZdrUVEvw4xHiHmgwlt0 2020-04-20 04:08:01 37.120.173.173 9001 0 +a [2a03:4000:6:757e::2]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r medidntdoit K9DfzTRijNGG1Dz4B0QFrr7nqLc NF7dPYxxq7p7YXuA8+ZimBnA6K0 2020-04-20 12:02:15 87.123.237.61 42901 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=60 +p reject 1-65535 +r 0001 K9GTbgtNW7YVz5mwz/dOrxlCaIg HNsSLiUIAn0CxouUDeOvUaO50I4 2020-04-20 11:03:31 91.92.109.43 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r anonymous K9QNYbMo8/yunY03AyziaV0FK8c e8/4tBHvfElxCPfHdH/lhZW4/2A 2020-04-19 18:51:53 123.194.142.123 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=326 +p accept 853,993,995,5222-5223,5228,11371,19294 +r UnivUtah0 K+WX0KIlWk6PRMv7Emt6ehKpc3s 6bCq9w13LB5bXXgO/T46FnOiZ4s 2020-04-20 02:30:32 155.98.5.5 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6470 +p reject 1-65535 +r stellarator K/Bd1hC5pAPAfY0XSKhXNuJJ5B4 8sR/87Z/pm2zj21LdzhSwB4vwbY 2020-04-20 04:08:12 93.205.163.143 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=404 +p reject 1-65535 +r RavenSecurityIO K/77SDn295armgKH/f1R9ygO6i0 GdJix/qvkdJD0gh80XQtYgmM81c 2020-04-19 21:03:18 80.210.72.231 25 110 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2760 +p reject 1-65535 +r Nana LAZHYKpmV+LFdd2JfCWIsXCj/xI nbBcVtEFMHHvqbVCcs5DHK09yNA 2020-04-20 00:43:11 167.114.103.19 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=785 +p reject 1-65535 +r HiBuTorNoEx LEdwvulDu2HedIoAcPMcH1V7CJ4 WHQRvpH2XkLzorOI4Aap0QhvfVk 2020-04-20 04:12:46 93.244.144.114 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=853 +p reject 1-65535 +r Unzane LE4VzUDuPS1vBi8Erf6bhcjDxSs 4qMKVK+d+og84+iVizSYIeU3erc 2020-04-20 12:21:36 184.105.220.24 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=531 +p reject 25,80,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Lexa LGyXDgJ6me/z5pd80bzdlYbgv7M 2cTjFO5zOH9r7Gpno1yHmHvF8Eg 2020-04-19 21:10:41 89.107.57.79 80 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1160 +p reject 1-65535 +r dani LG4lhyh0N/oQv7FFzSaR/WBchwk p1lNOaHc9N6pS73EEUYSYKk4uUs 2020-04-20 05:22:01 160.119.249.240 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=329 +p accept 20-21,43,53,389,554,873,902-904,989-992,1194,1293,3690,4321,5190,5222-5223,5228,8008,8232-8233,8332-8333,8888,9418,11371,19294,64738 +r rittervgexit LHUsGACJ3cibw//MsX+s/ur9eao hfoUki5laG4nlQv91AGUthVqUxw 2020-04-19 20:43:45 185.165.168.77 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=859 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r livefreeordie LHwfAPNMIF6v7Rqm66nv0mtz0Hs /+HLQOURF8GALpEmEPc1iFTlOP4 2020-04-20 11:52:37 68.199.157.183 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=611 +p reject 1-65535 +r ckti LKcSAwwrt+D5g8pKSzgmfQ1HRfY CkWtP5/lqrC2iOwQZDKKj8UHH68 2020-04-20 11:56:58 80.194.62.219 80 443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98 +p reject 1-65535 +r Unnamed LK3yVEEdoX+FVFSSX2jj4TTSPu8 uT9PPp4jBXBtqJJz1x8gnXCzD8E 2020-04-20 10:17:06 54.38.214.30 9001 9030 +a [2001:41d0:801:2000::877]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5590 +p reject 1-65535 +r geri LK7FWnhU/jyze+gDKAhv34nggsQ NXJLgs5rjV2g72wnlPy8D50/8qI 2020-04-20 11:26:00 185.100.87.206 9001 443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74000 +p reject 25,465,587,4899 +r Assange016it LNMXxiSAO3fq0yyWOCiEsMrU2z8 mFfoF+cpWNlvaulIQQ/005wkOic 2020-04-20 08:54:04 91.201.65.29 9001 9011 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3610 +p reject 1-65535 +r Unnamed LNQZ2hBkBllVVXB6KqX8/Z8Wlqo JEpHD28daxLhff+qqJQFMPv4vuY 2020-04-20 07:06:24 138.91.18.238 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=459 +p reject 1-65535 +r onYourOwn LNVHTjPRJikVa5L71h+qsi0HsPc VYlvhi3ONobCaz4S+ELRrxFmOAA 2020-04-19 21:07:30 85.241.106.203 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9500 +p reject 1-65535 +r snap280 LNkF7XjlI9k8bJDJ2b368Nf+2Vk fBk7t4N9VDdJxms32KjUAect+Mg 2020-04-20 02:17:19 24.127.121.202 38223 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=700 +p reject 1-65535 +r hothand LNw/G6ixzGmCZv9cQCT55Rm7LAg cdy5lSsRHUTGxqeu00KAdAo6x44 2020-04-19 23:11:42 88.115.22.244 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r bed03eafeacd LN4j8/L9WLQ/8EeRe5ZKue3SbBI Pam8YZZLsA8coO7Ij+PDkm2GzjU 2020-04-20 08:13:02 51.81.254.21 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9240 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r dairy LOLe6DC5VO2jprtX6nQg4PXuPBM 3dky6RTpS33WPMLQ6qRe6D4AzuA 2020-04-20 06:10:00 207.180.230.109 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12200 +p reject 1-65535 +r sinsg LObF3bUWOitkAPuWvRDGBQ+0Ovc qCN06p3jFXep38t5/LMYLpVZLIQ 2020-04-19 20:16:47 195.123.237.251 9001 9030 +s Exit Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=41 +p accept 43,53,79-81,443,531,873,981,8008,8080-8082,8888 +r Doedel24 LOlqih2gMmZMkPV0r/vs4Ypujfw BLAqAqLGNzQPwiu6hi4oPgTn5us 2020-04-20 05:04:57 81.7.19.110 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r ridin LOm+H8iLnQ+gPzh8nk8AC11LKuk T1uozE/tqX53CmzcprP7qUjIef8 2020-04-20 02:53:29 51.75.129.204 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=72900 +p reject 1-65535 +r zeta LPTLNZtXY/1g6RZR2CnZzb5+I28 +ykQk6I7PcpE4PKta3OSmkfgFTg 2020-04-20 03:16:18 163.172.7.233 143 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36 +p reject 1-65535 +r HyperLoop LPZhzwWpB96lK4Uq9oGN2njBoPk fPoBsIiSake55BemGUUNLPL1t8E 2020-04-20 11:54:15 51.154.53.96 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7280 +p reject 1-65535 +r ThePromisedLAN LPbWY8wKOP8dYpJxYhsEEdtOQM4 pn61nuKb7XGIwc3jOlh9Daos0eE 2020-04-20 09:32:19 69.125.70.73 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r ThePlague LP27eFRK8QYsH3DHbWqQDw+Cw/g iDnlfqtxSs6cu73esHNH/3wuxok 2020-04-19 22:58:16 23.129.64.209 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p accept 1-65535 +r InglebardRelay LQYdZVO7CmIAQsUF/1dyWF2ovtw 5aR9ERQxBelsy1aHgk6/OGCZu0s 2020-04-19 23:44:29 5.135.176.38 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r snap277 LQq3sbn8y+dD2/PJI+Do2dCnyro t8lFFBPahP9AwzgccmSfKo0SsYk 2020-04-20 08:18:31 93.30.153.129 38357 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=300 +p reject 1-65535 +r ICSIL1xDEDISx1 LR+dWful7Na+WgsAGX3CgfwsQMQ AqwR9udrlrfF8flJRbQ9o2VwL5E 2020-04-19 22:12:20 192.33.193.24 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=42 +p reject 1-65535 +r Unnamed LS7iZU+2dZaW4AMHpU9QQC8J2TI GGpd/B9KTvzHBvRzg0YLdQvmCQQ 2020-04-19 22:14:05 51.83.41.148 9998 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r reporterx LTF3iO6OvRG+aY7Firhx3G4Pwpc CXEC45OKD53Hnh/c2booRpDDmhE 2020-04-20 08:23:54 95.94.83.36 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54 +p reject 1-65535 +r MYLEX LUFpcBbABwF0vwebracgdgQIahU JZ3WFsWfFvQWezNBkYGwgVrltzQ 2020-04-20 00:10:33 77.123.42.148 444 800 +a [2001:470:1f15:325:52e5:49ff:fe66:911d]:444 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3280 +p reject 1-65535 +r cloud13beam LUWyk1mbLahbG3UXcZxgFEU8trM R03MPPir62qUoBqnWw6p74FIhmo 2020-04-20 12:00:59 18.221.85.232 9001 0 +s Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=42 +p reject 1-65535 +r aanetuk LUfwOfBO7APqvkhMwBd5agq0gkA fBWuxxFLSmz1fohbglviQ6OVTtk 2020-04-19 20:57:56 90.155.5.6 443 0 +a [2001:8b0:1628:a008::aa]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p reject 1-65535 +r texthtml LVMcF4J+AFTfYS8m7qrlEiDP55k srm4HsAuMkNs5jqf1GSiWmZziaM 2020-04-20 06:19:41 62.210.148.97 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=77000 +p reject 1-65535 +r tor4ever13 LV02kes+Kpk4n4xqBuQqvb6xNW4 nlu8hZVdemNsvGzB1v/6O4Ktzto 2020-04-20 06:33:10 45.62.228.39 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=960 +p reject 1-65535 +r TM LWPsJMt8p6z7wUOXUqVKkWGVBn0 NNeJ+uvaJgTdbWFW1eWlzJD7DZo 2020-04-20 01:44:26 115.70.167.41 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=202 +p reject 1-65535 +r hiboo LWyTojNjaNmld4QW/U3d2X/zfUA diorLwpMo6y2SqwtmBCkcBvNzxw 2020-04-19 21:22:28 91.121.83.108 44931 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r tor01as208196 LXBYOv3pDHw9nP+fDAdvDAIswpw fQy6GXwh5Am4rTvnFOkmgLFlbFc 2020-04-20 03:07:20 45.154.168.135 443 0 +a [2a0f:bf00:2:0:f823:96ff:fef5:b2ca]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r ExportShuttle LXjRy8z4IZgiEZv6A0b/IzFvGRM ZzNcTOicWMHhL4KJDl5za2FV7HI 2020-04-20 01:39:07 8.209.94.85 9001 8081 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3420 +p reject 1-65535 +r rogemedic LYLvd+sHrys7G8FAqrUnjjlj1k4 +/8Coeg3wo0Vaks/+37NYGuBXgo 2020-04-19 19:42:41 208.38.243.113 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r sauronkingofmortor LYr6kS4rhiO7LNrNGTMiCdUk0aM D7fhSpRxqYbkYuFMlI4BqiPOUn0 2020-04-20 11:21:11 137.74.116.214 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17100 +p reject 1-65535 +r godzilla LZHMYMu517n3TMwkfxZdWeAM5Vw f7PHlNG6vtnVLdDGlP/QKw9ROTs 2020-04-19 20:04:56 23.237.80.90 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4600 +p reject 1-65535 +r Yuishy La6ptzaBKyaRQe0YImlTSZoW2ic 6jjsulPH9fBfy7u9mv/tWEMS8F0 2020-04-20 00:47:54 178.79.160.57 9001 9030 +a [2a01:7e00::f03c:91ff:fe93:e774]:9002 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=230 +p reject 1-65535 +r rwxrwxrwx La/mepvhEZJq97c9fao/f65lptk VwIxIZtMBkyN5EI0oLo+5OsbFzE 2020-04-20 08:53:20 78.46.120.54 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=71 +p reject 1-65535 +r mongoboy LbyLmVQnX0Lm2p2wY/xQV+6fDEg U9NeZKoMDieol3rRB0tl+PODRxU 2020-04-20 09:02:34 80.60.245.234 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r maximator LcfDp34u8KFdFuvKAFC3PckefCc I7eGlGj5n0S+q8hAzHk/ijfsD5g 2020-04-19 19:28:48 212.47.233.14 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42 +p reject 1-65535 +r eclipse12 Lc6n6DC7d8mzMu63wVAaXuK6AAE 59RSQ+l9gMDh1KFP9LiOV8uhN9I 2020-04-19 22:10:09 88.117.48.161 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80 +p reject 1-65535 +r undso Lef2KUM2xHwL348QhW9Ug0iy+2M 1dVlQ7xfnjXxIyqh4C8rOfzJRdM 2020-04-20 11:42:21 79.143.183.44 9001 0 +a [2a02:c205:3001:5506::1]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r ParadiseTorRelay3 LepmRVE3b7gDILDKeyNDtax51hA K4EJQNLzb9JgRNzT3+it/1d6Aqg 2020-04-20 01:37:16 193.182.111.132 80 110 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=9650 +p reject 1-65535 +r inculpe Le8cX0UpZluwilk8Zbr2kX6dIIE 4fuQA/067Wip1kwQPc0ntGMLAlQ 2020-04-20 08:08:34 172.105.59.110 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1030 +p reject 1-65535 +r erbridge2 LfWGlMGFJaSJL1FNAQObz0SgVDM tysljRILJWjBnQR0BOhy33UozI0 2020-04-20 08:01:20 176.31.211.86 9001 9030 +a [2001:41d0:a:3616::74:6f72]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30300 +p reject 1-65535 +r smell LffRsUcyly31G/7dZgYcx1cebfo yXXGrMl8NTF2pwjSDHD4ABIvViI 2020-04-20 01:09:57 205.185.117.253 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3060 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r AccessNow003 Lf3qXdQVuVWUv7EtWf6EEWf5S18 q/mKgnlQQUCs4/i50IVFflADAGA 2020-04-20 10:32:13 176.10.99.203 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30500 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Torsten Lgg2zmH8+Yw0AQA0vTZE/jlH4Z0 U8purHBX7uKJ42Fc93ORc0aAn6A 2020-04-20 10:01:41 159.69.250.201 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43000 +p reject 1-65535 +r WalkWithMeInHell LhgU/Epy6mOVoVfen1cd5gcYnKg 3mZc6kwtfcVO2gm3Rg9eYDn1DH4 2020-04-20 01:43:08 85.212.120.215 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=224 +p reject 1-65535 +r Unnamed Lh1D0AmtqeMvh31zF8UAIx9UXrs YZd1XeQpuFfYu9aaT/Pdbgf+XlE 2020-04-20 04:13:54 95.141.37.112 18616 10098 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1230 +p reject 1-65535 +r TVISION04 LiVOJUofxm1q2WjlZ7IvN4wGMCY 737/HObpMX2iA9/YyeQ8KeFmiU4 2020-04-20 04:50:37 87.253.152.203 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r InTheWeeds Li9CTNnA+2uw8WOQv8tGhTrjfME ZtWjcfrHVXCELUXh5NgdOPJZ0cA 2020-04-19 18:59:23 71.19.154.6 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r tidal LkFM0ogjta61H9Fyqg7j6eubypA VfyY0TU3ovC2vhVbcwgLo8zDL0s 2020-04-20 10:08:31 70.63.106.230 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1260 +p reject 1-65535 +r niftyexit8 LkTo64x3EcEVe9gCXwcWXP+PorY TU/58ebtJBYYV3mvksdWokUgHeI 2020-04-19 20:27:35 185.220.101.39 10039 20039 +a [2a0b:f4c2::39]:10039 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24200 +p accept 80,443 +r Unnamed LltTl83X8CeY+XE7LD2Fw/77r74 g/z75t+FicR2t4tnWkWr9ygMV/I 2020-04-20 06:22:11 138.197.171.88 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=620 +p reject 1-65535 +r snap277 LmbSDMQOMDX5Kfeo6LazMDpIwI0 jmtrRvXfpzCIMZ5DJU6Hcf9yM0s 2020-04-20 03:13:44 86.234.166.67 38697 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r mashedPotato Lm7g1j7qqf8ESqkvlR5XZxBv9zg XAc9nmVaraBCG8YXLrJLtisznS4 2020-04-20 01:29:06 91.250.242.12 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p accept 22-23,80-81,88,194,443,706,749,853,873,902-904,981,989-992,1194,1293,1500,1723,1755,1863,2082-2083,2086-2087,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8080,8082,8087-8088,8443,8888,9999-10000,11371,19638 +r torpinkbyte LnLNr6Eq4VR3lfm6/0AvwWtlPOA qprZU2QhDQhbQ8dcFH6++mDDurA 2020-04-20 03:01:34 91.220.220.5 9030 9001 +a [2001:678:220::5]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4290 +p reject 1-65535 +r znxpar01 LnLuq+TuGRg776oQ2Is8FoKcn5k rpoR3SHw+2EBI/Q0092KwgUzbHc 2020-04-20 07:40:44 163.172.142.92 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21600 +p reject 1-65535 +r SolarPower LnT0pute08AYKlSQDjpnHFyNstg TwGQ1Zl4XLDwVPb+Gl/u/FzTs6k 2020-04-20 00:01:26 134.3.166.154 993 8080 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r Unnamed LnsD1lF0+T8xJd4QYsWoSE3mWMQ gFWELtYa8Q1nMiUOCMiT2zmnRek 2020-04-19 19:51:22 167.114.89.207 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9930 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nonanet05 Ln12u70iuBP548jaFxXDuRnYzvI CP9aYDEn98y9vh4QARESQV3epXo 2020-04-19 23:08:09 198.251.89.176 443 80 +a [2605:6400:30:f718::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8510 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r 46df0a18bd19 LolQIyb1VxqcVxObzjtVK3thu8I Qytsva73Tw9f/lRSsFCt5YoDiR8 2020-04-20 07:32:38 51.81.253.203 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r wltfseE37Cgd Lo5yYuOe8WYcwRc6oPRzHJIZdaE ZWlLRdOwUJwMepN1iE6Pjlz1n4k 2020-04-19 22:07:01 149.210.150.150 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8350 +p reject 1-65535 +r Unnamed LrMScYNBR7sLt2YHwJdJQxvEgBU mW/Go1tKmH9q4X3OFqwG7n7jzmk 2020-04-20 12:06:24 198.98.58.23 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Alastor LrPCMBgGlKHoSAAeIPNvdqIocDk T+JiWPoP1e01IFy/HZ2wu/LkxPQ 2020-04-19 21:21:00 62.210.123.24 443 80 +a [2001:bc8:30c6:100::dead]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48700 +p reject 1-65535 +r ToBeAnnounced LsBC9CdMyKVDgceOjRvzIvomoJU gOEHsoRZcMX7e9RMYHgutGr4YcI 2020-04-19 23:16:59 96.246.192.163 9999 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3380 +p reject 1-65535 +r QuintexAirVPN27 LtTSV2aXNxPrjFaikL8H4GuFvxI RDstC3bIiFvOk5srTqzBFqRYxzg 2020-04-20 04:33:23 199.249.230.80 443 80 +a [2620:7:6001::ffff:c759:e650]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14200 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r hamburgooo LuNBeVyK9V/GhGZ8nZqPxXUh/qI 8WXb5y8/P4YqJwChMRZPyB77F4c 2020-04-20 07:49:11 31.16.135.198 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28 +p reject 1-65535 +r snap277 LwFk1TcTjsj4hasfh5qUviewFP4 qBFErOUcxjCxFNunAK5HW6LxmkI 2020-04-20 07:35:42 82.235.113.201 38949 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21 +p reject 1-65535 +r TOR2DFN01b Lwm9bZotWn1tJsF2Uc6Ozwt7olc AMUOltG0ZWb0L4HlciwTK4wuZ7E 2020-04-20 10:47:54 217.182.198.95 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38000 +p reject 1-65535 +r Minotaur Lw8yqx5blDyn0GLAPxiWDIbnDZQ dO+ceZcLkwfEjTN0FNcv41Oz4AI 2020-04-20 10:05:08 97.74.237.196 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Coderi LxNXDQFq871/v1RP6+9++jsUfN8 7ONPyK2+7I+k+qmcNJ/nZqLQObE 2020-04-20 03:16:51 200.98.137.240 9001 9030 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62 +p accept 22,43,53,80-81,443,636,853,873,989-990,993,995,1194,1723,3690,5900,8080,8082,8332-8333,9418,11371,50002 +r OrgnicCcount2 Lx2nHs9J+gP2abOPSLiveOdnLYU 9xRjQeInHRt6xOTf/EgchebVzqo 2020-04-20 10:48:23 47.56.94.159 9101 9130 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-4 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=150 +p reject 1-65535 +r ephemera LybUMlgoX+s55DIIiN+vqKDSDhE pTGXRZeXcLa8Jd62ijtvUwZIIDE 2020-04-20 09:45:25 95.216.1.161 7973 7712 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24800 +p reject 1-65535 +r b33333f LycQFSojRLHePvYZ6FyxsphkPSc bAKwNwoBkkbxxITLTxqrKb3bV+E 2020-04-20 06:54:57 147.135.4.68 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24300 +p reject 1-65535 +r barwin LyuNW7op99vUEWP/UYenfkRsUn0 KzTgkJ5Qa6vPJTaBO4cCKvIQR2U 2020-04-20 09:44:17 138.59.17.40 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p accept 20-22,543-544,554,563,636,706,749,853,1500,1533,1677,1723,1755,1863,2082-2083,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r YoloMcSwag LzOoNMMhbo9BaEtRFKer5o4hazs urroMmJstcL8n4tkgpK4b5loNz4 2020-04-20 00:22:26 178.78.241.182 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5030 +p reject 1-65535 +r arachnid L0XNvWBY4migCEyU1JLKvfv2nkw 0YOBTsJn3sWwuYDyfDU33Kmzrsg 2020-04-19 20:00:46 23.237.36.114 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2400 +p reject 1-65535 +r ServerForge1 L0xgPMu8ooewTsqw6w7snfypztk rsTpMleJ63dbdpfWr+NpWWpgB/Y 2020-04-20 11:12:42 71.120.197.19 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12200 +p reject 1-65535 +r DomisTorDE L09fuwVbAddT+o3Ek7nbsQQ40xs HlG1SjCLYV+cJzPkSiR/crmVav0 2020-04-20 05:49:51 87.172.103.15 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2330 +p reject 1-65535 +r kookaburra L2BSWwbis0+PKrAwKvRcoMl2i74 fkSIIGXSsSaB5SVLgTFk5CcFz7s 2020-04-19 22:18:46 31.13.195.122 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4800 +p accept 20-23,79-81,88,443,8000,8008,8080,8888 +r DaddyCool L2Es3YNisAezNBOVAWUB/Zp2Gx4 m8VQlQjBSdKurb1rUuGhtnb9QSU 2020-04-20 02:15:31 79.124.60.174 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3340 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r antoniou L2RN3vi6oxugJA5sbTZmXZDaV8k zSID74RSp7SshciILFmOil/12hE 2020-04-19 22:32:30 5.135.115.34 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7430 +p accept 194,220,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftywabbit2 L2TqUnxKpvmeJhMY3R/xJ4KOJSU dioJ96WJ2qtuChAt4VD8DIL4Xvs 2020-04-20 10:52:47 185.220.101.194 1194 2194 +a [2a0b:f4c2:2::194]:1194 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60000 +p reject 25 +r fpuzhpx L2epQFINHJ5mSX04R/D97lRa58A In33D8WOYko2kpw7TP3cTY4W0K8 2020-04-20 00:08:03 23.92.19.230 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=310 +p reject 1-65535 +r crmh L2n4xNwC3RWjm/20B4p5HYns6qI Y8romCX6hQM/UAEN1fCJCDOGEhg 2020-04-19 22:01:00 78.47.11.224 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35700 +p reject 1-65535 +r 0x64657573 L3cxXK5HdVDkd3O6WxMj9/++Oj4 PmLPGjFCHVp4P5NDSDuEdFXYmCo 2020-04-20 07:16:53 207.180.251.11 9001 0 +a [2a02:c207:3003:3204::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9310 +p reject 1-65535 +r angeltest31 L4uVANyYwT/SjMUeR9NBbeQj7Xg +DLzofn3N2hZhH99+yr3yHoA0Cg 2020-04-20 08:11:20 185.101.35.219 443 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2940 +p reject 1-65535 +r dutreuil L5r95D3I4/BYAzBMAb09vzKRaaw 4V1YBZ7I0IjP1sqiVZUiFVi4pps 2020-04-20 08:03:14 213.152.168.27 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r tapiri L6Sz1GCHZaNa1O9hwC3IiXO//0c pC4h9xL/cTUALSzbpuCZtjVEl18 2020-04-20 09:53:36 5.9.60.4 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=370 +p reject 1-65535 +r uname L7vDR87IXPuLxo/ZHX2JyROVpuM UYuJowhx/JSHwLvcKAzFp1geyPk 2020-04-20 09:03:20 86.57.149.10 1443 9130 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=2790 +p reject 1-65535 +r citizen17 L8WveVpXOqqXPr/qOUjpIhE1rOw QcL3SuFhxaD9bzVdDJrU6S6U/lY 2020-04-19 22:55:22 83.97.20.100 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r lumipGoesOnion L8nJgZdFaBHhuByIhIxyKvJQWCw KSYo4ptZ+lkcgKP3yzGjA808tYA 2020-04-19 22:21:07 185.233.105.61 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1520 +p reject 1-65535 +r niftyguard79 L9A//ievIN1rHL5avv73sGaT1Vc 0ezfrBNWxA77RhgXImQsHYxUvXk 2020-04-19 22:16:58 185.220.101.157 1157 2157 +a [2a0b:f4c2:1::157]:1157 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r revopromostik L9QAfnCFG0vBK6Heqf/EjKG9guI g+eDknITcXe5cRny2xaDlA3CFdk 2020-04-19 21:42:38 185.225.19.168 9001 0 +s Exit Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r maisterikabalakki L9xxovV7gzn+EYKzhu3LcaLt34M IZrk78C6pizk/Ww+ubb6qp9eBrU 2020-04-20 07:27:18 81.197.96.73 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=94 +p reject 1-65535 +r GrayBeard L+1QAPf7eBpU+W0aUCLdn87uRlI ZLE6yQQUyjmvOILmzE3SOjm06TM 2020-04-20 12:42:22 71.187.101.250 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r Unnamed L/XqWzJRxRDnx1B6hpj94IkQwwQ oWM8as+v+0dY0W7T8KdPUlY+DQs 2020-04-19 21:48:24 37.120.193.42 39959 48772 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=270 +p reject 1-65535 +r lifeisabitch L/uuvE1KiMqWvV9rDTodGnoA1fI Lw7pZkJuPh1rnel5Qli6Zw/Ba6g 2020-04-19 22:43:28 54.39.202.202 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8700 +p reject 1-65535 +r Unkn0wn L/5fr3DSDnawR0rp5AwqC1P42fA HDAi8o9Xzwhe7DDSHzO79WCThkw 2020-04-19 19:50:31 5.39.72.2 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41400 +p reject 1-65535 +r NetherlandsRelay L/64nx47BYEqmmUYHgjXBO4Kbsw zff/bJRvRQH4T+dnOr7TtG9y+TA 2020-04-20 06:03:27 34.91.80.184 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=466 +p reject 1-65535 +r smell MCS4+gxBHpFyj/9y942an/K4bCA ppE07+P/BKIaF+fjs0+q5S/xOFQ 2020-04-19 22:23:21 45.9.148.216 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8870 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Unnamed MCkjGX3h0O78lSEbKfEJHaRdG2o ttRNeip8ODC/lPcAMnu3wBRfAmo 2020-04-19 19:02:05 23.102.75.243 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=469 +p reject 1-65535 +r xangaeN8 MDEyfGdp1yJPlFw6fR3uxrOJels m7vxnP4a4Xh5UDU5igBhH6AuWII 2020-04-20 04:28:50 77.13.249.155 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2840 +p reject 1-65535 +r sagfreundtrittein MDP9GLvWWMXs6Sb7F9Imm/4zc1g TbY3ajgy6rYdrRyRTltAVpjl11k 2020-04-20 08:07:36 51.158.166.230 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=34500 +p reject 1-65535 +r Ukko MDUJq5EO8ge3Q4wnQ1xKL9V58bE TzwStEgbWxlChRlpg+7JMlU+qqQ 2020-04-20 09:06:43 95.216.33.30 443 0 +a [2a01:4f9:2a:2145::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=75500 +p reject 1-65535 +r kubernetor MEnv5oaTEjLIHqTdl1r2DJYs7QE K0tk5lUR9Vu7Og2OqZbVNDAPsrA 2020-04-20 02:31:12 157.245.26.52 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=683 +p reject 1-65535 +r torette MEtjGxvFFwXa57r1Zkh6/iWAc4A 4BAHAxEPM8PJW6yyb3G3krz3Qxg 2020-04-19 23:25:59 51.91.110.62 9000 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r kostirez1 MF2jPsSbF7GDgDPJm4JN65JlBoM 9CqfMNuItWIxTLTEy/8ZmZKl+GM 2020-04-19 22:38:19 85.255.1.158 9001 0 +a [2001:15e8:110:199e::1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2540 +p reject 1-65535 +r halah MGkKxA/NB0r5GKKL11R1fCgHZ1U q0jEwwlu6GOTsCoVqv6O0r4BgHM 2020-04-19 20:51:37 80.211.211.235 443 0 +a [2001:15e8:110:52eb::1]:443 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r hrmphhh MIKKWtDcfd1pOFKb18kB0MDzXE4 cKHE+m75792vN3xf3xq6qs5Ji9s 2020-04-19 22:05:46 173.230.153.109 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r king MIS2tYyQfAOp5Ue73BccRF+6ryg sI6mmPtig0UMFfDVFrXz9wTb9kg 2020-04-20 04:54:55 51.89.213.90 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 MIof/slh/EOvOSJu8DmRiyTilPw NyukegDeioeWq9znsM/m1Q2jbC8 2020-04-20 12:13:51 186.60.153.216 41003 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r vamir MI/kDkmfaH1dYBq/Vrx5ZiTjwOg ZWv6UpG2CJpRXGgmKhghAiILh5c 2020-04-19 20:04:50 94.100.6.23 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5000 +p reject 1-65535 +r tor4ever3 MJzUNluCSBI8wZxkuRZT936lkKs YoVqvQTVF5nZlTNGfEJ0cKL2M+I 2020-04-19 22:21:02 45.62.231.6 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2510 +p reject 1-65535 +r snap278 MLVnFEZ2zV8ovYGUlf9AL3T4pug eeHwCI99JXfoPugFLFfcLGhyGD4 2020-04-20 08:43:57 176.167.172.205 41161 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=641 +p reject 1-65535 +r HorstHanfblatt MLbPD8ugUF/XEFkHmZx1HXma5NI y3Qgwp+QTdhWo3XwSszVMArimXk 2020-04-20 12:09:40 5.189.146.133 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1570 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r torvic MMC03ljPuzUEhbMmoNZzUuATjM8 AhtGeZ5GRUF2SiW/FDsXtcYLIak 2020-04-20 11:15:05 5.189.164.230 8888 8080 +a [2a02:c207:2009:1479::1]:8888 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r Libero MMGbgZgfRQxAIwbi58+2w/ectrI DsMBW5roQFMGqn8s/jPpH1VmLKg 2020-04-20 12:32:48 64.113.32.29 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=20000 +p reject 25,53,465,7676,8888,10010 +r Unnamed MMx4YqDC9Zyvw7dj7uERMHYRmv8 LzMjNHa5acV+H7RzSt2mPH5uoUo 2020-04-20 11:53:09 209.141.58.91 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5370 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r savanna MNRXMXeJ4gRJy8EuAvVlj6I+C+4 xPiBjKr0W1SUIw30ohtkWc+sgSA 2020-04-19 20:52:31 176.9.17.112 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34600 +p reject 1-65535 +r niftywabbit MNv3p3P07jv20bdAfa7PQCIKyM0 zbKioC3QqRZiMhtVTRvC2odWP44 2020-04-20 10:53:41 185.220.101.193 1193 2193 +a [2a0b:f4c2:2::193]:1193 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68000 +p reject 25 +r niftyentry113 MOdHswWJlMzL6vi1tHkanxYoq30 B3LXI+kNvvt5gx6n5S/GX8oGdLc 2020-04-19 20:26:03 185.220.101.113 10113 20113 +a [2a0b:f4c2::113]:10113 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17500 +p reject 1-65535 +r Zicar MOiZqv63Qp/qQ6FfK0N1nZZeKJ8 I4d4zJ+msiE61L5juJDLN++afvo 2020-04-20 00:35:49 128.199.44.47 444 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=644 +p reject 1-65535 +r snap277 MPCAV/aMHX5hXH9HsVNCrpwz2u0 fVx1n5353ZAytd3H2LzBxIGtk4M 2020-04-20 08:28:15 77.79.18.145 37781 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r cheyne MQBW41ObLunyJ7DSMLCDVVQFFHU 6TR1C2PulLIPeLUtWpb6FHyHgM4 2020-04-20 06:47:48 50.7.151.32 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p reject 1-65535 +r sentinel MQZYwJHEmF8vNN1aSrUo0ht5opA 2mqHihqlLb8VikHAyZAkky37DjI 2020-04-19 19:55:29 147.232.191.48 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6740 +p reject 1-65535 +r DigiGesTor3e2 MRpFM/eiQV9CNGpsj6d+b9J5WUw mwc6wJopg1djm/oZELuMYD+f3N0 2020-04-20 09:40:58 94.230.208.147 8443 8080 +a [2a02:418:6017::147]:8443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r BESTIOMONDE MS5qMEqt5Mm1y+WW84q5FY/D8bo 34t/V2PlqDIXOpUrF2QMw98rafU 2020-04-20 12:42:36 92.222.127.232 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r mulloy MUGaZBiLyAcO6J887mqpjqrH6Og WDH3TxNiVlz2P7g8+ynmcvs0UV0 2020-04-20 04:17:13 46.249.37.109 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17300 +p reject 1-65535 +r FawkesSwissBlade MUajOVRujXXSu0hGySw2mKQNzvA 7LG0rhIxN5iDffr2M7d22PPWzB8 2020-04-20 00:10:51 151.24.114.144 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=95 +p reject 1-65535 +r nodvrelay10 MV8L81XZbWeCZ9e3CBJ6y8h7p+k jKIcm1QhjlMITb7Wn1MWYVCUSVg 2020-04-19 19:48:33 45.62.245.142 9001 9000 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4820 +p reject 1-65535 +r Watchtower2 MWUAbaRps8uxGeiBtfdcjul+XSE LSJSP0rpiBuh8o0nGNrJs//+n4Y 2020-04-19 22:46:17 66.228.39.83 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.9 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=823 +p reject 1-65535 +r PankyPL1 MW3kXv+1NnHJ/VPOCZKVKEZwmik TrgieLxpEhI9GvRI/5cdBEUYwKk 2020-04-20 02:07:44 51.68.136.44 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10900 +p reject 1-65535 +r Unnamed MYytGgCzPS9llYIQsJuJN4Numa8 +IJQFI14IYkrFj0Ejn96+AoYJBc 2020-04-19 22:04:44 91.39.81.93 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=330 +p reject 1-65535 +r redonionring MYy3/A6uuSMR61G1t448rUXrzyE xtutDg3RPUPftodEpAabEPdPw5g 2020-04-19 22:42:46 45.79.181.228 9001 0 +a [2600:3c03:e000:1fe::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r snap277 MZiG1PmL4VWunRFNPjhqzI8PJk8 CdAS5NgOcG5LnIY9fmUuqgjoVfY 2020-04-20 12:41:36 94.253.159.38 46499 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r zeos MalxmMbivr9X64/H3FWiCK01A44 EBTKYMIVEYYeE28/x001yurafAw 2020-04-20 10:09:12 68.183.194.242 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=458 +p reject 1-65535 +r psychedelichipo Ma8jyZpWSx8dXIpdM8pzD8W3k1Q +49RcWNcbXDkFgtdlZs41rRiCRc 2020-04-19 21:23:36 194.230.11.153 19927 19928 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=993 +p reject 1-65535 +r anonymouseTheFirst Mb+Gmu1qdFW4VmsxdVU2K/wFTRc o1nMNea+uDchspnsyB7fX5uP4kA 2020-04-20 06:41:30 80.255.7.165 9001 9030 +a [2a01:4a0:68:21::62b9]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=812 +p reject 1-65535 +r hellohuman McMVMmOz+TIrWC9KBunlFfAzjE8 IoI+qnwx6prz0ZVBwhQc+8O4uJk 2020-04-20 04:48:29 104.248.118.241 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r Belgium MdJwo4UF1L+7yr9xfp+0vKbd8v8 zBGJMUJKJwau5gAB/2bB+bfj/tI 2020-04-19 22:11:27 45.128.133.206 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48300 +p reject 1-65535 +r Toast MdlfqGGDky79a0tvtvB1TPEBAZ8 okC6VNSh6WRkT2odvCuYKLsPFRs 2020-04-20 06:32:28 155.4.70.10 443 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15200 +p reject 1-65535 +r torcow2 Md34ewRkyKo3Ffmsk+imGeYOUDE FJ0TJMA+B6R70QPdNdbY6oYXgt4 2020-04-20 08:55:14 66.70.222.240 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3670 +p reject 1-65535 +r TubularRelayPiersLU Md7RmZw97p2sFIt8laE64J8w9LA 3aJnhGdpQOt3HeuvX/YHRsVrNBY 2020-04-19 22:17:07 104.244.76.56 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13300 +p reject 25,465,587 +r Unnamed MeLOseUxCGMpbl03skNJ2kLAOco 6zbZtcqa4DEXHhxUEAdtIpEW6uI 2020-04-20 07:00:40 195.123.226.52 80 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r JustAnotherNode MeRWfqR8ZHoq7Hd5zZwMUmrzpI4 knuQgnsem8tQbzX5mdrYz5QQOeY 2020-04-19 20:36:42 87.236.212.128 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10600 +p reject 1-65535 +r Unnamed MfFKl0FgOV3Mt0j5RLpoqYVgeDc yOuSYuzVrkRThiF3FFE2c3oKbe0 2020-04-20 09:13:18 14.13.85.96 58048 58049 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=326 +p reject 1-65535 +r niftyguard09 MfNzVxqm7LTXMmbhFNWLCvcic2k jw17D7EjLfF5c5H5eV0ZNzziUKE 2020-04-20 12:44:40 185.220.101.218 1218 2218 +a [2a0b:f4c2:2::218]:1218 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27600 +p accept 80,443 +r Bab0 MhoWUls7qfL7kP0mXFz0dXRM6xA 0/T8vscvmuFTaloBUG0uR6z5ya8 2020-04-20 08:16:36 195.228.75.149 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39600 +p reject 1-65535 +r HefeweizeIstGut MiuCaO323/90fIaGqHgyUfqC32c iv8icvGIY7oXpnP2DfAXxTN9vyw 2020-04-20 12:27:24 80.255.0.180 9001 0 +s Running Stable Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=78 +p reject 1-65535 +r BananaNode03 MiuzP0iHIwsHZ/VLoIpFC2jXd/I cjl42yz4eZIfU4U+rAOhkP9/0Ek 2020-04-20 11:15:50 90.231.75.5 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p reject 1-65535 +r bauruine204 MixuOpc7wQ/DbeMDetJ7yJ8Ucjs STd563uqtn/H7jF9WZGCMn37Gtk 2020-04-20 06:03:54 212.83.154.33 8443 8080 +a [2001:bc8:31d3:1dd::1]:8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25600 +p reject 1-65535 +r TOR2DFN01a MjkAfOH7Ls398gZ98juUkpXcXvY IqfHfP9WgGICtwACZkcrOO6vq9s 2020-04-20 11:33:43 217.182.198.80 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110000 +p reject 1-65535 +r TahirElci Mkbsyu3E/ylJtlXgJFr/9C+Mnfw CAfW5/5dpGH2UZVdGU00iNFUWDk 2020-04-19 20:31:33 144.217.60.211 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Alina Mk4T/XlXE73W6LTfAkOHQsof2/E o1JfA7BRRhrolSgH0eny6+DvBLk 2020-04-20 05:01:49 199.195.251.84 9001 9030 +a [2605:6400:10:80e::1]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 25,465,587 +r silentflash Mk4vVuBMIylZjqxRLDRVrUXOSow ez/aEDwX6sPrkBKSTJdiV3wOvFs 2020-04-20 08:07:25 82.165.122.222 9001 9030 +a [2001:8d8:1801:10c::1]:9001 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11500 +p reject 1-65535 +r Swartz MlX9L2BxZezPPcLNQ7jGQx8ZYEg tOzicEp+KjFQNct/Lhtofil1ZMY 2020-04-20 04:06:33 72.46.61.208 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r Unnamed MlxqApVHTVBj6zTzfJ8xxTl2gKc 01DWQIrVJbAnBNvKhzwCj5AWBF4 2020-04-19 18:54:30 167.114.89.204 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Kakkapissa MmWMHxcPIre2FBDE0TmIVe3hr1U Cx34jcACa1crp8J7C9ep8xUcxwI 2020-04-20 05:56:51 91.159.139.61 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1960 +p reject 1-65535 +r Unnamed MmYqwXfpXfpXCmHx+y6W8i48Pok 6zI0l4AWlpHsuZmgx5N1kjqE7sc 2020-04-19 20:02:57 139.99.178.25 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=525 +p reject 1-65535 +r Unnamed MnVYmhVoLLfTcBtxmZM2Z02G7j4 l1PrkvhnZ8lEHjfuU7rmg5AaalM 2020-04-20 06:37:30 51.79.86.175 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 25 +r demang Mn9YI0OLjshuwzNVwUfYRVqxwUs 5XgJbdxoZN9egpTVPw44EeuVUAw 2020-04-20 04:37:05 93.115.91.66 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p reject 1-65535 +r FreeSpeech61002 MoJxVQGhHVWUISFJu0q3lbkI9Ug O+G5qCdz5YA1/t4rs6fBgfB8GzA 2020-04-20 05:08:53 87.177.73.175 61002 61012 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=470 +p accept 22,563,636,873,989-990,993,995,1194,5222-5223,8332-8333,11371,50002 +r Rhea MoKEdvT4ThXEK0w2ClzY3kw8K+c KSPK9mMPTa5xBdk2XUsf578dl30 2020-04-20 00:41:13 104.131.11.214 8080 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98 +p reject 1-65535 +r UrquinaonaL5 MqHtcHNDze/8EF7I3waKDhVN9s4 uFtMjGl/iCq3yV4gwVn41W+ip78 2020-04-20 08:06:35 107.189.11.86 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r Tordom MqQ7DBU8Ipj9vSSjspjak2jcc7g 3yuPGxq8fCTDZ17yUHLYrmvPc74 2020-04-20 04:08:02 95.216.168.133 9001 0 +a [2a01:4f9:c010:1997::1]:9001 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r helloworld Mqq6jsV6oY4noZ8x8REv5q7uQT4 LAvZVxCBqImbvJ9M7M/mn/cgxn4 2020-04-20 02:33:24 198.13.54.184 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=65 +p reject 1-65535 +r Acrolepiopsis MrGROt6rDsbYdRaZXXVdfVpE/lY NGnJJOZUE/bmpgfOgODQSeU2t6I 2020-04-20 11:01:33 99.199.146.224 8080 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4700 +p reject 1-65535 +r BahnhufPowah MsEQC17xmlv7tDHo1CeBwtCdMcM e7yGeVKoD7RdagPXqjE6Lai9ZtA 2020-04-20 03:34:26 98.128.173.1 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14300 +p reject 1-65535 +r AnonUS00 Msa4juvU9vWqYfFZUujYjq18Z74 dgtfcbHMbI+jkO+opzun1Ds5pNY 2020-04-19 20:03:25 40.122.165.48 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1970 +p reject 1-65535 +r tomkai Ms12yNfR1LYg/K7QCyvMxXTyHlM U7D/tGiuugtGMz6lDOR9PK6aruU 2020-04-20 05:32:54 77.58.214.153 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4300 +p reject 1-65535 +r PorchPirate4 MtKJuV0c15DQcME/XRGw3BQF0/k nnb2HtrKbWMz7l37Jy9XbjA8WYc 2020-04-20 12:37:44 178.175.138.61 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28300 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed Mt8LjKwJl4jTE6aMEP0T7wq/HDA 9AfaqBN+GZaYBlzXJH69ceeyc6g 2020-04-20 11:56:30 205.185.116.74 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6040 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r loiu92 MubMbGtCiyBD8LPnj3My8QFtc+E URTiWInCTVar0wRXVBnLeShV6T4 2020-04-20 11:25:44 5.135.0.26 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p reject 1-65535 +r hajmat MusojA77UpZMz47yi+a8f/WSu1g VS47JxyMtoxiKX7h09e37kdQ+5s 2020-04-19 22:56:41 171.25.193.139 443 0 +a [2001:67c:289c:4::139]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6780 +p reject 1-65535 +r ndnr1 Mu6RHZaL4+AW7KVyux7Qqe5D/C8 rndtmcH+XQSj+z9T3ZpY+TVkcvU 2020-04-20 00:21:35 109.105.109.162 60784 52860 +a [2001:948:7:2::163]:5001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=36500 +p reject 1-65535 +r blinkenlights MvUZgXkZ0pC3/aVq9ckOV+VgMvk 3kWRV3A5RgaVt4VjM/EyzvoIBPU 2020-04-19 20:45:32 192.3.148.27 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=330 +p reject 1-65535 +r sci MvtMiVqp4lxgdgG+igQdg8taAsE 6EsMT8u4dCX9N6hbqq+cTwQ0Lbs 2020-04-19 20:04:17 95.179.218.180 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=2820 +p reject 1-65535 +r SilenceOfTheLANs Mv4FlkDcVEL6UQJiqHsm2R2HPxA tNlOYabaU8oQ7mt1Am5sMRjaU8Q 2020-04-20 07:26:52 188.97.0.27 9001 9030 +a [2001:470:6d:25f:f87d:2ad4:775b:f006]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=772 +p reject 1-65535 +r TeamTardis MwzT22rSZtxwzbUSsDaVfQPZvFk oc45KrjhC73igpwAD/JP5IL6zyA 2020-04-20 10:37:46 185.100.84.212 443 80 +a [2a06:1700:0:7::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4390 +p reject 1-65535 +r Voltaire MxxJnzb9eSqniFLZFjSY9OK3kpw J/Pe6TmxPwyzCQSSirA9dRK0S6E 2020-04-20 03:31:18 51.15.40.200 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p reject 1-65535 +r citadelEXIT Mx/J4SPsIId0hoRTQ7LTALj55Fo Bdrg6Ih2iZdfA7PEYS6lm+Zt3IM 2020-04-20 10:52:40 81.17.16.148 9001 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r CalyxInstitute05 MynnNsyhZEnQLVZ9Qmg78f15hnY QzbCvh9UN1hP0MUTFrj9tWy/cng 2020-04-20 04:29:23 162.247.74.74 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r central2rave4you My3JC3k48VqotgfAWMZssAV2LN0 34xawVJzumQl6mu28/i7Q+VQ/o8 2020-04-20 05:15:58 188.192.249.209 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r Wadera MzyHS1MrPqfhpAmAt2VvyuNOCKk A1mOnwCqpH6tD7eScq4zE2Rj6cg 2020-04-20 11:07:19 88.98.255.146 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38500 +p reject 1-65535 +r Zimmer52019 M0Uj13I+3GM8E2ypz+nCASzML+g rfYHhEdYCcjgzNy+sU3lUVeyvko 2020-04-20 02:59:19 178.17.170.105 9001 9030 +a [2a00:1dc0:caff:10d::234b]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4310 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r whiteshield M0eSORftnJ7BdH1bOMH15kM2Xb0 rpiDUxKGT9a2T5cUqWCG8kNNzBo 2020-04-20 07:52:12 176.36.64.101 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=980 +p reject 1-65535 +r tortillero M03yFkMiuY/MVnvERJR7dKyS2uo jnA/XiLxtrt2CSbCL3aNscdAAIg 2020-04-19 19:56:04 90.94.83.26 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p accept 23,43,53,79,88,110,123,143,220,389,543-544,636,749,873,992-995,1194,3690,5900,8332-8333,9418,11371,12350,23456,33033 +r Proedias M12IFDBwCW80SMMTUGxSQox7sIo JHXf4anj7eZvrJicB+z4aKNCP3E 2020-04-20 12:17:49 79.236.166.32 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1360 +p reject 1-65535 +r snap277 M4CyFtwOOsFceBxrodZzcv91Tdg 01UQGzEUr0hOtK97/mIdhu9ukAo 2020-04-20 12:16:05 93.81.248.221 38821 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2870 +p reject 1-65535 +r JdMtOrReLaY3 M5JYiPXbTNAU5XGMs7H8gr/hrTc UBc5gi8nVwNcJbaG1ZBg9mOVuGY 2020-04-20 07:14:48 95.216.170.68 443 9030 +a [2a01:4f9:c010:2232::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9390 +p reject 1-65535 +r SoleLonelyRelay M6ps/hYaaYFptUjJ2XPa5t7Wvw4 S+q9lzuXrn5bM708OyjkBt6uqP8 2020-04-19 20:11:50 213.32.65.85 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21100 +p reject 1-65535 +r snap277 M6902I393YbrMqNdWGA3m7ym1Ro AiGt1K0yb9zt+YSBmi1Kqg5D9Dk 2020-04-20 12:38:31 68.8.113.193 34069 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=429 +p reject 1-65535 +r c M9iPMxQIFB8qLMVjI55U5I96IRs SoB79jf87GkTV9nDptLBju/BmvU 2020-04-20 02:46:48 151.127.52.79 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r 2HG M9ujMEM+KRW9DuZnh6SIY8gYwLs sAyw6Y6P4nTUTu6EWfrSJ9R0oMY 2020-04-19 21:37:22 163.172.68.222 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=750 +p reject 1-65535 +r snap277 M/C0uBxWmNZKgfFwbQje+W3QsB0 aSpN2FzBel7g/0SCU+OZoUDjVnU 2020-04-20 07:07:21 86.200.219.44 38713 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18 +p reject 1-65535 +r snap277 NAawjotay5qoazjxRyUkDJSPFsg N03zo3nwPedrtUjqAvhbslCTR1k 2020-04-20 09:46:26 219.79.239.203 41031 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=232 +p reject 1-65535 +r Unnamed NAigGpSb4VeXBREvg88r+1+oogQ Ac0EuhKsi4IxiW65ghWwDqdvzW4 2020-04-20 05:03:36 95.168.170.43 45536 47439 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=150 +p reject 1-65535 +r Assange005nl2 NAsJrM9FqYcRq7Bngg4lovIUUsY SZ01Z71ee7QfYXtD83YPaQjz2CM 2020-04-19 20:37:36 51.15.0.170 9201 9211 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16200 +p reject 1-65535 +r abgtor NAs6gBBb3Oo6Yl89u6rslNGer+c KAhdfEUNHT3fgb07TbvxnFBRnhE 2020-04-20 01:40:13 92.247.55.102 9090 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.15 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1040 +p reject 1-65535 +r Harambe NBM8wxks91OAibFFEUAN8huloHc zo60TGxbsQiH/1dqQvmKUNLBb68 2020-04-20 00:34:13 71.179.1.95 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37000 +p reject 1-65535 +r aergia NCoax2TYkkjmZFjAd8/2aNBf/zQ RYBzVhuJ/clflWWwpKn1IgX0egI 2020-04-19 22:13:27 37.187.98.185 22 49030 +a [2001:41d0:a:22b9::1]:22 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2850 +p reject 1-65535 +r pf32c09f2e22 NDjaLM48+H2kbc+kC2ofFUpzn8Y bYw3NVzbAVjM/xac2KYaWDtTprw 2020-04-20 02:42:27 205.185.124.65 9001 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=466 +p accept 53,80,443,4242,5222-5223,8082,8232-8233,8332-8333,8888,11371,50002 +r MiRelay NELxgTnktuOryyWY3yV5CesQaZ0 +Y/n/qlKYW4McYXVrp1jNHhLDZQ 2020-04-19 21:51:42 97.85.41.147 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34 +p reject 1-65535 +r Unnamed NENmjJ0P2HdFH4xljsxB3caMALo z1sGM3GCJZ9X38kYuREmTuPBBDI 2020-04-20 05:16:02 178.150.67.61 443 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=28 +p reject 1-65535 +r Mewse NF4Dzvt78EYT/KFFMvONG7ntvUc 3+In/UuIZ0W7FxlVshCx3TKSX20 2020-04-19 22:39:31 45.128.133.242 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32200 +p accept 43,79-81,88,110,143,194,443,464,531,543-544,554,563,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MorlockRelay NGVR8vMkxn+jLS6cHGL0YsEx7fE 4rZJEO9Fl15Oda20W+5QlR1+/mg 2020-04-20 10:01:03 37.24.227.141 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=370 +p reject 1-65535 +r pocketdeer NGte/N9NklvPSw8EjOd7NvLx3fY GXn6hav4Do7VDZbZ6PzFrL4LKEg 2020-04-20 12:30:12 51.15.37.148 443 0 +a [2001:bc8:1820:191f::1]:443 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29000 +p reject 1-65535 +r Unnamed NG9WWop/AXNP2a8IXp+qLEy+cfQ F3dBVJ2R4M8Zs512T4CyVyc0YSk 2020-04-20 10:25:47 104.244.79.218 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Hecker NIQ59KPZWebRSBBw2oGhNTQ0Gcs /3Ctp9J9tHaT4Al0vu9ah6Z4Sqw 2020-04-20 10:04:23 89.163.143.8 445 82 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58600 +p accept 53,80,443 +r Molotov NIZeubk2vm59Z3vIpyy1TWJ0PSM GdTFKalG4uxBW5Hqz3WM2HSqZ6c 2020-04-19 19:35:51 192.155.93.63 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2300 +p reject 1-65535 +r niftysquirrel NIuJAT7d2Z5HVZUdHsKE2f7XEiY s7vmCiStGANcdCmLQm0joNB9RGE 2020-04-19 20:27:03 185.220.101.32 10032 20032 +a [2a0b:f4c2::32]:10032 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42600 +p reject 22,25 +r snap277 NIyILY2Zy2cifakUF8gzFKNB75Q w4fSFhu+lLqZxHh8IAEZp0en3+I 2020-04-20 12:29:46 91.166.30.192 40755 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4810 +p reject 1-65535 +r GreatAttractor NJNzkXO77QXVLxDolTHIArlXfxw BVlqWfhGmygfaBtF8rZovF7QcUQ 2020-04-19 19:36:18 46.182.18.234 9001 0 +a [2a02:2970:1002::a8]:9001 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p reject 1-65535 +r Waldmeister3 NJedvUdf/tnPZVbjSd3t7mkQQ0U SpafOUoQ5gDuSnW+cyXaaBoCx1o 2020-04-20 00:09:36 145.239.7.170 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67000 +p reject 1-65535 +r gaia NJ6i7ABcFnt/XDDPYN+m2s9sNB8 0CzoG+y+rOcy3OoeohQ1LqQiORY 2020-04-20 00:35:22 193.148.69.162 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6680 +p reject 1-65535 +r Unnamed NLEKHA89/Za3JfZLpCTKete50bc /e6v+p8b+q9KgDvDUn/+j+dZm3Q 2020-04-20 10:03:36 49.212.203.103 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r snap277 NLd21Zk7zTKCk6kbY2VXfsG9rzQ vZa8mlpFyYGoXkvtonQDaCN0nfc 2020-04-20 12:22:35 79.25.45.18 33685 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=607 +p reject 1-65535 +r manette NLhJUq/NsARE8ngFpe3vX33VScc hdo50FV890epkHij8r0Js4yEAFg 2020-04-20 10:52:28 185.2.43.87 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p reject 1-65535 +r donate2me4bandwidth NNcnaXcYL8lBsITTIzIwbLUkufA rhfmLKPvEY4VmnWQ6i+Qs659Wgc 2020-04-20 11:29:44 193.161.193.99 19399 80 +s Running V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r nodeXX NN2tvlq3ndAgVobYU58YIFbPnms Gl7DZm0MPmjJDRUlyYaRuJ7BNMw 2020-04-20 10:10:35 213.202.232.18 8550 8050 +a [2001:4ba0:ffa6:12f:213:202:232:18]:8555 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18900 +p reject 1-65535 +r ishouldeditheconfi NN5/kCilPVI413mwDa90OP3h16A Q+LdRoY7tRmP/d5Q8PhsrFUrgl0 2020-04-20 08:38:58 195.201.33.216 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45000 +p reject 1-65535 +r livia NN+EQ/as0aVDqqEKdiGjieMaRCI E1Q4USxbxNNu10A8JXl+arEEuXg 2020-04-20 05:34:31 46.36.39.134 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8400 +p reject 1-65535 +r b0rtje NPPQJqaMsMU2If5O44f6wSlmIdk J6MOmW2wJyfGWuNRaqD7rtjqmNU 2020-04-20 04:29:22 195.154.156.5 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=23600 +p reject 1-65535 +r niftyleastchipmunk NPXTPdRtf704CxFWcTKhh3O8T1c Ejo6a7V2K1DnJSEx0ssDGDl6E7M 2020-04-20 12:25:31 185.220.101.130 21441 11441 +a [2a0b:f4c2:1::130]:21360 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25300 +p reject 1-65535 +r leonide NQlNTyQYohabHAXUkFAn7obJ8NE cSPNdEcf1fZ6XKaRWYLI5ccH7V8 2020-04-19 23:09:36 91.234.19.55 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r 4663334194545314 NQq3K4dEzEDthpnm0ymMsUIV9Wg viJynQ5sPCILzLTY1OC+EnZr8Y0 2020-04-20 04:14:33 5.2.72.113 9001 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2340 +p accept 80,443,8080,8443 +r thardes2 NSMXH3ymOnXu+4ff6YyKwMkPerg 4ljJl6jRGQk5EruKicgl93KgLrw 2020-04-20 06:12:33 84.162.122.165 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=148 +p reject 1-65535 +r Unnamed NTDDBZp0XLF40KAs3qNreypzln4 ryhnRpsBeuiEtJdRzFdh9pAsIIM 2020-04-19 20:01:41 167.114.89.202 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r madadtorwus2 NTQR68c6Nxq0m4XOEu0M0eqi68w m17Dm3NbtBuH7t9OUbozx7Jg6A0 2020-04-19 20:41:51 13.66.193.19 443 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r fogbank NTn5b8zcZFx4AQBvkoZMuv1KjrI 2j9hmQyEm1nD+5/Z74OUA2HboO0 2020-04-20 02:17:12 213.144.142.28 9001 9030 +a [2001:1620:ad1::36]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=104 +p reject 1-65535 +r Speicherprojekt NUf699ZSa76BzAf6ytYSqZvdmHY c+At8yIlVGPTgio259FutDzLbMo 2020-04-19 19:55:01 5.147.248.158 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9400 +p reject 1-65535 +r herminia NUgSnjtUv0uDO7y64hTbBcpGrms EYHbgPxXXI906IEjuwH/3WKQUt8 2020-04-20 07:31:47 93.115.26.181 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r Free NVE7HS6nBkk0bDxtNPY9aYLjlIo 5u2uDwHDs7jX9EQR269MW6NqX0g 2020-04-20 00:17:41 5.1.56.52 9001 9030 +a [2a00:e140::34]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=28000 +p reject 1-65535 +r flatcap NVNAJz542sZksjKOxG1hmY15cUE H1fhpxOEJA2F2EDK2u0ZtPIoEiY 2020-04-20 04:55:06 178.79.161.177 9001 9030 +a [2a01:7e00::f03c:91ff:fe93:4455]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3500 +p reject 1-65535 +r Anon20200411 NVzPGd//vmpdC45MyVak2f92qSI 5B7wFVNGzy1PYswaqBFurhk9/fM 2020-04-19 22:43:38 207.148.7.28 4567 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=292 +p reject 1-65535 +r alchimist NWrLotESyk0UV/J9LqB1m/gu6Jg YCRwzZyutA8AbzX3yLlAWcee99s 2020-04-20 12:29:22 137.74.189.95 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r Unnamed NWuUutMJZ5DkCXkImBRKQDCsIlw QFKGlH1ddSGAGIc46d13Ttf5gbo 2020-04-20 12:05:37 130.225.254.103 143 110 +a [2001:878:346:1:1::3]:143 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25300 +p reject 1-65535 +r shawnthesheep NW+rburVOLohJKeuf9VURnlKPok mwM/Kp+SglQmuk87vSJEgJaNOGs 2020-04-20 01:24:39 188.40.33.217 9090 0 +s Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r prebensprutter NXdU1ucKL9tTFh9nTTb/OtCU9Pg NhaQxGFl6kKEgA8klJpYjdC9w8Y 2020-04-20 01:34:59 212.60.123.161 9828 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6020 +p reject 1-65535 +r Growl NXzr2oxqRUjKaRp0j4hFC2S5TQI VBHYuY4TSPcCFO+TRi2EWW08f8I 2020-04-20 03:49:16 103.16.26.194 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=418 +p reject 1-65535 +r Unnamed NZFBiEAbgDnCq93jqIEMxhwR6G0 9ohXWtJYX+5CkI0pF9fGOtcHx34 2020-04-20 09:08:29 141.155.144.16 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=99 +p reject 1-65535 +r taz NZGeGXxsfzcqJsdH1mrKajlkKz4 mw9ZfjYicQvPf65GDHBaKLXo+oM 2020-04-19 23:39:11 193.104.220.35 443 80 +a [2001:67c:13c::35]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=160 +p reject 1-65535 +r Cryptocat NdoEqSY0ryOSy6avFY4AtViaHPo kjnYD8hUDV1Xv0uZfitF6/g95i4 2020-04-20 04:31:14 91.64.6.18 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6900 +p reject 1-65535 +r seabreeze Nek6WHw7ZbBoZWnuNz6LwFB/fg0 QzidZ1smXkpSn37kOat1Z7R4phA 2020-04-20 04:49:33 185.15.94.14 9001 9030 +a [2a02:ff80:1003:6::14]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19 +p reject 1-65535 +r Hakkapeliitta NemPsLWR3zs1f/7dPa2xDa0CfX0 06J4yR89mMxRIyV4amulK0lDF9Y 2020-04-20 10:34:45 185.117.118.59 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r TheBadBADdRAGON Nfmn2ak8CpmY21iN71lZdnneebc OtNGmG4oi+SQ/uyYNpU+SdFu3zM 2020-04-20 01:03:46 198.199.118.134 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130 +p reject 1-65535 +r divisionbell NfsoJ2v0HA4O+1bK4WwqtRB8+fE vo0iSjG7YOCl4g0Y/pApnNN62sQ 2020-04-19 20:26:34 212.186.218.74 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r Casper05 NgRcGQDsP98d2pvsct333lDa8CE foppkVi3xq4YP+sGgolmWimtOE4 2020-04-19 21:20:10 163.172.211.128 443 80 +a [2001:bc8:3fec:b00:b007::]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14500 +p reject 1-65535 +r snap277 Ngm3i3BuurjehoAUUMepSsBCcok 4CUNA8M9g5d8IeY4tTdnN04NnPQ 2020-04-20 10:23:27 85.14.74.217 34615 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=66 +p reject 1-65535 +r martyr1 NhZlP87E4bgqQdxURUJskl2iAsY 1G0nY7DnT4pXUICfPUcEzHRdMt0 2020-04-20 00:28:07 51.158.109.217 9091 9031 +a [2001:bc8:4400:2400::1811]:9091 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32500 +p reject 1-65535 +r cxx4freedom Nh0zyW0PFhJ17mfiyR7hCydud4s OX9YqlBuQoXCUzhUnOsHWLnX0Tw 2020-04-19 19:36:16 37.157.255.35 9090 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38200 +p reject 1-65535 +r cndkwfSDC Nh+tVwyl3s8QocJ+w/iWHQduENI fDzZ7djkY7m8+TNnLSBCLJHaqo0 2020-04-20 12:05:28 92.221.30.231 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2220 +p reject 1-65535 +r yatr NkFAeMUhuhkWgmD23yPJeZWXYok JAPKFcxE5dS3R1Dc+jJolX+8Wg8 2020-04-20 00:04:12 142.44.247.102 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r ididnteditheconfig NkTJiuYt4vdlveO6QqP52HpZc0c 7gzEo2xhHTLLbq3K/OOpoCTp7MA 2020-04-19 19:02:27 60.241.83.197 300 301 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=220 +p reject 1-65535 +r LechWalesa Nk4YhIRpOFxZSDdvr3eKxh1M+2c ATmI2dFLGG48cV7ukcEd+HExKho 2020-04-20 04:03:55 89.163.143.8 444 81 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60200 +p accept 53,80,443 +r devilsrelay NlMhZ5aq5PJl1koJFWIF+UZnazE nI8A6OJvG6NmME1GF0I2VGXPF0g 2020-04-20 10:57:08 185.128.24.45 14919 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=299 +p reject 1-65535 +r server001 Nl85MECqKXncAdEC9QUsrQSPQvc sdpT4901ryzjjp3nbHcU6vPJQXI 2020-04-19 23:08:56 185.163.45.212 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4400 +p reject 1-65535 +r snap277 NmcAJgzcp0XCs56Fldw86kulr7U OWidqnvLg5wK9q1q3Vsk02CNgho 2020-04-20 08:31:12 186.155.197.56 34741 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1320 +p reject 1-65535 +r BostonSneakernet NnmDCTB20+tZgvqu8Gxlsp/M6ek gqzxks8jny6pRG6ZfMhFmpJkOm0 2020-04-20 08:25:04 98.110.213.239 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2690 +p reject 1-65535 +r KZL303 NoS4Zzowtz/tKANZxfup+VRpDUw ZhB2FVe17lwMkfLkN9Ey2IRDr2s 2020-04-20 01:47:00 99.122.201.244 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=545 +p reject 1-65535 +r Quintex33 Nof+x+c/Yaxm964lHn3ua72MAlI dkqM7y5pKGVIMA/cbK9q6NU3qXU 2020-04-20 02:37:22 199.249.230.113 443 80 +a [2620:7:6001::113]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14200 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r reallylittleserver NproiiaGfFpV8RzD/ZAGvdzIy4Q FotH0PFMleS6ZPXckQYDG1H2vro 2020-04-20 03:51:59 67.71.32.137 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=78 +p reject 1-65535 +r Mjoelnir NqNrZf7Erjfu/MpyIOtrXU08HtU dI9nfTYH/plJIuUjVDATsi/Drn0 2020-04-20 01:18:19 84.182.180.136 1443 0 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r Zimmer22020 NqXFAsMXKfJr3JI+S1+VAbCiC3k M3t2aIwqgc+dvYToI7fA7DY3vsA 2020-04-20 10:50:19 176.123.3.222 9001 80 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r DiznayRelay02 Nrq7vAbiv50smSNxMkuVuBLhCkA 67ndH35fN38VGdII9nB9SraRawc 2020-04-20 00:21:04 51.79.66.196 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14300 +p reject 1-65535 +r Schmaller Ns+wfgcblKf/DnEuU1RSBsV1FpM NL3TSCsZ11yTyG1/GoET/YGZbNI 2020-04-20 03:32:44 77.185.81.19 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=77 +p reject 1-65535 +r Quintex40 NtaEeDZsuGJ4ZnV+vOf7PBf8HLg Ij06LPZnmxmXJFQ0SXWGem0cW60 2020-04-20 12:46:19 199.249.230.89 443 80 +a [2620:7:6001::ffff:c759:e659]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17600 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r kishaver NuugBc4bvZsWRgCkZm2eo3CC2Dg 3sV1PN3a34s2zMDc65kO7/3g3Ek 2020-04-20 11:28:38 134.255.102.63 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r R1610091651 Nu6NR+VwuNVRVGCply88/Z7f384 7Uf+xszKANt+473gTUEK8nxq3Vo 2020-04-20 11:32:24 84.196.17.95 9443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2730 +p reject 1-65535 +r ThorinMiddleEarth Nu67b47Tt36i+K5D3kqHlevtKrg OdB2Y93KCt2DdssoQiz3V14SZDU 2020-04-20 03:27:49 109.250.247.244 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=509 +p reject 1-65535 +r tor02aditaa Nu+rof/h0CRrNsFB+SJvTwm4lRw vLbCU69Nam3NhhkwA3gOgsEPMjk 2020-04-20 04:33:31 66.70.228.174 9001 0 +a [2607:5300:203:439c::112]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11800 +p reject 1-65535 +r maupin NvpwhbjPcpPe+oKowCgeDuQ/O14 OmKC5GuhbJ27/mTMEUcdyP2ah6s 2020-04-20 06:10:14 176.123.7.197 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5830 +p reject 1-65535 +r Unnamed NwsV5JMs92x6y5skCpYMICZ8JDA /xz3az8CvR4MWcMJh4fGdGW0hdA 2020-04-20 06:59:09 158.174.128.147 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4580 +p reject 1-65535 +r freeKotov NyCC8+Ad5qYzPTAynGkDoZ0Ojoc M779KevYHgP5ExdylErsiPUBW8A 2020-04-20 00:52:37 176.193.112.103 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5440 +p reject 1-65535 +r 2tangy NyO4VaErSOapzhv32Q6hFpALgZo R0QmKYdJFgo4ZZsYz2OcK92bUDA 2020-04-20 03:23:38 104.237.144.134 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=4120 +p reject 1-65535 +r StaySafeUseMonero Nyo4eUUniHMztS7R1wdgnYCMBlk IvdONFnBgJpqikjoVAzCrikfzDQ 2020-04-20 08:58:22 95.216.159.70 9001 9030 +a [2a01:4f9:c010:16b0::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p reject 1-65535 +r Zoidberg N0H6ltnunf1ltaULoc2F8EVngu8 HtR8a84AfKSoL7BPkSeWWQdOUPg 2020-04-20 11:42:13 83.97.20.68 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=418 +p accept 20-23,43,53,79-81,88,110,119,143,194,220,389,443,464-465,531,543-544,554,563,587,626,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5353,5900,6660-6669,6679,6697,6881-6889,6969,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9987,9999-10000,11371,19294,19638,30033,50002,64738 +r rasptorpipi2 N1NUCRAt/+kvPayAnkcOYrwn8d8 Cmg4gWWL3S9KoWMB8P2IADmntIA 2020-04-20 00:10:33 84.240.60.234 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r TimApple N1qv1OKAuVE2lp4ZGvTZofp8T9k 1hXTjhXNkTsq1SoUBFq2eH0e/EY 2020-04-20 00:32:14 23.129.64.183 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8300 +p accept 1-65535 +r ebola N13LstvZTlJjvAwBXwyedWZpYX4 aSgKbONK0/5bxx6j2P6SnmK3oZM 2020-04-19 18:56:12 64.79.152.132 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Gnampf N2D2cUC2Ziv7OLkkXCtRBFW4jkU RpSWWHz+7myHGS2jj9CjqlqsA4Y 2020-04-20 05:52:47 87.168.27.71 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61 +p reject 1-65535 +r MLaBnetTOREXIT01 N20FUpuQF5S2DZKX+hBOgYf39Dc YcXFpQGfjsRsoKEzGp3EEfVPbB8 2020-04-20 00:40:32 45.137.184.71 443 80 +a [2a0e:a6c0:1000:124:45:137:184:71]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39900 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 N4A6rpj+knYB5PirMqx9Uscn6e8 l5vuYGNOtwH9QnZJaSQl5CV0+WE 2020-04-20 09:25:03 159.28.232.119 43359 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=88 +p reject 1-65535 +r c0by N4L0hIEEWqckeRNjfqzp5yJc8U0 dW4f2bfzXF/iMallpp1nnH7H4OM 2020-04-20 07:15:40 116.203.219.116 9001 9091 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4720 +p reject 1-65535 +r snap278 N4hPhWv14E/7Luj+NadKzW5OK78 6Yp4+ZWV+xLWS42ti+iIzwX69+w 2020-04-20 08:25:37 80.42.1.36 43159 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=740 +p reject 1-65535 +r itsarelay N5EeAOWaO2kaqVZlsp6wcSwMuwA BM6tOFWQWpyYa88jmbM4ZvIUles 2020-04-20 09:29:52 108.61.96.230 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=105 +p reject 1-65535 +r BenjaminDover N7hd7DXcH+Vl2CVUTM2h+Rb5kYk azq3A7/wUCLCp+dp3hXd8D5zzGw 2020-04-19 21:30:42 5.146.220.175 9002 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6120 +p reject 1-65535 +r Unnamed N7l/mKoaUf8oJmDT5EDa2Wh7qBQ 9tVMYvme1bUnuCjSlAAo5tvDYJs 2020-04-20 11:40:28 165.227.107.198 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=713 +p reject 1-65535 +r coconuts N7syMwmL+bkJXCeDTmWi4X/4B/g +t32DcgGL/2gou3C9KNPDJDlhJk 2020-04-19 23:51:21 80.241.213.86 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21700 +p reject 1-65535 +r hsjeufh24h7 N8HWZVnQx4hOPSH33rWMddebmKg 1MCJfkSsGYIY9WOI6PR9QQ07ROg 2020-04-20 07:41:09 51.15.52.16 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r king N8bCerUSN3vb63NwPm7iOgzVOW4 7dcd5cUF7fYiNBhNdjY9NUUCL4w 2020-04-20 07:13:51 51.89.213.95 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SuperNifty N8uG0g0BBPi/3YL032o1PSa5Tpw uwRcBJrS1qCZFaVyx5btxv2VEAY 2020-04-20 11:01:30 86.52.8.46 9001 9002 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=273 +p reject 1-65535 +r BrowseResponsibly N87ZuokrsGmZ8rjLY4YaBkomwbs 7d9PUMlDBeqkWPzkuAPPN5SjZIY 2020-04-20 01:59:14 23.129.64.215 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p accept 1-65535 +r blueblazer N92bZwlK52/V4hVL5yZMxFPrY/g AlkRWER1BhsWSDAxBg5tE6iXRDU 2020-04-19 19:57:34 50.31.252.28 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=371 +p reject 1-65535 +r pKD9jZ19N1LiTvsjOF3 N93xkG7j25YTCnF+pUZnxk2seN8 eE+x5Ba7wT6h+tsNYqCnH2U/vEI 2020-04-20 00:40:58 46.38.242.32 9030 9032 +a [2a03:4000:7:3a4::2]:9031 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17500 +p reject 1-65535 +r niftyentry89 OAEpg+guDAgky9YuQ1Bgf4z5SXo UE6UFYhwf4vbH5vDzJDzn0tt95Q 2020-04-20 10:51:45 185.220.101.229 10089 20089 +a [2a0b:f4c2:2::229]:10089 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p reject 1-65535 +r Bahar OAufFTOq1Yf09uPnqtZh+Nu6JG4 s49fsyFwa4TvHapiFeqACvkMvY0 2020-04-20 06:36:10 5.9.143.163 9002 0 +a [2a01:4f8:190:22a3::fefe:dead]:9002 +s Fast Running Stable Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=27000 +p reject 1-65535 +r orencioretamar OA5p7dAt7NMjtWhrxYphbAkv48w NA5RKPQGBJDx0TVkKSK8qrB5bVw 2020-04-20 09:03:01 87.220.28.235 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=580 +p reject 1-65535 +r niftyentry78 OA95FF/5wjMsv0ExMGLJnbqbDlA XUJsaUagPX6IukpiIwohydeOYv0 2020-04-20 10:52:22 185.220.101.218 10078 20078 +a [2a0b:f4c2:2::218]:10078 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r madness OB7CCad/xTZblM4hlCC6Aabw2i4 yCQMlpHizP3wmKvGLghhxtYV4Cs 2020-04-19 20:36:38 142.93.155.189 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=418 +p reject 1-65535 +r justsomefancynick ODEqQoH1Bd0xyILTtAYCXHJ+cWI 533N06gKNiTz7hASVkEY7LUBBR0 2020-04-20 05:05:16 37.201.176.129 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=476 +p reject 1-65535 +r lftor5 ODiC50D8khSiGmDo1LEKIgJyETs iYvKVQDeYEqU3O08DLPX7h79zzc 2020-04-19 20:00:29 163.172.180.42 443 80 +a [2001:470:c85d:32:216:3eff:fefb:bdb9]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p reject 1-65535 +r dune OD67SplHnfnNi+VyTgm5ZPCY4b0 L0FNyJTNerye8pexSyNPYMFsquY 2020-04-19 19:06:54 163.172.90.128 9001 0 +a [2001:bc8:3364:200::]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7060 +p reject 1-65535 +r poussin OEeGLApJJqzLm1rc1vYrYnjYiBI +KcBkF5rLoNSq3Kxpq2gv4gAK9U 2020-04-20 10:29:01 185.233.186.146 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p reject 1-65535 +r Unnamed OGSkN+2uv3hZucxxNI4SFL7lv2I aGfmz7wc8z9fGFLu3JqH4XKu0DM 2020-04-20 08:19:46 85.187.184.190 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r snap277 OIgn23tVdJ23kNGejmk4ebRRKVg BJx1m1F0SA1bMUEjLDSKZuYuQ90 2020-04-20 09:38:56 84.117.160.149 38407 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=59 +p reject 1-65535 +r apx3 OKQrjXwOY0b0pIIWF3QK7obqiFs Dw7A3zqxVlxu6tGz7CKvce+9U5k 2020-04-19 23:51:19 185.107.70.202 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=51500 +p reject 22,25,194,465,587,994,6657,6660-6670,6697,7000-7005,7070,8000-8004,9000-9001,9998-9999 +r ToserBan OK27N7hq423OHA1rafZCWbrOJrU IZAwu5Z4DnalLezPp4kZio0mUYw 2020-04-20 03:46:28 193.159.74.81 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56 +p reject 1-65535 +r heraklon OLlEPS/wuhgHpZjPZKx3CXh6M3w lkulBzYE0bU3LOrszKcj/Rmtuus 2020-04-20 08:38:13 188.65.149.32 9001 9030 +a [2a00:1aa0:1000:21::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=180 +p reject 1-65535 +r N00dl3 OL5Lndtxm2EW5hpyRKiBRJIOVXE azbfi1+59Nl3Tsed2FEAn6T45Ok 2020-04-20 10:54:15 174.16.50.58 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=714 +p reject 1-65535 +r rasputin OMs9gDqtfnJJSk+jPY0x7WQttMs WJ0qj6rs9AXiEfQ3XulIgKTU810 2020-04-20 03:45:40 188.195.173.22 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4900 +p reject 1-65535 +r TykRelay02 OMyVqM6SpZHUpXeTWb7/uhP6G4g nPIZUGU6NRKaEMY0w4x4y4B52FY 2020-04-20 12:12:53 95.216.101.247 443 80 +a [2a01:4f9:2b:151f:95:216:101:247]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44600 +p reject 1-65535 +r himbeerschnitte ONCCGGJAg9Klr6oWHP1i99sCMaQ SToGSSlzZ3gAl0WymPgnh8jcb4M 2020-04-20 09:15:24 5.147.121.35 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38 +p reject 1-65535 +r StaticIT2 ONVne8jDd39o6N0Pb8IjYu14X5g 3revuaSHTviwBW4tlbaw/xYHa5M 2020-04-19 22:22:44 106.69.72.252 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r ieditedtheconfig ONx4MC1csQe21czALuTYdzqpEN4 tuQoHDCIsXz1Q8RJvyoae231E3Y 2020-04-20 12:31:52 95.216.99.156 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=45100 +p reject 1-65535 +r LeslieRelay5 OOBZ7qzYbk1H/NNfCh+9JqNLq4M iTbhy2UZGjmIyb4JkEdU7+QzBRU 2020-04-20 04:53:27 198.167.223.65 9001 9030 +a [2c0f:f930:0:5::65]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1690 +p reject 1-65535 +r Cheese2 OOSMlQnhj0BXSYWe7ymevBuClgI Fd1QfmJyRxV8xcw15kfSIWnMlf0 2020-04-20 00:11:12 185.21.216.198 44545 33791 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=78300 +p reject 1-65535 +r KonjikiNoYami OO8vz+csScY0/ggtbKtdj0I7RiY Dl/xz2Fw/PiI/pZcwIU0cLGUZ7g 2020-04-19 20:28:40 212.47.237.127 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2470 +p reject 1-65535 +r trabajando OPId7inkDc35RgqAZit3I1YsoAg neyITi4gtitkiCF1uQxLxF2mdXs 2020-04-20 04:10:23 94.75.194.221 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=63600 +p reject 1-65535 +r lfstmpc8914e6a OP0Cg5c0k/UslQgI1IlMze06xoQ jlDPCIJBHZMY6pztdtcpqj8M/vA 2020-04-20 05:29:15 65.188.112.70 4433 8080 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r EdgeCompete OQhx1ZNIr+tcjW5yxOfAzgCm4dU /J1PudfPCbz5Q2iw6kM07k1WM4Y 2020-04-20 06:41:53 45.79.223.211 9001 0 +a [2600:3c02::f03c:91ff:fe8b:4cf9]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1570 +p reject 1-65535 +r criticalcat ORDFygzFr+IscJ30caK1trSu3Jg lJedNfVX5h7H/svfSbbNF0Uw1w0 2020-04-20 07:21:06 46.182.106.190 143 110 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Reaction ORaiYpeSOC955cD3ijy8BFoCcBk gIvwDIX7E6qBEHTDX/qMFiQfjtg 2020-04-20 02:59:26 51.158.105.11 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=298 +p reject 1-65535 +r TwoFlamingos OR8NBTRdpWQQeTSflv6UwmmrFcA +HQP9x7R2eQUVQhoxR+/THbXWfg 2020-04-19 23:54:22 144.76.105.169 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8020 +p reject 1-65535 +r torMaydayGlades OTeeQXf/+w7ZDCAT2XZovShKF5g W3R4fnH9J7qgecEs4pIHVJy1Uf8 2020-04-19 23:04:10 85.229.87.232 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19700 +p reject 1-65535 +r snap277 OTwuWZ8Y+HWtwZRMPFWtHotqyko BuHqzdOg1LaJ103zYF21yyVXCwU 2020-04-20 12:12:22 41.142.79.169 43005 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r Unnamed OUfJymgO6Il/9cr9S1a+kS6+F9Q QomlEozfV9dSTWyni57TQ5nXmHY 2020-04-20 01:14:48 139.59.67.86 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=423 +p reject 1-65535 +r snap278 OUlvJ/oEWYtfrbhDcB5B/tSPdWU Fp7oGJcgh7jhHdIl1G4DYC5k06o 2020-04-19 17:58:28 78.193.19.64 42755 0 +s Fast Running StaleDesc V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5990 +p reject 1-65535 +r SumomoRelay OVzsT5eIV7EWnaeM8SCP0TtxX9A 9eGEygDNRCNC0ktkBMiAjr9gUhI 2020-04-20 11:04:40 51.68.214.45 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=8830 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r snukafly OV0pMmPp3uwYdFA9RbhUPausxpQ lDHRvNoaxbiDh02BCxGajRn7PmA 2020-04-19 23:27:59 217.160.40.194 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=96500 +p reject 1-65535 +r ExitNope OYOlidPrx6MAZO2HBXUojTRc57o tvdjH3COtQaQ2fP04Ke5YYuIz38 2020-04-19 21:53:08 88.218.17.43 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56000 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed OYl5mgNAyNlZs6OQj2QzEnZTd4Y mO+SA+P6qSzd89abqaAmqRw+CBA 2020-04-20 10:41:51 51.68.152.42 62332 47046 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=170 +p reject 1-65535 +r snap277 OY8xw4zjwBSOhyznUswRTrVvjDw o6eT7LtdBupnPbVqiXSikG+YhAg 2020-04-20 09:22:32 82.248.198.30 46311 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=580 +p reject 1-65535 +r sunburst OaVRzRiBURR9xNGVI9BqCbUofCk VzW07VLNzgSNGz+9wF2sDg+GgpY 2020-04-20 09:49:28 24.150.206.97 9003 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r cvbnet2 Oas1TxK0l/zUQ7hb6rW69LORz6w CeJuIG+vsq4gh+JhJNY5iZ3I4oA 2020-04-20 06:16:58 40.68.148.217 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1570 +p reject 1-65535 +r DobbyIsFree ObwoPZc0BzoTvjRqzUCRwPpQXKQ 1W1jDPutujWsOf1V8f+MQDPNXZU 2020-04-20 02:57:04 178.211.45.18 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5620 +p accept 194,220,389,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19638,50002,64738 +r angeltest5 Ocb4M9SwlSR3DTZV34JaESE8oKk ZkODqhLyNbvrWZPjiKYVRHx24AA 2020-04-20 07:42:46 51.38.134.104 443 9030 +a [2001:41d0:601:1100::2cd4]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p reject 1-65535 +r niftywabbit19 OfF+wb1B5lLRuASE0mjjkzR2/0I CPfWrbpq1NYUOEAxLGKWTqRqhqY 2020-04-20 10:53:46 185.220.101.249 10249 20249 +a [2a0b:f4c2:2::249]:10249 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53000 +p reject 25 +r vercingetorix01 OfI5kGAkj9N/7paZz934NF6Wumw qLtUTCb7X0+Qze4M4ZgGvzF25Cw 2020-04-20 00:31:32 165.22.145.40 9001 0 +a [2604:a880:2:d0::539e:a001]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=154 +p reject 1-65535 +r oirnonzasdfan OfTB2PNDvDTCbgJUx3oEjYDQ54Y WGEhHyneXwvKQgCF+nBesZBuM7c 2020-04-20 02:26:06 70.74.176.243 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1080 +p reject 1-65535 +r angeltest11 OfkZWUFnY6/TTb7sBUdEEblkstw FO7JvTc9QRZF9dtrInTQWgaoVZ0 2020-04-20 02:25:49 213.183.60.21 443 9030 +a [2a06:f904:1:100::4b]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6130 +p reject 1-65535 +r Kvikende OhRLyyaBq6EDuD1VO+/D65mhGAE sU1sZuyr4EqxJ6C7k32wt99RjvQ 2020-04-20 12:30:56 88.90.90.72 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3520 +p reject 1-65535 +r TokenLow OhujsIE+H9EYM8n0MPNQdmKlj0M c5VReh/o7bNW/+PNUxViNW64BSk 2020-04-20 00:00:47 37.205.9.131 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=291 +p reject 1-65535 +r Unnamed OiCcAF9YrwvN3txEI8/9OrO4JvU wpKz2JDCz3/rXni6lXUGuCmxp48 2020-04-19 23:25:58 139.162.162.238 9001 9030 +a [2a01:7e01::f03c:91ff:fed3:21d]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=101 +p reject 1-65535 +r torpidsFIhetzner1 OifMQUcGLk799G+Ej+p/8DKgTl8 l8Lgvz9q0+VvLXKS+wGT0mOISuo 2020-04-20 06:56:08 95.216.137.135 443 80 +a [2a01:4f9:c010:188::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34100 +p reject 1-65535 +r snap277 OjPJRacX3yyZIq1R17KJlMP4tDg grNM1HPiXWFmIDBpi2vb4//zsoY 2020-04-19 21:19:06 46.121.145.165 34345 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=33 +p reject 1-65535 +r toritico01 Ok0T9SpMmhOtYNlGFdTAsvX2njw AAH5jlxYHE/rEmjFGLKPmNwC/3g 2020-04-20 03:18:46 179.48.251.188 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=222 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Unnamed Ok1zpJ7Y/o4+aeHeVVcVikLv3BA g8u6miHAfPUlgVPSuG5gUCWGQ1Y 2020-04-20 06:33:47 84.107.102.129 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r 40e62fcce23032 OlHjKjA6Dgo6uKocy+mP+HkeI0E IAIGiQyrJoqnH/MkdGHDokGFfiQ 2020-04-19 22:41:09 2.233.112.151 9001 9030 +a [2001:b07:2e9:7097::3a54:4f52]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4490 +p reject 1-65535 +r torminology OlahBhUTc8yMUkoDSlt54p4/YaQ Y9UXz+wyiRvEoh5XOf/nzRRzvCc 2020-04-19 20:46:04 51.254.201.90 9001 9030 +a [2001:41d0:302:2200::2328]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23700 +p reject 1-65535 +r kockodan Om2Qsgg6Kskb+v+6sM4TaGuSSxU HCapOdXVfmNN9EoDzpawHBqiAoA 2020-04-20 06:39:56 176.123.4.66 49001 9030 +a [2001:678:6d4:5000::aba:102]:49001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p reject 1-65535 +r sotlar OnUoQ24N2WdfsSdQ8+3iPPdPSss Fy8teAqIYe2f0Jubm5CwhH+pyv0 2020-04-20 07:38:19 185.63.253.130 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6670 +p reject 1-65535 +r colon OoVXsGf75T8Wi76qfRTRKYrlKlI Ia/vnU9UnkxjqkH82/wN9KAdF7M 2020-04-19 22:17:14 62.141.36.150 9001 9030 +a [2001:4ba0:cafe:24f::1]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18500 +p reject 1-65535 +r ViDiBox Oog2slScVb1ishN9FLdD7qTsBEQ dy7//Ap85QO0WaxiGbDgZRNKgTE 2020-04-20 02:48:22 84.119.134.77 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=940 +p reject 1-65535 +r TykRelay07 OpAdHZdQDQIem90qBr5ahGBRzQ8 WVHBg6XJzQX/hJE7ev/3Ym3s4Yo 2020-04-20 07:20:43 185.96.180.164 443 80 +a [2a00:4820:0:4:185:96:180:164]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56000 +p reject 1-65535 +r Pasquino3 OpTvv0oiCzWpLQpbSoDWMkw8MGo hpGtI0H5oU8P1HxsmQy5oz9xSYs 2020-04-19 22:51:52 209.44.114.178 37837 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9260 +p reject 1-65535 +r happyLittleTree OrM0MxgZrAuhqK/gAtQyFnIQnKw AksmkvWBbECZEaNM1pwha/0cjO0 2020-04-20 03:12:20 79.119.98.193 443 80 +a [2a02:2f0e:3002:2a00::df1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9030 +p reject 1-65535 +r nati OrdPVwL/QL4eymZ0uCfrpQmUbsg WK9voKzbiXhc38P8AeABXd4YNb8 2020-04-19 21:08:05 92.223.72.168 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=604 +p reject 1-65535 +r 7a7742007784 OsnCBWdy9Iam8eJbhanFUSH0o0s B0JDBfALO+LXSZw+Kgi73QdQ3nU 2020-04-20 08:15:15 51.81.253.212 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Discovery OuzGJGSQwHRVltFKu+a4KhE9joU vefWDd6X3a1x2pPn42E5eWXvkmA 2020-04-20 12:09:54 85.192.170.117 9001 9030 +a [2a03:e2c0:f99:5555::1]:9050 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1290 +p reject 1-65535 +r Karai OvabPsywAIecobzQs2thnb9xIpE BNEqa27j6gG/1yqbnDJ6M7eVF+s 2020-04-19 23:19:49 200.122.181.101 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=447 +p reject 1-65535 +r Edouardine Ovg5DT9LgQPaKXz9UUs1dAeBuH0 dQR8iX6CNqx/rvy4O8nIKwPzQYk 2020-04-20 10:06:32 163.172.85.155 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r theia7 Ov2q2RoVtManaGpTqoYnyocf9JE R0VOy3h/GOIwxuDVOlvlAmsM480 2020-04-19 22:57:54 50.7.74.174 9001 9030 +a [2001:49f0:d002:2::57]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6700 +p reject 1-65535 +r angeltest2 OwfFAKwX57Wh7mFmE+EEoJSrh/M MJRn0sg0eSgVa/W0XNAiR92CJCM 2020-04-19 22:43:39 5.39.60.243 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=3000 +p reject 1-65535 +r Unnamed OznlN864zmqhy+SOQnrDDiR0P1E HtQ65Y2TD7ctP9z8nW9Cwa/BMLg 2020-04-20 10:49:57 69.167.16.205 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=218 +p reject 1-65535 +r Assange009de2 Oz9FG9WPltwOjrfQHyCfyIA8M98 ZqYI7HtZ0MpoUt6D/p1z5GxaTFc 2020-04-19 22:33:51 173.212.239.78 9201 9211 +a [2a02:c207:2031:2233::1]:9201 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8630 +p reject 1-65535 +r snap278 O0KpmZg1PpNWzo1h2elyxPU5dPc X5OBPoSW1qwfIRhLzdQ0wgheM8Y 2020-04-20 11:41:41 81.11.143.218 38233 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=802 +p reject 1-65535 +r BeTheChange O0Rlm5pLOAURxeqH72Qest/e3Gc yqS8D2H2Rauzwi9B9Nwly0DrC2s 2020-04-19 22:01:07 188.141.61.83 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r FissionEx4 O0xXKfgpyi6JW4Gvg0pj2zNtD/4 6frRygCvgkDS//HBLVBPgTUXryM 2020-04-20 04:28:58 66.23.227.135 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r niftyguard31 O08NzgeAzk6XYnBeOyAsz6BG1fk HLI97dN8rvZdzHDoMYjvJ1Dc3vY 2020-04-20 12:46:31 185.220.101.240 1240 2240 +a [2a0b:f4c2:2::240]:1240 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6500 +p reject 1-65535 +r FRNode1EddaiSu O0+iODHMacE2QYsDBTgaUQOjtHA 9fURavrzA0wsU8wmplLUbNAKVHw 2020-04-20 07:06:16 92.222.22.113 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 6660-6667 +r billingham O1xu0sHezrMr8a2beycvTOnOBlY sgc3ReKybUsKP7p45g3Gmidj5fk 2020-04-20 03:47:45 89.249.65.153 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r fiedlerRelay10 O2Xuo924kM9ImeZ1p7E40EdZ+vo D7knJPockFkS2Lv2bgr1oO1kXNY 2020-04-20 10:10:06 46.232.251.29 9030 0 +a [2a03:4000:2b:610::3]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4880 +p reject 1-65535 +r p1onX01 O2qOTX019LJM6gbXOt+AdaPSv/E U34OUWT5U/XuKDvXl/SOTY7/4pE 2020-04-20 02:17:47 5.39.81.102 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=53 +p reject 1-65535 +r georgysRelay O3v4H0h3p9xx/Y4tL4rj5vob4CE PU9zmA0H3T4yElpYtBZSmp22j0E 2020-04-20 02:08:32 91.35.17.157 444 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r snap277 O4Qo5Utg+mwNVsuQv+Fiq+HLgv8 Ewm3T2UkVnGLYzRUycIwk/+ijbY 2020-04-20 10:21:38 27.255.213.77 39061 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=358 +p reject 1-65535 +r RatznetRelay O4ZJSynFgfkHDbJifndcYY0HMos TVSRqVq4Pd0Yi/wFVUhZ8OA2aZk 2020-04-19 22:01:00 83.215.114.178 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=890 +p reject 1-65535 +r snap277 O4bGBmtdPZwtRIrRcQJcNtZBoM8 F58ErEvopZTFWGUx6r3AkW8D2C4 2020-04-20 10:53:39 85.72.248.193 44615 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=65 +p reject 1-65535 +r bereskaTor O5EDNu5n2UIswbG6lBqs8Rd0NXw Sthd07wrlUVNAN8f1UAwXyX8RZg 2020-04-20 00:44:57 185.18.6.160 6080 6443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=771 +p reject 1-65535 +r Eepi2 O5xVD5svJxbKY5i9oPtxXaIFQUI GCgKsyzzAY+eOeF3zzz2AJyJg6A 2020-04-19 19:56:56 95.217.0.140 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15500 +p reject 1-65535 +r TORque O6rOFJ2zFXSzJ7+DW1lLcH0SzVg JDrLYzHZmunGUgev9mN7y02sEIE 2020-04-19 21:03:13 176.9.137.110 4443 9993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64200 +p reject 1-65535 +r dexter O62z7/uHU0c2v6yaICSreEAb28M vP0rHZwWq7n+mQIe8FxepvSPGLI 2020-04-19 19:03:29 195.228.45.176 9001 0 +s BadExit Exit Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9530 +p accept 53,80,443,6660-6667 +r kerly O7A1UU+CRqw2e1Nw9P4SC7EdjG0 P8zSMZ1WCrldG/81Vno2qRHSYTM 2020-04-19 23:28:22 93.115.95.38 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29400 +p reject 1-65535 +r caersidi O7NMYwctnRDoNu5ClocT97kyX2Y iRFKu40UxSUXf62gmQB8x/GJWvI 2020-04-20 12:46:14 208.113.135.162 1443 1444 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5870 +p reject 1-65535 +r venser O7NMzY6pyATFxTYbIfM3Z/IggB0 Y+0Y07gTnH58QJ3A5c2qD0ClceM 2020-04-20 12:40:29 94.23.17.58 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6200 +p reject 1-65535 +r laruneheureuse O7R7/yeItTSluso3h5xI7r5eiAA h5GIcTh2WLz8E+AtNyOT3tlvgmI 2020-04-20 06:10:16 185.65.206.154 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=250 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r accidental O7cbqxc9u0+yS5CEPb1Q2PcEBuo qDXsu75EYhUeEFCRrK4gAbIBdYE 2020-04-19 18:52:00 185.18.176.226 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r Tiny O7+dmMfQWNfC5g9rpb1XTLTz/iY ChJeHTLINQp1s3R+oaJ9w8i4Ql0 2020-04-20 11:23:25 91.219.238.120 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r Unnamed O8fUJ21n1GaFfsc2nazhNCXWyLg 6XuTYIlQpCYd9XHpOX9asPeZTD8 2020-04-20 03:10:48 144.217.245.140 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=500 +p reject 1-65535 +r Raspi53Tor O9E3bNM57axq7881WnA6Fq+RNJY dsRBB8xCbu7YwJwusceekR/CyaE 2020-04-20 01:16:57 79.240.119.142 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=424 +p reject 1-65535 +r Arrakis O+4/HIEZH4K+2RSA/9YmHPf8Nm0 l9pULNdfYqt7kzI9XjPpokzm+uk 2020-04-19 21:20:05 51.15.76.184 443 9030 +a [2001:bc8:4700:2500::265]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13700 +p reject 1-65535 +r hers O/PwBA2vbmS2G0RWivjt5GD1fgI qibQhDvoULjKmCUJRVrWAEKK0AQ 2020-04-20 06:13:06 195.154.181.146 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=69600 +p reject 1-65535 +r BlackMesaAG PAGqNBBzwSWOwxdXix+jVh5el14 1kRAeJYYrjjeR/UX8Zt0KuQJSRA 2020-04-19 22:01:26 85.214.80.203 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34000 +p reject 1-65535 +r VSIFenterprise PAgKhnchtL4R87/rJcZi4mPkblY qvZvQClQM/gK81KcAIOCdR9H70E 2020-04-20 06:01:52 104.218.63.76 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5000 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 PBTtZhfqwgOTSTKfxbgxIA0XGrs ItR97uyZs8Vsa3QQJdoLOPEFzmw 2020-04-20 12:06:19 41.108.210.79 37449 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r Unnamed PB0f1RsEqN8znjJThqrsIR9hVjo ywne1ND2DkbYtasZlnD0YKo1KH4 2020-04-20 09:13:16 37.48.116.26 47331 52354 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=82 +p reject 1-65535 +r snap277 PC22jktQBeUizdcQQNfm8Oi4pIc Iq5ONGe1PCYdDU/1pe3WYuz/kiI 2020-04-20 12:29:22 109.190.93.217 33975 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r CyberaX PDl05dCt03EaXCy+RSrTGszGB0g ChGYFT5EFsqueR7XOOXEt2Sp1TA 2020-04-20 07:24:50 90.55.221.251 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=527 +p reject 1-65535 +r Schlawiner PEtfZ+CSJh3YdibMp2x0AqShzMM BC+Umn5QYQpOP1QYf3s9TbhmO8c 2020-04-20 09:57:40 79.208.168.185 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r AccessNow001 PFkVNI1zFQXEgRL08DI1/ee4yDc pl6UtHWN/+AMCammiwJ678dt7MU 2020-04-20 10:33:23 176.10.99.201 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r SpaceyBlueShip PFxBmWVHuTirH+NG+oG83UUr2tM FWuwcdQ8sr59juTgjOz0njXMPJU 2020-04-20 05:00:31 93.8.30.170 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7600 +p reject 1-65535 +r glenda1 PGOPlfNmcfxxaQx7viUuIZIARNU I0rk+zFyrpVV+AUeIHkkfbLNI5I 2020-04-20 10:56:33 78.46.209.112 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r bauruine203 PHlpnU+8N94aIS1QM7VtrgeawO8 jWq2o4DCbcTO/nBV12bnQUICny8 2020-04-19 19:04:29 212.83.154.33 443 8888 +a [2001:bc8:31d3:1dd::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26600 +p reject 1-65535 +r HanseTor PHlwK8xKpJjLjp/silGnKuiRaeo qBemgvyCtAVbGQ0pwMxw2IMxpQs 2020-04-20 00:36:06 79.209.234.3 51901 51900 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r F3Netze PInIDiaZ+2NYu7ZP3JVHr8tcA/c wE19yfFMCJErR5elvRDauqMeFQQ 2020-04-20 07:05:44 185.220.100.240 9000 9001 +a [2a0b:f4c0:16c:13::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84000 +p reject 25 +r QuintexAirVPN30 PKDRVWcCTS4LVX3Azz6WKzeZmnk rakfLjYx9rYYvYvTfdrHaO46WzI 2020-04-20 04:34:59 199.249.230.83 443 80 +a [2620:7:6001::ffff:c759:e653]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16100 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r FreedomBoxOL PKNhB1sKt3BxmJlIhGh2s7ImW6Q G+iG/+IQnYqwltRuDd4QlBzwiy8 2020-04-20 04:05:09 91.47.83.57 49001 49030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3930 +p reject 1-65535 +r rofltor10 PLQZPvTiOfztxNxDRo4LDWtnrMM KbhwYEhhh0e2lqivEbDifecyWRc 2020-04-20 06:43:14 51.38.65.160 9001 9030 +a [2001:41d0:801:2000::f6e]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16600 +p reject 1-65535 +r gongshow PLxUHyp2Ot1790KRkiklHiwGXk4 Oo3uOEK9wyRVwl8zHjLY8r790YQ 2020-04-19 22:46:55 209.126.103.140 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7800 +p reject 1-65535 +r Unnamed PMaCxozHfUGJv2kO8k5k3dRzNiA HL9OjZSfll4iOcGjeT5K1zY666w 2020-04-20 11:30:36 89.223.88.117 39001 39030 +a [2a04:ac00:4:5fbb:5054:ff:fe01:bab1]:39001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=980 +p reject 22-23,25,119,135-139,445,465,563,587,1214,3389,4661-4666,5900,6346-6429,6699,6881-6999 +r BurningMan PM+Vc/WRN+Unh9nDIqwZ0r0JC3A dUcJJjM2cylahxxyceMjY7n1ph8 2020-04-20 03:45:26 95.216.211.81 443 80 +a [2a01:4f9:c010:4dfa::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21300 +p reject 1-65535 +r wintermaerchen PNX3dmz46W/jFWeLDKxqW5mfxH0 R7+G3VUSXMnfTSolHNX/i8cBUmc 2020-04-19 19:30:56 50.7.151.47 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9710 +p reject 1-65535 +r 7023b1766263 PN/7d+jrhOROQl4Cc8GiYCKv5xo OH8x51C0ADxdNSuu/t4beMrOK7A 2020-04-20 06:43:59 51.81.254.30 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20100 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r modupe POkFJ9VxIpa1jn63zVf304jSX7s xqZQs1SeMd5UfL4V8hVBNk2goxc 2020-04-19 23:16:39 104.238.188.98 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=36800 +p reject 1-65535 +r OnionRaspberrySoup POpWuBdFXhPEsGPn0+dybChvfJs hiOOS+tHk2AbaPg/6k+9gfAkLgA 2020-04-20 02:06:33 82.197.215.30 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8600 +p reject 1-65535 +r snap277 POuhg/Qle2NAAly9ubVy4uvqSW4 fh07+7+ov6CfTYMXVWw+xgPX88o 2020-04-20 12:12:08 178.156.17.10 36811 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 +p reject 1-65535 +r FlexibleSdness PO9oNzrbd9cMKxfoCNWwGk4VZ6c e0hn0UqS5YHBXgwoCzm8U+dFDKU 2020-04-19 23:30:53 47.56.198.152 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=185 +p reject 1-65535 +r zesaver PPhtN3qK1vv04/9hoDqqXY/wB+I OFIqQ3dTxEzbpoc9w6owjroTY7E 2020-04-19 23:05:55 46.119.200.109 59031 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1990 +p reject 1-65535 +r ULayerButler PPrQeY/107mU9AuJcdSnnYQWWg0 H03umbdBZ5m8E5jn/FlumI1LDYc 2020-04-20 07:42:55 45.11.18.120 443 80 +a [2a01:367:c1f2::704]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r smell PP/A7I7yYnN8v2aArghAO5EREDQ YHIwVW8QhaftDDmBtEXEdPWF3iU 2020-04-20 02:03:38 137.74.153.5 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5500 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r blazeit PSJqXIHF5btoLJvx01VL5tXD8Uk E9JjyQfvl6o7sNBShqw2cy7tQu8 2020-04-20 11:07:06 89.163.145.239 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15700 +p reject 1-65535 +r lukmiTorHq PTZYeKJEbUCxNa63F74MmoQz/js LA0Fi/zk72cn4BaX8hHLBsBRjdk 2020-04-19 20:25:31 178.0.91.187 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63 +p reject 1-65535 +r TorZabehlice PV1heMRFN+NpKFOzRDhfZXKlV2c jXWaNMIHfMkHCIgTNE1D2K5JT4Y 2020-04-20 11:37:12 87.236.195.253 143 9030 +a [2a01:5f0:c001:107:2f::]:143 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p reject 1-65535 +r fs0cietyRO PWBUH5IVH5ZaiWNenheBY+wXOmM ZOoJ1MeGDlva7AT7eqGDroTG4gg 2020-04-20 03:22:41 193.148.69.35 53 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=5160 +p reject 1-65535 +r elektrobier2 PWFd75fzh2MfUCAfr6bntn/fP+8 yDJkEPz1WdHAZ6kccDYfUzLdC1E 2020-04-20 10:33:24 46.165.254.40 8000 0 +s Fast Running Stable Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r jackyes PWNvudJOp4HDwnZsBRBkxsocDZY wxMXiQnJb5FaKsRsSsdrBJ2bLKw 2020-04-20 04:20:29 94.140.114.177 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3490 +p reject 1-65535 +r marvin PWx3bovp6K5dBZFZQReZnjxUmMg fb6TFnOBuR3IVSSnVUDVD5ggeFw 2020-04-19 23:07:52 62.4.15.84 443 80 +a [2001:bc8:3f76:2301::84]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15700 +p reject 1-65535 +r JonDoeLastsGlitches PXM5ihNmMEtj0xQ4IBKfe/7Uojw xToKRJOw7tnX9oHm+87QHOhCU+A 2020-04-20 04:48:47 91.65.216.178 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53 +p reject 1-65535 +r FallingoutofFour PXarJ6wvQxji/ASQr55o9ExdWHY MrUFDEYFrzI3gvzgsbBPdj4oFfg 2020-04-19 20:10:23 159.89.162.77 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=909 +p reject 1-65535 +r StarbucksBathroom PXufr5atYD1anDjlQ02RMGghILA 8ucp2fsMxVdWDB5F9P/UqqcFPus 2020-04-20 03:48:14 68.183.141.111 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31 +p reject 1-65535 +r smell PX3stG9+IFatDJQbUmqb39FaP/o 4GUpmDyFTDQTyWC+ETOWZ1PkWO0 2020-04-20 06:30:23 51.178.185.234 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20300 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Torstrasse PYeU3xHJfRc9rKi9JPnFCdL+C3A MrnbI6GdMZNEAcTQqdGoWWvOz2Q 2020-04-20 11:32:40 51.15.252.175 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r Penguin PZijdOljaDtOjZnJhfudz9bqeqA fJbiWeJusm0agPtq4+0HPs0ylRk 2020-04-19 21:08:06 94.16.114.153 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4210 +p reject 1-65535 +r megatot PZzoA5m2jAE3f+xCOV45m57Rbhg yMhtd96ZMxyBJwOMZdoCR9OZRIU 2020-04-19 21:07:45 185.165.242.5 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49000 +p reject 1-65535 +r summerisle PaVGAOYV5a+EHAP7gdcyFzVWK1s V31Y29dHThxuD3IKW3dSTum/ATw 2020-04-19 19:35:51 82.71.25.129 9001 0 +a [2a02:8010:60c0::f3]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=164 +p reject 1-65535 +r GoAwayDAN PamPRuIEFCpeF9/hlR1HNOdD2nA FhN8kEJqJcswzNViDzAQU+bV9Vk 2020-04-20 06:44:40 89.74.97.7 9001 0 +s Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16 +p reject 1-65535 +r PorchPirate3 PaqRQ2QBuNSaOApSI9g609Zhg7M pajjlsErZMot4VtJMixRsTlfSBs 2020-04-20 12:36:34 178.175.138.60 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25300 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Fussy PcdIwt/x+OnaVia7PLqv8x1wbBA kTtzufo0ggsV5NRu0EBSrhsNrHA 2020-04-20 03:37:37 51.15.109.221 26173 5029 +a [2001:bc8:4734:6907::1]:42612 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27400 +p reject 1-65535 +r TykRelay04 PcqVWH+Rfz8hK1mHMbl724W/7pI Gf0I3OHy2YLPsSS3A8Wsqm82vgI 2020-04-20 00:33:37 88.198.128.218 443 80 +a [2a01:4f8:13a:890:88:198:128:218]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64000 +p reject 1-65535 +r snap277 Pc2ZzxKCtSTO/2xBRkfAjzMsXsg /BlTddySCUpFIiI9fMl48We4Ntc 2020-04-20 07:42:46 81.53.7.1 36279 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2970 +p reject 1-65535 +r FlorzsNode Pd0ejsq5ue54/VyPbvg22/+61d4 3bQppudFWoRR5zFy6Ii2LoKI/BU 2020-04-20 03:00:52 149.154.159.172 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p reject 1-65535 +r sonsorolDotNet PeVnwTUMDoWMYUeuywbqmz6vMmE ErMsRBh5/zzoo/BPG8Vay3pa3A4 2020-04-20 06:31:05 71.174.105.126 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3450 +p accept 21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r Instigater PefnRJ6NIR7AVYhwojDAGowec28 kxVVkpRYXBLnNyVz9Hpwzxerav8 2020-04-20 03:53:55 91.105.203.93 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13300 +p reject 1-65535 +r OhLordy Peuc7qOtoSGam5N9rd9STCuX7dA PxGjdI0rhyYybzQfaAA0RF7i7b0 2020-04-20 00:49:26 178.17.171.201 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r DerRaffke PfKMaiH58GP6FkD3NnvoFDgW1A8 yjyCCidMFqSpFQINm9FtlGVwjD4 2020-04-19 23:21:10 130.180.111.194 9010 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1750 +p reject 1-65535 +r Anyuta Pga0C84nsEqvASqFXeH516WUm9A e36v57Qd91bbn0tVOjtD3tMNtms 2020-04-19 19:59:08 94.140.116.170 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5270 +p reject 1-65535 +r Unnamed PgmezYHYWT0wDJHI8qvd3u+DwNY JjqvM40GYewQV7vzuwdkAHrN88I 2020-04-20 10:30:04 51.15.235.73 9000 9001 +a [2001:bc8:4400:2c00::c:b09]:9000 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18800 +p reject 1-65535 +r Kudymyr PhLj11QBLTDCeHptJS5hmRuXmOA DTF3Vg9QxXRPsIoDkZ4j8i0WJiI 2020-04-19 19:33:51 167.172.252.56 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=1940 +p reject 1-65535 +r hotzenplotz PhPi64fM9WkFZO4z6fn5+Asin7s HpdyYHnzIYopZP1EH8Dd1/eDd1k 2020-04-20 03:21:33 31.28.168.174 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p reject 1-65535 +r Unnamed Phj+ur2UzcmGQWyVffMj/t6Xor0 +MiPS6/4KL5TFmXERkCOVfGTkow 2020-04-20 12:06:57 62.210.99.238 39819 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=498 +p reject 1-65535 +r AsukaWATARAI PhpTCqRDlSYdQliZztOnOsTqun0 7CWhnir2IYJIFCkf1dT/9S6PZuY 2020-04-20 11:02:47 160.16.228.57 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=47 +p reject 1-65535 +r judas PiyTO+VFhcdg/W0vP6ejPjc6cUU hXgnP2dD0fk8EZvpv55TJx7XG7s 2020-04-20 01:59:48 46.163.76.170 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5 +p reject 1-65535 +r neyaoz PjAFpLQ/r84HD/4Z1TB27CLuCUQ goMX6PHzVT3RcDRyWc/AWrbywDc 2020-04-19 20:20:03 174.138.44.242 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=358 +p reject 1-65535 +r serpent Pjr6+e7l2F8e7WRKds39c/eJHno 5A8J6+OfN0NO9OZh1BP3DnmScKA 2020-04-20 02:59:33 136.168.201.153 9001 0 +s Running Stable Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=27 +p reject 1-65535 +r RelayFoxEarsTK PlCKR97UzUGCoNhwD8wubkjB9ko F/xtv8tXiEjDRYqml9z1+OneZRc 2020-04-19 21:33:27 185.132.75.125 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14100 +p reject 1-65535 +r RSF12thMarch PlDLypiiD2N7xFUf1PEy0GLbmlE CLxOdJbGZX6tuCPW3Fhc4vp+eTc 2020-04-19 21:32:08 185.220.102.7 80 0 +a [2a0b:f4c1::7]:80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=73500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed PlPTl52wfv1zZmHJNKHe0UEntoQ shSmKweJTa4E2DIYz2p3ZFGv+N8 2020-04-20 03:38:33 217.79.179.177 9001 9030 +a [2001:4ba0:fff9:131:6c4f::90d3]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=76200 +p reject 1-65535 +r snap277 PlrZONnZ3Rdq2iCCWPFq5NAoTuw EpIMW3DucWhMSU425FfDLq9aqg0 2020-04-20 05:54:29 73.14.254.96 38627 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r RLDeathrasher Pl5J2nmT4w85DOGKmLT9Kzu9j1c ZHHefpTcjgARxGgYoD3jsgZVqJ8 2020-04-19 20:21:06 176.92.45.102 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=677 +p reject 1-65535 +r gudegast PmCpAQ4r+Ok4f6tsP5OaKdprsdg 7T7xYnO96OUnl4Df3bMO6c96uyU 2020-04-19 19:41:36 210.140.10.24 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p accept 22-23,43,53,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233 +r baphomet PohzeXmKm2J5P8LghGnGqS4dvM4 f7gdpcufzz7ShaZ9d/Jh6dRcsiM 2020-04-20 12:30:28 85.214.244.13 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=77 +p accept 43,53,88,194,465,873,993,995,1194,5222,8000,8443,9418 +r Technoprenerd PoqRwecUJht0ve7mxp9jB/Gs6rM Y3Bfp47nHPLNbdWtun3PZuzdJ5w 2020-04-20 00:58:39 212.182.169.185 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r Unnamed PpV9hp4N2Cn6JJ4i2KdBqjC5OMI PYXD3f+XipAs1DF5iS95Ecvcl3c 2020-04-20 02:47:28 81.95.191.168 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=221 +p reject 1-65535 +r GolfGoulag Pqx7mYPy2z0USg50oPeyaBF2Qvk OJPDKkM161irorpMEk2FvCB4prI 2020-04-20 01:41:18 178.17.171.210 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15500 +p accept 43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r timequake PsIVqGlUriu7TBxwINpbl7Ipshc bkNUqIWcf0w+SMd4iRm4TZvM2Dc 2020-04-20 01:18:24 85.212.133.191 5169 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3820 +p reject 1-65535 +r twoface Pt0AJF2TZkozpyS6N3FQ5VMe0DM /mhhZVjzNyLCugRHNm+YIYtp4t4 2020-04-19 23:03:14 185.8.63.38 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p reject 1-65535 +r bliblibli1 Pu63Ah2XTTi22XvvtV5eSFUaj+o NlJ9PkVZR8/NzDSSrHupT6LmbSw 2020-04-20 04:34:57 185.146.228.130 8084 8085 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37100 +p reject 1-65535 +r Tor4eevooroh PvN1/jRk1BuDbJSdIZUivE6D5ts QFxYZRu8dnakTjngbIDZWE0x5eQ 2020-04-20 07:40:19 168.62.201.153 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=862 +p reject 1-65535 +r joszef PwZbsLAvsjA+FEOD0WxHp97XWuc 5dIlWg1S5EBBpV+YuVQgo7Qprqw 2020-04-19 19:08:25 195.154.209.91 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42800 +p reject 1-65535 +r NYCBUG1 Pwkphum4fT/aCbcfo6YCN4KFx3o r8ybxSLPj0spmF1LYJa0iuo/BHQ 2020-04-19 22:27:40 66.111.2.16 9001 9030 +a [2610:1c0:0:5::16]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r niftywoodlemming PxKftx6ysBm0dAOlVS6y1A5TafI PXt1IlxcZBzix5RlwzPE3icn8Yw 2020-04-19 20:27:23 185.220.101.30 10030 20030 +a [2a0b:f4c2::30]:10030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 22,25 +r pinetorrey PxWBVZUisnvRNC8qOgAi8nP6k9Y SItyqOmfteL8wcS1rfxcg+eN+P0 2020-04-20 11:17:29 45.79.199.67 9001 9030 +a [2600:3c02::f03c:91ff:fe4c:5613]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19700 +p reject 1-65535 +r bahbahbahtortortor Pzayjb+heQj74jZctvQqn4RQxFM X9IEE6FY3FF0rTs9yh9S/axnJNk 2020-04-20 05:21:44 67.183.239.1 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=79 +p reject 1-65535 +r TorresDesNodes Pz6RHWT43tcSCNYUeCq+1B9Neg0 PX23UA7PCmqFKbQxlJ9hzqAZ4to 2020-04-20 11:05:27 95.217.22.2 443 0 +a [2a01:4f9:c010:65db::1]:443 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p reject 1-65535 +r arbitraryTessa2 P0PQWEomE8nbYxOC/0htxrleocg 7FxTjeNib12uCuK9y9elBAJigjA 2020-04-19 23:23:19 95.216.19.206 443 80 +a [2a01:4f9:2a:1430::3]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40700 +p reject 1-65535 +r 0x616e6f6e P1DRHeVcAouPPvwnK7HNkTjB+aQ 1Uxt9N/aG+VUAMrlXQRjGqpO6fs 2020-04-19 21:05:47 178.17.171.78 443 80 +a [2a00:1dc0:caff:f6::28ad]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r PIAzrhexit P2LwXoWdf5iwhvcCox93FNVm5Jo yKPBTyltiF7g/vP/al054LAh4jQ 2020-04-19 21:16:40 195.206.105.217 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=138000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Eyjafjallajoekull P2V2at4GfZ0Ikg47dNq5BA7dJrI 8X9VUpZLYPjn9N7128qi+ZZiGK0 2020-04-20 07:56:48 195.154.235.190 80 443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=46000 +p reject 1-65535 +r KingJasperTheGreat P32wFab+tK/1KVJlYF5qq+WPcuw FKcNiHWp79oOh6pCRlItGM3V/Xk 2020-04-19 19:28:55 93.211.84.117 61461 61462 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=160 +p reject 1-65535 +r prentace P5IsjN7VrOGBYSkUO4FQMbPA5+U zU8fI7r6y4Su0BvpQ2bQD2GcuWs 2020-04-20 10:07:07 115.146.127.224 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74 +p reject 1-65535 +r PrivacySvcsExitBA P6BNr7OcjC07s1aMS3+EGUaR2cs 5MKcrIb8AXEO5ScqFhEAJXZ25x0 2020-04-20 00:40:02 208.68.7.129 443 80 +a [2620:6e:a009:705:face:b00c:15:bad]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p accept 22,53,80,443,587,993,8333,18333,50002 +r alqnetwork P6k9QemnxMR7d8DX9heZm21dC2I aHQeX0Lm/Jrek82AgzIyEUq5ZrU 2020-04-19 19:21:28 191.252.204.98 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=234 +p reject 1-65535 +r Unnamed P63i69P5h/FandGsRCI9OSsNiaI DULtVQhJHXQK9NxZoX1rf3pKIWI 2020-04-20 02:39:14 5.2.72.243 40000 0 +a [2a04:52c0:101:91d::c2b6]:40000 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2450 +p reject 1-65535 +r wagon P8J/zszkJIhA+5/0Op4UoKY7aLg 7XqlAmNgOjYbpLbnoyZGx5i9IAs 2020-04-20 08:48:14 45.141.157.226 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed P8SN7Xgeo69kug3+eAnEhO15h18 uymTHRsv2FF2ESewRyZj4fgTf7M 2020-04-20 10:17:02 51.68.199.110 9001 9030 +a [2001:41d0:801:2000::1bf4]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7230 +p reject 1-65535 +r SemaTorRelay01 P+GqFjRF3A4Gd7Uif1B5B8SHKjA vySeaB8WkMbHkhj18yOXc9lowFU 2020-04-20 03:46:58 152.115.46.132 443 80 +a [2a02:188:5207:0:152:115:46:132]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p reject 1-65535 +r remedy P+v7akkdMMrMLCmV7bQXF6b5TpU bU0CbHHojXwtacR2Cwf3D8VfJfE 2020-04-20 07:09:41 212.16.170.158 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r 19dotrs P/DdWsE3E9MZ4JxA6T4NJnF7hR0 G7scq2XHO2ThRKgaqcQ0DR+ypo4 2020-04-20 09:35:53 176.9.208.12 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r Unnamed P/37WponjHwwN0VgbbW2j8W5+t8 tdqRnPicVcp6cggMopd9fM5cUo8 2020-04-20 07:23:29 37.191.198.94 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9040 +p reject 1-65535 +r crypt0Dude01 QAwFNiPzbFw9HPxz8audpuJN7rc jH3h1AfqWX6VQzGFYIvT1CvLJsk 2020-04-20 03:26:01 5.9.234.149 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r explodingkittens QA5s9HQoVhMt3GVw1ls2zq5yanc kyCe6+JlotpGN2L0BfJORz0Noio 2020-04-20 02:30:22 202.182.113.80 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p reject 1-65535 +r angeltest26 QBCP36QO2wE/cpHztNo9QS7Tpe8 +wxpuOwzfeyhnED3+OPjvwh91VI 2020-04-19 19:17:21 89.223.100.121 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3080 +p reject 1-65535 +r ramhorn QBHhuw5bmiKvZltVO//d4ipRexY 6Stxxmm8Fmv1Ty8WDOtWLaBVnBA 2020-04-19 23:41:03 194.88.105.30 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 1-65535 +r angeltest24 QBpmdHcTA4zu9u0oyK/rcFcO68w So5UQg7RXgeAPJ/tiZp1EKvW2i0 2020-04-19 22:28:42 2.56.241.243 443 9030 +a [2a00:b700:2::1:27d]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=881 +p reject 1-65535 +r niftyeuropeanrabbit QDFGBoOungUS02IMJ1jZh1isbJM wE9JjD393Z/cgLMqglEEu9Lp9g4 2020-04-20 00:14:39 185.220.101.141 1141 2141 +a [2a0b:f4c2:1::141]:1141 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68000 +p reject 22,25 +r snap277 QDJUWBYNzz/Fwdw47MYEuz67Lh0 /x0Z9hIfRqG1SNj/wVMkzohzI5o 2020-04-20 10:36:41 77.132.158.33 35343 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r Assange023gr2 QFXN3/ez+ealBEdgmjAUdTqC6yY 7eRZqBD4NtYiljNr29E5J+VAZcE 2020-04-20 03:01:26 185.4.134.104 9201 9211 +a [2a02:c500:2:110::2d49]:9201 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r exit QF81oQVWYR+4HKPlwBvxpU8RvUw Gw15HpdhwI4RM+eOfcpGFNv7lQc 2020-04-19 23:54:00 107.189.10.93 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r thatRelay QGC+g45H/f/+sEXK9mMKxmOuKtI hDxoqKnc2PsRTAsJFld0+NFy498 2020-04-20 11:15:40 85.26.114.26 1003 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1130 +p reject 1-65535 +r TorExitRomania QGHFU8qIAhuDAvCBQ2UHCq5hcnA sSMf62PAcB5G6OlEnKHR47+flt4 2020-04-20 00:56:09 185.100.85.101 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7380 +p reject 22,25,135-139,445,465,563,587,1214,4661-4666,6346-6429,6699,6881-6999 +r sqrrm QGeIqRCMFPEAZ755YJhesuyCJNI hyKCcDeBtpaOkCnCZmpiRH3EgCw 2020-04-19 20:55:05 185.25.51.202 9000 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5650 +p reject 1-65535 +r tototoararar QHajXYPf+E51Y5N4/faP7zMC2Os hVO4fhkwpQzLsKKyxIjYzfAKwdY 2020-04-20 04:00:08 45.76.147.227 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=70 +p reject 1-65535 +r sereya QIUKqVW8GEthfxLBysRBSqMhgFQ xfE57AI8/d/LefxAufI0PPz6BeE 2020-04-19 22:39:06 51.38.80.214 9001 9030 +a [2001:41d0:801:2000::152d]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2890 +p reject 1-65535 +r ZogZog43 QImvxo88vqjRNfXXEQ2qihTzkos f6kOX7b01x7VNUd/EE4Zr6lMWzw 2020-04-19 19:15:23 90.46.62.49 9005 9034 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3990 +p reject 1-65535 +r arighttospeak QJnepoJope0mEHjeFzSJEzShRvk q/4PMKbtYRP+TYwP1uSvgrYhQQw 2020-04-19 21:27:06 82.161.50.30 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3540 +p reject 1-65535 +r elektrobier3 QKYNHx6K++0i/LMLP74uJ1oUz5k noV7DEhNCxt8ZrLQWVVJ+lLhXZc 2020-04-20 07:01:00 46.165.221.207 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22100 +p reject 1-65535 +r snap277 QLxYQ5drCoPmgXAdv/1pjNUS+uk 4enZwzRD/PVlG2WitoL4TIG5x98 2020-04-19 23:31:06 24.155.206.170 35697 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1000 +p reject 1-65535 +r Jans1 QMdz2fKxYUPNsq22Yd3GuxLvPiw 5AMvgvL7J9mHsCojrlQnnAB8W1g 2020-04-19 18:35:22 212.51.149.23 9071 9081 +s Fast HSDir Running Stable StaleDesc V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=646 +p reject 1-65535 +r chocolaterain QM3pNrBLRXOkciM5YAZEPKXqyEU faj3jjWSnIAfGU3Ka2Pp0JnOzQw 2020-04-19 21:19:40 176.9.53.202 8000 9090 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=94000 +p reject 1-65535 +r Unnamed QNJz/je1ZK4ihi98cgkBwPCCy04 fJ7qfkG+74tUL1Y9Iyj88Lt5bwY 2020-04-20 11:11:14 51.83.171.236 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed QNPM7uW5viEoaEwV5XaY1Lodgm0 zcE8HvNdOMi5d+TUA7fz3tNKFws 2020-04-19 22:53:32 148.251.211.211 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17 +p reject 1-65535 +r SedanUK QNoCgeXbwpJX+xuU2Y6a9YZNor4 39gvVj5xpv8dHeBWKBQBG1+ETow 2020-04-20 04:24:55 93.104.163.243 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57 +p reject 1-65535 +r Unnamed QN01bo88U/qSUbVhz5VjAnkar/U q9NyVpPrUvcgqZ6BuSwneqEySew 2020-04-20 07:54:17 89.163.224.250 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21100 +p reject 1-65535 +r Quintex12 QOfWzlCF5M3aMdUaKdFFfrU/Eq0 fi+5XoVyzDx3EtjSzoZJLUD0LMc 2020-04-20 11:48:26 199.249.230.102 443 80 +a [2620:7:6001::102]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15600 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r fennee QPrkVAz0wSaxsVwPXgSP29ZuLYg bv2Ho8OMb98nQ0GREM+PqPHQo0U 2020-04-20 01:17:55 50.7.178.34 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=51 +p reject 1-65535 +r W0LFF QQEY6HTSJj8c3NVn+Bh1qOOLKzw 6tix/wzjrMb7GQBefiGfHSVi8R4 2020-04-20 09:11:41 176.9.75.110 443 80 +a [2a01:4f8:150:7227:9000::10]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13200 +p reject 1-65535 +r Unnamed QSq51qdh7K22DX6k8ss4nAr0Lz8 cFKRRkKTDPSWQ/meIHkaOaR+984 2020-04-19 23:27:32 185.236.202.58 60257 32476 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=95 +p reject 1-65535 +r MCdrKNe QSuqTeRNp9FFg95jzrPfiYNeasg Ye6RG9l6Q+ZSrdGBO05p7Nkoyn0 2020-04-20 05:00:44 37.49.107.200 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r rubricatus QTMX7eX6iCMY9HuHUlMacm177wg dIVmlhmDEPO4yKlKz9sKugnFBHI 2020-04-19 20:02:49 185.246.128.130 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=229 +p reject 1-65535 +r john316 QTw5SYYWCcjkH2+bCDOV62qnjTU GN1apWXCCfz+pgEWGtBVjAoh5Pw 2020-04-19 21:35:51 209.141.52.11 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1540 +p reject 1-65535 +r FissionMasq05 QUJ0SMQWQoMhMMLCmvH+rDs+7TU 34qg2VrPusAZQcx4MBBYtb0vRIM 2020-04-20 11:55:08 185.213.155.172 5753 6068 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nonanet02 QUOF4LqItveHDDiaYIGbsGMI6NA 7dwtxHwg4yHX6LMcxZTRJBy4u1M 2020-04-20 11:39:01 198.251.83.248 443 80 +a [2605:6400:10:7ad::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9780 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed QUdEfzMRvMpB5YQ0c8Suo96SlDY i0JmpiBplr8hDOvhkvvd3SniCFA 2020-04-20 04:49:54 131.153.96.218 58751 60763 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=100 +p reject 1-65535 +r fsociety QVB/VsigNDv0aHGYx+kN8utxUdU XUgIZ3wveq5u509bg5TYTccz14s 2020-04-20 03:29:43 27.133.132.9 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=635 +p reject 1-65535 +r jupitera QVObj9VflNxgF6Kc3MYjl38RijA dbn7UqcgWbmSN0rI6tcXAYXkHZA 2020-04-19 23:52:52 149.154.152.121 7654 7653 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=821 +p reject 1-65535 +r snap277 QWNXgeSa0VWPh2pRLywccGCSqFY 9lNAZ8y64dvPzXWJf2fejgtQFuY 2020-04-20 05:21:47 179.253.32.241 46699 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r Unnamed QY/SQzNyceraPT4bFTXnCucyRGQ cXsMO6L4AWO/wKy7TWbvRR/p/QU 2020-04-20 10:42:24 91.219.236.122 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2460 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed QZf0gbKtID6hSB7to7Wk3GsPJ2U p11A2Ci/9P9A/G7pn7sy5ZBCwqw 2020-04-19 22:55:48 144.76.119.9 15077 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48 +p reject 1-65535 +r rofltor02 QaPBYmnHtj2263QdvdtOH1hrFZI NA+FzrN9M50vyGhfvSuvotRfBOM 2020-04-20 10:24:52 195.191.81.7 9001 9030 +a [2a00:1908:fffc:ffff:c0a6:ccff:fe62:e1a1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r Unnamed Qa9CtL9wASRk4TvMZiETZycNVe8 zDl0HMsYSsArwumQp8XpMi1OavI 2020-04-20 09:30:19 45.12.109.112 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4000 +p reject 1-65535 +r comnetkyberpuhe QdL22GbnY4E4z58oKigPlr0CDSU cEO8kLmblZVMYxm7n5jboAw6AuM 2020-04-20 12:28:25 195.148.124.199 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r hyp3rion QeBB7GdmIv/uWfVrx1uZzQ1H9lM qBD1T61qUr1mgfngNmpczVaofAk 2020-04-19 21:19:48 95.216.98.55 143 0 +a [2a01:4f9:2b:1148::]:143 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52100 +p reject 1-65535 +r snap277 QebEqPMvVJgVoi9MjM9sIc/bOPQ waNP2cOVkXeO8rUcVKZRFt+l3Qs 2020-04-20 08:19:23 37.144.31.112 41929 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2100 +p reject 1-65535 +r RNVR217 Qe7Ez6AeiYJkPxrzzYQxUynStY4 ctiRXldJiGpYGYYYQcZrR2pStoQ 2020-04-20 08:38:55 95.211.147.99 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=53900 +p reject 1-65535 +r Supergrundrecht QfB3MSB3QoYNQ6xCb7ri85R70co WfTAQ7bbJ0ng1SEkcoZkA4oo1iA 2020-04-19 21:34:14 87.118.110.113 465 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.2-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r Unnamed QfOf5015uS+EHzikBYYL6ogjnTA Vb9u97DL8+blrZ9SX7Irg2l8iss 2020-04-20 10:01:52 78.92.50.128 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 1-65535 +r snap277 QfYuqHmlxbUSgunHptXoOCws368 acqs7SoQvrYezbx8ia0EH62ivkM 2020-04-20 07:11:49 86.211.150.72 36169 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3 +p reject 1-65535 +r relay QfZVgnPLSseYrqJd9NW+CynVCCM TZ3BJrhojYuZysaObsVztnOk6tU 2020-04-20 12:15:17 64.227.73.144 9001 9030 +a [2a03:b0c0:2:f0::152:c001]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=83100 +p reject 1-65535 +r GDOSGRELAY01 QgH/8Lqx3832+6cQriuGCFngal8 O3vkL7zJ+MXun216xt635Ezfq2I 2020-04-20 04:13:29 68.183.230.130 443 0 +a [2400:6180:0:d1::67f:a001]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=760 +p reject 1-65535 +r arnecloud Qh4dt8Ln+lZUhGRgwTY66sECraY d4fwNbC4Yn0zIAw/bIa1Y14VYHU 2020-04-19 19:52:07 185.194.143.84 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54400 +p reject 1-65535 +r yuicat3 Qkqcw3pdCdoKkQzYs/OzdSQxhyQ CjOTy0ldrZkyhAx8c3KUx8Fi7hM 2020-04-20 01:41:40 71.19.148.20 8081 8082 +a [2605:2700:0:2:a800:ff:fe64:64ea]:8081 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r RunningOnFumes2 Qkv4aSfoDZFlibsSJIvUaLtHBoQ LhRz0Bke7DAMBcBUv+hw5mp74Us 2020-04-20 00:50:44 217.12.221.131 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2180 +p accept 53,80,443 +r torreyamos Qlg1NwwfvheMIctTx2Zy8SveCRo bGZxLpTXBhQ3fVn8hotqUDv99Us 2020-04-20 04:46:04 178.79.169.193 9001 9030 +a [2a01:7e00::f03c:91ff:fed2:e593]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=102000 +p reject 1-65535 +r farroni Ql41jpT7U+fxGvLZq2DeJfU0uho F0m96KORGvvlB8eeOf8JkjZe09s 2020-04-20 12:36:12 46.19.143.139 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11400 +p reject 1-65535 +r AccessNow000 QnPm0WLtJxehz0IHolQATNP1MHs aBlALqqUsYJrgyqE3tBlvMobdLQ 2020-04-20 09:33:38 176.10.99.200 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50400 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r loxodonta Qn3tqijTlnLz2bdxQXDHJGNGcfM 3hFbYWwZKm16A1RWZ60hPOuetRY 2020-04-20 12:31:00 212.232.29.101 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=139 +p reject 1-65535 +r Grga QoBogRfLM+LRoHzYTdrTs/yWha8 LgYqJN8BxoQZeN6+8mNPPLdyx1E 2020-04-20 05:39:26 193.77.182.57 443 88 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1950 +p reject 1-65535 +r FuYoRoKoNa QocCP5WVv0ZeNUKaBFjJJOz/IOE 9D95DD+cAbtTZvADkS6i0yEmbvA 2020-04-20 06:57:45 2.93.140.57 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p reject 1-65535 +r Unnamed Qo34NyX08jCdIF3rNovrBPLgjoQ Hj5UTkuDspYHYT42361dmKnhVOA 2020-04-20 08:08:56 185.104.185.170 23098 27893 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1070 +p reject 1-65535 +r ididnteditheconfig Qp19h33ctkXuIe5FLWDzZOVijnQ FjUb/Q3hH2IItQSc5x8wdqGNfPg 2020-04-20 10:06:11 50.5.47.96 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r googlerelay QqvULflfmg3VlOS2TbzkFdFlJig JzmDRGEZwU+aqn0WETj2CIjJMKA 2020-04-20 03:40:36 35.192.188.190 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r ENiGMA QrT1LFsR5NOYVfZUlVQlsNWgWYs LK17y9IWMjQMgqOP/UA9xOBzWds 2020-04-20 06:07:57 5.9.121.207 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130000 +p reject 1-65535 +r Unnamed QsbqYO8Ws6H3tC3vwIhwXw/4CW4 vyURQM6kiHNdUfCiOSs9BdtrFrU 2020-04-20 12:33:55 167.114.92.57 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r thardes2 Qsu137OIAzRSNXQmzfdFwrzw71k lFn3OM9532NaWNcZubu2siR3qdg 2020-04-20 12:15:42 79.203.127.89 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=99 +p reject 1-65535 +r poussin QtWDNTgbybuMntmNOQEJ63Tby8Q fdr0MXjG6BZU2hdE59c3A/Qz/Fk 2020-04-20 02:47:48 213.169.148.151 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2300 +p reject 1-65535 +r RosaLuxemburg QutVbiWjwzojiraK/QQyc9D8a0E u0zgw5Jz98uWHLnq7lvK3IZD4oI 2020-04-20 12:04:06 149.202.238.204 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,991-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r CalyxInstitute10 Qu2R3Tdo9qKhlNCUp0Msvo2gBLE 87LOr49/Cz0qbz+8TrRhlT3oAMw 2020-04-20 10:31:25 162.247.73.192 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r lftor1 Qu/zUxlSp6+G9ntnSfDYx+XrK3A PFqASFgagMY56vkmJH08zRKNwHQ 2020-04-20 11:38:01 163.172.165.157 443 80 +a [2001:470:c85d:32:216:3eff:fe68:4e6d]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r viPool QvREKfH4zSXJiSuEXj/EN027BbE QtgZz/VfE+WzdnKvMD85Qm+oD0M 2020-04-19 22:52:19 201.38.246.66 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=150 +p reject 1-65535 +r ULayerMcGehee QwFjRNfkyy5z8onVfv+dZKyqgns KDuTz+aC0BPAnSRc6hOTVqPE184 2020-04-20 07:24:01 158.51.96.70 443 80 +a [2602:fea7:100::5b]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6700 +p reject 1-65535 +r TorOrDie4privacyNET QwKNAHHeBVGA2qgt4gC0L9ITHCM Y4twLP4ZNZjIuzmkoSvd2V+phFU 2020-04-20 04:07:44 37.157.255.114 9002 9031 +a [2001:4ba0:ffff:c4::3]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42700 +p reject 1-65535 +r Isidore QwZyzXFi+oirSdiRw4VneZ80YzM 8lesIfbtXsSZiU57bqQo3YVYFnA 2020-04-20 11:34:45 52.214.94.163 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19500 +p reject 1-65535 +r Squarty QxYn2PbowvwuBL3+Wu4z5KiBdEU xtfiqcOxz647g4005RlXez0wCiQ 2020-04-20 07:11:58 31.156.97.29 9010 9033 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2120 +p reject 1-65535 +r DataSmuggler QxfLG+0MYJCr67RUQKBArWg4PKw zFs1emhxjGWC0PnQ4ncI4np2FbE 2020-04-19 20:26:47 139.162.191.243 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=330 +p reject 1-65535 +r yuicat1 Qx6mn8QIm+QwSq7Dj+rovI+HEcU MPJy0xiWUvCf8cbxhCLHAsBA/38 2020-04-19 20:39:10 185.107.83.71 443 80 +a [2a00:1768:6001:16::71]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r QuintexAirVPN5 QyCfbVDGV6Vv55rwHKafnvGb0zg CQLb7GwaqQLr4v7ENUD2dw3ap7I 2020-04-20 11:14:06 199.249.230.116 443 80 +a [2620:7:6001::116]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15700 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r 4bdb654c9ded QyPzX3KQsxtyORudDzPSdOu/wHQ OfqlNAbYI1r0ZXGIWY4UnTG1W14 2020-04-20 07:29:31 51.81.253.210 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed QzdpTjaA147271ZUUFe3UYC4zso 2xtKiCxIBoMy6ONS1JCiI0+Rz00 2020-04-20 02:52:46 62.149.2.188 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p reject 1-65535 +r Unnamed QzhhsDF4HsMOxFva44qEk8J9CPs Dlf0VYlWi3ywMUvlBwEymmkxVh4 2020-04-20 02:24:38 192.110.160.146 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=690 +p reject 1-65535 +r devguardianproject Q0Cx1OkRhhn5fbDlTTjtkZ4Rx7k GzBFPOaAjonuT7y+Ze68Y7nlg5Q 2020-04-19 20:07:47 37.218.241.203 8443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=94 +p reject 1-65535 +r Unnamed Q06h+5C/45fOrcIv15qWXG2EuwE d0PN9v4aPvp43ea+R51NOaz6VP0 2020-04-20 03:18:34 96.255.209.36 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19 +p reject 1-65535 +r Mack Q1LViyZB6MF4d1Dv06B6iCJJZ6w KDr7X6XUJb7sRFArDDPY6df5NIM 2020-04-19 22:23:48 95.153.31.26 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9970 +p reject 1-65535 +r MCP Q1P2h+HRxqqXiThZIO6pKbyCVgM PTV+m8kJOAnc1ph5R6u745rMk2o 2020-04-20 10:46:47 67.241.69.119 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=390 +p reject 1-65535 +r snap277 Q2ShViFiJJIq/2sbI78nKNSLl7g 4IO3NF8f2vTKM+FYmCQTSkJkNX0 2020-04-20 06:26:56 70.189.27.13 34961 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=36 +p reject 1-65535 +r ShinKanSen Q2oY8ZwSEtYUK/1IlL3JxQJPdvQ qBDwe46YHDh2pNju+Z+tR3wsk58 2020-04-19 19:25:04 199.181.238.174 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r FIrelay Q3FDqOLYazvrd7ns1JrHfNNg+9o EqVd+asSdIX4pvemEU9q8xdIEs0 2020-04-20 07:38:43 37.228.129.53 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r Fission10 Q43JtrXFN10zK7M41+XBue9EiWA W8XtM0se0HCbIDIC7YW9vqFtrn4 2020-04-20 01:25:21 54.38.219.249 443 80 +a [2001:470:73f7::5]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35500 +p reject 1-65535 +r FreeAssange Q46MIUV2rxNIClUNRcEW9DMzwxk 9aev4d6Z/yH+7/J2bVDyv5XBtz0 2020-04-20 07:58:37 158.69.236.60 9001 0 +a [2607:5300:203:292f:8eca:a71f:80d1:1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9060 +p reject 1-65535 +r dolemite Q48+pMn7DbY/U3ejJxq1Q1+tfgQ oVEVy/5LIbat+oeYNSIIli3s3z8 2020-04-20 05:00:00 193.108.117.103 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6940 +p reject 1-65535 +r torrentor Q60zdnNbSiJ5IK0G0tm2lws8dd8 85+1dEUcBcov6DkgJkv/Zzjk7IQ 2020-04-20 08:41:50 78.94.74.236 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=250 +p reject 1-65535 +r DieYouRebelScum1 Q68kBxtACRFinVvJ/CDeM1+d/AA tfbmeIwsznlfmEGVFCL8fVAcgHY 2020-04-20 07:58:44 161.53.160.104 9090 9091 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2530 +p reject 1-65535 +r Homwer Q8g1NtrM0RD/EeBJqJAGT2+HvrI KkXCo/42yCIzAawWdYGk8j7XQ40 2020-04-20 10:05:59 144.76.91.46 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=102000 +p reject 1-65535 +r ahoyhoy Q93vBUPsEbdiMwWQjgu0jjcz8Io zRqjaE+ajFNwF/eBtQqOOAuQzLs 2020-04-20 03:58:09 51.15.89.20 9001 9030 +a [2001:bc8:4700:2500::b5d]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=995 +p reject 1-65535 +r Linode Q+GHuMc2H0fqlo7VOJQ1hl1/T+c 1HqcnYzE5XQc0LrmdAVX/KMPlWU 2020-04-19 22:54:44 158.174.102.213 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r sakurako Q/bu2GdKiPFYOV9P2g1rnWEZ3ow hI2HPiSilabY2TrvplsN/faGtvo 2020-04-19 23:33:01 193.218.118.150 443 0 +a [2a0f:e586:f:f::150]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2530 +p reject 1-65535 +r happytobeofservice Q/8iiZxoEfHwN11fFn5IoSDxQHw fcHAsn1oxQJwBCavYwIbc0myEGs 2020-04-20 10:13:21 167.99.170.96 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=48 +p reject 1-65535 +r fujiwara Q/8zRqP45O0n9jHclWxM2NYXPXo 9Hm0ifZvMAC0SowDzToxrdR6Kic 2020-04-20 04:01:01 195.154.107.12 9001 0 +a [2001:bc8:6005:126:ec4:7aff:fee4:6de2]:9050 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=92300 +p reject 1-65535 +r somerustyrelay293 RATfATyQvpJUjnMjlnCkkYJsyMI pAkCtpu8WFYB9GyewsDVVB3pkXE 2020-04-20 12:33:40 71.19.146.189 443 0 +s Exit Fast Running Stable Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r SamboTorRelay RAgFrG5giIC/er/HEpSrjRHhL2c NuHnnhBgbL8N6Mnuqw46bmHvKx8 2020-04-20 02:12:55 95.110.146.16 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2900 +p reject 1-65535 +r IamThePower RBlvIJNuEnFP8fD032h338aAdq8 ZRbM3npqX5hzR6WCCuapis8vdA0 2020-04-20 01:26:49 80.47.75.185 443 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16 +p reject 1-65535 +r dotfunc RCavWrUF/TIq6O/KZQ7pRG7WLgo 2kaoFQ6wDwYGPxRn/BPgGPd50cg 2020-04-19 20:22:23 85.24.183.236 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=978 +p reject 1-65535 +r tor4ever20 RDEUqGc5J0Nrw/j8/m4IsWsdX4Y faNFLwieEdQIwZQnAhoBiftayac 2020-04-20 12:49:10 45.62.236.117 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p reject 1-65535 +r Atomsk RDVONen3+XrydobQOw1ZFobjU5Q gsjOP9P1vYvZU492D6Yd6gUcJ5I 2020-04-19 23:34:21 51.15.115.217 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28000 +p reject 1-65535 +r MonsterEdgeRangers RElrGMaDVq86WKytg1Qpw3uUMu0 gvBg/gwzCoN9tWv/E3PrhRKnmGM 2020-04-20 09:07:26 91.148.141.117 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9870 +p reject 1-65535 +r snap277 RFDPUL5xfTdBgP/F/+FrERDVxug zwnFN+sX8PA86JG2jrSewZLyAxI 2020-04-20 07:46:49 109.87.32.69 34475 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3740 +p reject 1-65535 +r Shakira RFF8ct0Mcgbitun+ORdAauivMZM 6BxEuhLVl4d7qLW/YmltIfCP0hU 2020-04-20 10:37:41 217.115.127.34 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4230 +p reject 1-65535 +r Feidhlim2 RF2JHObHrD2A4e3KYfkh06bpHMU 7UDlfVm1fdLiBPNZ3NSMkvrJlzI 2020-04-20 00:49:23 188.192.138.7 9031 9032 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2790 +p reject 1-65535 +r superheld RGn0Qf2rJWV1JisBO0TUSzfk3Is a26tgrH3VraaiE45Y4hhw6umdTg 2020-04-20 07:57:18 212.162.42.186 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2560 +p reject 1-65535 +r RedLightDistrict RHMLJFAhO8Pi2qSFRFjRNPBkT/I okUWzYS4I1C8QxbwM/I+17/sxkw 2020-04-20 03:00:38 185.181.229.77 9001 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2860 +p reject 1-65535 +r m0rix RHok80AsR3TYnnqtLYdtC/ZOMmc g7j+Ug8nJUE5lMVUTup/cm78zWk 2020-04-20 06:59:19 62.171.169.46 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9450 +p reject 1-65535 +r Unnamed RIFQQz/+HjbtuMcoxV80ummc2W4 F4Ed/wqWR42OuR81xf1mdWks5xE 2020-04-19 20:24:04 185.243.112.85 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=311 +p reject 1-65535 +r beingthere2 RIMJeGf2REUz6qotOLVHm+HzZBI b5RJxL3h747wTRPXYY5/1OR0XOw 2020-04-20 10:53:41 207.192.70.250 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=997 +p accept 8333,9333,9377,9999 +r HORUS2 RIjuqMoWdAINn8wqF24f25YG8LM 3Hm9hRhk0Z4cMkAQICj29kW7Ylg 2020-04-20 09:09:05 95.216.145.1 1066 0 +a [2a01:4f9:c010:8fb::bee]:1066 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15600 +p accept 43,53,79-80,123,443,464,8080,8088,8443,9418,11371,64738 +r sriyani RIs2YXJV2C/Fek2prRDeh9tlRhc pPRMwlhdPJYMPnHWtGH9prD2I7I 2020-04-20 01:50:22 91.219.28.99 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3820 +p reject 1-65535 +r raiteNode2 RJXeoP4SAOhnUGXw2ljiHJOmFso ZQDyLXoz4LVHl3fp+wFlPJ+uyFQ 2020-04-20 01:18:10 94.130.180.220 443 80 +a [2a01:4f8:1c0c:40d6::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12000 +p reject 1-65535 +r Zwiebelkuchen49 RJ2KXUtOzA+7ZZwU3NcSrcw+Qd4 bHSQVl6ZuS7OT6Ag2+xnDWWbKcE 2020-04-20 06:22:33 85.214.95.94 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4800 +p reject 1-65535 +r Xavier RL1wwT2qdRPW9HdzgEF4sAnyHtU qGS9+lV5S3iUIhWPS4HW9NPkYjI 2020-04-19 21:46:18 176.9.148.20 9993 4443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=92400 +p reject 1-65535 +r niftyentry62 RL6FA6SG2qQSCPGJV9PnV4BmJck cK+f+z5kwam4ECJLGSSHw35YwKY 2020-04-20 10:51:48 185.220.101.202 10062 20062 +a [2a0b:f4c2:2::202]:10062 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p reject 1-65535 +r JDNetX RMkKjy+ylO7dCe5pA7WotJQ7YgQ dkLBWRBohW4VabIbiSTBRULDz8g 2020-04-20 03:47:40 205.185.124.4 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r Unnamed RNmMw67cwaLQRpk69zNovYrsaEY qBWGoKY6rrYLdX3EGxx5RzpSgGI 2020-04-19 21:02:17 82.221.131.161 2030 13306 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=789 +p reject 1-65535 +r Kroell RN8QB7VFtNgFfyeQJeuzPPmb4ic 5qSAtrZ5YRQDytRRlOadKRuqP8o 2020-04-20 03:40:26 80.241.214.102 443 80 +a [2a02:c205:3001:7714::3]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17800 +p reject 1-65535 +r Alphator RN8osVIPC+Z+6pjwzppMXyv6iAM X+/W3zInQSmgEU3mUWxF7E7fuGI 2020-04-20 03:56:16 188.68.62.198 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36400 +p reject 1-65535 +r botches0fief ROOZkeucafaWAKTizKzhm9KSKu8 Ybz3h1ITRnm1e/9nUAZev5+RKp4 2020-04-19 20:46:16 72.89.125.139 27133 28004 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r snap277 ROeXAWJtKVzKsocTrvea7twQRL0 PZBbPjWi15s/D1ySRCFffHzgMs8 2020-04-20 12:21:56 80.139.157.244 36807 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=900 +p reject 1-65535 +r Unnamed RPda31FTQCgHt9LlhEtryNUCUHk fuiSKsW3tSfaXOYah40JocpwhA0 2020-04-19 19:37:35 95.211.189.23 32596 31695 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=992 +p reject 1-65535 +r peterfromthehill RPrxJJ1Gx5zjOlI02FASYcQOZw0 N8omuEJoWqz90yd8DHvfR9UTyf8 2020-04-19 20:05:36 78.46.38.250 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9100 +p reject 1-65535 +r MangRelay RQOAejl79porcKR49RoKM6XJUlw AczI7P42PuFEOT5c/vE5yBvmDqc 2020-04-20 01:22:29 207.229.65.155 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5760 +p reject 1-65535 +r Pi RQfCWCy/4oc1eFmB8EXFQjI+rbs cNKXKACXzxoR8iIYF2xMceklK8o 2020-04-20 02:24:35 148.63.180.161 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=142 +p reject 1-65535 +r myVeryNiceRelay RQq0at/VQbOQWlxhQLxT64xoyaU grm+VzR1MUcs8rZUB3wtTxTx8D0 2020-04-20 08:19:17 193.29.35.205 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5500 +p reject 1-65535 +r bektarVorlon RRjd2uoTyAxhmhOTzacwF2Zkvwk amHTFJQQWbvfsFWZ2J/GGzA+vS4 2020-04-19 22:47:18 92.32.33.116 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r cryonoxnet RRwUSjWq1Hr5H84wIbS5gvaBEzU C+0D0FCF4UzOFLN5jugYIQyxdrY 2020-04-20 07:04:05 45.33.124.98 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=313 +p reject 1-65535 +r lazylamerlimur RTPkLbk4Tu5TuiRdXYAZ+LYWB4E g3Ixs/ALYDCgrHT7CX5pjb6iMSs 2020-04-20 02:06:25 184.88.26.151 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=590 +p reject 1-65535 +r vwamarok RTQEWDUMiOTFJqHVUbsURkOrp5Q G1v4+u6TgMTTVPgtBEPE+g7A+Kc 2020-04-20 12:40:04 79.230.94.53 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2130 +p reject 1-65535 +r lftor4 RTp2OYS88+L72Us88q6Q6gLkoUU iwtr5bsV6gigeS/xhNPuSeJK/nU 2020-04-19 19:09:40 51.15.203.131 443 80 +a [2001:470:c85d:32:216:3eff:feee:38cd]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8700 +p reject 1-65535 +r 9ntus RT296YrRM1adQFXkfZfnOyISfJ4 WMwuzt7xrGM+KW/HDy2Peg5Dz9M 2020-04-20 01:04:57 65.49.201.36 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2780 +p reject 1-65535 +r FOO RUnMA46n/BQmX8bdZmqRy+VnqB8 MkCKwNB47VNjHIfUHJAKmTZKbPI 2020-04-20 10:10:30 178.175.148.32 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Dumbletor RUvnUlakpewrf+LrLhxi8nNqsXU xEpqxaUTWlH6NUraCeZzdurM6tQ 2020-04-20 04:10:08 51.83.43.118 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r debrouillard RVLNoDtE9tyQNwvQjsJP5vkvQGc Hg5XQBdIZ0Co3W9yaxBphRjPtsM 2020-04-19 20:41:03 89.39.67.33 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4820 +p reject 1-65535 +r tjwtechsvr3 RVgvTM7ku/ebRKSFP92CkIsI1Kg xS0MhFzA2N714PUtHPlsLWUrGfo 2020-04-20 07:22:57 51.15.7.86 8443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5300 +p reject 1-65535 +r pmfgrafrone RVnxYr9ze7qqaRF3rj14NvoRf2k O1zdB29JeY7gW4/UIHDmWnTO9qg 2020-04-20 03:18:02 137.74.57.96 1610 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63 +p reject 1-65535 +r chonk RWH8CFw/OnJx/pYDF/AtzR6cEYg socz1r2g7eRofIKnCxkHpOvqPd4 2020-04-20 09:14:03 66.206.0.138 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=43500 +p reject 1-65535 +r niftyguard RW9uSZjrF7l121oZJzYHho5fivo mimC3KGdSLaVrMS5Zh7izTZ2btQ 2020-04-20 12:45:04 185.220.101.229 1229 2229 +a [2a0b:f4c2:2::229]:1229 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22300 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r AUEBTor RX1gNalTgFuC0qmTPt46DqS2df4 CbeRWXY++SJk4K+E//QmlxO6Jjs 2020-04-19 22:43:44 195.251.252.226 80 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4080 +p reject 1-65535 +r zacharyit RYV9WBy7VqUBJpHk8RaVxm49iPg eusuLAfIhws97A+4JAUHEAG/XXA 2020-04-19 20:20:33 68.52.63.97 4672 4673 +s Fast Running V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=852 +p reject 1-65535 +r Tomoko RYaEscQvOA43AfV4K0mqfA1m+rw Y5DE/AGfvZafgb6+IHnXTbNy0VY 2020-04-20 07:57:44 80.240.216.253 9421 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4400 +p reject 1-65535 +r yuggeit RYe1j0lIdbas8eKbHWSyyTvVM9M JEEzlMCq8KSyVtqyctzhut3HlU0 2020-04-20 10:56:33 188.226.221.243 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79 +p reject 1-65535 +r westerbaan RYg7ITnWCblTbhKHrCLW/EgKFhQ CC1fTEe15v5TCWqchSO4iBwFrf0 2020-04-20 10:45:04 62.251.50.232 9001 0 +a [2001:985:5431::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1090 +p reject 1-65535 +r StoNet08 RZMQ4MOnLKrK4Qvuu3SE1yTJyMA Eq11u+vs+BEtt0x6Ss2txMYElC4 2020-04-20 04:32:42 82.183.25.47 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p reject 1-65535 +r rockhopper RZoR9u6PC+Lwj3LhVbheq/XlSjs TTiZdRtKybUSzA8mAFtFQLfw+u8 2020-04-20 06:29:54 23.253.57.42 9284 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=234 +p reject 1-65535 +r snoopy RaUoZFS6VT+s9Wz0rl9MxtLQlbA 7hIGAOFw2Fu9+6Ev+tUzK5G5qmg 2020-04-20 01:23:40 81.221.214.10 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=559 +p reject 1-65535 +r smell Ra5jOTYoAaB5Z7NJTHbqMlFzk8o QExguhA6Qyrri2AzPHwQPkXAtRE 2020-04-19 22:23:20 45.9.148.217 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5500 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r FuckTrump Rc0ZnjAvIJCAJpB6UhSMYLQqpAQ RpFbNftyQ4fvI+oIEBzmx3R3NZI 2020-04-20 09:22:30 90.3.65.115 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5980 +p reject 1-65535 +r snap277 RdWam/o2k4CP4PdiIN7UzOmPwK8 bh9WwdCm1lFOPvVrjZxnipZRZuw 2020-04-20 00:07:46 41.76.158.106 37505 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r BlackLabsHelpTor RdgaWUxFi6oq+trcUHtseE62jWM 0k0CV1tOwB9g0ROE3CXT+XNm/m8 2020-04-20 12:00:32 69.119.185.30 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5620 +p reject 1-65535 +r Feuermagier RdjB7v8EQEOqaAbEuRMPjxie8xY kCPclFZkZAAAA0Oxs/Ub8+GgrgI 2020-04-19 19:17:06 213.178.26.41 9001 9030 +a [2002:d5b2:1a29::3]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=334 +p reject 1-65535 +r Sw4n RfHO3Q2Bviv5CKfO+Op5lIbkIgY dNA29TAUaBDfVACt9HF1T2hya/o 2020-04-19 21:38:58 95.234.197.65 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r Machiavelli RfgM/OD/ZergEgSbr2YIT3bm1os ryDoN0O4Ag7bgrNonyiF7qfWXvc 2020-04-20 00:42:21 45.62.244.154 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r BigAppleNYCExit RfzcTN96f32ae+plpj1q0Cq11j8 tWvSJxnUeZaruIiJjP9+3KdHh7Y 2020-04-19 22:59:08 198.98.61.88 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p accept 23,43,53,79-81,88,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Unnamed Rf1AEkOFQpR4PNg2c2E/9WXZpmI QtheCid/Mgpc8spLyWq440aLgMA 2020-04-20 07:04:27 178.63.69.254 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r PY3J4NWQP7ZGG8X RgzfPeCO40hbMuhT2gd2SZuQAgo uiu37dqZl4SmpwFRxADTze8maDo 2020-04-19 19:28:50 192.99.253.155 443 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5640 +p accept 80,443 +r FissionEx2 Rg5biCdwwZdhvFdHVBkT2yrQHjU nSRuf/UCylL5fLTsLHiKQhMwFxM 2020-04-19 20:27:26 158.69.63.54 443 80 +a [2607:5300:201:3100::34b0]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r CryoBBNx Rh1uoVlmx/mbQ9N63BFrW45H0TA kwMyYqF+YgkW8WyiBxO4wrzVrPw 2020-04-19 18:56:13 51.254.45.43 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=70000 +p reject 1-65535 +r Cotopaxi RiOp7FO/2DFVkp5W1ve1W15xjCQ vZEWduzHZvYaxEKya3nbfT5qPDA 2020-04-19 22:03:38 163.172.157.213 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r snap277 RijpjGC04GjNdl3mgmQ3BSOhHu4 bZOz06L1F4vk1O31f+zgvS0MUvA 2020-04-20 12:32:11 2.3.51.103 45309 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2 +p reject 1-65535 +r gnosti RixMlxcN6U8lGkb0x0EDKGStG/s N8E1KkwDlKSONMv87Jx8UHfBMt0 2020-04-20 03:18:23 193.63.58.76 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4340 +p reject 1-65535 +r snap277 Ri4FS0qCschmuawjzcLq+OdNj9g 6J0uV7vTbQ0B7HTmaftBCRB54fM 2020-04-20 04:33:00 64.228.181.7 44851 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1080 +p reject 1-65535 +r Srv11MuchRelay Ri7LX/lMaraXHkUXELdIviD3zIs +2kFP78y9R67NAaeVg1e2pwbueE 2020-04-20 10:48:18 167.86.102.12 4443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17600 +p reject 1-65535 +r ceres Ri9Jg9+/tOVXcGhDCTybSXoj35I PiDC7gTZf9uUuYah75Hn5pYkZ5A 2020-04-20 06:45:00 45.79.70.219 9090 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5890 +p reject 1-65535 +r Razor Rjn7Xl9M2aNEyuAzft/lNeaAhnQ ed6ZCqjwtILv6+H8gaymX9TBjJA 2020-04-20 07:37:41 162.226.56.70 443 81 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=540 +p reject 1-65535 +r Unnamed RkjbwNvd9oZkr1sIMcCoOo8K3vU a1uJs9o0XBK9tOsiRFJf7q92hMg 2020-04-20 05:06:28 95.42.88.88 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=906 +p accept 22,143,993,5222 +r Voltage RlmmlDcR72lSHiF/GHHJnSovk+0 a3hsGryjGw/8nj0rkf0Qo/E9Ts8 2020-04-20 07:43:16 88.99.70.107 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r angeltest14 Rl0XxvwpfjhXtcbxUgBqHiEpROo QvJVhIfL93Kvs671vX19td3OMpw 2020-04-20 05:21:34 195.123.245.141 443 9030 +a [2a05:9403::86]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p reject 1-65535 +r toritounam RmHeltP46SOZSwUhjyN2DI15NaQ 5iWJeNeEn6PhZ8IfahSgwwpvSv0 2020-04-20 00:52:16 132.248.241.5 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3300 +p reject 1-65535 +r netneutralgta RmRLE/ZAkBjhTs7h6VlHQAZMnyQ NsVt5I9zRGVQlQuEz3BnaT7N/Sk 2020-04-20 10:14:16 167.99.181.20 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=638 +p reject 1-65535 +r PhantomNew Rmt0dsyTrAVrg/adhL9EZ7dGLXs vILvcdKoBhI1Hsr+Ro6+CtTDrzM 2020-04-20 05:09:11 109.236.84.72 9001 1900 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2040 +p reject 1-65535 +r alzey RnNmFsWoldY2yT75+KKJw7yT7lM ocnxp5IR/Hvp86zFS9JQJRtsYXg 2020-04-20 10:27:09 89.249.65.249 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10500 +p reject 1-65535 +r arkadia RnZGpAhYcObeaJomykzIXc7iXks ej6Xk+NQAgOrGA8kTfn9lflJN+E 2020-04-20 04:00:16 78.192.118.230 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r nodvrelay25 Roh0ih3nRAUu768ABLgZ4OnTUq8 mUvWH/jvF3bsgWOT/pOTzpCWM2g 2020-04-19 21:45:58 45.62.229.58 9001 9000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r Unnamed RpMFrlbZ9EZGjovoeAIZ7tVO7yU aLTwMyyNHbWLVg8CYlXZUBt/bYI 2020-04-20 06:04:44 54.36.112.239 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1090 +p reject 1-65535 +r snap277 RphCVxUxnlEvVPoZvoHziYhMYYQ UKz5SF7Smx1mwT5S5TBQfUfxbYE 2020-04-19 22:42:20 190.171.243.60 35717 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r NeelTorExitB Rpn6+griOr7l/C8EMHhetSWPcUg qrVi+6Y0QmvSEFn8mn+bh/3yXZY 2020-04-20 05:36:39 71.19.146.41 70 23 +a [2605:2700:0:3:a800:ff:fe87:5681]:70 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2970 +p accept 53,80,443,8080 +r au0akatala RqTlbJylmjsH/R3+mJEZTgyP1vA HSvtVNUkzTDTel15cJ2hYLSoyBk 2020-04-19 19:45:06 103.73.65.32 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=160 +p reject 1-65535 +r snap277 RqUK5AcaxaDIVfn1nVWWOWmkd3w aL6shn+X0rT8wn+L2+ymuhnlNms 2020-04-20 09:09:03 109.229.159.23 36521 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4560 +p reject 1-65535 +r jobiwan RrHJadCkXK6Qjsx+wP7370yFWWE YFV1tQLqktwEFqZfxi/oMhy7qmg 2020-04-20 03:11:12 82.72.48.100 9099 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=378 +p reject 1-65535 +r Jorropo RrxXz9yR3nXL2n0mSh/UaEoEi1w jAk6oigSXnAftFCmnptNG2hD+mU 2020-04-20 10:08:29 51.75.127.200 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=870 +p reject 1-65535 +r snap277 Rtr0glktYkSm1L0DxtajIQWFHCg TXYwR0AGV9MMmr9k4MXqwPPQUs4 2020-04-20 09:56:49 60.240.114.65 39325 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=65 +p reject 1-65535 +r cophisolem RvMgHcvoijEK9OXPVF5YQGkRTMc w3i0mXn4IX6UMIckFDTvrDjvueA 2020-04-20 10:22:19 151.80.37.126 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9210 +p reject 1-65535 +r AccessNow010 RvkO86NijBNNu0ZU0OT/frkUtpA SuYu4mVl5FSYfcaa1vJQIOSp8/g 2020-04-20 10:33:09 176.10.99.210 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r runesandrelics Rvn7lDkXhY9hjyZIWV3qzZMdRAA 8dcVuWzQAaU89TRJQwyT5zNEIhw 2020-04-19 19:33:08 54.36.108.162 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67300 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TesTOR Rv5Ngc2q01kMO6jqcHGg7Bu7IeY HKqr9Ym8SH9WD0q367f/JbL7iJM 2020-04-20 03:36:46 219.117.252.228 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r niftywabbit20 RwvFxqi9HZ/btVaJ+zAwMQGB6uI stCCfILkcJCeKVxLOxgTvLm+8lc 2020-04-20 10:54:21 185.220.101.250 10250 20250 +a [2a0b:f4c2:2::250]:10250 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37000 +p reject 25 +r BSDNow2016 RxFC2W/H7sohxVY3svAPBlvvZV8 SqLAInCuneRCKNOgwtdXBAHCqvc 2020-04-19 23:14:57 158.69.218.78 8000 0 +s BadExit Exit Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033 +r rmblack RxH6fzYEL+isArT5nCdjEzSbKgU QsVs2hGFmW96TzA+TtITzB9sAyA 2020-04-19 20:07:14 95.222.20.43 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=921 +p reject 1-65535 +r LLXnonexit02 RxJRIyonhWJblFgGTT3qA7i+Exk hQApogLhsyyPHGN0Fs7S5HjxIKE 2020-04-20 08:04:05 51.158.23.91 8442 0 +a [2001:bc8:2db9:299::dead:beef]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r ChomelesDEionos RxdepcG4MK1y8u0UwIm0Q3WDduE iQlBlSlAvlxwFkeqbeNaEPbtAFw 2020-04-19 22:30:29 93.90.200.181 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10600 +p reject 1-65535 +r Fatsani Rx0bQ9OQBPYM1ITxW4Pzbm2fvBw t0eJY64/eN18XLLqZjf+k+hM3p8 2020-04-20 03:24:24 185.161.209.99 14130 0 +s Fast Running V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p reject 1-65535 +r 5n0wt3ch RzL6beEFnwqv1Y7/e7ppssJXn4U WuERDJCbhV+iuimZusrGl3ysVU8 2020-04-20 06:22:27 99.100.63.13 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60 +p reject 1-65535 +r GeosCoolRelay R0ZI0t/BwGClynTIpZdoB7f7X+A 834zkriPpXBLomTrdURNe5dzpGg 2020-04-20 09:33:52 178.17.174.242 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r ursula R1H7VZSZ3gXqQR3+8kcLYNXaiuI g4IMOgWG/Bxlrey7Pd/HByVeZ6w 2020-04-20 01:06:43 173.230.160.38 443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45 +p reject 1-65535 +r yewDelroth R1s012dWkQwR63dS64KF9r4Awe4 Z1IPeWDGBVVERsol4YyizcSXqQU 2020-04-19 21:08:31 149.56.130.157 143 0 +a [2607:5300:201:3000::1b25]:143 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p reject 1-65535 +r rastanet R2wyG0+xBwXf3b+AkXerX7veLNU zCop9myT6gNHEl3Y4002tcpZ1R4 2020-04-20 05:26:06 85.1.64.198 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=25 +p reject 1-65535 +r stork R36oS1/5HVTWgdY6PhUQ5VzE1BY 6bvEbpVppAedl53GuY8FHAJ2m0A 2020-04-19 20:32:20 81.234.212.83 1194 1195 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6860 +p reject 1-65535 +r mordel R4B0mZSyNVf3RYa6EotNwBpUZnY E44Q261rnLMp5aH59IUUs0ZdHc0 2020-04-20 06:07:31 71.19.144.106 9001 0 +a [2605:2700:0:2:a800:ff:fe39:574]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3760 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 R4Q7QbrSQkBKhP0OqzmWKy9q68U DS+HW3NK4iGCSpyT/ok1lNR9Z70 2020-04-20 10:41:13 82.247.163.51 38071 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r Unnamed R4sOGJMMpBFzaWea8yn8SdkRCWY javQUVyXtq5pedDvGivvGyRbXuU 2020-04-20 03:32:48 104.206.237.23 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9160 +p reject 1-65535 +r niftygrazzt R6PQBSXwQfOCs5i/lbxY4OwjJ2s rpgRnU2PAA/g1wS6b8y9PbMYLxI 2020-04-20 08:53:10 185.220.100.245 9100 9101 +a [2a0b:f4c0:16c:10::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46700 +p reject 25 +r linsensuppe R6g+xNFE+4CUpX3FrrOen28XQDY BWMAUh4tGOBMTkZKjwgskIWwv4M 2020-04-20 00:51:13 93.177.64.123 9001 0 +a [2a03:4000:38:410:c42a:a2ff:febe:b8af]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24400 +p reject 1-65535 +r Unnamed R748gLbIMSEVJ9GNHYTidQ9BLt0 oIaq6IPW9xtNE/bwFd9s8GoPmyk 2020-04-20 07:24:09 108.240.182.140 9990 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6 +p reject 1-65535 +r niftysugarglider R8QuIJTuSC58m1hrELq/tnVXAws A3TaXGsPqKHLCv0T7OfjOGzaGik 2020-04-19 20:27:07 185.220.101.24 10024 20024 +a [2a0b:f4c2::24]:10024 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42600 +p reject 22,25 +r michaelscott R+EVf32m34DsANdF1zrNewo4C88 MGZNe88hXLMRGFRV5MZvf5HKkLk 2020-04-20 01:58:30 37.157.195.83 38619 44776 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p reject 1-65535 +r CalyxInstitute15 R+STGd1neE8eZbV5M3G+RnNll54 OCzHfUvq4nxeLNnRtg1foXj+2cI 2020-04-20 01:23:50 162.247.74.202 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r UniverseParadise R+9277/ztO344CiKXlaA0i3LMwg UPSO8h65uhNpM+vHepO0mtZKARQ 2020-04-20 09:22:10 157.157.87.22 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r sing1 R/nR4BVQiZF/+nNO91kIkybDdho TX5UESrSUondsh/2MCG8FqrOMBg 2020-04-20 01:06:14 68.183.182.89 443 80 +a [2400:6180:0:d1::705:5001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=713 +p reject 1-65535 +r ULayerKiriakou SCpofxQYKXSSbOCzrP/I1iR+198 j1QIJgrX7GmLRrF6+lPcKj4EmyQ 2020-04-20 04:46:48 107.189.10.156 443 80 +a [2605:6400:30:fc76:b73:a5f0:846b:83c4]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r Unnamed SCwG/mxs9xaktaGjDkZASK5uNdI WSvhBbCAiFyDHd/1cmu73W1mfdQ 2020-04-19 20:28:02 54.37.73.124 9001 9030 +a [2001:41d0:701:1100::139d]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Grape SDNk/Ts30UO5dF6MoK4VpUycr3A Q5SN7BMfGKBjmf1UkiBH1fAG75A 2020-04-20 07:46:40 46.232.248.100 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r KherNl SDem3/yONoHXCtno0FfAKQk9ovc CvEauHsqOpvudaweTuwtgrUIntY 2020-04-20 03:50:34 51.75.206.12 9100 9101 +a [2001:41d0:305:2100::7cb4]:9100 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13500 +p reject 1-65535 +r Aerodynamik03 SEoQuiuNSKXwIWZ0yN1Q7ye8MvM YKEJwH/ocYdoCu9AB7wGUsPT6ck 2020-04-20 09:26:44 193.70.43.76 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r Locke SE9mbEkbzeIrReDhnRzqWsxalhE Rqg6jQEISWlC/RMyiMepUBXNG9Q 2020-04-20 03:02:36 51.15.80.59 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p reject 1-65535 +r mordoc SFbJfcTyJxvIlt+cq9IX7i2GnWg edCkLsS612vaS0pV5yp4G6VyIXY 2020-04-20 01:36:53 136.243.149.82 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=120000 +p reject 1-65535 +r Slaanesh SF2l1cX8eN/byZcQCV7TGlM+iTw Gf0tGJSzjpRMlJN2De6A6CU9wiE 2020-04-20 05:46:16 82.181.30.212 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1200 +p reject 1-65535 +r dc6jgk1 SGdANTuQWqRzH4LAtMwlghpixuM BfcsN1dBgA9vGjA0V/lStvklI2g 2020-04-20 06:15:31 87.139.33.217 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=4770 +p reject 1-65535 +r netwerxtorexitlux0 SGmBVltmMaXtNXA9p+RMIXtNVxU qgObMpNp2oPw/Baqv1G/HGSaEbI 2020-04-19 22:01:32 104.244.75.188 9001 80 +a [2a0e:b107:3c6:facc:decc::deff]:9001 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed SHb0MRG2Cw7X+0qnFtZV2hKcfGY MPcpyLyCv+kupdXur9vud5Zl83I 2020-04-20 11:14:18 151.80.194.85 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r BSDRelayDroid SHtblvQ4miHtF5Jgmu+5GE5iHP4 YpvtCnTVwaMfMtZWcubrtM5rqmE 2020-04-20 08:41:26 46.23.93.78 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=47 +p reject 1-65535 +r oxygen SIyUugDcODl74+oFGrO/j+ZgoGI WkZFGFnM8DuaCl5cV1Y8pwIJE18 2020-04-20 10:39:15 179.43.167.229 9020 8020 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r zapner SI5mO0qIwS5t5sEvemBT8Jv3pho 1kWQ+2lSPLgR6IQJB3XKDRGVZzw 2020-04-20 09:53:16 95.217.6.94 443 80 +a [2a01:4f9:c010:516b::1]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1940 +p reject 1-65535 +r SomeStudentsServer SJYG2mT9S2inbEk4YphpXmwwteI 0QMjOH4xb7ZUN5/t/RrGmqp8/Ac 2020-04-20 10:07:41 5.9.120.250 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16300 +p reject 1-65535 +r snap278 SJZmwBgpPS52wJLbFlSD3xLwNEw AFwk1Rz8vTPRAE+ADrEKODQEbPs 2020-04-20 11:22:11 78.229.98.33 40437 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r matator2 SKHRfOz7Oubw4QaUTNxxKYx16H8 FbcqddXAGJZx6WWC++ZFdjlybD0 2020-04-20 11:24:03 188.118.217.235 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3390 +p reject 1-65535 +r Unnamed SLT37o4fh+pUTJSY/0Y6bdw6R5U T2+SuZUZ8e1CSt7pWUhreBNBiIs 2020-04-20 09:13:04 31.31.74.131 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2640 +p accept 88,110,143,194,220,389,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftysteppemarmot SL43LKIQTSQi1JzTIQYOf2l7Utk bImbQSM+AQOOcDf3HKKc0JzJwho 2020-04-20 00:25:58 185.220.101.23 10023 20023 +a [2a0b:f4c2::23]:10023 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=55000 +p reject 22,25 +r king SNPLmTKh77hY4I/TafxkQb0JX2M ParGfKLU1/n1roBMJIhgun54XLA 2020-04-20 08:22:25 51.68.201.112 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Athekiu SN6DL0vmlVs/Px8GAxDzv9enkD4 ftIVl0hOr789vHkaXe1um0Ygq1s 2020-04-19 22:49:44 91.116.230.193 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r DreamingCSPeirce SOU3flwt3ZXtatyNic6Ngwre8P0 ph07wB0v6TjVVbLETgOg2UU45W0 2020-04-20 02:31:33 64.85.206.69 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=146 +p reject 1-65535 +r Unnamed SOWqt94HQ5/FNfUz9Lo4if3Uh/0 b9l9nWZfXKQl/ibNDXeY8f0fRoU 2020-04-19 21:26:12 158.69.123.231 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7350 +p reject 1-65535 +r Larisa SPUaAwlhB8lnP+lsS4dsAQuiKvQ fxg1n7E/u0HCl8JQvWnUGqU+VhI 2020-04-20 12:49:04 185.234.52.116 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6800 +p reject 1-65535 +r Unnamed SQstcMFQ+3LjH5qcoR0oUdlP1Ek 0VPhKCst4V5zv7+1D7byee07n94 2020-04-20 05:58:26 40.127.170.168 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5400 +p reject 1-65535 +r scratchy SRTzTXogG2bZftDO9M8s+B6xfo0 B+NMnXq/aPiG99qEDOnm9+0ehpE 2020-04-20 09:49:45 95.217.5.96 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p reject 1-65535 +r Unnamed SSkEGj/uaYmQMUvWHQ32lYxCGxA VcMi0W7rLYqksUBsjPGAaEd4OQY 2020-04-19 20:33:10 81.95.52.68 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=17 +p reject 1-65535 +r relay4freedom SS/5GmtDEQaB99XdOzgOU3aZ0/E BGXn+uCZdw0YKRoQUK0qag0jYV8 2020-04-20 08:28:26 83.209.53.188 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6450 +p reject 1-65535 +r Unnamed STHQU1yZvIX8fvC+a8C+C641hNg sSl+dxFJvVTU+GhYS6N6dvTGSZk 2020-04-20 02:17:46 37.120.206.46 42543 58043 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=159 +p reject 1-65535 +r torjanhorse STvu/ZhU8OfOuWoBpH7qg/TpOgA uDSLS50ZcaGkA4RWNxsylYc/yGg 2020-04-20 11:37:38 94.79.157.78 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=923 +p reject 1-65535 +r niftyentry98 SUJ1Blbq1qEZEow9KP1lPWvBSKI kFdN+thtZEekXBxEs4ISxxxGi8s 2020-04-20 10:52:01 185.220.101.238 10098 20098 +a [2a0b:f4c2:2::238]:10098 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6870 +p reject 1-65535 +r Dunkelzahn SVmFR09Ue12XrLKUHHrtBI1+fhQ PTWO78OQ785iSigHfiRvy7s+0FU 2020-04-20 00:25:38 176.31.43.51 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r AnotherTorRelay SVtJaGfIS7ySM4MB2SSFDyJuddo stAPqyZC0gUKWYc7wZ/AbI5KxnU 2020-04-19 18:58:03 5.135.162.49 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p reject 1-65535 +r Unnamed SYdzmd0Ogv4SMUg2EDiCM2j3cZM Ha7kxqNDkSL+r8yKRO6DhLaYngg 2020-04-20 03:22:38 90.91.246.132 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r Unnamed SZg8GBs6qlWqLWu4bpeWtRT4dXM 5wQdXzDw/qqUkz4g6sUyEOPmDxM 2020-04-20 09:24:42 77.79.141.24 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=306 +p reject 1-65535 +r HellGuard SZ+gFDMyBJEhYiWAH+BYnCULTW0 PZ9MPH3t7sLUEQrYa0ubrQixJnE 2020-04-20 08:34:19 87.122.107.230 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2730 +p reject 1-65535 +r ten001 SbFGeNQYJh1iFjKx3fWMx0zKduk BGV2je7nJkCopK2JLUDYpcnrr5M 2020-04-20 06:43:18 45.10.88.30 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9040 +p reject 1-65535 +r Unnamed Sbg9ETSudXd7DlPWpfNHVZXNFlQ 2517oN7Bu6bUza+UtNqh6fZgC7Q 2020-04-19 19:58:50 163.43.104.205 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=582 +p reject 1-65535 +r kleinbach SbxzASUPbYe81nbfya8iBI+W9Zk 3VLhcyiXeokLmkjHeqYGGnlKz1U 2020-04-20 00:22:26 91.213.233.60 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1780 +p reject 1-65535 +r r00tzone ScqSYoAencm0FKFDpYpoJVFJNno 6GJjZiZSempM1mniDFdm3Rcw9jw 2020-04-20 02:29:47 54.37.207.37 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p reject 1-65535 +r Unnamed SdHyLoyjYIF7aHo978FIuuVCuUc tg1CqA7YopBe/KJof0HiTsXqzD0 2020-04-19 20:28:48 206.212.254.106 39712 54627 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=140 +p reject 1-65535 +r Twoflower SfmjUIZNAwwcnjJf1CCMFV9QRuY fa52XX2dGyaD8SfjJCV3U1wl++4 2020-04-20 10:50:36 91.192.224.146 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1250 +p reject 1-65535 +r yoshihisa Sg5U5pNDt89hOMEYhDzoYOhRH3g GcQsipzCz+SFSCjezCF3Vvu+LSs 2020-04-20 07:44:37 141.255.165.102 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6930 +p reject 1-65535 +r Unnamed ShK1jRU868W6HgXc2c/+fF7PLTE 1QTmYzI1Mx9/C9v+ZW6u43tyAtE 2020-04-19 18:57:11 167.114.92.58 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r dlxuk ShWGhr0BGbiqlq/iq8DVWvRn3RI 4wmu+kZuKQD7POM5/O6lAgAObxs 2020-04-20 07:30:30 5.135.42.249 9090 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1110 +p reject 1-65535 +r tormachine SjuHTwGH8s8No8j3YGOwcPn3oU8 H9WpjAgDxJ0ha72UOnBnG4j2Tdw 2020-04-20 00:21:57 87.118.116.12 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p accept 53,80,443 +r FissionMasq01 SkEd2Ou9U5qgCQowWFa5yDj38tY Je34qceo//XwVT951QgUBGVfDPo 2020-04-20 00:25:00 185.65.134.175 5753 6068 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1810 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed SkbXpAD388lGhfXTppBozBwlhHo qxtp9i2/XipJY+wrBw22Mo3sbtY 2020-04-19 21:00:03 163.172.182.54 4086 9684 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=912 +p reject 1-65535 +r huskytail SlFHlS7jVTT3tpOH/z1AjI7mbWg vzlGuIGHCawb10HaqU/LyRlQ+uo 2020-04-20 07:56:17 176.107.179.147 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5290 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 SmAv+nTNmiqgoOxD1pa4hUwnuCY wVpwbVms4r+m6p6Taa6EMXthrr4 2020-04-20 07:39:41 72.230.78.85 33979 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1590 +p reject 1-65535 +r Unnamed Smn5ImthE7BoHVyTu9YNX8y+SBc G8DcjNgDDwFYODZeeCs/mcTgei4 2020-04-20 01:27:04 78.34.190.155 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=229 +p reject 1-65535 +r spechttor3 SnJJK6zngVVU5F9Kua8F1UkTbY8 bVsdZMsy8jS2EUhEC4zlf7zwS48 2020-04-20 00:11:33 185.15.246.243 143 0 +a [2001:4ba0:dead:b602:c6ea:90ca:4bed:2b51]:143 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6490 +p reject 1-65535 +r merecu So9SIe7PMNXRLVzYMSrlmc3YyW4 lvCiYQBJOkL+3GZEZrVP6pj5f6Y 2020-04-19 22:30:46 186.123.111.156 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=78 +p reject 1-65535 +r orbou SqI0x2el6AWE4gtmPfWzn5Lc4s8 WsiefvA4urN2mhGVOLHeOOKrs2g 2020-04-19 21:27:20 178.17.170.96 443 80 +a [2a00:1dc0:caff:fc::ec9b]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5580 +p reject 1-65535 +r shermbot5000 Sr/qvoCa65H/l/FBLNV8o79s5Lc TAosvNxx4oGHyzVEo07yli06v9g 2020-04-20 10:05:53 107.150.23.186 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r Stellvia SsTxIMEZxyNWvJwzvxTibSvwUtQ /YOuQ8O4BQ2rHaNPQUI/JQDuVEg 2020-04-19 22:54:40 155.4.117.13 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 SsaatycIytRUFxQ+eINhjqqLLQU 9O+LOBVRwNbD3pvNxwzmG4BNPj0 2020-04-20 11:10:26 5.12.32.140 35123 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1860 +p reject 1-65535 +r niftyguard41 StC0Cw/GecwwDzmLzr6dAAgz9iw 3XOHuKOmVmlr3S6DyovQypSyWX8 2020-04-19 22:15:43 185.220.101.160 1160 2160 +a [2a0b:f4c2:1::160]:1160 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28300 +p reject 25 +r niftywabbit15 StnBFqGULVinFEM8ok8IfxgDan4 q+Q/wPluiteqSMnrvGbIk6daYig 2020-04-19 22:15:36 185.220.101.155 13155 14155 +a [2a0b:f4c2:1::155]:10155 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29000 +p accept 80,443 +r snap278 St0chlvvj3UH3RRLv/6pVPCUnMk 68rFBxrnOhlrxOobkRP5uA8nu2A 2020-04-20 08:52:34 77.37.177.8 43041 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1390 +p reject 1-65535 +r Robotor3200 SuHPZ5tIpsZGH2QVw39EMGprfuw yfcOWkjEvYtCUnzrPsmd9nXyAcI 2020-04-20 00:21:02 54.37.229.22 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130 +p reject 1-65535 +r PankyDE3 SuxhL0OgQCpV+PGW81k8oEsAA+g m0NeTuVf7aQl2aDX1gwPt8hmcbE 2020-04-20 02:03:48 213.226.68.77 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8950 +p reject 1-65535 +r Qayshaun Svy+9hZdF/SBSiiKifUmHcA/xq0 gVR0sR9wJZRRalSnTRvo/zvZ0UQ 2020-04-20 09:16:03 185.243.112.128 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7400 +p reject 1-65535 +r Unnamed SwBKSp6lui7M1NHNGUUswtbR6Og k+LfTkW2dmAF2n3Yl1rw0cGJJsc 2020-04-20 06:34:58 185.51.134.26 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5720 +p reject 1-65535 +r Unnamed SwJJNBm5KHYIcZWzzvFrNaFoPMY 5lvo72a22JSff2dc0QPW7L7nahI 2020-04-20 02:16:50 68.96.183.200 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r Unnamed SwX01i6DZi0Kq2wrNTOBMDJrcaI CoE1F6aBfG+AUqdiyMra+pEbk6k 2020-04-20 06:54:45 86.84.118.219 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p reject 1-65535 +r FreeSpeechForAll SxZ1gWjU8zS+EYcve2uuLkRmTls FweXp1NNrMgrIKtyCJyVmc8UifM 2020-04-20 11:53:47 51.158.180.246 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17000 +p reject 1-65535 +r birnenpfeffimitzimt SxcEdtCUWTKEOPPmjtGVFsn3WoA LOdjAtKFaYGBaHKcBG6EHuhboTs 2020-04-20 00:03:16 212.21.66.6 443 80 +a [2001:bf0:666::666]:8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r flexible SxsCqUwDFfA3blamrTqTx5duRp8 4CJW/rt3HGGgtmJ3McacB+3rwLA 2020-04-20 11:34:16 79.219.255.159 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r bourbon Sy6XyjusOisUh58QnplloMIDFsI nzU2UhU0PVjY0i1WkgU5eca6SMc 2020-04-20 02:19:27 185.12.45.116 9090 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22900 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r idideditheconfig SzUVRd1YRz82sKIOVQCsbtUejNU xrS04sos2F3hLncUFxviJpGUYig 2020-04-20 07:20:05 90.145.175.245 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8800 +p reject 1-65535 +r wingedgods SzarSCqc6E+N/IgMimlxXu/IQ4Y oADx26tvjv1Wgz+uTK6cxsP+H/s 2020-04-20 00:31:47 173.160.180.189 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r Unnamed SzrHS045cqdbj7v4imiagZErgpw nj7YNN6+W/73DSP2fJhHL3USHkQ 2020-04-19 23:49:12 108.6.209.163 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1320 +p reject 1-65535 +r Unnamed Sz4uKHIKdGeAYcI0GrSb9LGP5Q4 8nlCUPLMpi52lGfpg5LOp2i6dGg 2020-04-20 12:04:32 51.79.22.229 443 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1760 +p reject 1-65535 +r dousnior S018cntgPvZ3fcC8PRaRecqXcUA 1h4nZIpuxJy0i/8a6qpfy3Mi94Y 2020-04-20 00:33:25 158.255.7.61 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8550 +p accept 20,23,43,53,79,81,88,110,143,194,220,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r M87Star S1ND4IOrV02xz7Oikbr6kI1bNSA ly494K4FiQoKJZJ+NLekP2QaITY 2020-04-19 21:26:14 37.187.177.2 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r tubealloys S1gvP0u03lbXco3rIqolU1CHD5g HHiqaA+ctGx2Cq9sVzRUoBhvoig 2020-04-19 23:15:56 213.144.142.24 9001 9030 +a [2001:1620:ad1::24]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=421 +p reject 1-65535 +r TORion S2jQ5Tku1vNGmjeIBjE1OpZVhjE aOkolG89FBaaInSuiJWJzHmqsgs 2020-04-20 11:34:01 192.99.34.48 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18300 +p reject 1-65535 +r Maryl S3vwOPf4QbuPB6ZZ0VlCq2KhtRc 2K6vg1CvZKdkMBqAbexLs6M6eLI 2020-04-20 05:51:03 31.6.69.162 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57 +p reject 1-65535 +r Unnamed S5qvzjQkycpikIxnygtXVo+4fkA EO/jG6ZPkn5abyRVLrHQ7lu9Gk0 2020-04-20 10:20:16 51.15.235.73 9100 9101 +a [2001:bc8:4400:2c00::c:b09]:9100 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17700 +p reject 1-65535 +r 4thegreatergood S6Bgd+sFsUTR+w6QDlwa/nOGkQI rxEs4ck6yKRLfcD5yEpCjk1aE3s 2020-04-19 21:31:13 79.143.190.233 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2200 +p reject 1-65535 +r chark S6rED+31aJT7RwSEboWOLyC6aJg DL82E1p5PjL6SfE3cmKkA9CLo+U 2020-04-20 00:54:15 87.120.254.114 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r JoaoOliv1 S7D9f2xGfGn15UFgEdbVt6QNTto hK+AeFGo+8J/T6OL/a53S8mszMI 2020-04-20 09:51:35 188.251.254.142 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2120 +p reject 1-65535 +r Unnamed S8WIr1wboeLCSQh45dP1ppKeC7c Kx019tVTigMV5YjXfXw8jqrU5Uk 2020-04-20 11:59:26 209.141.55.175 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r orwell1 S8h0wpChQ46f88aE8crCrDUaEus yoSLxy0HI7obn9hZEVgPe9HWqVE 2020-04-19 19:17:28 185.243.9.150 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24000 +p reject 1-65535 +r dokachin S9Aua3KC412LT9Jgv/ylkDL5wLk pqWszaXDgFusVDt9q/8iQjD+9K4 2020-04-20 02:24:47 91.63.41.25 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7390 +p reject 1-65535 +r Unnamed S92N7EBgUAIHdpe/ohREch5Z2D4 bL0FCtfeNTC5Aq7uCk+ZcgGmIao 2020-04-19 19:38:33 158.69.172.231 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r georgector S+1o356vbBEdh3jhnMmsev7E/AI cwlFMdHxuq6ZLXKmudKWiu9qvdo 2020-04-19 23:12:33 92.30.36.13 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r angeltest33 S/PSmbxQDDUIaPB4dJKRx2bHqm8 GnTi/wNNFIC32/E1Rztgt+Vt460 2020-04-19 19:43:39 139.99.238.17 443 9030 +a [2402:1f00:8100:400::3a8]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=500 +p reject 1-65535 +r Unnamed S/d9vWeWYo7GrCn1ZRzuGWnscxU Wj2VHnlrla5jld1+TeJ3X22XHeI 2020-04-20 00:07:24 178.73.220.139 443 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12600 +p reject 1-65535 +r karotte S/ycYxqT/0ujqoS8aTG0MQw4omM Lcf0R5aJ1igU/dl+QAGJtYlnzas 2020-04-20 02:22:30 109.70.100.4 443 80 +a [2a03:e600:100::4]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=96400 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r niftyguard54 TAfLM2XPPgalb9LcjspOl6ZSGYM UtYrXeia9BlF62oK08z+n43JPAI 2020-04-19 22:16:06 185.220.101.173 1173 2173 +a [2a0b:f4c2:1::173]:1173 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 25 +r tor7andersio TAkEXNbQm/IXINuT9/0yNjJbo4k 19Cm3gQZdVvWaIUwqalWIhwBG4I 2020-04-20 04:29:08 128.199.133.154 33443 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=655 +p reject 1-65535 +r An0n1m4t0R TDDawvdgK99JxHJ892CsejYP9Uc 7vMxoFej6GDmFYSaQhRu/be0vJw 2020-04-19 21:31:26 79.156.130.191 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4700 +p reject 1-65535 +r king TDa+INMNATCXlk0H3czsvBfPHf4 pX1z3ZQG3zZPMgDcooou+uGCgvk 2020-04-20 08:32:01 51.68.201.113 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed TDx85KqRPz67L7/QQ/otgaBaphk XKxlnkDDZ0ViN8zDGVFMpk4LBQU 2020-04-20 10:14:10 115.70.103.172 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=121 +p reject 1-65535 +r beastiewhale TD+0LLnwXCF6JZnOSZstjmsHO5s Tf5FId011WTkhLc4ij6amBhGVvc 2020-04-20 04:36:22 213.219.160.18 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=368 +p reject 1-65535 +r santiago TEQhE/FNB6jVhAy+Bc6Dfh4ghtY EWGlnx6swbGwWEyBvnWedHxO4qY 2020-04-20 03:59:34 187.144.211.132 443 9031 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=400 +p reject 1-65535 +r NoPublicShaming TEZ7kmNphggGMsAIMYTs2h/k7DU +5tdK0xSs1YPRtnIBru9Gts4hrY 2020-04-20 10:10:47 80.153.241.169 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49 +p reject 1-65535 +r Viserion TFuBNDQeZssJJGmF5AOfm/wK3OM 3XKaDr1UKWnipyHPuy6E6el0Wiw 2020-04-20 09:08:11 185.225.69.60 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17600 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Unnamed TIIPi9O6ZooRkB4xX/RW6kL7uRE DVfudFo0yMntcQfmTTuNTCgV/tI 2020-04-20 11:52:23 205.185.127.112 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5640 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed TIp46Vcqz2iWFWBvPIJT39iJ5pk jmhlgDMZmZZjrHXrUywUKHSC5JI 2020-04-20 07:25:19 185.113.140.110 51282 30931 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=305 +p reject 1-65535 +r Unnamed TKX4Ya38sHeYYbVPrlF+y2qw10g oFnkzOzUkw5x1WVb+lSHJxGjIDM 2020-04-19 20:29:08 46.229.55.97 32625 36918 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=225 +p reject 1-65535 +r grumpytechie1 TKZOZ37P8jsTjP5wpqAulL3zqAU sga/qtapo96semx0DeLkaIIm+lk 2020-04-20 01:52:46 185.103.110.248 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p reject 1-65535 +r CodePoet76 TKeCzgCtvN25PeP8rPhERTU9d3I hC9Sq8wQzKajTC7R9X+euwM/iDs 2020-04-20 01:21:57 50.53.115.97 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=250 +p reject 1-65535 +r mullbinde6 TKjQeHj4btW2S0uJAw/0YWBnIQ8 LmtfIlO3nhBlm9EaiY5Raf6oAq4 2020-04-19 18:58:36 88.99.217.110 9001 9030 +a [2a01:4f8:10a:4253:3::8]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r relaytorforall TLLepnx2M8/FEKfnJYTJyixYlk4 qXu/tO/INH8oz5NSGILfAUMYJ5Q 2020-04-20 08:47:03 103.240.90.197 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=644 +p reject 1-65535 +r snap278 TLb0NHLSBTGUCEvr+k04YQWUGsY H43KfdH3v5fuJY1+RLNcI5KFTs8 2020-04-20 12:13:10 93.157.112.147 35441 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r henkdefreumel TNTf/vOXHJAqIhANkRysY5vi71w BIfKyeky3UqH4VHyrK/Ol1BcdNU 2020-04-20 12:08:42 82.197.218.97 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=52000 +p reject 1-65535 +r raffertz TNzIM/twufORVSL9yQ5SxTH+7Ek h5XwMIoiysGiYMoXngBGlGWyDVY 2020-04-20 05:13:16 81.17.30.33 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r gricia TOsbaYRT25PlmmEBHDzcanw7ZKY IdW5O10agWnlR4GZjwIX/IE+4zs 2020-04-19 22:33:26 83.212.126.115 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2970 +p reject 1-65535 +r moxon TPBedd0joY5uVoHEAR5SVHhKPuA CB31JCZOv7+HJcWOp1aDIQbbdZg 2020-04-20 05:31:28 164.132.9.199 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1930 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Berkeley2 TPm66w3m1yMNa32g/0IMfP2GOIU ejQqJcgjgB9MwTi+4hQfEslEy28 2020-04-20 06:36:11 135.180.15.250 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r quester TP5l4W2+nZ7Qz/vZvu7k6uUM0z8 hZ45uMMvc2RVIFO+tfqL7v6rOYc 2020-04-19 23:26:25 91.236.116.87 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=28500 +p reject 1-65535 +r SpaceJam TQLSfIjhvucm08RMe9eEPA6SrbI yF2A81NGUYqVChWPohG3BE8IU4c 2020-04-20 08:07:24 139.162.245.120 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=990 +p reject 1-65535 +r artikel5ev8 TQ30aNyBb4CWcCwtosb9Z1Yfgcg PNXi1l3oGLEzduB3dzdsDOq7k+8 2020-04-19 21:36:47 46.232.251.191 443 9030 +a [2a03:4000:2b:66e:dead:beef:ca1f:1337]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r honeycomb TReT1CP9sZaOqnRV68BwoOSLM+0 KTDWGpf/NaywkN5MWLbyQCYBrkk 2020-04-19 19:55:08 104.168.205.106 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Bucefalo TR26P3H8etA8fm7nAUr6YQ7wAVI PMdTQ3GkPQkhwj2hibceYh5nyF4 2020-04-20 04:28:07 85.0.159.53 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49 +p reject 1-65535 +r snap277 TSVTDo2c2vYmKCPA38DO6Z436Zw XP8jRsX/UIjJIkChHIGATBzlld4 2020-04-20 11:31:32 90.209.72.226 33722 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r nigelFarageWozEre TS/LPGVK1q/KSvh+h65yc19kPYs PhCuBB3+8j6TG9z0EBFpBwDy0bM 2020-04-20 06:59:19 37.187.120.37 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=580 +p reject 1-65535 +r Unnamed TUkx4LioPzPfgRJ/EMZS2K9DeHo QL4nrvnL/3Zrmk4qrcWUFubmp+c 2020-04-19 19:02:00 167.114.89.200 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TheGreenDynamo TUk4tyW4lWF3OhYSFdiLfEXEPDU 3aHsZW/eYlu9Tc4LNIOmq/ICyZg 2020-04-20 07:01:06 104.131.108.7 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1350 +p reject 1-65535 +r stormwind TVKhLZrSKn4b5bVklTp8qcMdpnU oAsh25pflSLrG8nx907M9g+qDws 2020-04-20 04:57:16 178.132.0.6 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r pirelay001 TVLhXFY3+3BzbdOwPyqufCU79LQ TMMH1a3CtoT5XRAn1oMQX4bEd6U 2020-04-20 01:13:52 170.10.183.168 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4170 +p reject 1-65535 +r arbitraryTessa1 TXDwXdMIoupbZx5ECHm/rayShg8 9OVbzKi8gSpIp/L81/Hb0cQqLGU 2020-04-19 23:22:19 95.216.19.207 21 0 +a [2a01:4f9:2a:1430::2]:21 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23200 +p reject 1-65535 +r themossyboulderspa TXkWlji12vghswYkcl/TQY+FCt4 iSgReN/PGovDMWLokU62TLfO2mo 2020-04-20 08:17:06 45.114.130.4 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nganukadaskurap TXt9EyjhKhgNTz3zYHZd3Z9E+34 rSBkT+tKRh/6rBzYTS+kr4FwxPQ 2020-04-19 21:04:45 35.240.161.41 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=468 +p reject 1-65535 +r fancyorguk01 TaxDZ+CQM6dC232u3T7oII32MVg yvEfVC+CQG1Tc6GysLFRlLoDzLs 2020-04-19 20:37:48 78.32.231.155 9001 0 +a [2001:470:6d29::24]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p reject 1-65535 +r Demogorgon TbBJCgQggJqBSed4u6yPHpNJ2ew +VLfJTCiiJkJVqueFTuLqTaJc90 2020-04-20 06:08:03 80.211.185.153 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26900 +p reject 1-65535 +r diodeOnion TdEcPxH14okdV++fffQ77htRT84 pGL47BttYyk5Xu2MaNRc7TD4sZM 2020-04-19 20:50:44 99.149.215.67 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p reject 1-65535 +r Unnamed Tdi0b+ZtFVe9lEdzvniTx1vlLXw XK+i6wfJR6RQpDyJcb2HfWQrQjA 2020-04-20 10:20:52 51.68.199.219 9001 9030 +a [2001:41d0:801:2000::1a37]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r nemesis Td6Q4vaFkh8RWZS2zWfx/gRwTaU +TIc14zH/4fyqdt63bATDV//kHQ 2020-04-20 08:16:10 70.63.170.86 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52 +p reject 1-65535 +r lalatorrelay TeTwbAGexIFNSGUkwqKCwdx2U94 irxK8FEnk67zzIXOgrnhg4k7h34 2020-04-20 11:36:12 99.105.213.162 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1900 +p reject 1-65535 +r s4nine TeacHSPtt4TPHau51gKtInZ6fxU h22alxDpnXDXtxdxsGtT/Ir40vw 2020-04-20 02:54:02 104.248.29.127 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1350 +p reject 1-65535 +r Unnamed TfHzDAAb8Hfn9GYc09QNO7QWC2U ASfEZpydyoSW21qYstrKPvHBOvM 2020-04-20 11:15:50 46.105.191.88 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r minotor ThUImIy5SrjbPJO3yW+tVHdB6cM meiNk25/LQ/NuvmqLl2QsoZbYjY 2020-04-20 05:44:38 67.165.9.74 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=37 +p reject 1-65535 +r Eliise04 ThdSepsn2seWWFw/Nx4mdu+G+8s mQCVmoELsw+0oRGZvxlSeo7lIqs 2020-04-20 01:19:11 185.195.237.117 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r BeGayDoCrimes Ti99Myb7zjAFV7mv9GPMQ0qt0SA grvDdAd7WueKa52Za2346WT+7Ys 2020-04-20 00:31:17 23.129.64.189 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p accept 1-65535 +r snap277 TjI7bW7qATTHQxGwITmhiZu0I5Y yvxQVdF7ocFrJ/nKamXv2BCFhLE 2020-04-20 02:03:28 24.171.142.153 44357 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r nodvrelay27 TjK37JXjqBniu0mdBQZTJFfengQ H+9NsIW57q/moEpCVIfiy62APSU 2020-04-19 22:15:14 104.167.107.104 9001 9000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2190 +p reject 1-65535 +r Tessa TkGwD5MPPnJTDzOe9MkRzpfSrp4 fL2GfVEuaJrs44Ar+yyiqy43GkY 2020-04-20 09:00:11 104.37.251.124 12800 12600 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r ECANTorTOKA TlWeMCeQkjFb+QfavfAHIEc/gyA wHLUbCsCvv134chGVEMrpPi/nvk 2020-04-20 06:26:23 172.105.199.17 443 80 +a [2400:8902::f03c:92ff:fea8:ab95]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=392 +p reject 1-65535 +r NamsanTor TlhozCjEZuLJfe82LnmQoaM2xNM bDDreodl7ZR/njwExVIkI5Auw4E 2020-04-20 06:41:17 139.162.30.247 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=280 +p reject 1-65535 +r Yesenia TmblQQC6JFXkn48C0zb8sqa01Pg p1DarqqiOfBXN59dZ9O3b4Cp/Co 2020-04-20 04:49:19 46.183.216.152 25369 0 +s Fast Running V2Dir Valid +v Tor 0.2.9.15 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=5610 +p reject 1-65535 +r fento TnN7v8y+RakjzoJXfpnc/6vFv/Q I++7AbxmIhZpDr8b+qdSVKhW5JM 2020-04-19 20:16:31 81.17.30.48 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8700 +p reject 1-65535 +r Rasengan TolgccpqcS+py9DjabdZYmVMDRs pgpbbm3pgXbeJ2itkIYzju58GA4 2020-04-20 11:43:10 139.162.66.246 9001 0 +a [2400:8902::f03c:91ff:fe7d:e808]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=750 +p reject 1-65535 +r ymkeo Tozm9WUec0LB5+XtAx6CB4E0+w0 0tG7iEjG7W2i1TyoP2ONbosS/IE 2020-04-19 20:43:49 82.161.212.209 9001 9030 +a [2001:980:d7ed:1:ff:60ff:fe1e:4473]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p reject 1-65535 +r makeuseofIT TpG2ZWHuAbFlPhgD/lO1xADZZ9s ZT5q0kLiKvlxZQL82L9yTczSnbU 2020-04-19 22:41:15 87.154.216.112 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11800 +p reject 1-65535 +r brwyatt2 TpeWSBwedfddV+jB/IyO0RFDMxY ol3MbBjwtO/LnpEGK2JkqnsL8iI 2020-04-19 19:28:43 172.92.156.32 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9400 +p reject 1-65535 +r summalummadooma TpiqKVtxcZltGN0fahn2SrQDa0o JKqvEaY/01vwjfLA5onwpM+lvEE 2020-04-19 23:09:44 213.239.213.190 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=80300 +p reject 1-65535 +r estrade TqOBocr0QiwUIBtL95kDmUKpf/0 aQx4P8HSRpBnMNF+D2y9abHo5Rk 2020-04-20 11:13:05 101.55.125.10 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=175 +p reject 1-65535 +r d15a6fa9eb8c TqfzEaK9stuXaFmGD2ydfbFCJQ8 xgBvXNu2RM3vThvGmR3y01gu51E 2020-04-20 08:46:15 51.81.253.215 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snapfeli Tqyx30vUJSSupqG4AmYXsb9ZBFw C4u0UhlIQdZMCmfOq/VCHFWNAYk 2020-04-19 19:20:20 66.85.74.226 443 9030 +a [2604:5800:0:68:8000::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6290 +p reject 1-65535 +r torpidsDEisppro TrVWefqRNjuXNyVU+Nx8Y/TlsQE B3fpoq2QAtpYPaY5j/y+bh3jKSI 2020-04-19 19:15:47 81.7.13.84 443 80 +a [2a02:180:1:1::5b8f:538c]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9570 +p reject 1-65535 +r ForJusticeDammit Tr47GPfTjQov3We0elXLkGk2hyM RHbJdMfU3qxxTXdvBomTkrGXLkQ 2020-04-19 21:08:24 5.9.68.49 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30000 +p reject 1-65535 +r Dutch03 TsBVD/w32IOJLkyspJ+cKbsebs0 gWBPBVxvrwqwGgZKpIHD5HHjIIw 2020-04-20 11:27:07 212.47.238.203 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13200 +p reject 1-65535 +r cadbury Tsh6q+mGd5bSbNSx0qBoJAGAcoA jXokwcMlyyOaW4c/AcqXTQF6acQ 2020-04-20 02:27:08 88.202.128.193 46327 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56200 +p reject 1-65535 +r fuzzycat TsvzfklT9IqgLKMK6Sl4khiwfIA gMUdOAzeXHKmdKx41A1tP8/8VZY 2020-04-19 22:41:18 35.170.77.224 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13700 +p reject 1-65535 +r Anabelle TtA5gbkGe8wIpWU2LebTobPVglk bm6YgG+z0qRX7yyTW9a/rA+u1Pg 2020-04-20 02:36:22 191.235.114.74 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=475 +p reject 1-65535 +r FOO TtJayMbN6rrB7CFWKW1siPi3Uto oqFOwMT9IXRBqjDtqnPdVSHaiQw 2020-04-19 22:26:39 178.175.148.46 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r bedrock TtM0FZUvpS25VBGh2oZmPsGxCbk 7zdGzyvL7s40aB/WkLus98Rt2l8 2020-04-20 11:58:18 173.255.228.134 110 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=810 +p reject 1-65535 +r SNEIPAS TtUUXJicTJasyDciJN6N+t+AZt4 dTPvf5GU5D2dwVnxgbMmRFVVWs8 2020-04-20 05:25:52 128.199.232.56 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=150 +p reject 1-65535 +r Unnamed Tuqcq49k58qbE1U+hbkq/wZO1Is bfLjeUNMTFJUh74yKPtyKDGnW0c 2020-04-20 10:23:49 91.219.238.115 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4750 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nt892 Tu5ErpIrMNDtoGq6G9kky0PoCD4 UWbEJYDL96XWDi0qQU9pMcUy7dw 2020-04-19 20:25:01 46.4.102.254 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r tazzwei TvKPCsun24P1Ms9knbE6AML5/fI zj0BjnGvqo4ySaKtBLEcOISX6VY 2020-04-20 06:57:39 193.104.220.94 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r g0rynnas TvvNpbbFG4s95Bd3z3FcAk2VauQ cyWDFL3JKPyBwzJAHRJf6is12mg 2020-04-20 00:49:11 95.165.141.43 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r Binnacle Tw235of8fArlXI8kPaiw6yf78fI YFwbalPp1AOi1Mb7po84NPWvbuM 2020-04-19 20:47:10 108.53.208.157 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p reject 1-65535 +r Unnamed Tw5dThhMQOK5qJZkAFswih3uN1Y yPwLJCsJmr3O5jy7eQGiYyJYvp4 2020-04-19 20:54:04 51.75.143.146 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=16700 +p reject 1-65535 +r Whiterose TxHyRvhxyJOggHuJcBJlEpbXNwk WoGjw3SdknpG3Yq1Em+XNoRBdYA 2020-04-19 19:19:27 176.150.229.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2840 +p reject 1-65535 +r HamburgsTor TxvkAL92Qz8rGsSmEy/nMy/buDU ggTuylGhNRbzmTXR+zee7BferBo 2020-04-20 02:17:56 77.0.165.74 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1070 +p reject 1-65535 +r greenonion Ty8PTabnOCs5j5B+TFufH8LMo9s NOuI7T9NxtPLPVBoAuTjLsIz2Y4 2020-04-20 01:15:10 192.236.160.88 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 FlowCtrl=1 +w Bandwidth=101 +p reject 1-65535 +r CottasRelay TzBW6dS6w47CEABjdFIhVTYw7Ms 6pQKmqzaOT0QUtOm9nBYGhDI4ao 2020-04-19 21:57:48 212.186.71.38 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2000 +p reject 1-65535 +r Fission03 T1ABV6v3ChqUY20minQqiyJ7i/0 PtPNMbbdFd9XCVAjxzYGVmc7gUg 2020-04-19 19:25:51 149.56.94.218 443 80 +a [2001:470:b14a::6]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9760 +p reject 1-65535 +r jpltorrelay T3j9Q+xehjKtXbbQsk+/Wf65ezs TrsQp3QBIbv65K2XwDFzSjhghwg 2020-04-20 05:03:12 71.82.37.4 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59 +p reject 1-65535 +r 0x616e6f6e T3p6YdICNLLEU/uM0wFMEA8eDeM 1I5hnrufCAJ782LG0baA1Wn5PVM 2020-04-20 10:25:57 104.244.76.69 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r walledRelay1 T5kCOReW2g1wFmd7ZiyhkTQATOc irpy/vvn4o43ir4/p17XEnZONso 2020-04-20 12:08:50 81.7.8.79 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r ATRinRO T5vjpUlzDUtXBeG4nWN8qCSlfaE VpboGgkhwH0vpXZCGurwr7dA5gU 2020-04-20 08:53:52 45.14.150.136 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=853 +p reject 1-65535 +r allcats T6H0AfjD6DJgMeeZQEW+Z/NgM6Y I2Ko5xEfG1JRqsOnNXejp2dP4bQ 2020-04-20 04:02:51 198.96.155.9 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=640 +p reject 1-65535 +r Unnamed T6tm3TbPU6TR+NkzA3+lCa3gY7o SEYDgnk376EB6mCMvgKSZGURju4 2020-04-20 06:29:48 165.227.216.31 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=791 +p reject 1-65535 +r mrkvotor T7jChmf3hcnMmL9zF8dtrsgHLm8 r+WjOsTK6bfjVZ3Sf46jEn4jeko 2020-04-19 21:59:45 80.79.23.7 443 9030 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53 +p accept 20-23,43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19294,19638 +r stefn T8ZajqBfBVNWdLsgZQmP1Af+zSI apn8q7PObxwtSnPsfYZL24Lwx6k 2020-04-20 11:52:33 5.9.12.212 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15 +p reject 1-65535 +r Unnamed T9ro1sdhtM5EF14cFdHeH48t8do OlciAeFOa6w6ZuVBtnZHWQSihRA 2020-04-20 00:56:54 85.92.108.200 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r FissionEx3 T9361Rsk3au2L7WQcfTcQh52xoU kjofwztVdNwDok05GaGigIZ2WnY 2020-04-19 23:01:33 159.69.207.20 443 80 +a [2a01:4f8:1c1c:6cde::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39400 +p reject 1-65535 +r Cicolina T+P9Z/LwbYrZKSF6NX9iP8fGktk B1ep1AKvPV3mM6iLEGwBaVAB5pE 2020-04-19 22:19:15 46.229.238.172 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p reject 1-65535 +r snap277 T+4ylQZfzNA6+sVnvAGlmHfkows UxaJZeGv5E5WjfV6NQqMyBhsNbY 2020-04-20 11:45:27 46.174.244.175 45591 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=502 +p reject 1-65535 +r RelayOnSatan T/VPuxc9lzYP/RhtL/ioXE7fzEM FfopNlVOkgNLyZg5mEL2u9UpBN0 2020-04-20 03:19:04 151.41.154.70 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2980 +p reject 1-65535 +r TykRelay08 T/jtfAcrX47ClkWBUea6u9a8MhE fc/SwuSXtA1TTO+QZn/3Aji1Vz4 2020-04-19 20:04:53 185.96.88.164 443 80 +a [2a00:4020:0:4:185:96:88:164]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29000 +p reject 1-65535 +r iSOcHTorRelay UAjkmVSsDKBWX+ivYdYWFyEqy8c Achv/Rwbd8bdWOLkTKiNZruCpQQ 2020-04-20 09:09:04 5.9.158.123 110 19030 +a [2a01:4f8:190:5176::123]:110 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1690 +p reject 1-65535 +r ididnteditheconfig UA1uPTtlzzHBDqxoIZM/YKeLDf4 dj71TlnOelwRq42gVJqM6y7zvnQ 2020-04-19 22:13:49 198.54.128.69 6285 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r nastja UA/k1rUphVovlaDLNPKhDViJ6ME uUz+fI47PlwS/4+Y33F0hWrD5OY 2020-04-19 22:45:16 134.19.177.109 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=95000 +p reject 1-65535 +r ParadiseTorRelay1 UBD9t/+ET5hWMepXnxNhsbFyrZQ qIasowNOUq6EImvm8C3/SMykYqU 2020-04-20 02:21:53 83.168.200.204 80 110 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6190 +p reject 1-65535 +r CalyxInstitute04 UBs9vyULCUoFyl28QkrUw9RnIaI LApIZLpxVQyaxsmDk1KXQfGfHC4 2020-04-20 09:30:59 162.247.74.204 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r galates UCd0ugRm066benoOoiWcxiuDmKk +L0+KkBUGwjCPTRzlN6r6M2VUZQ 2020-04-20 09:12:29 94.16.118.23 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r ip7 UDmSWLX9KTkrrPazGXysphgpU+8 Oifz6g5cme4Ov88hK6Y3ibSOOCw 2020-04-20 01:20:50 51.15.177.65 443 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24400 +p reject 25,119,135-139,445,563 +r AnonKorea00 UEAtPa2D6JI813FZFyhMhInFtes TleRuoTWcf8SJpdaARe3til8bfc 2020-04-20 12:18:42 52.141.33.89 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=294 +p reject 1-65535 +r H4ck3rm4n0m3g4 UEPl0unOmQZt8fvwsY4GWwgTGGM ahmQwfkpKZ1H3oZBRyr7M9CFjqE 2020-04-20 02:20:00 80.241.215.37 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r muffi UEeWLpev3InJue6YMi8+TLe+tjk jEXNkpEaNQr4fts1tW34WJxdaMY 2020-04-20 06:25:54 167.86.112.70 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7600 +p reject 1-65535 +r whiplash UE8j3HNEWdu6WLLxGkeZ65RRiKM v8ZHIsmSOqpLq7HoD2r2NGQ6+TU 2020-04-19 23:49:45 93.190.143.41 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24400 +p reject 1-65535 +r Jans UFhuJb4Gf9H3OZmFUO3csaFMpbI XyuAG/kPOvrDGJRmx6D3q2AJcGE 2020-04-20 02:35:05 212.51.149.23 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=762 +p reject 1-65535 +r d3xtor UGdjmUeSIImZUp0DwBZ3TIFDhqg pAf9k7BQC7hUsDEd2/DNin5S5Ng 2020-04-20 12:18:35 86.121.141.9 18213 9031 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24800 +p reject 1-65535 +r Unnamed UHwoxl67PRnvMfE4A3B3nhGYXQY iFAWab7olPkEEPnvLG3t4hCycQY 2020-04-20 01:14:28 159.203.22.51 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=88 +p reject 1-65535 +r CheenaTorExit3 UIJXWMwtpB3u9q4pyyCoA73Mb3k EykTJ7u3pvLVcQA0k78vKt1o9dM 2020-04-20 10:15:50 178.175.148.224 9001 9030 +a [2a00:1dc0:caff:14e::9ecd]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4010 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r JdMtOrReLaY1 UI6qpTIse/BIyPrbv7N9Cj4dkmI XirIQKPq886hHs6ueGAgTszApCA 2020-04-20 05:14:05 159.69.184.172 443 9030 +a [2a01:4f8:c010:189b::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9180 +p reject 1-65535 +r ASock UJmqlFN/Ls615PKwXhQr7BOAdto s7x8MmyewdQZS2CyzyVz8p43Q18 2020-04-19 18:54:23 103.234.220.195 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98 +p accept 20-21,43,53,80,443,873,989-992,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r zwiebeltoralf2 UJ6rTF0QyamiS06gzkAsBHotZOY twXDxpCZT3A29eqWJC03AdPV6IY 2020-04-19 20:48:24 5.9.158.75 9001 9030 +a [2a01:4f8:190:514a::2]:9001 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82600 +p accept 53,563,706,749,853,873,994,1194,1293,1500,1533,1677,1755,2083,5190,5222-5223,5228,5269,5280,6667,6679,6697,7777,8074,8232-8233,8332-8333,9418,11371,19638,50002,64738 +r niftywabbit18 UKDPtlTTn0IPUtNisd9QoSsz1aA CEXwodUsJf/6jyjYY/yOr+fVep8 2020-04-20 10:54:18 185.220.101.248 10248 20248 +a [2a0b:f4c2:2::248]:10248 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19400 +p reject 25 +r erbridge UKQ5eDJLtX6EnqPcZ7a0h8ugjOY Q1GBpWXdc4yryPPnbSSoPkfl1Ww 2020-04-20 03:12:32 87.123.103.254 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=932 +p reject 1-65535 +r F3Netze UKqf6mo6YJaGJ2xM8MKhr7Lsyhs vxRdrdwuRAtwgRvQF677kdm7nz8 2020-04-20 07:05:15 185.220.100.241 9100 9101 +a [2a0b:f4c0:16c:14::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=65400 +p reject 25 +r Eepi ULa+Z3zggxUcAMTNRybZALrRhys 0xrREan6vTq6zX2ppBPVUNiPE+4 2020-04-19 19:51:03 62.78.196.84 9001 0 +a [2001:14ba:2300::64:1df1]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3220 +p reject 1-65535 +r niftydiatomys ULeHqfshQXv9e1BncH2/gtcdsRw 8Ln5ipnIjWq/CmbODCqk8VjKC/c 2020-04-19 22:15:53 185.220.101.139 1139 2139 +a [2a0b:f4c2:1::139]:1139 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59100 +p reject 22,25 +r ChristopheRelay ULrU5IZGeXeWEH7PAZIXhJUkcgI cYcCwV+l1c8XaBKJJo11Nz4Rn0c 2020-04-19 23:09:51 23.233.5.61 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=510 +p reject 1-65535 +r niftywabbit9 UNFHOiE9s0PpdmTHHAnSjsJpLLM J38aL2wt2JlwnvAGPCciEm+8pg4 2020-04-20 10:53:26 185.220.101.201 1201 2201 +a [2a0b:f4c2:2::201]:1201 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74000 +p reject 25 +r snap277 UNgmrBkfR5KhSagSdOn4GIFVL5s juiS9qI9UhPj8NYARLh6A28w1dQ 2020-04-20 12:08:24 117.242.30.113 39073 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r binar20140514 UOHenYpHs1B2RuWQ6v3+uUpI/Uw F5jtFCfdmGbKJJSQMaq1r05hRnM 2020-04-20 07:33:23 130.180.23.230 110 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=104 +p reject 1-65535 +r galaxy3 UOPOoNfrlkS4m5ZXQ3lyeRlnddU mliLimYrcryMH4xBRIHPu/+eoDc 2020-04-20 09:31:52 54.67.75.217 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4700 +p reject 1-65535 +r eclipse06 UPYhatcOJrn+cICDgKF1S9890OU 7w69q25qKTWjB8nklmjj/PyRhmg 2020-04-19 20:58:02 81.16.33.32 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r torpidsUSwholesale UQF2wHAF1Hsj5nlvAskyQaKaoOk /Kmggo0Ao9WvX9TZnjLmkZL3FUg 2020-04-19 22:05:08 69.30.215.42 443 80 +a [2604:4300:a:2e:21b:21ff:fe11:392]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20400 +p reject 1-65535 +r 2000me UQ8Usu/6jKQTHwkIHNaYLGFOpQg gqQli3nOmNYSvEyLaudUci7Isu4 2020-04-20 01:46:38 46.38.235.14 443 80 +a [2a03:4000:2:a11:3a58:da1f:cffa:1bc]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p accept 20-21,43,53,79-81,88,110,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1293,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,3128,3389,3690,4321,5190,5222-5223,5228,5900,8008,8080,8082,8443,8888,9418,11371,19294,64738 +r lolMordekaiser URQqHfZEUcd1DsuFeINkpooHzsI bVcTYSbssaxe6wCc3KdrTAStAUw 2020-04-20 12:20:48 82.223.17.164 8080 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p reject 1-65535 +r MLTorNode02 UR9m5ASV47Reoh8AI99xTbSHJXo tGnRSRiGhyrSY8nm4Lrsz0A9qTU 2020-04-20 10:20:28 82.59.205.29 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r ucube US1wHubFgfuZWedkL7iixLLRpGI GuEisiVhxBgg4WvXi83iDG+madY 2020-04-19 22:33:18 173.73.247.219 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56 +p reject 1-65535 +r LetoAms UTMp4999YeVxIC7YhuUnp0TuUvI B8M1OfyYT0wOxSI+c8Ve8/Qv56s 2020-04-20 01:33:57 193.110.157.151 443 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2620 +p accept 20-22,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 UTN9g9a9nNELJ0Qk6r3Z1DwzoIY RqKBA0M5qX4gJjOeFdHhl1HLY/4 2020-04-19 23:04:30 190.53.75.178 46791 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=58 +p reject 1-65535 +r stellaranomaly UTdMjaRZxnMp/9XHUCzK5BlJEMw AAi5YDixUDRcFtNQbBjc1a4m1qs 2020-04-20 12:31:51 96.65.68.193 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=800 +p reject 1-65535 +r verrueckt UTdT0sShJG3MISQcW+UCLMvSZFw PO7IzfcF+8e+ni6Wmnhd19pzoSo 2020-04-20 07:55:30 88.99.61.201 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26300 +p reject 1-65535 +r apx1 UTd8SWgYVS4mNYOkTHlt8/sLxxs Yu+BXFFJMFwt42c7ik6JrItbGtQ 2020-04-19 23:52:40 185.107.47.215 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=64000 +p reject 22,25,194,465,587,994,6657,6660-6670,6697,7000-7005,7070,8000-8004,9000-9001,9998-9999 +r Unnamed UThTb7WYFM9lVZqolSavhlCsQx0 CBxP5/n+O4pv3B/1IMWIfm+L7co 2020-04-20 11:47:37 185.82.216.57 42899 39793 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=97 +p reject 1-65535 +r Unnamed UWA0/xXJbOhB7M2HbvYEgCqlxlA HjVVIVJ3/kvZ5ZuNZJih7XHYtf8 2020-04-19 19:54:13 89.163.225.115 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23200 +p reject 1-65535 +r Artorias UXByDpVAkOYoMD7x87rv2sRTR5E ZOE1rdUX/1VkMv78VaFd+nNarlg 2020-04-20 04:13:31 191.232.244.192 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=454 +p reject 1-65535 +r Unnamed UYAK84sw7RRU3XTLQSutztX2BZM Z8L92nxgLt2xRASV3WnicOOgjTM 2020-04-20 06:57:25 37.191.206.197 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10900 +p reject 1-65535 +r snap277 UYjVdDN54Z66rzkSdLGFS3FOn70 Jq/sJdnVWHG6HBGNiij17lu6pyw 2020-04-19 20:27:49 212.45.92.231 44561 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=765 +p reject 1-65535 +r snap277 UZTR2guo8sDQmT5MFCAgbog+Mr0 3pBz3Zt0W57LzuVshtKXhKXZLyc 2020-04-20 11:13:54 102.103.66.73 44733 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3 +p reject 1-65535 +r nodvrelay18 UZXMI2HdYrYgMqjsf3qjUdVnwVM 0Sh8HK4ScqW0P9Kfgmkc1oI3jbo 2020-04-20 12:45:10 104.167.114.202 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2150 +p reject 1-65535 +r HEGX60RelayA UZfgsOeF41R3rLaD823mm4fmvv4 wRtIivem+oNPcCnnv8FY/Gs7rZ4 2020-04-20 06:09:25 45.76.116.56 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=109 +p reject 1-65535 +r whatever UabOk7ilBnPUkTs7Z1PoHACRRJg eBd+kQVef0kPVMzuXriNejqCix8 2020-04-20 04:27:37 213.144.156.192 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2630 +p reject 1-65535 +r notoriousgib UaiiKUTyKOotYBQ00SeGSxsLD4w YKbAJ7Xv2ovK2pb8krHUesgJkMc 2020-04-20 10:23:57 103.200.210.66 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r mycontribution Ua5WVsgc1BdHklOmNjoSOgB6IjM tlH7zdnmo7aMDpbgCMyFcHiyI9Y 2020-04-20 08:04:42 51.38.64.136 443 80 +a [2001:41d0:801:2000::270]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7400 +p accept 20-21,43,53,143,220,389,443,531,636,706,873,989-995,1194,1293,1723,1755,1863,2001,2086-2087,3690,5000-5051,5190,5222-5223,5228,5555,8082,8332-8333,8884-8892,9418,11371,11964-12966,19294,20001-56001,64738 +r wobble UbP8yrcUAR4xdyP6rLcY3Oxu5ec SSCIcK+Zzp6xEAnH0M1ITztvtVE 2020-04-19 23:59:20 174.34.225.215 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=810 +p reject 1-65535 +r NoBodyPi UcAJbz1+4qCCvDZ6Kfgcn82b8nM uUunw+wd5DqgL6B06bGuhxIklAM 2020-04-20 00:53:48 79.21.183.84 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26 +p reject 1-65535 +r Alpha Uc2dsANXQF/EGvD6UTaI0CvaDA4 s3HOkB3Ri/GlWsr77NEivN/dq/w 2020-04-20 11:10:31 31.131.2.19 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r TorMcTorFace UduL3O+LivxF+5YrVdvQ+MQL+c4 doDQBxzsFthPxW3vvcY514Xc3NI 2020-04-20 11:57:58 67.211.133.100 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed UeGL0iz2e/jBEI9+zJoCU7cv7Bg oNGV7jiJMph8F8iJjdIoeVFjMMI 2020-04-20 07:06:52 209.141.45.119 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4340 +p reject 1-65535 +r torpidsDEisppro3 UeHPYT/W+fEf4kdDyR1vmYGAfYI U4PXmM6LDxQrv7GxSOSAtZnchPI 2020-04-19 22:08:34 81.7.16.182 443 80 +a [2a02:180:1:1::517:10b6]:993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3050 +p reject 1-65535 +r bing UfXagY4nMKKpbmlZipdgEhvvQoM Jx9J4HYdwu8dliYCBCpu+4zcF9M 2020-04-20 04:36:57 128.199.196.93 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=317 +p reject 1-65535 +r bosses2 Ufcz6sTf0SjPlXoU1fLcAjgD0aI hv9rKda5bhLfThlz2AynmzblaXI 2020-04-20 07:08:45 104.57.231.27 80 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7300 +p reject 1-65535 +r wille UgGdol90VV+GHo6rkechD1IW0d4 Kla3virlwMbrdnSK7js+AyyXnK4 2020-04-20 12:27:12 83.227.105.35 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=931 +p reject 1-65535 +r frenchonion UgJlZSY5Y6TafApzfkOFCVFAXNs h7ureGOaj1KmZ1erj36gsp/aok8 2020-04-20 06:54:03 51.91.121.255 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7680 +p reject 1-65535 +r anotherrelay1 UglSCYrsCKn68oAkgqYasb8urCo PUrccWVfThPaG2c/PzOTCSVZwaw 2020-04-20 07:04:01 144.76.118.86 9001 9030 +a [2a01:4f8:192:7355::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p reject 1-65535 +r niftywabbit11 UgyFq+bnMc7MKLEFWFQFP6ooBhs Fw3zgB6LL6motcKj65Bf4vZ9sow 2020-04-19 22:15:45 185.220.101.151 13151 14151 +a [2a0b:f4c2:1::151]:10151 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p accept 80,443 +r Unnamed UjZXx+7EN4sutJZZxJx5bys3ktw jcNprlXk74Tlv0L0IJn4vOlT/zg 2020-04-20 00:41:16 128.73.122.211 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4060 +p reject 1-65535 +r t1r Ul7jTBp7iaud9YUkbeMOMnApE/U DFg0Ly5iQlGANSDm50EjZh+kn60 2020-04-20 10:27:05 144.91.125.239 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r RMB2 Ul+mk5pjNFjYiGlFVHRjhkV6WB4 tGD9eVo5721dvqQIpQhLz8P0bmc 2020-04-20 02:07:22 91.8.210.123 80 9040 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2980 +p reject 1-65535 +r Theoden UmJVbUSn8kNJkP3hrnlzxn30nlg UgQKrSGtF0opfqgESTjWjQa5mGg 2020-04-19 19:24:06 176.223.141.106 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p reject 1-65535 +r Unnamed UnL666bCe7hQhCpds2WxuGZYU5s 8D7bY7FmIVIErzu1F2NOrdMPHPI 2020-04-19 19:37:02 185.219.133.40 84 21706 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=530 +p reject 1-65535 +r Dutch04 UpOoMfDvUUYLN7N8I5vJdcB36SA cXsJs9y9YyDivpRVME+Mih5VALM 2020-04-20 01:20:34 212.47.247.109 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r BobsHouseLU01 UpUoYLgQed5zEGIhbwRD24nBR5A /NRESHFU8pZMWHdgrbkesgroIq0 2020-04-20 09:58:48 104.244.79.77 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6940 +p reject 1-65535 +r Jarvis UpcFShLOGGZgogZCTPZgjaJm98o JxNeRLkaTLSvMF0QdNig2HxemCQ 2020-04-20 05:38:38 82.158.117.162 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r asfnutt Upyj6witbsF5G1EQqjVApM+hGX8 ++nbelDOuzRMDPsU5NOfqGFrgos 2020-04-20 01:31:44 193.150.22.27 9001 9030 +a [2001:67c:24e4:10::27]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r morata Up2chODWphQdQJwbAtuBsrjo6XM 15RL8UEyF7VDjCnjX7hYFAOQA0c 2020-04-20 12:46:47 103.236.201.88 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=530 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r KienjochFR UqAi8W2M2/AZ4TLxU4oXmPFnlzo RCy2oVF3PF0fAC3OO7wu21u9LmY 2020-04-19 18:51:16 51.158.170.28 443 9030 +a [2001:bc8:1828:2b::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26000 +p reject 1-65535 +r TangerineNao UquHZ+Eww1GZIMdwcucvNHl5quk 6KSiye04fbs6GITBPdfg3VBfhuk 2020-04-20 05:49:42 132.145.49.42 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2070 +p reject 1-65535 +r Unnamed UqyMgu1p/YV9wpfjvNjacBQuZAs +YUUXN0WTSvqeHo7TMxiJSdkoMs 2020-04-20 12:00:14 167.114.89.198 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8860 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ieditedtheconfig UrOMeDFLWVt4TXzBvfpzpjgYcm8 780AUMnoc5fvY39tTDsgz7mOAZk 2020-04-20 00:11:37 116.108.127.28 443 80 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=141 +p reject 1-65535 +r AmirTaaki4President UraHZOJssE2uOr4foBgm7yc3bGg RM2HFT5W5B2gsdNrWVk14SvNVys 2020-04-19 22:00:13 46.101.178.190 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2630 +p reject 1-65535 +r BeastieJoy63 Ur+tqL6qAbpGyPdn+DwY4v5Qwbk 8ccWd0hPfqudqq4fbT7UkxrX+hw 2020-04-20 09:43:00 85.25.159.65 80 995 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23700 +p reject 1-65535 +r jesuislavache UsGJ/wH99/oXfWZ4w002L3vEXoU QxOFezbcj9yE7LQZDJZXhUPC+CA 2020-04-19 19:50:35 93.23.182.133 3456 3457 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=388 +p reject 1-65535 +r Unnamed UslYf6YTwBE4E12j3z5dcldSRi4 L/l1J2UJW7zsIVwsMsXDeXNotrY 2020-04-20 06:23:49 139.99.55.186 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=570 +p reject 1-65535 +r snap277 UtPYgnbSN2xTMnTbXZBpBs2ZePQ CNNv9Uro92+DGZHV2DJu8BPPq+o 2020-04-20 09:05:56 87.231.31.74 40749 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=96 +p reject 1-65535 +r hellebuz UtX7IATGcSfHO3FHgjj6ZhIr1EM j++EzUMlRPDVFqcBTo2ua7DB40w 2020-04-20 11:37:02 62.210.181.119 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48000 +p reject 1-65535 +r Unnamed Utazc5Bp109eBaOOB3PBZiFKQgA dkVcidn4xQ60V9NqJPpWqWyrgmw 2020-04-19 20:59:57 69.4.82.204 9001 9030 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17700 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r TVISION02 UuAYVj+jHRPWd24Il69oqj4h6gg h+wk0NthkQuIt4yI/Y8oJIHCfp0 2020-04-20 11:31:31 80.127.107.179 443 0 +a [2001:981:4a22:c::6]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4330 +p reject 1-65535 +r OctopusMulitplier UuSASo21X3lgSsA2ESJoIK7aG/o slHHoXeHdE7s8JkXvXdDmknIMns 2020-04-19 21:04:00 63.140.30.205 9111 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r chasm UvDJOMvL9CQxD3pPtWM/Zk3eEhc 5zZP35d406qorWOO35l3zYu8yV4 2020-04-19 23:12:48 89.111.20.20 443 2013 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=834 +p reject 1-65535 +r spargel UwJ3hmRmoUJfQ6c9v8tfx0EMmFI YE3XyQdiRikh0X7XheWE43XG+pY 2020-04-20 01:17:16 109.70.100.1 443 80 +a [2a03:e600:100::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=92600 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r pineapple Uwz4YEoMca0RP58548knprlSL2U e6BdVmc5YuqSESXIy/d9QDxlFHc 2020-04-19 22:29:40 79.207.112.56 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r FriendlyExitNode2 UxGFvIFCQiWwHQe1DPauFR39npM CZoRgqqOt0AA9b19XNGo/HE65JY 2020-04-19 20:53:53 209.141.45.189 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39100 +p reject 25,465,587 +r Fission08 UxNNljfZ++Vl+h46+CsjzJZMVtY /XVy1XpF+nUUcLcKeHUK2rxdFKM 2020-04-20 11:25:08 37.59.76.255 443 80 +a [2001:470:c91a::7]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34200 +p reject 1-65535 +r nicetorbox3452234 UyoIxQD12oXQxn2BzioT64h+NCc LEr3cGipDPPWA2Pq0oPvc1x/SNA 2020-04-20 12:43:21 81.187.237.57 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.12 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=41 +p reject 1-65535 +r Unnamed UytcrPUXhy7nILU9cbxJnEeWTrE HJ6Gqfy5fWZseU0gj5YfWRjCyXo 2020-04-20 07:09:44 71.19.251.218 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1600 +p reject 1-65535 +r ethergeist U0EtzFVTNbQA23J1DtC+CNA013k qd1Prc/Nat4a6Qg1y6pXvJpDkc4 2020-04-20 09:45:16 176.9.28.164 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4080 +p reject 1-65535 +r revostrips U1hpSs7KQ0MCXj8pOrZ79hRGbXY Lq93q/RhIzVufOrGP3IU6VJdWDk 2020-04-20 10:31:12 195.123.245.8 9001 0 +s Exit Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r Nozel08 U17AnMnHb4ZGUZhZOqalqs123b4 dzWQCisCHP1C7cIsDJViIIO1ZHo 2020-04-20 11:54:44 51.158.22.87 443 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29800 +p reject 1-65535 +r berders U2irjZAzo1dynTV4YXpkk6tdo6g wHNFElmd7j/UQUAcWMNGh110P38 2020-04-20 02:55:51 147.135.4.38 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19700 +p reject 1-65535 +r KaarliVPS U338IBnHf/YKCim+81j39tbGhog xMwAY0BLtUOV285FdjEfHOOFQls 2020-04-20 09:58:04 91.134.137.99 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Unnamed U4CHvqrlFpRI4DCk0FnoZrtMNJM YecyjgGyk60jpZbpw6rSWPN3H0s 2020-04-20 05:26:46 142.44.246.156 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 25 +r ip7 U5EGK7YvW4Eos4D3koWeyNzJr1I kLbD8dQl4/kHytZUvz6fVCOKK9U 2020-04-20 01:17:02 51.81.253.22 8000 8080 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 25,111,119,135-139,445,563 +r Nozel02 U5q8ya8P2AJ46JRXoWY9q66/gd0 HKp4nMgGhJ0C3cjOnhDL546Yf64 2020-04-20 03:46:52 163.172.210.193 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r a471165 U5+2xpPtGMcoLPOoeKSt1TheILY q2oC/Uia4y0j0BeQUJpcfnfbewc 2020-04-20 01:29:06 188.194.255.211 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r 42isNotTheAnswer U64XtVjfour1UbZQ9iYLPjH76tA wzsuNbjTh6Wmm6MUadWvW1msYEU 2020-04-20 05:56:36 46.165.253.180 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1850 +p reject 1-65535 +r Nicodeamuz U7N59AY7O5GySn3/zC9lM/UbMkU lXi2hYTvWmA+X/4WIuwEwIsOirU 2020-04-20 09:34:00 216.197.76.237 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p reject 1-65535 +r 2livebrew U7i1wqM8SJtUMA1Vi/7iw7EvOHU B+6323zivtmBQVX4EkOcLTuUfoU 2020-04-19 23:58:49 104.244.77.111 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3520 +p reject 1-65535 +r Aramis67 U8n0lU56czK7DGEMW44EygZa8ps A+NNBvkhY2mCeEUzmSmFhEwyNnk 2020-04-19 20:33:11 178.17.174.239 9001 0 +a [2a00:1dc0:caff:126::a5c9]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4490 +p reject 1-65535 +r niftywabbit4 U8vUKFkY8Wi5LQXKqbwM9Jnfcsc Nl37/fCFet7cMAfUPXuIX+Bt5PE 2020-04-20 10:52:49 185.220.101.196 1196 2196 +a [2a0b:f4c2:2::196]:1196 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=51300 +p reject 25 +r Oirat08 U80aHHD37VOuxOLrghs8o+bhb3A iltbv1HD7AhV7GD6zncTpATxo84 2020-04-19 19:19:43 81.177.255.154 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=958 +p accept 1-65535 +r Toready1 U9ebv+213hw89IObKHWFnOVNe7E zxCBXtekMJMzvy9WNnsf8W9dCKU 2020-04-20 02:15:12 158.101.139.86 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=652 +p reject 1-65535 +r propsy U9kFaqakxWhnTrN+0BjJeNA0i5Y OZ9x62sx9qO9SfNCjbm9w9KPG4w 2020-04-20 00:09:15 31.31.77.176 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r 4a1b19f37d7b U9q5Qiis/qrimMMRGGDA8qaA1MY 93Pba0aC3mNTB11tJ+XOcFyL4+s 2020-04-20 08:23:49 51.81.253.194 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ILikeTor U+ia2bkyB0nwTcp1fxxNrOZiBbk lYvWx5V3ckwjpn5JmxDmFzhvOf4 2020-04-19 20:38:08 167.86.127.29 443 9030 +a [2a02:c207:3004:380:bad:dead:beef:babe]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p reject 1-65535 +r snap278 U/DjGC6zuS6s/JUBfLUEiuPbtOw cOnaskPmskkcmmS9OVUl/gXadWw 2020-04-20 06:29:49 209.93.127.251 33387 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1050 +p reject 1-65535 +r revofack U/l9hz9m7+oBGWGJ5bkrrMvXG/k UhzYCA26yl1j9hFvjjZgd1qxAdA 2020-04-20 09:50:14 94.140.114.190 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=211 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r weirenminfuwu U/8e3IUor0I4+3UBgx5rrP9LQtI i95hhHbWCNTxdEzV5wiWtX9Zw6o 2020-04-20 09:07:43 195.123.225.112 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p accept 53,80,443 +r Unnamed U/82iQLRJPqagG0UmvIsOmNXsVA 2uV6xGtuLvOt3H9c8L0YOeY5BoU 2020-04-20 12:36:08 191.114.35.150 9001 0 +s Exit Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r itok01TorRelay1 VAv71Y1/DjyzTgHDLRePIQvdJYE oU9hYtDestfqOqHCATeMl4WLozw 2020-04-20 08:14:07 14.12.148.98 8704 8705 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=220 +p reject 1-65535 +r snap277 VBAvk1w50VAjHIymwJ3ncO23+Os scT1blpZUtQV8IKWl/Nm6AiYpOc 2020-04-20 12:14:49 185.110.74.135 34413 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1340 +p reject 1-65535 +r Assange004auX VBLYYsdiXxReFtPYMfbTOp+vXuk hMv+L+UXCt/lHd5RgkNKOzF9Qh8 2020-04-20 00:49:05 139.99.172.11 9001 80 +a [2402:1f00:8100:400::9]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1410 +p accept 53,80,443 +r snap277 VBXx8MIopc8UfLczvZajsexDe2g gySdiEcOf/fcfodhpLQrjWGPozA 2020-04-20 07:30:24 78.246.201.53 37875 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r orangeApe VCVov/w2J5zgyp1P9JcjMEd/heA o+5RermW6e1Mzgl9o8rWdaD4chY 2020-04-20 11:39:16 37.235.55.83 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=780 +p reject 1-65535 +r Airlock VCg5lOQ+26aYmivGTEF+MxUPyaU 1rj/kHPLEmGQWXWyHDfs4KbHDGo 2020-04-20 00:28:26 37.97.253.176 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=510 +p reject 1-65535 +r snap278 VCk+xuszoY3nORERxJ+zOWMzMq8 e5vq4sOhvhou9TQZ6xLySWtonnY 2020-04-20 12:02:54 31.48.144.114 34879 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1110 +p reject 1-65535 +r grog VDb8cqverDm/WOZOXhLEYqfT0Ig sNrW7EtBugAPdHqtMgjmbs1oRH4 2020-04-20 03:07:40 176.53.22.142 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5770 +p reject 1-65535 +r OignonCA VDcdZPSu2M0e+O0bWMclxAY73kI 4WXgg6Pdge3sn8M0Wa5Z268x72c 2020-04-20 01:36:57 144.217.75.110 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13500 +p reject 1-65535 +r CoudroX VD+W0MF826wyb2RNsMihcZO8z8k VEral7j4YJiRwX6BbT0wrCvvOz8 2020-04-20 12:33:06 2.57.236.215 9000 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26500 +p reject 1-65535 +r onionXsrv01 VEzbbEHyQx4W+xJyYsQr++HllQo GrFMvmLvftLxogv5Uhxvau8Y4Tc 2020-04-20 12:16:42 80.100.27.41 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34000 +p reject 1-65535 +r Zimmer3220 VGBRAHJFo8UGbKSAKxroEfDEFyw ys09RY8c0rd64biOaPafIpzck9c 2020-04-20 12:43:03 185.146.157.196 9001 80 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r lftor2 VG5SqXn7D7vfHd82D7IKoD0iqs4 /tsfTqGtiPfH6v7dAzmFzAfpLiY 2020-04-19 20:00:16 51.158.102.143 443 80 +a [2001:470:c85d:32:216:3eff:fee8:4c2f]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r choiseul VG8IQIbMV9V7tU1f9L8qEqrOX5Q 80O3oThBvE8+45BHI2WVfDV5ico 2020-04-20 12:42:59 79.134.235.243 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=883 +p accept 2000-2500,19294,19638,50002,64738 +r kindofawildcard VHv8Qp2fyN7EAJ7I2oVRMblmwMM nJ3V7Y3YBShxEizaejFhi0OU7Kw 2020-04-20 00:00:00 104.248.135.7 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6030 +p reject 1-65535 +r Tange2LV VHwc21FnmOxmoB8EpYhNzhoVGRk GJxkFNEjgvz3/Ux5oAKbTVvJhoQ 2020-04-20 01:41:20 193.106.166.105 29001 29030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=62000 +p reject 1-65535 +r chaucer VH2lb2uItsWWs+MIaAPNpPDvjyE 5x8LRn2xsz/t78Wph85kFzZAuJQ 2020-04-20 08:26:58 192.160.102.166 9001 80 +a [2620:132:300c:c01d::6]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10200 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r taki VH5uaK3htvSSxERDWIqTlhBAHfs KOfcaYpKREiQEqxsKkPQxmk81Uk 2020-04-19 21:18:26 51.15.54.117 443 80 +a [2001:bc8:1820:c0d::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16800 +p reject 1-65535 +r ShardsOfNarsil VJLnYGSKq7e+wIvIfo9y9V+7qQ0 Kdww0wax56zFFcdYsKIHVfoU3Gs 2020-04-19 21:51:39 75.176.45.87 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r kima VKNeWC+eF4VC7M+kjb4U9AFymWk 2bUJqWDJdX+XmC2xP7EIRseIs2w 2020-04-19 23:57:59 107.152.35.167 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8400 +p reject 1-65535 +r ulula VKQDobAV9uWmQa0SFTCWa9hzE24 jea1z2y+pNo3WOyOzarOp4MAOrY 2020-04-20 11:06:37 81.6.43.252 9001 9030 +a [2a02:169:200:d::15]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3680 +p reject 1-65535 +r QuintexAirVPN22 VKSCC0bmVQm/PiuJLmaTCkF1nek 4yrZkIotKz30qiM1xUDXaCl5SKg 2020-04-20 10:56:39 199.249.230.75 443 80 +a [2620:7:6001::ffff:c759:e64b]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r snap277 VKo/3wT8O/+QuVdytPiIFXbuuZw MEz9xo3ZDP2jr2AgQd/lQTJitRo 2020-04-20 09:58:45 24.56.39.147 41387 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=638 +p reject 1-65535 +r unlobitolon0 VKpMz+gfTdc5HYN6uwiS11NV3zA vwijfqIXuZLJ7QfrqLMCQbBCiIA 2020-04-20 02:17:08 178.62.94.243 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=87 +p reject 1-65535 +r snap277 VLZyEJ36a7qyrMV6DjybrVZjkxw lE2vtgxLPtnbjLcJCeEUTYp1YIE 2020-04-19 19:21:21 91.167.89.29 37151 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4230 +p reject 1-65535 +r king VNASsk5UsLPG+MzP1xf4/puytEA UksxE+WRryKDRZ33F4Lxtk2w9ec 2020-04-20 08:20:50 51.68.201.115 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20400 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r uzieka VN5j9FhwWLeRUqdaAjjX96AnkhU 1CvtAK4Fck9e8rLDpUzoyg8+sx0 2020-04-20 10:27:12 192.36.38.33 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=67200 +p reject 1-65535 +r macaroni VOM8/k1zH4rIam+aV0Y9bNht+5I 5/1NAtgfsjP8898kVAq5a7MRVI4 2020-04-20 01:40:10 91.219.28.85 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1 +p reject 1-65535 +r Unnamed VOO7XDCdIJkfThYAP/YIOcIWx1Q EMQKYRe/2jJBSoM6koBFSU3HITg 2020-04-20 03:58:35 75.159.40.37 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r nix VPXYAN2Xg/zyIA6A7z0ahno/bWs zdDoEWurSip/6S9Xv7m8CAIpn8g 2020-04-19 21:36:16 195.154.119.203 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14400 +p reject 1-65535 +r arbitraryTessa3 VP+H4Yz0s1G7B4pkCk3FJllpSF4 bT9p4Qf6YEqfbE+Jozr2InNymyU 2020-04-19 23:23:21 95.216.19.206 21 0 +a [2a01:4f9:2a:1430::3]:21 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r Belf4gor VQSx70MSj5pjqY50eCvYoZIL3jk Ko+reiLdDBRrIzy730GerxttFcs 2020-04-20 07:19:14 151.51.144.130 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r KiandChi VRJVdJH4fYiPxIX/ZIQmWnVKv1M tD0vdXyvK6EG2EIPTV7IwNei4K8 2020-04-19 20:31:09 82.221.131.5 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9980 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r essence VRnZreyAiU0//VZLWKxCWus4zbM IpHOHb8CnPE0Ry89Xo6o2AYqEMU 2020-04-19 23:33:44 138.197.144.191 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=649 +p reject 1-65535 +r StriveForFreedom VUA7llOoH2jDl4fgAL2fl+HzslA 8HJu0S8tQ+vND/xx97xLtkhp6FE 2020-04-20 03:57:30 173.212.231.228 9001 9030 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p accept 53,80-81,443,993,995,1194,8008,8080,8443,8888 +r Hypnos VUtUEEoWM6xZsha0IiQPqClZV/w baIxcLBVW3c1ggIAfb2z84fZ60U 2020-04-20 00:42:22 178.7.15.157 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r VeilsOfTheOnion VVgNcbMXoHL0pNz26k7bAVc0ruc rvuJPZTSC2xUigYGpKd98Sc/qJc 2020-04-20 04:29:22 104.244.78.147 443 80 +a [2605:6400:30:fd57::4e93]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8920 +p reject 1-65535 +r jakfrancjamoze VVj1RtKplt0vS2piohjfI4SEUuM iUnjiE3ZVdT2OxfwG0x1ln5BEeg 2020-04-19 21:36:11 5.135.156.12 4899 9997 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=810 +p reject 1-65535 +r snap277 VWFQBDD51s5A1maXcE15ca5bcGc YnTGY8LidPA9QLWhltC4hKG9mjk 2020-04-20 09:22:59 37.6.40.250 34553 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r puente VWy3jQpB/yA1rL3OV/+eYZWpMG0 TIE34kVcc1Ey1wfzpbrXHGhah+Q 2020-04-20 11:15:24 103.104.244.25 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=740 +p reject 1-65535 +r ogopogo VXrOyFD1Tu5lg5+Dys4rCCW+gR4 AtXuzTyl5BI9zrOmv2onjep/Pp8 2020-04-20 01:28:59 192.160.102.170 9001 80 +a [2620:132:300c:c01d::a]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r KUEXBON VXs5FG6xIcjPoixIrXi9vbyP86E SL0Gj2o/zZmGWpsW/SU+rzoPo7E 2020-04-19 19:32:55 185.86.151.168 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p reject 1-65535 +r DeezNode3877619345 VYBPnTf3snvQQms8sGxktND5VUY LvKN90fm/M09J15s/HESiCj4Muc 2020-04-20 03:05:16 85.165.62.233 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20100 +p reject 1-65535 +r t0rnod3 VYK77BI4DjTX37jCN5OaCzF7IF4 R7w0i10Ji1DAVZpfLdqiSiYE9WA 2020-04-20 05:03:19 91.126.47.64 9001 9030 +a [2001:470:ccc0::10]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p reject 1-65535 +r snap277 VZzm3SGkfBr4usjz73wlFiEYHp4 t/1rbWkbQ6B2lEIZxDjP/R3dWuA 2020-04-20 12:24:23 24.228.48.185 39609 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3100 +p reject 1-65535 +r Unnamed Vakr4qdsZKWg2w1PYdXco3tV7lI pvb+3NpMBkzbvzwcAbzuZ0IYDys 2020-04-20 04:31:48 213.220.220.60 443 0 +a [2a02:8301:0:e:20c:29ff:fecf:4819]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 1-65535 +r Assange034us VbWp25wrV8A1Q3o8xSprEdh3y90 ZU+bVSj4UapM426y1R9tNrM2s44 2020-04-20 00:56:09 162.212.158.82 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9900 +p reject 1-65535 +r actinium Vbz+VQs2lmsjbbSNS4jdo2ddwsU 1UZppYpX0+5qH2u5b4p0sQdGq9k 2020-04-19 21:30:16 84.19.190.178 443 80 +a [2001:1b60:3:172:1325:102:0:1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4334,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Johnny5 VcItE0IS7jQNgRwZm4jHvLlDtzI o1qiX2TfAh1CIQwVj1+yFkoEegw 2020-04-20 03:24:16 87.221.45.78 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r tertuny VcaEfoZsUMorLtltpitXN7MRB20 0MAXszOe/AfJ7k8NK7yv8W77D/w 2020-04-19 23:50:00 66.42.114.168 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=1110 +p reject 1-65535 +r raccoonsociety Vd/IIeg55t7xcpQghcXe0jAskLI kQaJmRpe0J4ExWS7ZLRhDXv3nao 2020-04-20 12:30:00 188.40.152.137 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p reject 1-65535 +r fmi Ve6IZp4MePP0p9O3S97FkI6Yqd4 R7jc/u+LwhT4IkNpBxKqrDyMJbE 2020-04-20 04:50:43 217.23.7.103 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6340 +p reject 1-65535 +r RASPdatenschleuder VfHO0+JZBFpDpHbLxtMPdsw/Ybc rYJ77c3Yo/Br2/bCJpJrM1bLqow 2020-04-20 04:23:22 92.117.237.63 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r tor4ever15 VfVddo2wi2Iahi9vp6xabNmi4p0 Qp2PZCCVq2iak7/VW7c7ogmyWjA 2020-04-20 04:47:28 45.62.228.29 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r poisona Vff1bVjIxAqanfPVCMHyagTeNgw NlszReQFwD0ntotR2BQ1cdIXLkc 2020-04-20 04:21:16 87.245.100.100 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=968 +p reject 1-65535 +r king Vff3zDAr3zvb+FvspmPBX+aUH+A 3Q12nGoBQL6scKHBKCxnTkQfnMw 2020-04-20 05:46:18 51.89.200.104 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14400 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed VflcwpVGJd+qyjo/WdoN6qPG5Xc ZjVT0GfS+2tNFU5Z2fhZZBO+wIM 2020-04-20 07:32:37 172.86.139.148 42448 0 +s Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r HedyLamarr VfmFfvT5H3ycqprhqkQg+A312NM XoAfJncxzanxZwNuxTBGwago2X8 2020-04-20 06:29:58 134.101.28.3 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=76 +p reject 1-65535 +r peoplesCYBERforce VgOU2U1WRtrLxiPWHUO5CepCKd8 qYsZJaB8QyW+c1YHLWCIy20oCi0 2020-04-20 04:09:15 54.37.137.0 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p reject 1-65535 +r Unnamed Vh11R/NRsNkFFEhR0pBaC55RK80 jczv7W5Fni2h4G8lothTtWpIX1s 2020-04-20 08:00:56 102.37.1.72 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=255 +p reject 1-65535 +r bakunin2 ViQ02YfPSdRWSbdq3KmTvqj3hHE 0/6THnzOgdDOE0lt9XP5ojSoIgU 2020-04-20 01:15:14 193.234.15.59 443 80 +a [2a00:1c20:4089:1234:bff6:e1bb:1ce3:8dc6]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8800 +p reject 1-65535 +r jimtahuGrimlock ViV+dPqZm8+h7CBYkjQqCWRblhs gDgvoyoU0ABWQyg3qM3ZKvvbvU4 2020-04-20 12:33:56 136.37.197.178 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=145 +p reject 1-65535 +r niftydiinkarazan VihJXZk5qME53UQUAt5C9wErcJI 01wxVe+w/ID5mL3eRm+xZjEt4QU 2020-04-20 08:53:07 185.220.100.248 9000 9001 +a [2a0b:f4c0:16c:5::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41800 +p reject 25 +r niftyentry83 Vixhx/iFdB1ZnbehI1eR2Si+rf0 R0qGGQ1LI2fh8RCpvaL40Nu+fsU 2020-04-20 10:51:31 185.220.101.223 10083 20083 +a [2a0b:f4c2:2::223]:10083 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r snap277 Vjo4Sf+hkBL+yn1JtKbGw63toPc 6Vj94VFI3xQcBXMcEnWNtEpi5bI 2020-04-20 06:47:04 62.211.17.47 45537 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=808 +p reject 1-65535 +r Unnamed Vj24UUJGK/xEevwW9tj00KSjwyo YS4JTIr+2nNL4So2zVWT1PKZwF8 2020-04-20 06:42:55 217.12.204.170 4427 31331 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=958 +p reject 1-65535 +r thorfred2 Vj+CMIH0XsFS83TaIvl5+2ckvok Mx/UKHGe5gAWhUcj9mizAgrwZXE 2020-04-19 22:37:32 89.163.224.143 9001 9030 +a [2001:4ba0:ffec:8d::]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34000 +p reject 1-65535 +r QuintexAirVPN8 VknLIVjalPt0dBXyZii+wH+ldhY vQ8PZDAxamZeJtdH0HGTpzk4xXc 2020-04-20 00:19:36 199.249.230.122 443 80 +a [2620:7:6001::122]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r ThankYouMrSnowden Vkp/HQMUElr2AJbN4KiH8oZggkA 0jSHKNvkGrMSwV1gjtnttIFuKCc 2020-04-20 12:41:03 213.152.161.149 2055 2661 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r yanmaani VljDYy4LDFyCyONzUI6LquknakU eHusQ86HzAJoevlpoO7cgY0dJ9k 2020-04-20 10:52:01 83.97.20.244 9001 0 +s Exit Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=442 +p reject 25,119 +r GermanCraft1 VmWjkEyJ4i6XEwXujBmXvKQSPGk IYvq7ry0gU5ixCKsobkAnK6T9ww 2020-04-20 01:38:23 95.216.138.16 443 0 +a [2a01:4f9:c010:24d::1]:443 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=28000 +p reject 1-65535 +r FOO Vm7QvHN9bE1HKN11lHAoJfGFe88 cRAks86D4BS6nzJ0HTAILgQu0f0 2020-04-20 03:56:36 178.175.148.44 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6420 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r VRchat VnIh3VhtDjiKaFn7M8CWlr0gFRs +BVnE1314HpMkiPOxqS6CIN/rE8 2020-04-20 07:04:03 104.194.228.240 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5700 +p reject 1-65535 +r scurra VngczJ9tKf6hSHmatYhCnIk6Rzw zUe41Kc4Ll+GZEo63aLtPGq2Pu4 2020-04-19 23:46:19 87.118.84.158 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r FishersTorRelay1 VnhGCCQssVtw7Wy7j0Duo7Yq9p4 RNdmncIqendSjhZnhalROV5Skb0 2020-04-20 08:48:13 138.201.3.75 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r Berkeley1 Vn6XhUWMYF5ZICdVx0iY48lvscw /ag0Whsop55HQ1N5xWlz7hFV96w 2020-04-20 09:29:12 135.180.15.250 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7100 +p reject 1-65535 +r niftyafricagiantrat VoUHUglu5jcR+ZsvpagSR3VhaX0 7R1ICmGvjRX5MlxdAwIT3X6Ku34 2020-04-20 12:21:16 185.220.101.132 21202 11202 +a [2a0b:f4c2:1::132]:21361 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p reject 1-65535 +r ankerman VoWD2eRsaAReITHPQD5I8h3xHwo Tqh3/GTpxFM2SPAtmXrDn2PmOK0 2020-04-20 11:09:51 51.38.107.117 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6910 +p reject 1-65535 +r youedittheconfig Vo3Gb7am571GLO+XozPs47l9B0o l599DseBpncQ8n7ZWAOGn2gmH6s 2020-04-20 12:09:27 51.15.18.163 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=65000 +p reject 1-65535 +r RunBSD Vo5DT3JbeCjRfvKzPC9cyE8Y/OM LwQNvtH9IHxJJ2qDn7z2SPNhn7M 2020-04-20 12:44:45 91.219.238.148 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p reject 1-65535 +r Akka VpJ+YbUebzY/tVSYFQpt389wd/I n7fqWRvrRl+SOMX3T4NXxihHJqI 2020-04-20 07:24:12 95.216.33.58 443 0 +a [2a01:4f9:2a:2145::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64000 +p reject 1-65535 +r relay VqCZ2l1yfOmA6kb3h4pv5m8oubc HCE7abQX6BavqQH3hoKB1LK1Geg 2020-04-20 09:20:05 45.32.102.37 9001 0 +a [2001:19f0:4400:4caa:5400:2ff:fea3:b28c]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=769 +p reject 1-65535 +r snap277 VqGlpvppaSYWGxKQlFlWHwW6MbU l1lDi0nvIlus1ep/67VVdQTJ1lw 2020-04-20 09:06:33 193.250.84.210 39005 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2690 +p reject 1-65535 +r WaffleIronDome VtZhBsZCvgD0A7mAUhaYcMjAh1E 0seq3nmxeHpZX4Ctnk5z3g4yOUg 2020-04-20 00:06:14 83.97.20.82 9001 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=628 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r PeoplesTOR Vtb++2tKhiPhclNnxOmsE+hbaKA JiCn44U1gAI2+aQqsMf/KMqcQp8 2020-04-20 03:45:25 45.79.85.85 443 0 +a [2600:3c01::f03c:92ff:fee7:78b9]:443 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p accept 20-21,53,80-81,443,1194,6660-6667,8332-8333 +r torprops VtyommtBraMOiR72X9zAcdwFB5s 8VYkW7N31TjhBXOx/UIzFA1k6c4 2020-04-20 03:58:28 70.96.196.77 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3860 +p reject 1-65535 +r Bacon1 Vt792M3iGm/HpFAXrDmZ1SVbbS8 RyRl7n2q7IqeayXnmTtaEavhNwA 2020-04-20 11:35:20 95.216.209.193 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4780 +p reject 1-65535 +r TzBakery VwcaeWZfMQf2qu7tlsa7xA69HZE wIK7JHGDNkC3cr+xixJ3dHVykuM 2020-04-19 23:07:36 149.28.245.104 9001 9030 +a [2001:19f0:6401:1871:5400:2ff:fe96:506a]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98 +p reject 1-65535 +r king Vw3NBzDJvGD+XID0BHPe5pipXVc 7OycJ5O5E2fHpVhoC1pvfdbJ4Qo 2020-04-20 08:22:51 51.89.200.123 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r anonymous VxJjgE71X0moYVqiSiAkS3d79Tk 2uh8E+OpJhA3EmF3evP0UHYB5OY 2020-04-19 22:00:00 138.201.255.245 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19200 +p reject 1-65535 +r eclipse01 Vx0q9ZhGk0jkQsq6dV80SlgXbKc qEGRV4n8KJwyBLsyLfa/Sb0Jm4o 2020-04-20 00:40:14 37.252.187.3 9001 9030 +a [2a00:63c1:c:3::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r b33rM4nR3l4y Vy/C5tiejXc0iKdvBd3uMXOgduA XIydVCYpBBYbUpvs7d4F19yNMZo 2020-04-19 21:18:24 73.180.143.119 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p reject 1-65535 +r figue VzSFbarrURN1Rx+lh3Q+yHnTDfE hluABc+pckyPRoSxIcDGrCKTBJ4 2020-04-20 01:21:35 82.64.167.199 9000 9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7240 +p reject 1-65535 +r loglessRelay VzzD2PHIRaozqkWTtoyg1HFWqjA w7MgQPlu/Rzq8b5nCMe4Oae/TLo 2020-04-20 06:11:56 163.172.184.32 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1980 +p reject 1-65535 +r ididnteditheconfig V0Bjt64dPxNsI9P0KmE2UdA6Sgg p9LN+qy+krNlAhvuvp/JQpry5VY 2020-04-20 05:46:41 86.201.252.9 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=105 +p reject 1-65535 +r pythonian4000 V1FRQkm0p/pRhzY7tsT3YSZykTc CUU1R/V2QM0tFypikdEsCrz0Iik 2020-04-20 07:26:47 173.230.128.232 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1970 +p reject 1-65535 +r snap277 V1w7CzrxwvCI7co10JporCH9nKY Ryko2VVdCbbfSHOn/dle+Hw9Hkk 2020-04-20 00:25:28 73.139.64.136 37089 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=306 +p reject 1-65535 +r Unnamed V2mJ0FtiwF+S7IQFuLaxnyqjQiE sR5zqvaReFGvDRZYVetT/jW+d1w 2020-04-19 23:03:41 163.172.94.144 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=909 +p reject 1-65535 +r JMBHVN V3GSpCJ6mvTQ0xsehVDYERin1mM UPYrjjB2R39JftJ+EaxWkr/NrHw 2020-04-20 00:01:12 54.90.234.122 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84 +p reject 1-65535 +r crowcastletor V4bQTFoohdGeYG8TxCA/YK7jgRA KR5vcj6ZweJN2mPDBiiOA+6CDh0 2020-04-20 04:23:01 96.233.74.18 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2240 +p reject 1-65535 +r marylou1 V44Afl5FNfv+93WNhYewe0yMXQY L8vXffJnkDHXFtOyBx5CU6aNB5E 2020-04-19 23:54:10 89.234.157.254 443 80 +a [2001:67c:2608::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r cavefelem01 V44BPeYUZ5tq+CB6ilh3EWdZFDE 2r/pulXVVF3+6sclwm56yabczCA 2020-04-20 03:02:36 95.216.61.100 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=32900 +p reject 1-65535 +r daWiZaRd V5rMA/KM+XnmF5ZDq2UQ5E3AJY0 r/LGmGZa8urhUHUljXbtnPKpNbo 2020-04-20 10:21:51 46.142.9.135 9001 0 +s Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r smitty V6rGTAum7fxlTHGL3vhudRdqJHI 53hJywiAg3Vdzm2xCLErb0zDN2Q 2020-04-20 07:37:40 65.181.123.254 9001 9030 +s Exit Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Unnamed V7aHPC3DYuWkKoCftWJM2joCVDA jtrGb/UhnPQIJ4Ho6Eksl/iAvZM 2020-04-19 23:25:05 69.164.194.10 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=651 +p reject 1-65535 +r alliumursinum V7cA6+o6D204v5FfWLhsAXA34mA NaUKrENM21fEw35p5sAEtfUBXbA 2020-04-19 19:33:03 178.254.30.86 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r itok01TorRelay2 V76AaPvF6mZhy+KpyKTf9SgVsGk DcWy+czX6+GDfCEVb/CWYUus0Ok 2020-04-20 08:05:54 116.91.207.250 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r snap277 V8TqI8wEL0GcJ9+Vc50EOoKjCCg cOU16xURZZsUcK0T4sKl+OsnDPs 2020-04-20 10:14:58 134.249.143.159 41352 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2090 +p reject 1-65535 +r angeltest12 V8bfW5PlTrnI25ACnZ6aERG9NNI Bks9jOvS4rPA75X3SIcWi4VlUu8 2020-04-19 23:27:27 91.201.65.91 443 9030 +a [2a06:f905:1:100::4e]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5440 +p reject 1-65535 +r snap278 V+LR7CF2g+H7/2vvMjJJ5l+s5Tk 0MtD4rwgUxMm2OS1tDt0P/xgxOE 2020-04-20 05:09:52 84.7.247.37 35493 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=123 +p reject 1-65535 +r lilm00 V/G1+a344LCJJG4nYmpS8w3DEPg obZZbBFzdbqrMB7Fj/K2g1QVeYk 2020-04-19 20:07:24 198.16.109.31 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=10700 +p reject 1-65535 +r ph3x V/JzcWxTEO7sa5ReY0+u4vX3sE0 Q7NAkjW4TsB7l3jB+9z3yob5+Is 2020-04-20 11:17:59 86.59.119.83 443 80 +a [2001:858:2:30:86:59:119:83]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4500 +p reject 1-65535 +r smell V/oa5TlX+mfsAiy+m2gmHsX61yQ iTrLQcNaS48nms2Gwze+ifyi+ps 2020-04-20 01:26:40 209.141.52.137 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5490 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r kricklen V/ySfxza3skzgOJH7pSaN4eg234 JmE8LhyxbwOJcaf/uBpYdZ6aBMo 2020-04-20 02:22:08 5.63.37.19 35278 35288 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p reject 1-65535 +r koume WAkGBdL5DUxjqtQ8O4qS5DjJeC4 LNO6hzxmx37knVh3gYmxxAzynyo 2020-04-19 20:18:37 5.1.74.171 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=672 +p reject 1-65535 +r tor01k WAxR4ChROhXKw3D760C+CdlIhhM Cx7UFWHfZfhCqiEngXRm/nSHVpo 2020-04-20 06:37:53 51.15.106.64 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed WBLI/tM5HRjLDSFNlQzjd28uZhc SBaVldJdK131HnBImvVW+JgpTmo 2020-04-20 10:28:55 104.244.74.181 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r rofltor21 WCDX4swpBGIjOEW6gH1hZJTPDX0 tVQMQwh7XAdiS1/gGQN2b4+eddM 2020-04-20 10:52:41 64.137.189.39 9001 9030 +a [2607:8880::489:27]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r Torshow WCJOjlNE7LDm/7tHDFPyxx2+Y0E GJUW11glu93KW1pGxOqKel51k88 2020-04-20 12:10:46 62.109.10.150 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10400 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r gio6 WCMBJzuyg3Glngmhk/o52nr8MoA pNZt9+FXU4aikWTFxSvIYveFx1I 2020-04-20 10:34:41 95.183.52.42 9042 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31900 +p reject 1-65535 +r BobsHouseLU02 WDJmjCH/N1xrd6m+sB4r/cfNnEM iihxTgw8rVviydjhGGWcjdJuFsM 2020-04-20 03:30:35 104.244.75.143 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5620 +p reject 1-65535 +r kaitlin WDMt3aFUFcs9E/Xso9VL6WG4xFg N1T19XyMEM6Q2/kVuNipzpG3/Qs 2020-04-20 04:48:29 141.255.166.142 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p reject 1-65535 +r duat WDVlQ4TqfbBrJYGjmZcw8V5Rki8 gqbM9kFl3eOzA03x96o+gi1Qd6c 2020-04-20 03:04:41 24.151.1.51 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=360 +p reject 1-65535 +r niftyguard26 WDzvz/drMYnTo3yBpJ0WGdBNyzQ z2wS1hUGjlCeZnGt3VGT1UXPTvU 2020-04-20 12:46:19 185.220.101.235 1235 2235 +a [2a0b:f4c2:2::235]:1235 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r justanotherrelay WD8XKY6QXR0bz460na7lk5tR/XA tH3xoLxhi1TcpLWZ3ymtgn7Fc7I 2020-04-20 09:00:44 79.160.238.152 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=306 +p reject 1-65535 +r 5705860553591637 WEfVoBxHFmFD9zjHcDNEUXs56xA J7H84+wDI17nYD6QHU7e8TXvtyA 2020-04-20 04:14:30 5.2.72.110 9001 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p accept 80,443,8080,8443 +r AgentOnionMumbai WFVog8l+AbRjlhG69D68hDwNG1E pO7zJjmDAg2vL7doI1f9JEuFS+8 2020-04-20 05:59:39 172.105.41.187 443 8080 +a [2400:8904::f03c:91ff:feff:d19]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=911 +p reject 1-65535 +r Sklavenmaedchen WFbbiEV4kV58egt7EeQUWx0qTis o9iEVCNgbRNFgUi8FlNpf3g/lxM 2020-04-19 22:01:00 91.106.170.116 9001 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15600 +p reject 1-65535 +r Unnamed WHerSw4DqM2tkWVk+qcn4zUuvec /CZBDqiV01shzLDF/0r6juiFQxk 2020-04-20 06:40:55 95.133.63.51 443 80 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p reject 1-65535 +r alxu WHserx4i4UjvsBDaozes3NTbXLo LIy6slT+sP6fHrYmdHOik/VxJIU 2020-04-19 19:32:31 198.98.62.56 9941 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p reject 1-65535 +r serpico WKcZlxLA5Ss8Xy+Oiye1pivli8g lZX8/MdJDzLZ/fGaqCRPFyd2MTE 2020-04-20 02:33:14 45.141.157.50 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13100 +p reject 1-65535 +r iblech WKmSHdChOJNWY0YlxbFKzBGUqVw 8nwEblLIk3vd1X26UsygUYo4TBw 2020-04-20 12:10:46 79.143.177.192 443 0 +a [2a02:c205:3003:5755::1]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6660 +p reject 1-65535 +r king WK3GaZ7tCgq1rI42kvNaHoeXJMo DON3L6EhFXrZlSPbwQHnouZ/DEY 2020-04-20 04:46:38 51.68.201.119 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7150 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r UnvisitedNativity WLRLVZGpbsCBFLBBzGsbsVId8r4 tk+W3Kk9E1QNYwKB9azl9FAVTaE 2020-04-20 01:38:33 199.195.250.77 443 80 +a [2605:6400:10:549::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p reject 22,25,110,119,135-139,143,194,220,445,465,563,587,993-995,1214,2525-2526,4661-4666,6346-6429,6657,6660-6670,6679,6697,6699,6881-7005,7070,8000-8004,9000-9001,9998-9999 +r Torrot01 WLxjFCyIH4jQjgcd62PboJ3mIUE Uz9+uxBokrXAGWY7w76/AYtg3cQ 2020-04-20 04:09:32 95.216.197.155 9001 9030 +a [2a01:4f9:c010:4a6c::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22500 +p reject 1-65535 +r snap277 WL0ejJ0OSu+ljwk/lMNIv5UuMZw pSbIpZcZv0uvQlAp+p1lZzbNh/s 2020-04-20 01:18:08 163.158.20.204 9001 0 +s Fast Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r RTTY WMlIr6MGX4TZgJXPjBjei1NzhBE GbCEZWPb9LaVzDXTQfOttR3wMkE 2020-04-20 11:05:45 85.249.40.197 1443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r gandalf42 WM8u/gAjhvAq2atFJDLhTFiPld8 FFmrlEpZTmAc8ZTIpsYNdQqmW5M 2020-04-20 02:03:42 31.24.8.174 9002 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=852 +p reject 1-65535 +r JFWenisch WOZ83ffKLivVI4nrLicOCaHDdvQ FG1r3R9GiNWJHU/KHmJdFHb9Anc 2020-04-20 10:13:17 78.94.7.142 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p reject 1-65535 +r ThisAgain WOiaBVZOaET6zF14pz71kyIlYaI +FcPCH39lmU1oslmSVzjgGj8JnQ 2020-04-20 06:26:43 94.140.114.74 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19300 +p reject 1-65535 +r SamAAdams2 WO2cnDXkM+5Ydk1iiStP/VGKPNA JgVJ6PtHcEGgXyAYheqCFNxfs2I 2020-04-19 21:12:43 185.21.100.50 9001 9030 +a [2a00:1158:2:cd00:0:74:6f:72]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p reject 1-65535 +r jaimalator WPq1in3I6ZuTE/bkiOIUDUvihBY Rq1IjeLQ1Q6+cTBfg6pZQpAwo1g 2020-04-19 23:08:44 193.70.40.121 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19400 +p reject 1-65535 +r zwewwlNL1 WPwqqzeSrDeJfTQzH09OADQd7Aw m3iPQ+ly6CFOnB9mN2PMo7I/f/c 2020-04-20 11:55:26 185.14.30.57 9001 9030 +a [2a02:27ab:0:2::22]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=19400 +p reject 1-65535 +r fondueplausch WQE2wTzCdHuMSL9z2BVFQnn2DF0 9ReTT/8eXY0oFwS8xJri84HyrCk 2020-04-19 22:43:27 46.126.161.205 32772 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p reject 1-65535 +r REX2 WQhoZYtoUq97sgMW22PNyEUI7C4 2J12FwjlAxL1IaEzFkDWda3w8yA 2020-04-20 04:46:40 27.122.59.100 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=590 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TeutatesTOR WQuiClhTvxt2980GZQH+u6dyyV8 lM+oubTgKhbLOAVO7o+rbb74cDQ 2020-04-19 19:30:17 78.194.2.61 450 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2500 +p reject 1-65535 +r snap277 WQ7qAa5PnRY1ah8gFhXH0c0O/i0 X/h9oxrrAxO2JXjperojhtSzybA 2020-04-20 07:53:05 92.139.179.231 40967 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2900 +p reject 1-65535 +r crowdedfire WRJSnQhh0vxSv6ZYmahIDDZbaHI e2563cTJqWJG0fcL1gewCN/ypPU 2020-04-20 03:04:02 136.34.66.221 9001 9002 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8080 +p reject 1-65535 +r snap277 WRqXeOP4Ewe7dgtQB98m3miVsec 15cXrFV4fndcnaFqQtaii4rjQew 2020-04-20 07:45:31 77.149.41.43 33625 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r Brixx WSTvhKrSEHPNWFFdFkNVOnfXs18 CoaLLkLRwPrT+s7/FONWPNPLNTU 2020-04-19 19:22:20 188.68.36.46 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r cookiedough1 WSqLcwq4co99wbT62J0Ia+MZvSc Y4sZw/KsorTVrFqzvvAWBlpwhKc 2020-04-20 06:01:15 66.220.3.179 9001 9030 +a [2001:470:1:19::179]:9001 +s Exit Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6660-6667,6699,6881-6999 +r Unnamed WUGT5R84LjQIDXa17K9ce2fPBe8 NEbJ9YBYDAwTZ3K/xoYZ2F50mms 2020-04-20 08:25:09 37.191.192.239 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p reject 1-65535 +r notorious5 WUNnKqpeaBE5Fnz3jlS6JvokJeQ cx/p6/xZjWHexvyeF0HhmrO+5bI 2020-04-20 03:09:44 45.77.216.153 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=732 +p reject 1-65535 +r Unnamed WVeZC+XBvBwDdpBIyoFtE3kLMXY r/iY4tsHaau7aQNHL/sPGJctzls 2020-04-20 05:17:16 104.211.224.144 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=612 +p reject 1-65535 +r fpoestueckscheisse WV6fqG4GAh1TRl/wNlx/+SpKEV0 UabWbpmqdI3ZlpKtdIArHN40cBM 2020-04-20 02:28:08 217.12.223.200 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1650 +p reject 1-65535 +r isnotsocial WWgDCABO0y8E4cVqucaLFMx7W3w /RFmqrEB5rPSUkh4WVVHw9WwH7s 2020-04-20 07:56:34 73.225.8.164 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1960 +p reject 1-65535 +r 555nase WXQirdra9fsnJzabfvx6p2uJ1hM ZOQlGpl6LUThoseotN6o27Llbpw 2020-04-19 20:27:29 37.187.3.106 443 80 +a [2001:41d0:a:36a::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7220 +p reject 1-65535 +r amazonas WXSz9MZtg7vJYi4PDwI/5IQo25s TrquhcOpBR4dCZFZryRG8d9xy0Q 2020-04-19 19:05:43 77.247.181.163 443 0 +a [2a00:1768:1001:21::32a3:201a]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45600 +p reject 25 +r TorNuc321 WXk4K1sq/lPTpPZY4huXHFRK1TE OK8D5CLCKnBl1R9JCf0ZkvGfr2Q 2020-04-20 05:15:21 83.252.4.77 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16 +p reject 1-65535 +r fran1 WYeK/gbUULcje4RNTSnHG02P7GI kgkcgXkbQQ4sbyrvp4vvowNUs0U 2020-04-20 01:05:52 198.199.100.10 443 80 +a [2604:a880:1:20::2f0:a001]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r harleyz98 WY6g5ZXFQeqRtENLxkPwERCGKsU UpyGov/s2ZAWGngvBKmPQnyT/fI 2020-04-19 19:10:46 51.254.143.96 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r FeatheredRelay WZegMElZG5QDjATFhLlNkE6KduY jb64wGlAwUb/ZTmdK5W/3VFCjxU 2020-04-20 08:08:58 86.52.129.134 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5450 +p reject 1-65535 +r dunnosomething WZpW+rjoqou0Z6tzCtofEjgn5Ac tAlFrR7RzVCQZK3j26IV4KeMEXw 2020-04-20 04:48:48 88.198.14.190 49001 49030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6860 +p reject 1-65535 +r FalkensteinTor03 WZpwh1YEiZOhApsnde74yeQLtkA kG4EsOiW7wvzwu4uswE+L7j0lRY 2020-04-20 03:19:38 144.76.236.14 443 0 +a [2a01:4f8:201:120d::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=48000 +p reject 1-65535 +r ELOO01 WZ46D5vc1YClVf6BPTs3gZ3hhB0 iGJ+POzwHkaFzoDbndVAtL0dGXY 2020-04-20 02:14:00 217.228.178.45 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=215 +p reject 1-65535 +r LopayneVPS200NC WadVeCwfl31tzXbA7EUP/MfCnlY k/FIqVuuntI/0H3zxnT5Id7Drhw 2020-04-19 20:03:12 192.145.45.190 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10400 +p reject 1-65535 +r mercurya Wbcc2YFpb9hbW5FgI6jMJb8WMNU zAk2ht5UPs6S8zemJ4ZsuEYs0ZA 2020-04-20 04:16:58 178.209.46.173 7654 7653 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=459 +p reject 1-65535 +r hagardunor Wbo1WIpjNG/maujPZYgYQg3W5bI PmQ94RQZKs5FZQeLaYp24Jf4Y6c 2020-04-19 20:43:37 51.77.202.41 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=225 +p reject 1-65535 +r king WcDMCxTSxaArK8kTjTL75wFOQqE jKVMCiA2LNXxr+kE4XZUESAtkf4 2020-04-20 04:54:54 51.89.213.93 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6990 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r perkele WcDYils8ZVQc9j0N2I7xWjedN44 IlyEi6x5Gsjgb9wRmJipkqv/6iQ 2020-04-20 01:15:48 51.38.64.68 443 80 +a [2001:41d0:801:2000::20e8]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18400 +p reject 1-65535 +r snap277 WcFrTo4veF5fAyTAgFy7QWoIRmU KH5cNjwZDGjYrIOQrSr8+rUHNCg 2020-04-20 06:15:12 181.137.248.115 46165 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=254 +p reject 1-65535 +r SnapServ WcZVL74b13mVqzpzc/3V9gltoEY PVn6vwc0iWGRDNxa3+4ye6676/g 2020-04-20 09:15:28 185.133.210.54 443 9030 +a [2a06:e880:1:2::b]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2300 +p reject 1-65535 +r spaghetti WcqW582jCrNsWXtJnISL2EV0XqA Voh1hLFQ7Z5QxfYYXZJgTLhSOok 2020-04-20 12:17:48 5.135.177.107 9060 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r cadory Wd/krJd8/ZHl5Tg6Wvv+HaoPRrM 8H7SbPCcIVwiLKQ8MSmoFxlT/ig 2020-04-20 02:13:37 83.135.78.14 19003 4446 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=340 +p reject 1-65535 +r Unnamed WeM2OhcvcBeMQYtp2NXwzYHPdK0 +dcT5CYlI+sBryRWeSKrNAYkXXc 2020-04-20 12:52:04 31.220.4.122 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=195 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r NimixRelay WgIDu+B9vTSpvRjOmsmPu1jI9c4 6VGk3KsfnH+FoHwr0PVzdAF6Cbc 2020-04-20 10:07:22 109.196.235.46 443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45 +p reject 1-65535 +r Cataclysm WhJ8ZbJ1VAqQ2/YPM9Vbr11RK54 sgmYOVayRH1jAmtZvC7pInoLVyY 2020-04-20 08:15:30 150.107.76.13 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=148 +p accept 20-21,110,143,194,220,389,464,531,749,853,873,902-904,981,989-991,2082-2083,50002,64738 +r Trenton WhT7u6+EISSgrzxlD0MCxbVJqxc xYygCyopaBxqykSLLKXeMqZwrvM 2020-04-20 11:48:54 195.201.22.234 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=8470 +p reject 1-65535 +r forTheLoveOfHotDogs WiJO+sRT9+8tBDXjNokN7Nxc6/0 A4xGX2IW4IRXwTv0rRnOEgBsC/I 2020-04-19 21:34:13 46.105.227.109 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18200 +p reject 1-65535 +r ScholrshipRemote Wiwr8lhk8YWqkdKRWUNSVgmsfxM UtRls1/SPeJXZL2Eilw1s4d4zUo 2020-04-20 03:09:47 47.52.59.100 1080 8080 +s Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r noregerbest WjUqVaKuts+3VcOwoGu/J+IgzM4 osSlEl5I++R5j9zMM4cAxyuBOaM 2020-04-20 03:20:09 92.220.0.139 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1820 +p reject 1-65535 +r nonanet03 Wj/47X+/PgttTMNbBF6X+Ed3y+c qhISIYc0kkQZwkcQv2d7suCVZQg 2020-04-20 00:43:24 198.251.80.172 443 80 +a [2605:6400:20:13ee::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 WkOBXp0Bo/Hc4oTgIzJhDl2LYPw ns5vLB1CDpQglLx1aQ7PMBRBaQI 2020-04-19 21:35:03 170.254.16.37 33122 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=161 +p reject 1-65535 +r Luxembourger WkmrCPaKoIfNfhgpnMVld9igd0c VOIHYEgkQ7e83dP9XPEcWcjqqZ0 2020-04-19 22:54:47 104.244.78.233 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,11371,19294,19638,50002,64738 +r snap277 Wm2FRbCgt9ajXXwPH0nNUWw4Y4k 3VoHJnN1bGP4E7sJXP+HbW/7B7E 2020-04-20 07:19:55 109.128.84.6 40803 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2940 +p reject 1-65535 +r Unnamed WoavyewcTnvuEb6YUKJxtSHI+c4 NTRmR67iyhigfJRbaTLdFIwEkuM 2020-04-20 02:12:13 102.37.12.136 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=294 +p reject 1-65535 +r AcMNPVTorBox WqKsNz0TLiHxG/+ZFnr5K/HLfEE 8wsHcedKAYNaMFO42+R7KZIY2Gk 2020-04-20 04:14:37 188.226.222.19 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48 +p reject 1-65535 +r niftyguard WrwpqeYs2zzyBVUom0RsxyJFcQs vycRnpKBBGo8IJ1ES0J6bDrVdqA 2020-04-20 12:44:28 185.220.101.239 1239 2239 +a [2a0b:f4c2:2::239]:1239 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r Default Wr0Gqp4RXbNIBTcDvydQ/1UAxw0 pZrzBehXC9ChLcdoQN//KKUtG78 2020-04-19 20:17:26 108.81.207.192 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=262 +p reject 1-65535 +r schattenbahnhof1 WsRtOTx+H7DffzQkc3I5on+Vhsk 9EXKfUr3xc4iymMVUTeuo3uxEh8 2020-04-20 07:20:49 188.68.53.92 443 80 +a [2a03:4000:6:e34b:7cf3:194b:368:22d]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2710 +p reject 1-65535 +r Unnamed WtAO3o8OpSb2wXcMhoj4t4asvW0 8c8Dzu1aKt+oUHVylwPd4hi2vLI 2020-04-19 23:59:54 107.191.118.171 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=97 +p reject 1-65535 +r Netwerxtorexitusa WtHVNTc8BbsWJL0qdt3nE+l0JA4 TSo36JEuM/mkgOM51sI1Mm93EA8 2020-04-20 04:09:12 173.208.195.102 9001 0 +a [2a0e:b107:3c0:fed::ded]:9001 +s BadExit Exit Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ULayerAssange WtP7ZY5JC62VFfNjN0qkHWXTGgI ruQYLMnK67lKP7qD4TRFaxDiGGA 2020-04-19 23:18:22 107.189.11.246 443 80 +a [2605:6400:30:f645:938b:e84c:1249:c27b]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26600 +p reject 1-65535 +r Unnamed Wu21b2jUaw3xKonMZoAIl2w3Y9U /tWHKBsXkjFmLl/Ue321Yex2brs 2020-04-19 23:03:04 37.200.98.117 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1220 +p accept 6660-6667 +r snap277 WvFj/ZKlzEtmib8HWQXCSoSUSCc fPMRLfk6WIsGWtZVOLYOdTP8hpc 2020-04-20 11:49:37 80.6.160.152 38901 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=739 +p reject 1-65535 +r whitenoiseRLY WvnpzFkD8R9taqYB6yEuVprmbJI MmL9olvByErxUmtgJy6TsrjLOg8 2020-04-19 20:31:57 159.203.29.240 9001 0 +a [2604:a880:cad:d0::2bf2:2001]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=112 +p reject 1-65535 +r FuckTerfs WwJqZSyfG4+mogLK4Ldqz67YIIw l0dloYQ5ctjnw6ucoGUvOvX75mM 2020-04-20 06:33:36 49.12.6.97 9001 9030 +a [2a01:4f8:c17:23e1::1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9690 +p reject 1-65535 +r neurosuse Ww26wshUuOsODdOa2Utm8v7cSHE Vsj6VgR+nHYxVT1OxmbOTT4kzNM 2020-04-19 23:05:43 159.69.27.103 9001 9030 +a [2a01:4f8:1c1c:2170::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17100 +p reject 1-65535 +r fastlane Wx8NrzeKH6/P1fqc3GbRAj3AJ24 fOGkir5eiCdwTc8msi8mA9sPW4E 2020-04-20 01:59:46 178.63.25.10 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63400 +p reject 1-65535 +r NyquanKHW2 WyCijMtsWTEk4ld/qqH12YtM0zk E3XnsqiYY1X/vE7lvYGl2iJRQoY 2020-04-20 09:24:59 31.16.223.74 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5630 +p reject 1-65535 +r Unnamed WyOIW5hED65YzKqFvCj928rleOM qh4wdflCEC/9DqGiuZsZ77Uh6sw 2020-04-20 12:04:00 158.69.172.225 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed WyVljhwlbN9M9s8Uvlxt8E/8O+4 XMwfrr7iseX2/8Tdz81HHN6q9lw 2020-04-20 02:47:22 5.39.185.164 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15 +p reject 1-65535 +r notamateurhour WzT8MZiBk4xt38bbWtz7U4GbdZU Szahc6iu6DOjCtxSV6/HXsvRGZ8 2020-04-20 01:05:25 192.34.80.176 443 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=670 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 WzZU6RdPs/im67HJQJbW5ugbivY 0s8scJVeU6ojkcXaCsvSJ7N96lM 2020-04-19 20:18:01 73.244.74.74 34111 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=72 +p reject 1-65535 +r FreedomIsWon Wz7Ih0GFlrvpopHCqEWk7/irBbg 3564zI8ZTOjd6YHY/8xuOqhEdDA 2020-04-20 03:32:20 144.217.85.34 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5340 +p reject 1-65535 +r LauchRelay W01rhFrDzJfrMWnQx3RGk2QyKUg PYX5TQ34hMKr15dYZfgrGML9TWg 2020-04-20 00:39:12 148.251.55.246 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20400 +p reject 1-65535 +r snap277 W1OyuIAqeno6Ag0zNrx7Rmm0q5s LwBX2V8Yvm1DXjCQ25Kmxs8Cc60 2020-04-20 06:12:19 160.179.201.118 35175 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r foobarShizzler W3AdXIBvkdijxrPpJiRyfsQ+JsI 3PKJ/wJpw/bTWyebF7ZkXOxbnaI 2020-04-19 22:16:09 51.38.115.191 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r raveena9001 W37NgDELNea5X8iH4UPIic+MKEE D9KjfGO0ME38QfEhM6rffzPFZoo 2020-04-19 22:16:01 78.94.186.133 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=945 +p reject 1-65535 +r OurHelperForU W4eznIS4CNOm9vyTSJnBGAqFd/Y y6Y6C2BktAoYOANJVCOoRWGECoM 2020-04-20 08:39:18 109.74.11.81 9899 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10600 +p reject 1-65535 +r Hawking W5PlziYOaDstIm62twGj7Buit1o r+JGwISW7MsQ0a8EMCTh/clqPDg 2020-04-19 21:14:05 176.123.6.20 443 80 +a [2001:678:6d4:5000::acab:9799]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2030 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r niftyguard44 W5u3pUPCwDWkI6a0EXgOUGRXgsA 5GvG4y2NF7fQ115AW5INlAk5rFQ 2020-04-19 22:15:54 185.220.101.163 1163 2163 +a [2a0b:f4c2:1::163]:1163 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21100 +p reject 25 +r gurke W6GbXVqwy5746jPad1hbdUSUALA g5u41iHls5EZOVUx0pw/IN+CJYw 2020-04-20 02:20:19 109.70.100.8 443 80 +a [2a03:e600:100::8]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=108000 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r v5p0j W6Nej5PqyToB4O9EK+cmbRlT8AE TirCzX7o5jS3z+6eS+rTxOQUtm4 2020-04-20 08:20:51 198.181.40.229 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1940 +p reject 1-65535 +r Richie W7UeZQNm0UyVAn2y8demm8WwBnY HnHhDLC4GKoI83VsgkaWlE0Pwi8 2020-04-20 00:29:40 217.79.178.60 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27600 +p reject 1-65535 +r Unnamed W71czv2pD0J7IvKfU7EZUxM3pks 6mo/9Ox0KLsJr9LdiH5JE8WSUMI 2020-04-20 04:19:30 85.212.56.69 9001 0 +s Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r theia8 W/FxY8vnPYzZ/b4DDJROoFcH2pM pLV/eD71x6muZfTUFksxd6VaAjI 2020-04-19 22:57:55 50.7.74.170 443 80 +a [2001:49f0:d002:2::58]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p reject 1-65535 +r 6bbe3e028359 W/OuNfREFjuxUda0xZJPNHXZekQ oOYGcWiIJK+cuvQKv+2HQcFrJsc 2020-04-20 08:17:37 51.81.253.206 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 W/YpF0rGlIypnn2Qd3rTcBvu8I8 DUpJM1wkzHmChz2xwMV+ICmitdQ 2020-04-20 00:10:34 42.62.251.233 35471 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r Unnamed XAvZHlqcrH+paYw2hg5abCHuZqY jKq2KHOwxNVEnUDIFYC7xmPTwTM 2020-04-20 09:43:27 45.9.250.135 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1500 +p reject 1-65535 +r Unnamed XBPhCIlohibtqAYXefqFkXeXpic kgyUmZZ3wmMhW5zCL2ftNAPJEVI 2020-04-20 10:14:38 185.225.17.91 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p reject 1-65535 +r snap277 XCEyFddIMS68EoWIwPhoWEF8RZw BYtupjFaKT9gNh+f4m+3hsxWbc0 2020-04-20 09:54:44 92.238.16.37 37379 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=616 +p reject 1-65535 +r freiburgTKom XCGEU9Xqzik2fWMaKiDjJZumclU I5+0gW7ygAtshv9WpJBb9map88Y 2020-04-20 00:12:55 217.233.225.133 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3650 +p reject 1-65535 +r collaborator XCITeeV4LnaXN359tI9ysvZJ6eQ W1KptRXFxaFD+EkRwCID0udTJPk 2020-04-20 03:36:03 185.248.151.143 20 21 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2790 +p reject 1-65535 +r TotorBE4 XEoWgvrfIh30b/oy/mWCbc95GF8 ldoWMTIlEjvckizLL0ZuRbq3mOI 2020-04-20 09:26:18 137.74.32.28 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r nortor2 XEtQX8/ODjQKhtDnlgskoT7VZ3w WPLBGmH1rjMXOxwI57bKbjy8Wc0 2020-04-19 19:28:04 217.170.205.14 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20300 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r KenRelay2 XF1h8nmqCBb1Bv1c6Gww8lYpHd4 U6s+Nj6qMxmT0t7YiSYF8RFw8SQ 2020-04-20 08:17:44 51.89.151.234 443 9030 +a [2001:41d0:801:2000::26db]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r godspeedyou XF5q9OpEa8GGoFOS/W0cmKoHd/w eEhRnh3F5lWyCVClnbdNL145wCw 2020-04-19 20:21:29 75.48.41.202 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9400 +p reject 1-65535 +r AaronOVHSG1 XIpg8/k2wfzWTZrPvP+JjlGk0Xk TXRE40i915Vfm1sNdWrg4IgodjQ 2020-04-20 11:47:01 139.99.97.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=669 +p reject 1-65535 +r t4cc0reTor1 XIuBGId3jc9wXz058Z5AohiJRR8 5dD4WierG8wgvmnnPZljNHMmZlI 2020-04-19 22:33:50 51.15.50.36 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17600 +p reject 1-65535 +r Onions XJaJUifkL9dLSxRFqa5ZvZ/0KHk Vsyfxba6KhDbx/+kMhjHoKGz1lw 2020-04-20 01:37:40 18.18.248.17 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7770 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,989-995,1293,1723,1755,1863,2102-2104,3128,3690,4321,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8008,8074,8080,8332-8333,8888,9418,11371,19294 +r Unnamed XJkiCHKPOVAXpkLShaQUeX+Mtik p8YdeeCxIigexenHk1RSzAebX80 2020-04-20 04:51:14 195.154.182.115 62768 60077 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=98 +p reject 1-65535 +r affectiosocietatis XJpm9Apj2cjflwDm354f1H2K0xc 68aMbpiOQ6Jgme/oc4DR2nqZiFg 2020-04-20 12:26:03 91.121.160.6 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=867 +p reject 1-65535 +r StevesTorRelay XJyjbTE0DKZL4JXPUO1xpQCFpHA gogOXKSmnlpMwDBYWqvJCutLXcY 2020-04-20 09:00:34 142.162.17.247 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5300 +p reject 1-65535 +r trustytohr XKEuTpcRAsxRl7u35VYlrX5BrO8 9T2agJJ53FJYkNIFWSCZCeq9m3Q 2020-04-20 01:34:14 37.187.2.230 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=685 +p reject 1-65535 +r goldman XKScl8SoAC223fhoWy3iQaEWr9o 6TqZ38R7gzdbPHORXPLpppHz04s 2020-04-20 06:28:09 81.95.1.115 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1790 +p reject 1-65535 +r Swords XKXrpI6tBM0aAxGU7BCXm2EceLY SX5RvEwpSj6lM9OoM0uTFljJ3RM 2020-04-19 22:38:28 128.199.132.7 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p reject 1-65535 +r snap277 XKuv0q0hfBqTQE/ukrCEWKd5Qlg pR49QsgqoTp4S3AqtHvODCClvw8 2020-04-20 11:34:29 24.38.210.244 38789 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1430 +p reject 1-65535 +r torminator XLMMJku56xfPL8authFZO1TDccI yT/rqIAs05Uds2lkfxU6aSA5jNA 2020-04-20 02:20:55 5.150.202.217 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p reject 1-65535 +r dragonfly XL1FOUVzgoKRyP6XgCMv39DSAt8 +TFyJWtJ2aVRvXeyOQ49oHdbDFs 2020-04-20 12:33:23 192.99.13.48 9001 9030 +a [2607:5300:60:3e30::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r niftyentry115 XMw1acZ7fxu3M2ZNQ99GRfKksE0 1bO+hIC9O3RAYJXbNqgYpTYyaSQ 2020-04-19 20:26:06 185.220.101.115 10115 20115 +a [2a0b:f4c2::115]:10115 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15200 +p reject 1-65535 +r polizeierziehung XOOtitBK3mbAA3o89ff3pA1Iogs hh/kLkwVnSRwT8i8ssEHxlZlwK8 2020-04-20 05:25:08 95.211.138.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 1-65535 +r snap277 XOdvZPCjuIgaMrn32GD9zoAHX2Q 6vcVYcDKerzdkgM6mlEIKcMi1q4 2020-04-20 10:45:53 176.167.233.223 40205 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=81 +p reject 1-65535 +r snap277 XOoi7JVZAvGnylvtM98Xszx+VBY 0+H0o+GGYfLJ4hPH/SYslFcX6ig 2020-04-20 12:38:15 167.61.123.140 44567 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2 +p reject 1-65535 +r ktor1 XPNC271hcL7gDNUqy0B21VEIXn8 3oTpgxVjcnc7ZyCGSKDbiiSrZPE 2020-04-19 23:14:11 95.216.149.161 443 80 +a [2a01:4f9:c010:b11::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p reject 1-65535 +r helena XPxIZ4DL1ERrdk5RYI1ldAA7NQ0 Aekz53Avttf+7OFamUrhALHXNJM 2020-04-19 21:40:36 136.243.4.139 8080 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.1-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=88700 +p reject 1-65535 +r noisysecond XRIJZgfqt/+BkNbPrKOsN5jOBeI 4qH/FJU/ypAWKyeZRvtjQ1tdqWY 2020-04-20 01:53:42 85.146.6.52 9003 9032 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r anduinExit01 XSYwN/wXVZazo0QTKwt1Xrj7HRw CaBd5YE3FEyAkqjdWAlBus8zM2s 2020-04-19 19:26:34 185.42.170.203 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5610 +p accept 20-23,43,53,79-81,110,143,443,531,554,563,636,706,989-995,1193-1195,1533,1723,1755,1863,2102-2104,3690,4321,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8332-8333,8443,9418,11371,12350,19294,23456,33033 +r tordebain4 XSdiw2Tq5p2CGAyfSLyEev80TFg M0XKNE0wK2KduX5ph8zSqvGTLZA 2020-04-20 03:40:01 95.217.3.165 443 80 +a [2a01:4f9:c010:520d::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p reject 1-65535 +r theark XSqMqhGdBShyLCQ4NQ+rDI3gGrc kqkkCrc6lWo8oW8UxEmyyWngAqU 2020-04-20 10:35:17 78.46.98.207 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r gabriela XTpX9JT9B4J2LFCKZpX0/P8WH6Q xqD+c+UPGPn8y2Vx9c8kBn9BdFE 2020-04-20 04:11:49 164.77.133.220 9001 9030 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r vlima XUG76RjE3+79YgytlJ34YqIcVlM 7HuRevN6vcVKLNvXBBtVosASZL8 2020-04-20 01:39:04 62.217.124.253 443 995 +a [2001:648:2ffc:108:dcdb:eeff:fed8:9f]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4020 +p reject 1-65535 +r eir XVRPQFXG/S8vaS1RnPp6Yn2NOQM 5WFD8FdOCVFSwYoyUjSdxdgSdPA 2020-04-20 09:29:09 88.198.36.122 443 80 +a [2a01:4f8:a0:23a1::122]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r snap277 XVV2QnExcbOaxafPhV+VvvNiHkU 2eJsIG8wBoK8j2AOemSSE+N4X2I 2020-04-20 08:52:58 72.198.211.108 38463 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=91 +p reject 1-65535 +r AutonomyCube XVgRhaEnfLabOtasKlN3oAY4Jh8 3nNyD0cXWPb1CDOpO3hMwC79Kjc 2020-04-20 12:24:08 90.187.52.233 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p reject 1-65535 +r snap277 XWbjXRubTRx2LF0VAjkoxucEfvc mSgbh7Fxa1HG+/DXJOD3hPL/9+c 2020-04-20 12:29:41 179.24.243.236 38947 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=266 +p reject 1-65535 +r UnivUtah2 XWmndCP+PSo88JoBXO2fCnueONE zHAgTV99+mQoQPyBE1v9OSvT4jk 2020-04-20 05:32:33 155.98.5.6 22 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p reject 1-65535 +r SwissLove2 XXFtu82NUuBU4pZZzKKnVxgy16s gFKVcxVhquK2379iGbbRTi2ZQc0 2020-04-20 10:26:15 85.90.15.34 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p reject 1-65535 +r Fission07 XXZXcLTbEQ2IeHRXl4q0AIz2XKw FuuK2ZtipUQuvYKetkrF5RArDDE 2020-04-20 11:25:16 37.59.76.254 443 80 +a [2001:470:c91a::6]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29100 +p reject 1-65535 +r Unnamed XXd8bW09qt/vGQIY8lqRemgsQIs VQH0UAqKew8oYdSd5SlcAS57vfI 2020-04-20 10:59:18 95.216.115.173 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26 +p reject 1-65535 +r nsaciabrb XXjX0qFva00xZv2dH9SnFbFKVt8 gplbgxPW1xw6mZ5AB3Jpx26wKSo 2020-04-20 00:22:03 173.67.26.206 8500 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r robinvps XX14m8NRINHgVaccNST0o+DORC8 Pdmsh6gPSUUvhxwtnAifh4vyTzE 2020-04-20 06:30:33 167.114.7.166 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.15 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=62 +p reject 1-65535 +r duhorg7 XYKXZYrQOBeMgg5dZzoiSCkFNzc 92hL4F32Uonvi22S1gAvXTZkWA0 2020-04-20 04:16:00 207.244.75.198 8080 0 +s Fast Running Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r TorOrDie4privacyNET XYSQDb5tY2VoSpZ1uBporOlXemg xPeDcodJaDWGnpnl/StTMlJxdWw 2020-04-20 11:53:31 104.244.73.193 443 80 +a [2605:6400:30:f7ca::2]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6679,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,51472-51475,64738 +r Unnamed XYjz2nMaAos9fIElLHtrmB892ic V8XKxF2/tHa3WE1b7D1C/As1WSs 2020-04-19 20:45:15 188.226.152.210 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=701 +p reject 1-65535 +r notespace XYnBy/Hy6EDMSPx1pGCQliqD8y8 x3UV3I4THYH2cco3LKx72pdIomo 2020-04-19 22:51:35 74.207.231.186 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=183 +p reject 1-65535 +r a6xzL5 XZYiMm0a5A8vTVcL4cf8dQXzUow oGKEIz/j2n8GRP4cXngcCDXJ3Lw 2020-04-20 02:45:10 188.244.43.25 9090 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=4990 +p reject 1-65535 +r HobGoblin XZb2H+0mwpkJO0sECe06GHZabbI kcmB46i8FZ/tFctI2F/jSnZWY74 2020-04-20 04:17:26 217.170.205.107 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=31900 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r kaspersiki XZe3V91tzNrWP4/4/th/Y01NKSs gIpDG3CWG9/MkaCQsoK8pv+dPqI 2020-04-20 07:28:56 185.193.125.27 9001 8088 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28200 +p accept 43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r t0rjaghman3h XZgT6c4j737s1GXfILnYcu3ZmOw xaG3PVggD/xz+41lKgskIVbYYEo 2020-04-19 19:06:46 92.117.125.99 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=256 +p reject 1-65535 +r bbkamy XZleyYPtPfnaq9Mrm/FUCv9CpFc YSjq9j2Jf1ymSntN8sB0XRP6L8g 2020-04-20 04:39:06 167.114.244.112 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16300 +p reject 1-65535 +r snap277 XZ9c9Hpm6yqYv3qg9rVXrA3RC+g vOD5d1GCJ/6wfYp9ZF2RVu8J34o 2020-04-20 07:22:16 82.28.219.66 45605 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=49 +p reject 1-65535 +r prserver XaabCGuDP8Hfzy2ci5w7AxN8fv0 zk2jyBtHKp61FqWUE8LN2Fmbmbg 2020-04-20 02:06:16 45.33.13.63 9008 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9110 +p reject 1-65535 +r Chenjesu XbmuJ6ROt7R2zASmbGenHJegAeY jW0AONNDXwnX6AfKMcO6v4S5+eI 2020-04-20 10:02:32 54.36.205.38 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=91000 +p reject 1-65535 +r zwewwlLV1 XcQPU1ft9ICakBCCgXIHLJWnNRQ CJLo5DyQe2HkXTpsikaPocI2y+U 2020-04-20 11:55:32 195.123.209.7 9001 9030 +a [2a02:27ac::19]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=5380 +p reject 1-65535 +r Unnamed XclFzo+yo35uJ5Xs0nCbsh+HFLA Iduh7NHIrfHECf7L8ZLaihrwgsE 2020-04-20 03:46:13 207.244.70.35 443 80 +a [2604:9a00:2010:a08d:10::23]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ph3x Xc9yppFhjQeq4uXfm/HZRQm7zzg xYni2rRgUbAsLt2blPGUM+Gkujo 2020-04-20 11:18:07 78.142.140.242 443 80 +a [2001:858:2:30:78:142:140:242]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4040 +p reject 1-65535 +r Innominato XdX8lO9YcEMGyGpK4kQfPZ+QeRk RN7uWPItFi8vYGON1dZXT3JWwU0 2020-04-20 10:17:54 78.13.197.127 9010 9033 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4 +p reject 1-65535 +r NovakTwo XdzwgxQw6pZpF+YmajUvT4SnVdY VmwTAj2uU/+JLNAcz7/NScLQGKM 2020-04-19 21:17:56 108.58.144.234 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6100 +p reject 1-65535 +r niftylinkrat XeN6M3Gq52OHSOtDyfHOZuCdRHA jbkEmtR32QWLsiG82eAV9LsiUlE 2020-04-19 23:32:22 51.38.164.157 20 21 +a [2001:41d0:8:d077:0:1:314d:208e]:20 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74000 +p reject 1-65535 +r CrashMe XfUU3KGRhp3F4pDMrdZyoM7pHSg fo1FtO4Dru+Jk0iFUbGd6F8nZIM 2020-04-20 12:24:16 213.252.140.118 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1360 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r TitounNet XhFK1ghCjCOzjMx32iLkzQwn8s4 uhCvvkttxwnl2MwHY9ES6S7yzGE 2020-04-19 18:55:04 213.167.242.183 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=775 +p reject 1-65535 +r Freedif XhgBT3kaH7omvHkkfppcYhJ4iqg WkcFLjHIxmgKLpHDeFD27j/htJQ 2020-04-20 03:36:38 113.161.52.138 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=464 +p reject 1-65535 +r Frodon22 XiE0zo06O3ql5Ze47+PmWbA8ArM ogI2ZqMLAS34a+lcUMXkh78Uf5I 2020-04-19 21:37:50 163.172.179.31 9001 9030 +a [2001:bc8:4400:2b00::20:331]:9050 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r snap277 Xij3KONh1iRZjaEoHUBmfzDsc/k FitoW8Pfgcf94y8G2gh4dnVOSOI 2020-04-20 10:42:32 46.2.133.110 34901 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39 +p reject 1-65535 +r Unnamed Xin0jBLeGcPSbl8YvTJ02rPMvVo YPTL8qypoa/lQbk/7CinyTlRP0o 2020-04-20 07:48:12 13.71.87.191 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=490 +p reject 1-65535 +r fluxclouda Xix9He5/E7mHQzo9Igyhn32pBHc DTDAD+LLfH0sVL9fP6rXfvDARKg 2020-04-19 19:38:20 104.37.192.156 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2000 +p reject 1-65535 +r 4dfd6315e32b Xi+n4NjxMrQHjk9Aj+AqXKZ3Z/U 7rxljCL0+f4+ToTN2q7I/Q72CsE 2020-04-20 08:24:28 51.81.253.195 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 XjDC2tpAmnmCo7U53Ca7a+X6mV8 HeQtS25Oj3i6PiOgzGLMox0Crns 2020-04-20 07:37:01 78.236.46.218 36035 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r 1TD XjqqJ5Cj6E/pVzglO1XovN9ginA DqBF2acc/ieT1dy6Hnnsqrz4LLM 2020-04-20 00:22:15 188.192.32.12 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=999 +p reject 1-65535 +r MacarenaValdes Xj/TG53CecBq0FHWi+CJFPbNO0Y q+xf7iAdx6N1Q+PcucIwkxuI8es 2020-04-20 09:50:01 201.214.186.88 9001 9030 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 XkoPxO+0d/WucwyxSCY1s0bI9Sc P4GYjHnHoFD6L2MT8wugnXeMDyI 2020-04-20 03:38:49 92.186.35.119 40615 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3200 +p reject 1-65535 +r Unnamed Xk0ebTFBPczBSKgFAiRXjLvxKIM xs3BP4wzmi1P9xNmh0IfXUIyXSE 2020-04-20 01:20:56 37.191.202.138 38443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8700 +p reject 1-65535 +r niftydagon XlK+oiEwWY8gDQXEK7ZnCcJOj2c 2bd9HFGNUzJQCGnHGoYy6bp1k50 2020-04-20 08:54:54 185.220.100.247 9000 9001 +a [2a0b:f4c0:16c:12::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44500 +p reject 25 +r Backplane XlZzjn+XqoHe71mvKElCk9+/zN8 Hv+nenmp2jd1ZmLssbT/khfmlEg 2020-04-20 08:25:05 172.98.193.43 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6320 +p accept 53,80,443 +r snap277 XmstK5eR1oXnQ09xZwj98t3ZOa8 qPDVGJHmjRWhekEyj4ir/NysP+g 2020-04-20 10:22:18 153.218.97.85 45281 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=310 +p reject 1-65535 +r sorrentini XnYqWLH3/5LnkaHqTxhpXKxmd84 F9qmUwH1k3+NOWBPDCmrOFHw/b0 2020-04-20 04:14:38 139.162.7.42 443 0 +a [2400:8901::f03c:91ff:feaf:a05c]:443 +s Exit Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1130 +p accept 53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,5269,5281-5282,5555,9418,11371,64738 +r AnonymousOnion XotJtmG+a6Ysfjj7ar3pFRn9Ycg CDzs5CSQ3sV2gP1LMoDlcwscecQ 2020-04-20 11:10:03 94.225.136.164 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=220 +p reject 1-65535 +r rofltor20 Xo6sSnvDuCq/cxB1yyflTyaBvEk grw60FNjqmxT2ydn+wmqClH5ca0 2020-04-20 10:29:11 64.137.175.65 9001 9030 +a [2607:8880::475:41]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r NinthPlanet XqfN6roztUpzaFMwyxV+MoQpSuI Q5/nsPG6E2yhaA9Vj59ZTNkWCr4 2020-04-20 08:33:59 185.82.126.137 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15400 +p reject 1-65535 +r yellowDog XrpKn0g+B/1xe6gd1vc0SvgvfV0 uVPVtjmu6AL5r+V1b56MDRDkaUo 2020-04-20 04:11:02 178.73.210.118 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=565 +p reject 1-65535 +r pansomatik Xr7iyE3NjILYtU4Qu57mjzRD87M CUNBbza2euaiuzrYwoKKvWMhyG4 2020-04-20 01:03:23 91.121.116.34 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=230 +p reject 1-65535 +r Lititz Xt1mKNXhPtAgoeoDwZRN1nabSXQ 1A/XHsBBPGPmuMvT7HOaYnFMr8c 2020-04-19 18:58:01 192.241.252.63 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=280 +p reject 1-65535 +r MyCoolNick XvCqru57EoLaDbq5Rmm3PjndUbY NxMbul6+ojkaUmQh9ofh7mSouf0 2020-04-20 04:54:45 95.216.145.127 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r ClericalChanneling XvZFC+gca1Fim0fdabOC98tILCc 3vZFJnRR42GFt6CFLIR2tMkW8eo 2020-04-19 22:42:51 173.246.3.69 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r TheK XwVj+VzUNiOv0L2jXaxWXOkjCgE QZ2cJXm3PtHEkW4oeqbiz3yNKxY 2020-04-20 02:23:10 86.245.143.76 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=843 +p reject 1-65535 +r theglassnymph Xwv/i/LHUo5B2xSSRfRzbHXMd3k zGZ/1y2+sXEq/MVWs9CaM4YajqE 2020-04-19 21:19:17 185.225.16.146 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 22,43,79,88,194,389,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ParadiseTorRelay2 XxyVWoP/7CVI0qRjfSzNCRJKGVc gTDQPcmsNotkLzuqFNvxXnM3K8Y 2020-04-19 21:19:50 193.182.111.18 80 110 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=8610 +p reject 1-65535 +r ooty1991 XyTyfHba0DtXcX1cTf40GlEpSuY 7L/nUuPDuyoPaiZlLvgI8bjX5AI 2020-04-20 03:00:54 50.39.160.224 9050 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1500 +p reject 1-65535 +r Planetclaire61 Xydqb3qnSvsq8QDq2ijHpvSLpQ8 156Gp0VpnTAe/6GlTo1EFqEeoM0 2020-04-20 06:46:17 81.7.15.101 80 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r QuintexAirVPN7 X0zRIJmvIPr5rf3OxlMWo3bQIBw hu3v/dkUipSIZbeq4CBZOcWoqy4 2020-04-20 11:17:39 199.249.230.118 443 80 +a [2620:7:6001::118]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14200 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r ThereIsNoCowLvl X1jpQX35SmZSmGT6ETRjVhSVikQ ow5mcMvHSSCoSge9NTw2oJyjHw0 2020-04-20 02:23:38 176.9.118.73 9993 8000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=94000 +p reject 1-65535 +r PsyloNet X1pZ4+ywmHQH2RarveYGE/g+oek NY7Bt707BIU09xn2v3+DlTJrF0c 2020-04-20 04:16:40 91.122.100.13 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3100 +p reject 1-65535 +r snap277 X11Qya7H/xW0YeJ0JFjX9w6upA4 jcNIHkNf/7ACU5qHpl6NPAPXdek 2020-04-20 12:15:50 90.9.95.79 45249 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r DrSaturn X27lcLOjZBeFHtLF5B/zf9RY2R4 Y5kiQRkPwSh3+fBnqjmlO/Gvr10 2020-04-20 04:12:54 45.56.100.84 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=740 +p accept 20-21,43,53,70,88,110,143,194,220,389,464,531,543-544,554,563,601,636,666,706,749,853,873,888,902-904,981,989-995,1194,1220,1293,1492,1500,1533,1677,1701,1723,1755,1863,2010,2033,2056,2082-2083,2086-2087,2095-2096,2102-2104,2221,3128,3389,3679,3690,4321,4643,5000,5050,5061,5121,5190,5222-5223,5228,5555-5556,5800,5900-5909,6463-6472,6660-6669,6679,6697,7777,7990,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8887-8888,9006,9101-9103,9418,9999-10000,11371,11753,15000,19294,19638,25565,50002,64738 +r FissionMasq02 X6dZb7K6LIiTN/i4LdcSe7skDU0 byDlN/IMwu/XVX1oit+iJHN+cXE 2020-04-20 04:25:56 185.65.134.175 10750 20753 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2480 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed X7F94uiXYlzcrpmp+naJreL0ppk na3IpZlqYUYYjyJ7vb6N8gOk2us 2020-04-20 10:10:08 54.36.112.241 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=730 +p reject 1-65535 +r torreypovich X7OEYF9T3L8csCFD0xjaPo7jiiQ tDvBXu0zn6YFE5wc1BD9KG/0ip8 2020-04-20 06:36:14 151.236.218.107 9001 9030 +a [2a01:7e00::f03c:91ff:fe46:7e35]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=92100 +p reject 1-65535 +r Onyx X71ZtIt2zLImrX+laX8bcyfBRRs f7sZnAbUY318087tPbDtSIFZ5b0 2020-04-20 11:50:49 89.163.242.17 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31000 +p reject 1-65535 +r pzodisoei2 X74TJC9n04sS3gdFunH06lq9BPA ca85ev1dFivjOwwmaTCeqIM2NKc 2020-04-20 04:18:10 45.10.22.18 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59 +p reject 1-65535 +r Unnamed X76esO1SjkALsf0VgwOmVVbdSaQ wN7h6htTc5LTUjSa70AWuToFfZo 2020-04-20 11:57:01 13.75.233.3 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=375 +p reject 1-65535 +r Grizzly X8kj2EkBQhGhUEeOOxXEolht7xM FFT+j5Zu4Xrgc/29xdI+2M/4FGY 2020-04-20 08:36:38 178.17.171.224 443 80 +a [2a00:1dc0:caff:e2::d96b]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5510 +p accept 20-22,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r TouhouBedserver X9DsuFPPPpf293eHw7bX7TH1kf8 tJCZje10bSKYe4FxkypdSUWixX8 2020-04-20 07:23:26 194.34.134.115 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9610 +p reject 1-65535 +r GreasyRelayPi4 X9jajoja25fRMqVq3nPbYPIak5M re3mVPlR166GdotANxqBBKh8wX8 2020-04-19 23:36:31 69.124.202.194 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3940 +p reject 1-65535 +r Unnamed X9/jfWriI3vCf3UZBbg8+ko6urE Id0CiC1unOyU4bI4dWkeuSdv8FM 2020-04-20 04:31:30 5.252.152.10 44204 36132 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=211 +p reject 1-65535 +r bigfin X+Pkl0JtqSBb9Nrh5EF8Hda8A90 rqnms/OkR+kbap+q62uCOSAQLBU 2020-04-20 08:08:09 190.2.144.104 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r kohlhaas X+g60Qa0mNWj6npI+3N0mvKJfls puVUBBowHLFSoFfQk+nsXKLalc4 2020-04-20 04:00:18 46.29.250.27 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3600 +p reject 1-65535 +r jJbzwynG X/AtQRPwpoiNCi7mxXxhoVi3VQw +MrOCf1mcGPFR47dkz1lrthTO4E 2020-04-19 18:50:01 37.187.96.84 80 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5660 +p reject 1-65535 +r 0s1nt0 YCdbUugQQHZY/UJ47bF0nHX5Vvk LczqUFRf7hoxRAR4FnBImVWL5E0 2020-04-19 21:27:37 176.9.53.58 8443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=71200 +p reject 1-65535 +r TorHelper3 YE1xrxG5h3yJN5NrTVT7ITb/DeU EGThedXjBzHmBuxxEah3dh6eeXE 2020-04-20 05:55:26 88.15.211.247 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=367 +p reject 1-65535 +r arcanum YF7kN17kw4IVyJSfWAiGN0n9T0o k1GEhGxnlnMHbKXKm/coHkpYATg 2020-04-19 22:56:59 134.3.11.142 4020 4080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=399 +p reject 1-65535 +r PrepreUseless YGhYk6V9ZlYqB1S+47am5oCCyL4 H80DNiZXg/QJHjFdbvGek4zh84Y 2020-04-20 00:08:56 47.254.134.152 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r avast YHBoffxIkOFAZLJeGvp9ELNM4uk /Sre2iIuDG18DMBdqo66LOYkeds 2020-04-20 08:03:45 31.220.30.218 9054 0 +a [2a04:bdc7:100:23::1488]:9054 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84 +p reject 1-65535 +r snap277 YHFHUlzC3yaxheiP1lud70DrwAU v1oBmuOVVj6zuHgZDOTARwKEX1U 2020-04-20 08:01:48 92.139.70.63 43053 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8 +p reject 1-65535 +r LeslieRelay2 YHaWUsBHEpEubiHO0fCNx5d4mnU DJ5k/LEPhpea48kV2cmDY6f9dc8 2020-04-19 20:38:21 194.182.165.153 9001 9030 +a [2a04:c44:e00:32e0:42a:30ff:fe00:e7d]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1410 +p reject 1-65535 +r nekopeg YIhRkcd0IKGxfvZ4b34c/OAX0Co QoJnPZxC6LvDYHmSsLZDO1aQn3M 2020-04-20 12:33:08 45.76.98.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=310 +p reject 1-65535 +r nodvrelay33 YJt1w5Dt39TEM8YfV+ef6BLJMCI xoYM7DHbEO/fAb4eXhEnBUI19SQ 2020-04-20 11:27:17 45.62.229.7 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2470 +p reject 1-65535 +r niftychipmunk YJ5Zj7agC894cpBrYCtwW2RUHFA 02EGGah1K0vGtVUkvf8lCQqgqCk 2020-04-19 22:15:15 185.220.101.136 1136 2136 +a [2a0b:f4c2:1::136]:1136 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37400 +p reject 22,25 +r Piratenpartei5 YKnh/k0CA4OkoP5Y5ZUJg9CNZec FRlUXEU4IPGJ34CmYfKp5Jm/E0w 2020-04-20 10:02:33 188.68.58.160 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=27900 +p reject 1-65535 +r schuehlein YMopV0WTCvpZ23P4d4NLQQDHtxI Jb4s6bqdp3K/I8LBUmSMurewufs 2020-04-20 01:36:25 85.92.108.76 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36800 +p reject 1-65535 +r freeAssange YM7VnTppUX/nK7AqKG4XrkM/Ryw he09q6MzC3W0N6KtvSKs4fRQoN8 2020-04-20 08:28:24 164.132.59.130 39001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=830 +p reject 1-65535 +r Assange022us YM7xnVKTxmJsGuAAM6K6femR8OE BK9nDSp24EGjW5UkdFXws5Ixe3k 2020-04-20 02:32:03 66.152.179.11 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p reject 1-65535 +r QuintexAirVPN6 YNNmf1auxcac9+j1V9sh3fbDYGA 553tS3/5W0RXKnAeQKG5B/2bn6I 2020-04-20 11:15:30 199.249.230.117 443 80 +a [2620:7:6001::117]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r valinor YNtIg5CFeJhACcwfVAXD+CEJTFQ 3EgHXGdJsOiPkhd5LLbnRFaRklw 2020-04-20 08:53:42 188.24.66.96 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=750 +p reject 1-65535 +r bemyak YOFYfAt+oUYrZ/wHBsDHKYp/ZNA fPExnSzd050R7asDJV7xarrl+GU 2020-04-20 01:22:08 95.165.166.133 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=718 +p reject 1-65535 +r rgiad YOTF4wbS2yKJDuJKCfm2wwrzlqg 6jlFxC1cr7QKzHDwGB5GioFnU/M 2020-04-19 22:08:26 198.180.150.9 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10100 +p reject 1-65535 +r Tor YPITnqPgZBCgXL1uglTmCpBjrZ0 PDlbS9TcA087K7/FrHp8WK9DhYI 2020-04-20 01:49:00 147.135.6.69 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20600 +p reject 1-65535 +r n0trace YQBBUscJZy7nOfJme1bvVVClEzI veEqkWqJHHmyhDFtJu61gUnFPjU 2020-04-20 05:50:23 81.169.255.125 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=33700 +p reject 1-65535 +r janus YRczdja4y5efCbZ1MEd9/8phv4g Wn7a7awEqKObCMOga7fmRPDZm/A 2020-04-20 07:58:44 91.121.143.199 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=162 +p reject 1-65535 +r DevilHunter YRjdtYDu3W/l+NPMDfHuF9iipMY Hd3c0PblVYEimHzqt8ZVZFlyXc0 2020-04-20 02:10:17 94.16.123.67 9001 9030 +a [2a03:4000:21:3ba:840a:fff:fe2e:3fec]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24600 +p reject 1-65535 +r SylvanasWindrunner YRwOyNTvkAiN0OaKtMWhl5vIBho ctw+k5u+A/o2HzfxlXnUqw7T7BE 2020-04-19 20:55:11 217.160.58.205 9001 0 +a [2001:8d8:1801:806f::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23900 +p reject 1-65535 +r HiddenCave YSdnweh3nFhWHj5es7z9X838QTQ 9acWCHjLHrzEICWhGtxdilUb8Oc 2020-04-19 19:40:53 5.19.204.140 8953 8954 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1390 +p reject 1-65535 +r Srv3MuchRelay YUCUyvBwHrVoEG5g7BKnhecErg8 8qDxkbDGZcMpACfqvasnMkGmh9o 2020-04-20 04:13:59 173.212.253.172 4443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r Cloud YVq+ot526zdgvFHnMGuqWfFc2PI MulOTIAELEGEb9oATc9P2Cj+34M 2020-04-20 04:20:52 46.166.139.111 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60800 +p reject 22,25,109-110,119,135-139,143,445,465,563,587,6881-6889 +r AquaRayTerminus YWCB7IKVk69CMlUN5v+qHXWzepA 7sd9pqKs07Ybx20VTulus7ENGSw 2020-04-20 03:52:50 95.128.43.164 443 80 +a [2a02:ec0:209:10::4]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r ingdal YYdbuH98a7m2Vr57leu/s9VQDJc 3f6mQMENB7ZdtLAksjfnJ/XGJts 2020-04-20 00:27:54 79.134.235.253 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=630 +p accept 500-1250 +r theredbaron YYt6D/gsNttS+TfysIX8C1iCR/s hBuP6OLFCkBOFWt2vUoXUXcByQo 2020-04-20 00:11:23 213.157.15.235 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=87 +p reject 1-65535 +r snap277 YY809LOkIfgB+A3ohZ6OnYXGBPU nPazHAYHU6se5ci7UDO5xfyLAj4 2020-04-20 03:13:52 134.49.239.153 43683 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=404 +p reject 1-65535 +r niftytucotuco YZNJ2CQkxgHK65QWGkz3eJk9ruc 02ty0MclOiZdYdO/6P6GW6VYOis 2020-04-19 22:26:07 185.220.101.28 20028 10028 +a [2a0b:f4c2::28]:10028 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40400 +p reject 22,25 +r codebykh YZPTCNkdbzW57T/Hn8CQf9XIUs8 KVlj5I4Cf08gr4UUMc24VBC/gbQ 2020-04-20 10:46:19 185.82.126.182 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=5900 +p reject 1-65535 +r Lupe YZj0vsG62kwbKf2tj6x42TfafEE 8UD5n3ox0ORo0Z2yfIqBTNbuAhk 2020-04-20 05:45:15 185.174.101.106 34361 0 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2760 +p reject 1-65535 +r citizen17 YZoY4pYAWLe9OHGder/ezLNUeA4 2k23xDYHUwMEO4Vm1tGenJINifg 2020-04-20 05:13:26 185.10.68.66 9001 80 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MuellerReport YZ5BPQyK/5W0VmInBwFqere02l0 SzkjSDyw4NaIq3clOozpT+baeaU 2020-04-19 22:58:03 23.129.64.202 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8800 +p accept 1-65535 +r VMHosting830m Ya95DveMLXPI49jiWW1CoarOE1k smyCyKpR+aiAt14A4cXvEXhjoXk 2020-04-20 01:57:41 213.61.215.54 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r zenhoth YbIh48+z3o+UNVPEWrutbPmIzP0 IU2FEFRfvrXUM7MIOLSRdMiwj1Y 2020-04-20 01:14:41 93.104.84.217 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30 +p reject 1-65535 +r pecurina Ybi9yRqnvJoF61o9ZS//iMmOaRE EnaYEhZEm2K7Yk3+PmLsuvR+GkQ 2020-04-20 05:27:33 62.141.39.160 443 8786 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59000 +p reject 1-65535 +r sendlingertor Ye5Me9gOtMnIsp1ek3BEFg5Kbzc zCVFSQnamrBko2duCosLQDcSGoQ 2020-04-20 04:49:38 51.15.112.19 9001 0 +s Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r IchWeissVonNichts YfF5CPw0wFWpVXTSDwnh7pkPygI 7iU7D7V/MRuxiMN+0ldF3vqpFPc 2020-04-20 01:31:09 88.72.49.12 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=942 +p reject 1-65535 +r fsocietyRelay YfJOuuxCkPrDHPNPD/zadlotlwU djK0Ps84CEUbVW7ukzLyocASllc 2020-04-19 23:19:21 51.154.195.73 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r throughhere YfOoQPYe7/9oLGJDU07OsJrf47M N4Qb+6OjIXFfs1+1Qe98Z76DkeY 2020-04-20 03:51:17 100.14.156.2 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r KAPOW111 Yfp+fHZld9duur8ZMwmT3vqK88M 3uzdb7nBxNrBp/jsY9z+VHr4ESw 2020-04-20 09:55:43 54.36.172.32 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=31000 +p reject 1-65535 +r Unnamed Ygar3cKewdk4giNYDrSwvIFXZgk Qfw7pps5O5ggBCgbeBvwwmqHz7o 2020-04-20 11:02:08 116.203.209.85 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=30000 +p reject 1-65535 +r torrunner3345 Yg24WcsPhrAvgZGdoQeZ5x2Sdio zV1dWtIH8oRla9ZcN4aGcNkb0jw 2020-04-20 03:55:58 198.27.64.215 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2260 +p reject 1-65535 +r VergeDealer Yg/c/xuudrmgYJgvQbjTEgXzkEg Rq9MVnekXbUtmhYRY/XlMp2IjzI 2020-04-19 20:33:09 165.22.212.141 9001 0 +a [2400:6180:100:d0::8cb:d001]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=820 +p reject 1-65535 +r niftyentry60 Yh6oIs6sCVhFoM//pQPSmTqxD/M rEKhHG0G6tsZZN/VT6G3Sht/zq0 2020-04-20 10:52:19 185.220.101.215 10075 20075 +a [2a0b:f4c2:2::215]:10075 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r UenoStation57 YiIzRlkRHZnenSaXCsxAIrKQ39A Hc/UrQGsvMxTS8MtouZpoDQeRo0 2020-04-20 05:58:56 51.89.143.157 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r fiedlerRelay08 YidKwX3M9AMKatjOvtDDbnuFktg lb1s8w21lH2OPJwxZt+fqOoFN5M 2020-04-20 10:07:16 185.233.107.110 9030 0 +a [2a03:4000:24:829::3]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5160 +p reject 1-65535 +r GIEBELWALD001CA Yi/wPNbrt10dtDmG46pQC4cVNvw j3vauOwGmNfSpmk0tP0zMQG2XZg 2020-04-20 08:40:07 51.161.8.97 8550 8050 +a [2607:5300:205:200::6a6]:8555 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r niftygreatmother YjL980/5B9wlonMn0cBa03D7J2c Bu8jO4bZta8rxSrUvHZf7w1AOwc 2020-04-20 08:52:53 185.220.100.246 9100 9101 +a [2a0b:f4c0:16c:11::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p reject 25 +r arbitraryKenzie3 Yktzkbl5DnzSr2pyOCObo9aSilc yBRjMQ+FsxuzQJ9HAmCh+M95q9E 2020-04-20 03:24:19 95.216.14.206 21 0 +a [2a01:4f9:2a:f21::3]:21 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28900 +p reject 1-65535 +r cb6d69607b29 YllyS2lJ3yeUgmNluz204f7Ku4M EtXOpreZQ73C5AdHpuIn5EAp/QI 2020-04-20 08:23:47 51.81.253.196 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r peterpam YnDSHWzvCksavqBzCYOq4IEmcBo bNhS7oqUqYrJwtM5RtK1tPyikmY 2020-04-20 03:43:40 190.10.8.152 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110 +p reject 1-65535 +r Fission01 YnErLCShabJDNs0v4r5V2mdHbIs htUeUe+R/+GCw8CYylNDYTddBI0 2020-04-20 12:24:21 149.56.94.216 443 80 +a [2001:470:b14a::4]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24700 +p reject 1-65535 +r tdipeter1 YnN3XLW9KG5lAvKOCWOxbpghCnU OFSmoWm6dF7pBtpGsqPw5pUrEnE 2020-04-20 01:09:56 93.207.4.107 996 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=95 +p reject 1-65535 +r zwewwlUA1 YocSnLnsR16Bag0oP+TkXWMqSks ssU5wrkpaYgQueXw8drizwkWaG0 2020-04-20 00:47:49 217.12.221.75 9001 9030 +a [2a02:27a8:0:a::100]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10100 +p reject 1-65535 +r thebrotherbro YoyCJAv8TnRnTiwgWGK9tioB3nI lkRxIkL4fqA/so8a9kckZM0YEiE 2020-04-20 12:05:23 46.24.244.146 8320 8321 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3100 +p reject 1-65535 +r Comet Yo2fTKtR5JRoi5on5doOcNY0aAY QOrrroMGE9X/C4uyiywgeswOneA 2020-04-19 22:23:15 41.215.240.118 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r AccessNow002 YpCi0I5euJyAkiPFx79SWXaQdR0 VGmcyXHWyT60P+Z6GM1xlbWDUuQ 2020-04-20 10:32:17 176.10.99.202 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r niftywabbit17 YpQpITGaW+xv80dLhNoJCLYOVQU Ba96iKpWiQTPlm8OpHpUq8I/DrY 2020-04-19 22:15:54 185.220.101.157 13157 14157 +a [2a0b:f4c2:1::157]:10157 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25800 +p accept 80,443 +r pilatus Yp3hHRW3YFIeE5Gy0HImmP3BA98 IfDeac6SE2cuswCNT9J2kDtN4Bk 2020-04-19 23:58:18 138.201.196.156 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r Snowflake YqYBWKLDAuPaeS16T1M59BMh5dk 0mSPWe6x8U9kYFXdzQiRFB4VUjU 2020-04-20 11:18:24 213.202.252.79 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38600 +p reject 1-65535 +r PixlPowerPC YqZpz2VBLzbV6BXbNf3yqMjGc/k tswpsPt7f4sWEf2xUwsKoD8nUKU 2020-04-19 22:31:17 70.31.41.162 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=660 +p reject 1-65535 +r Carrot YqbAVf1GMotLr9udLU4PkSznDEk wuoN5pZ8yZqsoJAWJMzgY2sExbk 2020-04-20 07:33:48 46.19.141.84 8100 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20500 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r xmmswap YqvD0bDV3kjeS4r1521aqPU1zN8 xfMVYP7rS49XCVFcEAMilZk5UcQ 2020-04-20 00:32:43 217.182.198.76 9001 80 +a [2001:41d0:700:34c::90:1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p reject 1-65535 +r MrMarioMichel YsKSuAGx/hu0KI8M14uOv7zrUMc qz5XpjLaYrzJG4FH/Oou3g12HX8 2020-04-20 11:21:55 62.178.148.42 9001 9030 +s Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r snap277 Ys0pIis/E6VLICYxWOzZ97mI7zw ChdP3VS2dClhSapSciVx0jjHXjA 2020-04-20 11:40:45 84.98.192.50 34603 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r lidia18 Ys2dGfjdjwWBMfkO+pnFXbbxvbg 99EDy5XXPWkBCMagvu46QFYy6rA 2020-04-20 08:00:02 46.36.38.76 443 80 +a [2a02:25b0:aaaa:aaaa:596b:bb14:6937:18]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2170 +p reject 1-65535 +r gpeduzzi Ys9JgnR7/ePAOVo4lFVL2Nw8XZI We+IBSV72MtMy+YYjIrVHUDE7Wg 2020-04-20 06:48:27 51.178.28.132 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19300 +p reject 1-65535 +r F3Netze YvSZTG86Wz5ZCu7OUiWRaWyN3uI sqdgGP9zHyGRdl6IA5QNW2RnSKA 2020-04-20 07:03:02 185.220.100.241 9000 9001 +a [2a0b:f4c0:16c:14::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=69000 +p reject 25 +r supersoupslooper YvV/8VOStNjrknFl5urO8jgekCA RpnHNv09H/eE+cDsGnGsG5m/zPI 2020-04-20 12:04:03 68.69.164.120 53 445 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4500 +p reject 1-65535 +r saveprivacyforall YvfWIZB6mO4dyTOrplILpNQaJBM Ingzuo+nyQLuyBqE0PiRn6q+Jl8 2020-04-20 03:17:11 87.123.54.238 9001 0 +s Running Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22 +p accept 80 +r unnamed314 YxUnipFxAGLZCyiBme+gbkqqno8 K5VEOG3761caVwcHR2LRuiD3IMA 2020-04-20 11:48:29 213.136.81.89 9001 9030 +a [2a02:c207:2006:2287:0:1:0:1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13100 +p reject 1-65535 +r Unnamed Y1QIJ8SDLSFJhOpHt6aMWT+fhi8 tFHE0+fLWZI9R9OZU6QE0xxPvh0 2020-04-20 09:02:55 54.38.92.43 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130000 +p reject 1-65535 +r durin Y1tZ0BC8InrK3Uayowsm4Yxnn5w zCNhRHI7OZ2BnVeqObx2HYsME6g 2020-04-20 02:18:40 91.4.236.249 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=895 +p reject 1-65535 +r FormerJewel Y2eU4PjxBn5VD6Ub9FcWP/4qwzU XL8eWhAmbPhBSh3cRHWwaVC1wHU 2020-04-19 23:54:33 47.56.197.246 9101 9130 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=240 +p reject 1-65535 +r niftyguard52 Y3LK3iuaYI5RFAAqeoJa8NEbRJo eR82Q/d5EAVHII5goTSlPvGooC0 2020-04-19 22:16:13 185.220.101.171 1171 2171 +a [2a0b:f4c2:1::171]:1117 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24700 +p reject 25 +r x86Relay1 Y3dZXDo8e5pBzPBQedfLP9mrRCo HxIJ2RRM9ulkEsZDUbGASxMyFzQ 2020-04-20 10:14:18 62.75.155.171 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=347 +p reject 1-65535 +r GetYourAssToMars Y3mTKCImR75+2Rcfyf3e0Ld6r7U SM+HfcYMABSVtCTyP36eqNJLFxA 2020-04-19 22:59:49 23.129.64.200 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7620 +p accept 1-65535 +r Aramis66 Y3vSaIQ2OHE9b8E6krPjb0tbD0s Rj3UrgPkP3kbESslOb1FQQBgiQg 2020-04-19 19:24:30 108.36.68.55 8443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=560 +p reject 1-65535 +r FlashLizard Y4nstIkTNLhGMA/dimglDrtbfFI WS7j37oVbCZF9sHlr349jbRHOLk 2020-04-20 12:07:45 185.82.219.85 9001 9030 +a [2a02:27aa::505]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4820 +p reject 1-65535 +r jeremycorbin Y42R/J72YTSKaZTQTDSZvAP1C74 88rO6Y1hXFLx9YU/H7ReGO9wdbo 2020-04-20 09:17:17 144.76.57.183 9001 8000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=78200 +p reject 1-65535 +r Badger1 Y5W0oO4ZaJZvguf6ap0SLbowE50 uLfYSAMicRsRp1+a7TxGTvJCBlY 2020-04-20 09:10:22 188.193.191.71 553 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3260 +p reject 1-65535 +r loudolive Y5YfjLDcjzymxGKmYDC8ACz7wzo 7ZKEp5HZd75lWm5v7i9qVXp+/k0 2020-04-20 01:50:12 216.237.198.56 10002 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=890 +p reject 1-65535 +r Gemini1 Y6DRsOSZrMVRBpc4TbysFqGLC14 vw+eNaF3Ne5NaKPEDOe/NezBMG8 2020-04-20 05:43:09 104.192.169.210 9001 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10600 +p reject 1-65535 +r torte Y7MvflOJ6NvF4bzv5IMS2nzO9dY +iJA8ZXx+E9tonUjzKu40j3Xrts 2020-04-19 21:21:12 217.182.196.71 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54000 +p reject 1-65535 +r snap278 Y7X1OimhWbLwxZv0z/qIAjSmOoY 6O6IyzQ2FWhyjZcXGC48/kmJ6C8 2020-04-20 07:16:23 86.121.20.108 36875 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4510 +p reject 1-65535 +r torifier Y7aCYa5REK3rCeOZFKd5RfdJnW8 wMcSPBQmgmJT43lyjkDpDgFBDF8 2020-04-20 00:48:35 35.180.173.18 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1180 +p reject 1-65535 +r mrTrololol Y7nrTgkoz4Zjf5ptqTd1RTJ6ZHE M9hHoP0C48bKAmefrxMD0D+DjaE 2020-04-19 21:21:00 185.69.54.127 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5080 +p reject 1-65535 +r zwiebeltoralf Y79Gpj+cIf0xXNBhs+qj6wUoOgo +qjg3+lKavXVQ908huS92a8QCQ0 2020-04-19 20:47:47 5.9.158.75 443 80 +a [2a01:4f8:190:514a::2]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=77700 +p accept 53,563,706,749,853,873,994,1194,1293,1500,1533,1677,1755,2083,5190,5222-5223,5228,5269,5280,6667,6679,6697,7777,8074,8232-8233,8332-8333,9418,11371,19638,50002,64738 +r TangeNLV Y8ardKXCiMIVndx4O7APiKtEQnw mZaMGroKlTNBIGaYoJXFKYCzpZ4 2020-04-20 01:41:34 193.106.166.105 19001 19030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=58000 +p reject 1-65535 +r dontpanic Y8gbyoNVcAaaf81IMS3qcH9suqI E12NaWBpPEnGGnU6oApmSFB1jM0 2020-04-20 10:10:44 5.189.181.61 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p reject 1-65535 +r Devuno1 Y803hygUrRYjwjnLegy5xOPOuSM eFU11A7lCz1BFOonHEBY/0wwVTc 2020-04-20 08:58:26 91.121.110.114 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p reject 1-65535 +r celotor Y9PlGHjCBcs5sM1HzdOzEmrLOKk Kwb+HLJL1MYQLDQNfxArfkMrjR0 2020-04-20 04:01:21 89.245.252.38 9090 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5260 +p reject 1-65535 +r HKRealDemocracy Y9mGumZlzsaizZX65oGujHyhK5w w0a8izjOtsOuMSfaHc7wWKecN6A 2020-04-19 22:13:18 220.246.166.228 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=592 +p reject 1-65535 +r Hydra6 Y95UY380n9aGzxwDaCe1voJrn3w 88/VScyCGpZY3r+hiWQM3MbtqxU 2020-04-19 19:04:12 51.15.113.84 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49200 +p reject 1-65535 +r ESCAPE Y+CUpUR3mWc8EUETQFj5SAdOqmM /2sNuDQGLdmjsm2iVatQl7vaYlI 2020-04-19 20:23:07 87.120.254.105 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9860 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r hviv115 Y/AEOBlGj9hsdh6uRbS3Lbmnlbk zEdEOo2u9qT+bjkh+etTc71uA0E 2020-04-20 11:41:15 192.42.116.15 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Unnamed ZAZkIaXJDEj4dQ6ddZtiOb01VCw 6SZ0paFAqc9lXj+cPt1F32hheic 2020-04-20 08:16:59 78.83.112.230 9192 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 +p reject 1-65535 +r EvolynTorRelay1 ZAa2n5XQb2qUz92D6F7pxBCgXUc ve/QNvfu25Bza1YWeP5Bmb3bdqU 2020-04-20 01:22:15 85.214.212.153 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23900 +p reject 1-65535 +r cattyanddoggy ZBa1sy+so4Z1euj0HkMKQzqIHB0 rEvVx9vJA1VNKOp5Krqp5JwU15w 2020-04-19 22:01:01 107.172.42.236 9001 0 +s Fast Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=250 +p reject 1-65535 +r Torben ZBzwrO27ntxnfMbbLDGHJgmqIeE sPWiXXdOgjew2vzfXdO3gXjhHS0 2020-04-20 11:31:27 79.199.127.10 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39 +p reject 1-65535 +r lodrich ZCCpwrrcbP0yoerJNbqgiAkmG7M tgsHVra24EDkWCtRo+77Kc+yaBU 2020-04-20 03:49:09 46.4.149.37 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=90700 +p reject 1-65535 +r cloakmodeengaged ZCMZ6EcgyYmb3Z2ptIbc1qmHe94 MsYiJiBWFQBECgk1HR21m6B0fv0 2020-04-19 22:15:53 98.251.10.24 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1480 +p reject 1-65535 +r PrivacyServicesExit ZEB09HJX+akG+apca4kmwVQKHag RxX/6lVEbdIbWShUCSxiwICd6pQ 2020-04-20 07:49:31 208.68.4.129 443 80 +a [2620:6e:a001:705:face:b00c:15:bad]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p accept 22,53,80,443,587,993,8333,18333,50002 +r niftyhutia ZE3sxaGHnA/iPekn3XBJ9Yu980k dBWaDhzwegqnojJtDQiAorjX44g 2020-04-19 20:26:22 185.220.101.3 10003 20003 +a [2a0b:f4c2::3]:10003 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25100 +p reject 22,25 +r theWOPR ZFw/BUXgl1pJ9p7CcsDD6ihYaCU AH4aMqZVCluPz0bK0WtHIrIaTUo 2020-04-19 20:31:26 212.8.243.229 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=81000 +p reject 1-65535 +r coco ZF3pv3ouhY+Ka0Xx9TA3EXbQI4o 7XN3dvE+9hR10FmljRJK15o65iQ 2020-04-19 22:59:39 144.76.37.242 8443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9250 +p reject 1-65535 +r jy77 ZHmOX0gYUgl6XB7nvJDsx5eJ7F4 dZapgr/R4RCB0Sc9NQCcD26e32c 2020-04-20 07:04:32 134.101.142.99 9030 9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3340 +p reject 1-65535 +r PercyLou ZHvya04X4NVElaSn7B5bObRN6kw 39nsJCj6/EwfMLGroKQv8tM/BQQ 2020-04-20 06:34:01 216.164.197.164 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3320 +p reject 1-65535 +r MrRobotSam ZH+34Ei+fzbGFh1D78s/V+UWklA FI0YrzgCTAYU3lH7Xap/UdHmkkY 2020-04-20 01:55:36 37.120.137.232 8081 8080 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=52 +p reject 1-65535 +r SirioIT ZI0D5TEWPIKL4cC44qUy+VZLVBM xWHRZZ2jpI5exsHLS//V9PKuHjg 2020-04-20 05:39:23 195.231.9.23 443 80 +a [2a00:6d40:72:9117:0:acab:0:acab]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18400 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r fr2xtracodews ZI6XcZ7exPDgjxzrjSTyyPWHNEw ilL4nYUYMjWeMHYz1a4T92xXfDE 2020-04-20 12:20:14 212.47.234.48 9001 9030 +a [2001:bc8:47b0:2257::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24500 +p reject 1-65535 +r kakeboksen ZI8gtUz3GebQL6oHqNpsocfu/u4 XCSRC62ItxFr6+3cug+6Mjt6Alc 2020-04-19 23:18:30 129.242.219.85 110 143 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=888 +p reject 1-65535 +r HunterSThompson ZJ0f6JIIKQL1MY3KaMsnTJZq6jY 5/1Gs20N7+GyU3/VMB0tuQF9KIo 2020-04-20 00:15:14 185.165.68.154 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=150 +p reject 1-65535 +r torpidsNOterrahost ZJ4PfN6b0Wl/ZheLfXHmeRkqpJI MPs99286TImkAS/vPVAwKx9etdQ 2020-04-20 00:00:06 185.181.61.140 443 80 +a [2a03:94e0:187e::1]:443 +s Fast Running V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9370 +p reject 1-65535 +r iloliloliloliHAHAHA ZJ6Dgahr03tdnA+VCylruO3EMK0 6gK5yHcnAuHPQ/oJ0ov36aJM6oE 2020-04-19 23:13:32 81.240.141.19 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=970 +p reject 1-65535 +r arshiba ZJ8M6LEgejD95FOGZykQGKvOzC8 0e0ZS/5eo3aMklMmYZFk9L0N1D4 2020-04-20 01:56:17 46.250.104.224 9290 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=65 +p reject 1-65535 +r NeyamRelay ZKC1ciYT3fwuuEiXxVD79KCW3g0 8fzfh9j6ICX9XO47IQnwFcPToe8 2020-04-20 08:17:06 51.15.122.103 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26000 +p reject 1-65535 +r Unnamed ZKcAjkn/C0+2nbguOdqkTeQcggg FFak1vl9nMnOPOUjMGSuGtT3Nms 2020-04-20 06:10:28 51.91.48.210 40119 35261 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=163 +p reject 1-65535 +r janitormentor ZKiDepevcXdchN4O2pRVKq7cQk8 uIKfykixS2bbZrclfWFWpuaqirw 2020-04-20 07:42:58 91.219.238.221 443 80 +a [2001:4c48:2:840b::c0de:f001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=315 +p reject 1-65535 +r AnonNetherland00 ZK/7vgF4Uxk+GQ74nWRgIwe3xNg XtDU2IlJ7vF5Ri/l1CPKHmhqSFI 2020-04-20 11:43:32 40.113.109.14 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1690 +p reject 1-65535 +r montserrat ZLBfmiEitdtK3LDm8IMZPzFwqQI KkFa9ZW+4wRL7MY9n7UtvUcMvQM 2020-04-20 09:41:40 141.70.125.232 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=748 +p reject 1-65535 +r eyedideditheconfig ZLWWf6fg9zcYXCepG/HPB0MElj4 zj/RRj18wwm9O+ROdLtiCOjoF/4 2020-04-20 03:34:18 108.61.166.134 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=750 +p reject 1-65535 +r Unnamed ZLknJ5P6tn+2yZqRNkaIJobNHqM ifWykB8YszHoDQYHRUzl/ef1mS0 2020-04-20 08:57:21 191.232.53.233 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=810 +p reject 1-65535 +r permanentrecord ZMsrMsEK3UuT1yW33tI4zM1tbbo cbdwdeS7UI9w1RytZhZO1ufEGZA 2020-04-20 11:32:24 204.44.81.158 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r lupus ZOEjHYeES7WGGp0+1P3fk7SnZwQ hgi2m/7inZdf2+LP8dtBOWGOPuw 2020-04-19 21:26:57 87.98.135.13 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13500 +p reject 1-65535 +r l3v3lup ZOJX2U5zknjVlUzIIMnX6sTnp7c Mas+x5hmNOG+wDr92UG4dhstagk 2020-04-20 05:18:22 136.243.69.243 8443 8000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=95000 +p reject 1-65535 +r w3ctag ZOdkhx88/QuuwEDyoGrVoLgYYQ0 gYFZD1JVuYhYVyiNzw3uf4VyjF0 2020-04-20 05:43:32 45.79.95.244 9001 9030 +a [2600:3c01:e000:132:10::5]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59 +p reject 1-65535 +r frigus ZOs8vM63YLn2R/obmkBTM5gwsCo cfxtEehVMgtvxrh6T4hRBRjhcvI 2020-04-19 20:42:01 212.111.40.177 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r Landesverrat ZPi8JoAhS2wVgbPf/E9lgvh9Rf4 b1E8oaI2P7Slq5y2djvcBdiyKGQ 2020-04-19 22:19:22 195.201.95.182 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7580 +p reject 1-65535 +r yetiready ZPybOFK6fsdOeb1AmdhQwzgAnnc XfOXhgUkVlcQ9bbJCsYHXiXroyk 2020-04-20 01:51:14 91.203.144.194 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9070 +p accept 749,853,873,902-904,981,991-992,994,1194,1220,1293,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5900,8008,8443,8888,9418,10000,11371,19294,19638,64738 +r snap277 ZR9S+q2sInJk0aTOIpEkSQRNDPk 2tess7LrEwjlfwMTwlevM61ad0k 2020-04-20 09:21:02 77.207.34.35 40403 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3220 +p reject 1-65535 +r Unnamed ZR+8fYx1yGz5YJ6LVy23cV4/4do SiDgOA1cvISymLLXY7ATqnZrpvc 2020-04-19 21:45:02 139.59.78.113 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p reject 1-65535 +r finely ZTDB9eRTzAjrsaHUtYNskhBgRzs BIJ3hpwc8Hf668jKDosiVRiX8gw 2020-04-20 02:57:24 153.92.127.239 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r noisydutch ZTLrUcHqi2dPSu/PoxMjrkxCEuQ 0MOgROUwlEPmO/cxRKFGCpC5Apo 2020-04-19 22:45:24 213.139.206.100 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2490 +p reject 1-65535 +r reim9tiehai6uFo ZTVkjFkwvVhQDTlaJTutY6ewkUQ lTtmZRIls9KBW5cB3mqyNeIY3+8 2020-04-20 10:40:19 121.118.201.170 9001 0 +s Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24 +p reject 1-65535 +r BlueMold ZTee7UiFmbChUS6A1HQ7yRJcswY D9FVwrUR0D+78xmIQC1TzKU1agg 2020-04-20 01:18:44 178.175.128.178 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3760 +p reject 1-65535 +r Unnamed ZUwKZXsZQoc+wxqyGycjBoiAkyk GE7gMqUMhS9p7A/5oyn1YzpKFZA 2020-04-20 11:54:04 205.185.119.56 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2850 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ParkerLewis ZViG7Lg6QOG+mJUT2MXGCNS5aMk MeC5qmC9YT98TbFKCtxLaPBFb0s 2020-04-19 22:18:18 159.203.41.119 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=250 +p reject 1-65535 +r tor4ever16 ZVoIYbhCBQk+bjqch+sSjJxPk64 8NbM6KZBFMapPlntE0NjneMzRXE 2020-04-19 20:47:10 45.62.227.73 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=795 +p reject 1-65535 +r king ZV5lsn0xY5cr5uOlH8+GI5O6Sck UepyLqWxM7tNmBClRBVw9hXU4qw 2020-04-20 08:23:34 51.89.200.124 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Mylittletorrelay ZV6QicjgGwvM66RYPqvdjTQ5bxQ J6SFUr/DinRw0qSM4aXodYeWKFU 2020-04-20 10:25:56 58.108.47.98 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=119 +p reject 1-65535 +r oscar ZWXzHZ7Ax9/+oZIL47pMc+81tcQ LSMreX3higBXMKdAYP9VM9ZcfRQ 2020-04-19 19:08:52 158.69.207.216 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p reject 1-65535 +r KenRelay1 ZWldH9sIQQYssEMCxWbgcJRk1ic TkGs65AZkigG7ok7WSKJ2U4fKnA 2020-04-20 12:21:00 178.17.174.168 443 9030 +a [2a00:1dc0:caff:15::d46a]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7660 +p reject 1-65535 +r NexusRelay ZWxCVoggmwx0YZvgiLzBRL1FqKY TKsK9DIVLdNl8+6bp3Y4+AP77KI 2020-04-20 05:49:08 5.44.107.201 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35600 +p reject 1-65535 +r mhgngq5364v9ny85y ZWxgtfyYEL7KFZub/wq5mYg63wI sNaVbPLqnJjaYyGn3g9u5fP3g3k 2020-04-19 21:14:11 91.121.181.6 9001 0 +s Fast Running Stable Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r Unnamed ZXM5+BPGOoJmI0FLMZYUcbrm15A FpbxtRIICLY35Wxcamnyx1By9OM 2020-04-19 20:11:48 104.131.206.23 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=233 +p accept 6660-6667 +r Asakusa ZX0vTddtG6eHfrLxdC7ZiY6wRik 7cz3GEixUGHUWd5i+EDgwAtSCtE 2020-04-20 07:31:12 172.104.78.197 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=703 +p reject 1-65535 +r RMB3 ZZw6Y+XYSOsJc9/hr+IUpsdK/d0 bpTPSRhQbXHQMCHhJhOvf672WjE 2020-04-20 01:39:10 79.251.180.45 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r smell ZaKobimsstrnzyi4SdVey6nOhYw rHnuiBXm1Pun8YPhYXjSKXDx14A 2020-04-19 19:46:54 51.178.185.237 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27100 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r goldsworthy ZakKuBxE3X2bc7VSmxFReYU0r3Q ES2/toUfQds7MO84aek5tTZWOCw 2020-04-20 07:22:42 160.119.253.103 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=477 +p reject 1-65535 +r Unnamed ZbHlZY/bmVD5giuQ12wwYWiYzMg G7+4pRqbf/c6szijIr5646Jrsog 2020-04-20 02:53:32 178.79.182.63 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=786 +p reject 1-65535 +r Unnamed ZbyluV02MXca81jMc5M/hbaN36Q 6RssXfhy4b5i+fS4UMqTeaW8Hlc 2020-04-19 23:25:53 45.79.197.155 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=510 +p reject 1-65535 +r toreffiorg Zchhgv2qy1nJ222d24MUiTNBWjw jnXF/l0iFwkgUf/Eb91uzct8UkQ 2020-04-20 05:28:06 212.16.104.33 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=980 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r fiedlerRelay04 Zdb+oXUhp/wuGmM67NM8FGrKMCQ /ijPozcB08IWlRHnt5Dr5DIRIcY 2020-04-20 12:07:31 37.120.190.160 9030 0 +a [2a03:4000:6:b39a::3]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4550 +p reject 1-65535 +r snap277 ZeHTjSo3aDyAUPnL5kqVyWzBmrw qNKE4I6mtCsOES0Hds07LcEycIg 2020-04-20 08:34:00 78.234.140.21 34421 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r smell ZeH58g/w5UCPtrGTGFzIaSoVC6A OpXJRCju+p9pTSjzl4J3STYSzbk 2020-04-19 22:23:25 45.9.148.220 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7560 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Fangio ZeQPft0o4s8oaE4w4Lq3cGgZz8M BF3xtlP2Z94J0bbzd1UQkw7NplQ 2020-04-20 11:39:53 179.43.169.20 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r AccessNow006 ZebrZ2YzMoreO9MWilkTTN3SHhk PLyg+IhiIlcX1xiKIn4hMZlM8AI 2020-04-20 10:32:16 176.10.99.206 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r BobsHouseLU05 ZfVt0l6ygyOL9qEMEKjFDX2DuTE LvTmRu9l25qaLqlUOLL+MN6Z+cE 2020-04-20 00:17:22 104.244.76.214 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29700 +p reject 1-65535 +r matuschek ZfXgZkHxhs6qsigAOyAZvmmEeTc R6paOboxOj94AbE9QFboEA1Sg7Q 2020-04-19 23:11:45 190.97.165.141 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67 +p reject 1-65535 +r eclipse03 Zfhv2LksOsAYh9hrIXHmV9XBn3k ywHKtt55Av0xvcaeX1soXip1Fxc 2020-04-19 22:58:39 90.146.176.221 9003 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=930 +p reject 1-65535 +r IHNIWID ZfukJs6BJnccXutSY087tebpOwg TfvmBWozK7OolEm8Wr0zQ1s71Jc 2020-04-20 00:02:40 173.249.7.152 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=769 +p reject 1-65535 +r snap277 ZgC7njLKTeVO17jT93nOPCgoiR0 jGmGOU+gDkoRyHlQf+A+zyoVk1c 2020-04-20 10:57:32 78.240.166.2 36783 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 +p reject 1-65535 +r sonic ZhDJd4QLqLU8GN+dyyexEjr4ajc VpMgQuNmbxpPvhJ9jVIgC4lbOcg 2020-04-20 04:17:02 62.68.166.37 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9290 +p reject 1-65535 +r ExwMiaTigriMesaMou Zh4IU0+r2+CbpQX3pzhINxxu9zI 28f+jj7R/F6nZctbjB7N1tquzD0 2020-04-20 01:58:44 83.212.72.189 443 80 +a [2001:648:2ffe:501:cc00:11ff:fe4b:4ba5]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8100 +p reject 1-65535 +r SweetRelay Zml62TZEqUvVbrx/1oHkrxq6MqI H9xkCYXgiT96vxmqf19u/1Db4Bo 2020-04-20 10:13:01 98.220.248.235 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1430 +p reject 1-65535 +r anonymousByPDH Zms/liC1V908J6ctkrTm5LHzawg fkfJlvzKrjVDPt85j/zkJWolKKo 2020-04-20 12:28:45 159.65.8.33 9001 0 +a [2400:6180:0:d1::73f:6001]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=570 +p reject 1-65535 +r RelayNameArm ZoQK9QNmSKx0hoid3kLyzu8iQOM vEgZzJwQFiUR31Mzdneqxp1qGxw 2020-04-20 08:55:54 35.157.59.169 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1200 +p reject 1-65535 +r rigel ZodAo8OH95vX10iODCv5V5ZUocs EKgo1xNFyvDr9vtPh2VkAlN+4V8 2020-04-20 10:04:20 164.68.125.194 9001 9030 +a [2a02:c207:3004:2992::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5680 +p reject 1-65535 +r LeslieRelay3 ZodfRclKyAfHdCQ+MlqZywOYMU0 OFajUouGCDSdGfqvUlYsZfJLS4Q 2020-04-19 23:15:32 5.226.148.19 9001 9030 +a [2a00:6340:200c:9000::2]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r jkVR ZpBag6SFik3Qda6gUUN3qfWeEQ0 Xt25D8aWNfwq5C9rI6Dphjo4R5M 2020-04-19 19:50:02 103.136.43.183 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r justanothertorrelay Zp5QNLbeLix8+8+erI2fWkd1eZY V64S5YT4HEJnD3SloXOaEBr0gX8 2020-04-20 04:09:19 93.180.154.94 9001 9030 +a [2a00:1158:3::1d4]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=519 +p reject 1-65535 +r daytoner ZrBtWb38kOvG7eecVYJ18s1HmbA FohFLqVgqZl/mG+rTglAv7u7+j8 2020-04-20 03:18:51 212.74.233.22 9011 9041 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1770 +p reject 1-65535 +r niftyentry97 ZrhhuggBZzFa49BPsS8Qllj1CnI vahkekCJ5t4li4PxD1U56yyi8wg 2020-04-20 10:53:00 185.220.101.237 10097 20097 +a [2a0b:f4c2:2::237]:10097 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17400 +p reject 1-65535 +r t4cc0reTor4 ZrvNDVj9uJGths4iomE6m+48onQ g9Tofvjs2viUjlcWJIaOfb1uc8Q 2020-04-20 00:36:21 51.15.113.85 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44500 +p reject 1-65535 +r spreadrelay ZsyqSo+koNuli9pcEarju6Chd7o ncCMJ24vOer7dcO72+cqiL5+b5U 2020-04-20 07:37:50 89.156.195.37 15891 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 +p reject 1-65535 +r Quintex37 ZuGejEdzCG9mmh4Go/jCO2wHkSk InM6MR8dZo86k8T6cBU22F+G2ZQ 2020-04-19 23:41:42 199.249.230.86 443 80 +a [2620:7:6001::ffff:c759:e656]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r TOR2503 ZvNcNtThmsVdr+dW5e8L/pRkrlk lxjFxDSincPVap0eXjpFEVEGZNE 2020-04-20 10:24:17 212.88.4.54 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=303 +p reject 1-65535 +r troyborgtornode Zv6YEsNUXwZRwO5zQnUe+1JRP6o vJWRooaGTWZpq4Eo81AGEWju6jY 2020-04-20 09:45:18 173.215.17.179 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4200 +p reject 1-65535 +r uname ZwvoB4MF6wXhMDRldqDaRO+0Bgk QgCtQEP2g8JQs1HYIsB7LOH6PyA 2020-04-19 22:14:50 86.57.149.5 1443 9130 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=3770 +p reject 1-65535 +r smell ZxkmbIKpQDRsBjhW8TBEqnXiMSg QGA00kNl/Z0BZdqBtW8bORUb42M 2020-04-20 01:30:42 205.185.124.223 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3500 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r magalien Zxn4f/P8rT44mAuyd99RpnT4qgk 8nUyPqVd/8lh35qgKBGqpZbimPs 2020-04-20 03:45:25 100.33.64.89 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p reject 1-65535 +r CaptainMarvel Zxpoq62hQC+wBnYFX0jqEjubBgw 76QY0JkanYJfOiCAv/saHuYQaKY 2020-04-20 12:30:23 212.162.9.158 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r Gymli ZyNJqTa2AsJSfaxPr8iKQCr4G+4 MUZ8QwHGpWldcUmNVwyYbZTBgGQ 2020-04-19 21:13:08 137.119.202.225 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=69 +p reject 1-65535 +r recklessbolter ZypWpYPGWDcuY6zrQ+f3kcKBlUg s30Bx70jeWCzX9wpUlnb5RAQWBs 2020-04-20 00:41:01 80.253.94.252 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45000 +p reject 1-65535 +r CalyxInstitute20 ZzwIGpUC1dOrk5X/QlcnS+THqKQ w+T/ICG3E9hOqKu5j/eDM5TtxIw 2020-04-20 03:41:25 185.220.103.8 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r elc4 Z0KzTnNcDd1nuQkg7yiBlzi2PsA 1uNc+oUf12s6Jg4BtmKqdZox3uY 2020-04-20 04:17:31 176.31.35.149 443 0 +a [2001:41d0:2:b026:24d9:6a97:78db:2bcb]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3750 +p reject 1-65535 +r Mainframe Z1EOU0GRyRFfCAxFZbLx80jN+ec N11thGOm0kLCO9iFQKuP+qn3dsw 2020-04-19 19:12:13 84.167.113.176 24192 22154 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2920 +p reject 1-65535 +r torshark Z1ScdD63qdBqdeN764JBfrsi6X8 vjXsqZlecJ+l2CfOklpZ3kKib1A 2020-04-20 10:33:50 195.154.252.88 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22200 +p reject 1-65535 +r fiedlerRelay06 Z18F/ezx3Pg27SdNZevpGcR0O5E KIgcjJt8y3c9RQXFzl+Ac0a17x4 2020-04-20 11:07:27 185.162.251.28 9030 0 +a [2a03:4000:1a:800::3]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r niftyhare Z4FHGBTfFkwqbxfNHyWEkj/eIQE gHuPftFFuFsWgBoalKePK63mSKs 2020-04-19 22:15:22 185.220.101.145 1145 2145 +a [2a0b:f4c2:1::145]:1145 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45100 +p reject 22,25 +r smell Z4ldF7zH2hEawuDx80i5mx5LWpE d+iWWxI8mBxVd1eo7M7kobi1oBM 2020-04-20 01:26:13 209.141.62.188 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5210 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r king Z4n3qL4LvxEkD6BfZmNDtZE4KjY pclK7uSpf18w5eOWgVNSjwsVjEM 2020-04-20 07:12:26 51.89.147.67 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13500 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r isecProject Z4597ga0R+NgRtFq7sFxahOzszw PLIDIao49Dxs8xP1T8nFGIRNWYA 2020-04-19 23:06:17 79.202.55.60 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=967 +p reject 1-65535 +r niftyfrazUrbluu Z5blMWBxTZCLObywBYz0iP+UAzY r2qYff5AQ2Ocw4ZNuKUfmca4r0k 2020-04-20 08:52:20 185.220.100.250 9000 9001 +a [2a0b:f4c0:16c:7::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42000 +p reject 25 +r tastyd2m4 Z5+9nB/O6idomAh1icX6wGH0tbw GRxZ3m4SJ85f7DDIjIu2HEIHCxg 2020-04-20 10:20:26 185.29.8.145 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6050 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r PlatinumOyster Z6SpbVhufx+WDwMx9nxoNv6HmGs YDQ3Xy+sw8IFHSJ8U74jMVNuCSg 2020-04-20 11:23:58 88.99.82.41 443 0 +a [2a01:4f8:1c17:52e4::1]:443 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30400 +p reject 1-65535 +r troy Z6TPuYcI/ytKctao77C20Kkw9zw 96Z5qxuKk/CguBKNW1CvDj7JCKE 2020-04-20 11:17:09 188.213.49.176 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MiniBurger Z6iLZXbM79ktL8avCbK1fgg6nMM AeZxM2dVZFLlZkBytjUEelP082o 2020-04-20 03:30:57 79.245.30.245 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1090 +p reject 1-65535 +r Unnamed Z7VpMAm6zKjvDIfn1uGTQPEGxeI a2F3//uVUedKfLzJ4xaLJZnOQ8k 2020-04-20 09:12:45 5.189.89.233 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3730 +p reject 1-65535 +r Camel Z7wbWufUTj6fX5CJ26rqwos1EMg RPnQ3CIED/YIJjNRS5Ayg6Fhcvk 2020-04-20 02:12:44 45.79.91.126 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=800 +p reject 1-65535 +r khao Z833pNBumOVarllbvr845kxMy/M lCOLQ36tzW0I6gAb/mbNI/4yrdo 2020-04-19 22:41:23 87.236.194.23 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 1-65535 +r Unnamed Z+jKdZvWrCRuIL1l5bifRwoo/RU 9S7S08KxyMFaC7kuJWcWyAXp6d0 2020-04-20 10:25:41 199.195.250.29 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6930 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r citizen17 aBMIIYGb7/RSk4+mYp3Fmo0EM64 VeaKsCrDlVK6W7jNr9GCZGdZd9k 2020-04-19 23:55:01 83.97.20.98 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=340 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r smell aCy9G+AlVWRipmni7lxEuXLgrz8 yifiMwOSReYIiPWEKpBTXBbTLX8 2020-04-20 01:25:58 209.141.58.95 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7430 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r mothra aDFaCsX7Lf5VlDoqF0qwJTXNz6Y QKXoDRP5T8NLr96xDXvQkH9gtsQ 2020-04-19 21:02:46 173.230.158.86 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r r3duxTORrelay aDmvIX+u2zlV0S7ZgEzZKgWmzcg NLvWyVItw7gQYIXSr/nfCMcTd68 2020-04-20 12:26:15 77.20.122.131 443 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1990 +p reject 1-65535 +r PESEC aDpmjr1eJ1iJtRDK6kV1IBbj3jA oWdkj9hoHOW/4mX/EgHbFdJzvMg 2020-04-20 08:18:35 5.3.161.176 9101 9102 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2240 +p reject 25,465 +r BORGSPACE002 aEfrmkdWrrirdBs4mtJqm/Uw6Xk YYbU5senCrzTK/OitaV4/tzbS8k 2020-04-19 19:52:39 86.239.234.121 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=742 +p reject 1-65535 +r unnamed aHc9P/e4zvzu/KMq5yAV4tOMYsE V6fCuH1qEn4jGG1H4YLSqJXMJnQ 2020-04-20 09:39:15 51.68.170.247 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r HOSTHATCHhWkekiAL9O aI2AA8fZcSrsYc1ndrwGx2L2bRs Ht+yyhs52UBJUUk1c9FlWCtoW/Q 2020-04-19 19:39:15 103.73.64.18 8443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=182 +p reject 1-65535 +r sFtor4 aNKr2TYjOlaeK0bWIogWFJoWtPo vyiNp/3WykKPECkWuTyw/CzK3m8 2020-04-20 05:25:51 88.99.31.186 34746 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r jujunz aN/bG5H4ve4jRA4EqZ+niDBkBWw 53sGRRdURbNPCiiFc779MaLY8LU 2020-04-19 19:43:39 85.195.242.56 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48 +p reject 1-65535 +r Pichincha aPF1zKvnJ6otIwm82HiUmc7jbtc qcDeju6blpRWNybBUV7s7XNW3ZU 2020-04-20 11:03:21 163.172.139.104 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18500 +p reject 1-65535 +r smilebob aPXyBeK/6rIQPQp04m6qNXQOtuU JlgEpfvdZBFr4Z0Hz3gZkI6CwOA 2020-04-20 01:25:58 51.158.154.65 9001 9030 +a [2001:bc8:1600:4:208:a2ff:fe0c:7722]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r TORminion aPvnKw1BHDFOx/Jyy1s/FMJCkkY lv7OKZcUmzzb7ajZE6t0zeomXo0 2020-04-20 12:08:06 195.154.255.174 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2880 +p reject 1-65535 +r etam aP+l42uVJXb5NODAlC8+Z7L9IRU S7Nls1mxpqgsU8F8rsQkc275ZyA 2020-04-20 07:33:55 80.72.43.250 9001 9030 +a [2a00:c90::25:2]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r OrcaTor1 aQP/H/1qcQx9n+nve14j7wRlCUs sdMyaLq2zFjrBmoZlE3F+BYHemE 2020-04-19 22:05:37 212.237.25.104 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4940 +p reject 1-65535 +r Unnamed aQSmRUFlhTE4HpSe/omhXUw/qNA r0vU17LAbgUMiGiI9USSQpVjl+o 2020-04-20 02:06:20 141.255.164.114 42406 56340 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=88 +p reject 1-65535 +r uname aQtNotR9ZDxO/bmVQXtI+Zf7woE zG+3ZaNGdf6PTB05sTlZIaoOCgg 2020-04-20 02:52:59 86.57.149.12 1443 9130 +s Fast Running V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=3950 +p reject 1-65535 +r randomretorng aQ2kLJxHV3o4M5TOSvYb5iiCTiE MvryASM5yeVyn9ktPLHygeGSVaE 2020-04-20 11:15:45 145.239.118.243 995 993 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=249 +p reject 1-65535 +r URKIGOM aRIiltN/x9M4dT4+wZvGZqEFZqE 44yG4WaBwKULhAYt+Pdte63/L8c 2020-04-19 20:45:38 82.165.67.222 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9980 +p reject 1-65535 +r minty003 aRmoZW+Fgw7Vd4/j/dUi8/GP/28 Eecbt4R3q1b7xREIJ6KKsto/zRc 2020-04-20 00:16:48 91.250.84.156 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6980 +p reject 1-65535 +r torror aSh5lW342s9fjuEjFs7x3i/8Hs8 r6jsvbJqjwjh+IeCypcKWiRuqSA 2020-04-20 10:43:40 88.217.143.53 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=28 +p reject 1-65535 +r battaglia aTmOPRM3rGgW51dRbTYAp1wes64 5P2sVt+/eBAV8l30SbpqZphqyJ4 2020-04-20 01:35:07 160.119.249.222 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=230 +p reject 1-65535 +r LuXun aTqYJYTPTde/IVi2QMz5p1qHsb0 /sa7ZeKSyr92XfarjU+jc8OXuBQ 2020-04-20 10:29:54 89.221.214.122 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r Nope aUAkfgTIOdJoVD5/YlZqkeQFZ+M r4u2UvICHsHRJ5WW9Fzn0t3YGTI 2020-04-20 10:10:01 176.9.57.152 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38800 +p reject 1-65535 +r snap277 aUNutOAAu8dmcljD4G4RtsX5II0 78n1Hk1yrnyLp+qIWpH7w/0u8OU 2020-04-20 10:15:25 83.199.118.50 43333 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3800 +p reject 1-65535 +r Unnamed aUlwNmUxiVMSB3RrPQ5Oy1aIjzw Kv02L3F08LWxrEFCsVEedTGeqDs 2020-04-19 18:55:24 86.80.108.228 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130 +p reject 1-65535 +r FalkensteinTor02 aV2BGxMGc8Lejc/FqedCeQvSUGY aVmQqpQu68OFf67jSofEm9mtyPw 2020-04-19 19:19:48 5.9.44.29 443 0 +a [2a01:4f8:161:32c7::2]:8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=51100 +p reject 1-65535 +r JongeDemocraten aWIEGaPQB3Jysuo5UqH0aID9+uU iuJzHOzC6muqrUs1baw4HmQ1GQ0 2020-04-20 12:11:14 213.108.105.71 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=154 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r 0x616e6f6e aWI3dyLEql5WVA9PlpPfpSVEmXQ drLA+fzyxw0QnjFWXRbZd7a7p6w 2020-04-20 11:49:29 104.244.72.73 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9270 +p reject 1-65535 +r helper56 aW2oOaZLBou8+eMzmMOFjm5miVI ACKdWnvIDF03WIfwRbouvoZr2qU 2020-04-19 23:20:21 124.189.44.164 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=162 +p reject 1-65535 +r butts aXSRDvmV74tF1GKF/RX8+ENHu4Q TYpBdqy6uza2dSvHw3rw6on29Ss 2020-04-20 06:47:50 54.37.136.45 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17000 +p reject 1-65535 +r snap277 aXVldX0P5x1i2QAwO41fzxEme/o NvhvDyjD0MfMbRPcEWL/RGT9O/Y 2020-04-20 08:50:27 80.44.98.107 39067 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=409 +p reject 1-65535 +r greenlantern aYuHCM9OoC0nygknTzNRtPZqWDQ v/juFnDnPDzvdjF0LvkAUhKhQ90 2020-04-20 07:06:56 179.43.158.176 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2410 +p reject 1-65535 +r snap277 aY5el9SZBWEzteMmmm68eNoryoc VxeAFc4BMylWac6PH2isMjRcm5s 2020-04-20 12:10:32 186.49.40.167 36027 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=306 +p reject 1-65535 +r NixoPixo aZHsbZbRo2Zhb/IxivbYkJnHLAA hU2EB9Mnn29cscY+xqf8mIRDd/A 2020-04-20 09:44:09 176.231.6.215 443 9091 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1120 +p reject 1-65535 +r taster aZOIAwr8XBEIIshd6XpRVFsZKYc PoWqlitepgcFBZJdw5LnDAETQd4 2020-04-20 12:49:31 5.135.199.13 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15200 +p reject 1-65535 +r torvlhdk aZ02htYHtZwZxVtMBjx8GEEB+Hs s0vAWx8k9RO3lVrGXhM096pmvh4 2020-04-20 01:10:56 90.184.239.156 2001 2030 +a [2001:470:28:4a6::7]:2001 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r blablablabla aaEo1flSZ3SX2gz8OMXOVa7Q6jU asCXOB4J48/VVr8nNVgoXwAnQ4E 2020-04-19 23:28:40 148.251.201.51 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=62000 +p reject 1-65535 +r eclipse02 abU6WuUCXaiUf3wy9pypA3XtKk4 3KK5S3sf3DaPyBeBI5lRsC8tCP0 2020-04-19 22:08:10 37.252.188.140 443 8080 +a [2a00:63c1:d:140::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r qwerty12345 abzKgCBjCieBvJY653ZuIru7z5A +gJWTXtpw5AJPgigST54Zm5N7gs 2020-04-20 04:20:09 82.197.218.212 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=53 +p reject 1-65535 +r ovoschee acCQyfHKXCdeXsYg98yFJ054rqk +gy/hJ5znzimCNOd4Blq+Ptw4VU 2020-04-20 02:57:47 79.136.153.114 9090 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r xdefTorEvey acTCz89rQYY2l2tf/AFAo74hExI cWEVYg+if1CUnCS7T26IIHCGXbA 2020-04-20 09:42:30 178.62.251.184 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r SimonBolivar aez7cxwrCqe02HRu81BK3LHwpVY 3QFXB3BA2DwWhdjgwe52R/VgHwY 2020-04-19 21:07:14 46.232.249.138 9002 9031 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8350 +p accept 53,80,443 +r dantor agle17JULNtPzcHitnUOW9Dpshc Lcmq+5tSmX1fxe2BNBdCuFt1sP8 2020-04-19 23:11:36 77.162.243.170 9030 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4150 +p reject 1-65535 +r ispy agunalLJCg098/kzBjo0nqzj9pc wuwBBKDUrRYyt/qID2rDQfxwEYc 2020-04-20 02:26:23 178.128.56.199 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=364 +p reject 1-65535 +r faust ag3X6aEfD3s6C8wrhrlwwowabvU N2Ss9Ne7aciY8g9ap6AB8oih150 2020-04-20 12:04:33 94.219.22.32 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=896 +p reject 1-65535 +r eererwerwerwe ahIQCsHSXsbPn7pIdS1Gp+AlG8Q bzDn9yDGBQwDMr1HRW6MRgIsrTA 2020-04-20 04:41:47 37.120.156.234 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=89600 +p reject 1-65535 +r lagrange ahOU1l+TALIiYpSEW36sJEjtebE HEh4FnsbEHx0CzHBbPmNoirH0p4 2020-04-19 22:49:57 51.159.59.115 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10500 +p reject 1-65535 +r neurodump aiZ22sr9vQDFuUvTQ2kJV6Ert1g NXBKuPKUrQxpDGeGQnYMhnlbbRk 2020-04-20 06:04:47 116.203.93.236 9001 9030 +a [2a01:4f8:c2c:86ca::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=24300 +p reject 1-65535 +r gangstatestOn175 ai8MBVoc3nd0G6fZPY+uhWyG9Uw Ws7OFAFS+lebciqC0NaP63kTPzw 2020-04-19 22:24:43 31.214.144.175 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=527 +p reject 1-65535 +r Unnamed ajL3S4UdKD2ps9J+qzDGMsVThdM gxHc14Ahpy/FDPOuKJcCu4Qgo0U 2020-04-20 01:45:38 188.166.91.194 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=843 +p reject 1-65535 +r bliblibli1 ajXuE9Q1T/CgM3TAY7ECkGFLtqk cUI0+8CGI4o3CsJ6eQ2POuTyWTI 2020-04-20 04:34:59 185.146.228.130 8082 8083 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37800 +p reject 1-65535 +r magritte ajZYcHWKHj56nuDoK8wNYiap6qo aUCfSVT8vsBKQ07VKPu3f1mj+gU 2020-04-20 04:29:33 37.221.195.23 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r Unnamed ajdfATq65cmg4CilUyKCrionK6I W9oqzPmLnr16eKlcnqhjuQLQqh8 2020-04-20 06:28:59 54.36.103.223 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=640 +p reject 1-65535 +r Mewau ajxG80FS6E5iRgiJwwaqh4kA5g8 j+lIGHwlI1+MrzBzBr/zV9GGWJ0 2020-04-20 00:54:34 159.89.138.162 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21 +p reject 1-65535 +r maxomeister akEqCe79GRreTuSvC5hhHhChVAk dwR/Fwn9Pg9y+KQBft7RLg3eR0A 2020-04-20 06:33:48 193.218.118.160 443 80 +a [2a0f:e586:f:f::160]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5400 +p accept 20-21,43,53,79-81,83,85-86,88,90,110,143,220,389,443,464,531,543-544,554,636,706,749,853,873,902-904,981,989-991,995,1043,1103,1113,1194,1293,2086-2087,3690,4070,4321,5004,5190,5222-5223,5228,5287,5675,6880,8008,8082,8232-8233,8332-8333,8502,8601-8602,9418,11371,64738 +r Spinach alBiHgl2BEhUwN83JVh1el++2u4 ejeLaO6MYiqLcJuIjoZPdbqzflU 2020-04-20 07:34:06 46.19.141.82 8100 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MusicGivesMeLife alldrQg/tDJVEiJQiXuH1jLlelA xZnt4lMBn3LtfzBfs6yBia+h1zA 2020-04-19 20:27:08 174.59.212.195 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r snub altlC4MPQIKG/4cHGNPQC1aLcEU sf8XRMApvwENkmHSpZ76elRCSdA 2020-04-20 08:47:03 205.201.63.48 9001 9030 +a [2620:10:6000:10:0:74:6f:72]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=5800 +p reject 1-65535 +r YouAreLoved amQsr3O9vsZN2aRLm5c8cLPnRwc JRpwDeulv47UcNRF+vvuDq9sGEQ 2020-04-19 23:01:13 23.129.64.180 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5400 +p accept 1-65535 +r hinshaw am4WjH+ykJ2+vKe/Q7gYWDw38+o /rqhqnvq01BPgRxvN869s1ArmPw 2020-04-19 23:18:51 89.33.246.114 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6320 +p reject 1-65535 +r TorMachine anVR7uGPeKmBMJboK/hPdA0yuRE hJkgNCUChYciQzeU2LnvX96n2MU 2020-04-20 00:57:42 95.217.16.212 443 80 +a [2a01:4f9:c010:609a::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15400 +p reject 1-65535 +r NikowskiSecondNode an6GMRcULvsCHT8payBLp8ILz8A nPABWcL3G5x54xnDu5PSGWVUFt8 2020-04-20 04:12:17 51.75.64.153 80 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r Tortellini aoBJ1O2P+QKdQKOK8u+XyRX2EVE 7/Tes5KVeanZIdXcvpCpkR9oaEc 2020-04-20 08:30:35 144.134.156.40 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=69 +p reject 1-65535 +r nyanlay arYCgGhmxkiY//HCrc8YvYCqmgw QAK7xgsp8QNVqH3rCud7JenI8hU 2020-04-19 19:13:19 82.207.222.168 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=93 +p reject 1-65535 +r de0akatala asq0OUqUu//zkUlxQ+O0nIR5hnI jjT0IP8KBzSKD+8ixJWX1qPs18A 2020-04-19 23:02:26 195.201.141.166 443 80 +a [2a01:4f8:1c1c:15af::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r OrphanOrOften atPqVbh8gJcfNT66cQ9lUCAqk1U fGipfFE9bm14kyE1q+WDgzp5Jkk 2020-04-19 22:21:04 71.19.157.127 993 9030 +a [2605:2700:1:1008:bdcf:70a4:ad52:f4e8]:443 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=520 +p reject 1-65535 +r Rigel2018 atbRy+721hwiOgTnCigBU85/lkA ln5NYDh/T5L2PFJzgMnCnvR0rPo 2020-04-19 23:30:19 94.16.122.65 80 443 +a [2a03:4000:21:525::1111]:80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p reject 1-65535 +r figue auFX/yIBsrdNrm9V1pD0xQmzDbk t8Uf4ctLjRTdYO+kIAtk9CQU5lI 2020-04-20 01:20:47 82.64.167.199 9100 9101 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r Unnamed auF+3ZR04V86kDUHadZkgiKa6qE +0Zt+YcA4TjCsQt6IozCKT4tm10 2020-04-20 09:45:56 13.77.56.55 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=160 +p reject 1-65535 +r Aloysha aubArwWj8miM1iQfqvXyAn6AMrA kwG9ViGSnwSjaWyB36/GPIkBJWo 2020-04-20 06:56:11 93.95.100.170 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3430 +p reject 1-65535 +r idideditTheconfig awYrD9/qw8b5ID+5WERR4pVXTa0 Ha8bCV07GQpILuLgruS3Vs5g+yU 2020-04-20 12:28:44 51.15.37.97 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=43800 +p accept 443 +r TorFreedom awli6Zxiz9/K1tkThLEdSZ/ObUY VRZdemHj2HTmHen/ShtQop3QKI8 2020-04-20 01:30:30 167.71.219.124 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=240 +p reject 1-65535 +r smell awlvD01GtyLvTa75TuGs7SmIKj4 k6q/20NRLqgYv4WCL6j0i4X1ABU 2020-04-20 01:26:31 209.141.42.3 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Bledo aw91qmi1AqjAm2KOX1WLkEED9H8 u+xyGQahYdI40b3vrPLByz57O9U 2020-04-20 10:16:16 62.42.138.162 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=83 +p reject 1-65535 +r hunterwolf axOiwzMftfizfwruk0HVzxwh860 nuZFfyAc26y4o0zQQbZ1ekioZ3Y 2020-04-20 03:12:08 142.4.212.102 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p reject 1-65535 +r theLamia axPdN0940xQQ6h432AL/ca3dKrQ 6om0BF7LMzyjE0hOX7f/XSAdOdA 2020-04-20 00:22:51 83.252.53.83 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68 +p reject 1-65535 +r ParckwartAykut axhd7rJJ5Lphguygd1MMRemKbF8 bqmrXWcnrA6DILIObKl2oPSoAvQ 2020-04-20 03:14:49 84.176.234.249 24107 24108 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r pmffrrbxone axotiX6gyVkyFFmu0GZyJI7qCqU qiG/Jkr77NascxrtG/B1Pl8JUto 2020-04-20 11:06:53 94.23.214.156 14510 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44 +p reject 1-65535 +r LaMarreTAO ayY7RbM7jixzq4D5sNc1OLRL110 KwzUz9rMcNeO3nzyonxn1ZSM6Ao 2020-04-20 01:45:14 178.17.170.13 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3660 +p reject 22,25,119,135-139,445,465,563,587,1214,4661-4666,6346-6429,6699,6881-6999 +r Unnamed ayzzHH+TUiS8IoXR+Kk6IIxxnEM EHlF8aoHnA+axdhOmZvjN2E46aY 2020-04-20 11:21:45 89.39.105.228 53114 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25 +p reject 1-65535 +r hasselba ay4f9bKto7GVCg7+bSL7CehG7uI 6j0uvZHvEYkltHTpB7FWJTWyT/U 2020-04-19 23:33:23 94.79.137.182 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=85 +p reject 1-65535 +r snap277 a0RMNFYps/7Fz83FjQGHLCDAhFg X0DjqUia5vDE3wJMGY2a40usG8I 2020-04-20 08:38:21 78.217.177.50 38707 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r snap278 a1Qj+WsQ5qwO2p/8ocQGNEj8NGs qD6DRXFjTLTItZqPPKgbhxeJpNE 2020-04-20 12:57:29 1.222.138.53 39989 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17 +p reject 1-65535 +r Magiville a1pjv+6o71jagS9PBb6YyGmAnfs Iliq24RBaBMLpgVwXNI2zSWp7dk 2020-04-20 07:49:54 51.75.61.194 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35000 +p reject 1-65535 +r Unnamed a2PLm0XQ9QWtOqUa+Lf6zqQ9zhA gYPeCzE9iQOOxiwT9XJUGr6gv3A 2020-04-20 11:42:28 13.75.77.143 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=80 +p reject 1-65535 +r Faentadeg a2vTA5XX7Zfnfqt0fS9AEZvtXX4 0ea4ACvr3iWWKkLUBq2T+8zBCG0 2020-04-20 03:17:12 96.43.138.43 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2400 +p reject 1-65535 +r king a3i5zFOuKs64Ny5FThZ8H4coaEA tmTtC/uMB7bc4jOPV0a+ShC9jjI 2020-04-20 05:08:48 51.89.147.72 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11700 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r torpidsDEhetzner2 a3q9I3zyXl94fzZa9fxMhvAhOp8 qp2FOcomCeDRuWr0emad1/46HRM 2020-04-20 10:02:07 94.130.183.13 443 80 +a [2a01:4f8:1c0c:4312::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p reject 1-65535 +r sethsBSDrelayZ8350 a4BXGKl79lPLVUYIC+dWUF+b1l8 ZZxB+kKkQi9BA+bnwqFkFv/pG0s 2020-04-19 23:06:41 151.197.240.154 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9600 +p reject 1-65535 +r slacknet a4jiD+6OtH8ajjAgfzJwBcYaAT0 oVceZ+nLPnM97EsofALsVL/qUGw 2020-04-19 21:52:37 148.251.221.163 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8810 +p reject 1-65535 +r gashis1hn a5eZEyxodZmFtNBJeQKtbgQ7o3s T0v8343ZLgfumqFea83nsB8e9To 2020-04-19 19:04:56 46.119.236.224 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1500 +p reject 1-65535 +r cebolin03nl1a a5mbJhxUNRh7rDcSRySztuLgHPI rwBnCGU9dxoxePQW2K+miNmdjPU 2020-04-20 07:03:23 51.15.122.193 9001 9030 +a [2001:bc8:1830:2231::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35600 +p reject 1-65535 +r Unnamed a5tyV3JWij54fgZu7jOAi/9Gfr0 THlKd1/ScaOfuDtIcDmVfn2tL3M 2020-04-20 12:38:46 142.44.133.93 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5970 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r AMDmi3x1 a52DhD29aG27gGaYm/zJAwP2ewU 9wi9h81y0/INaBnyBCGRGPJdgEc 2020-04-19 19:45:21 185.125.217.66 9001 9030 +a [2a02:f680:1:1100::174]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1670 +p reject 1-65535 +r angelinajolie a56oknq26U4hYGfmU3IYI0Olr6I KhHpsbufdLsdylZHp0J7ZjQVNPw 2020-04-20 02:42:12 62.210.83.207 8080 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.1-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68300 +p reject 1-65535 +r theia3 a6VNeAWkT2OnXXCv7I0t9rp7yuA neQFuQ9X4Zl5KOC48OD4BFJdFAY 2020-04-19 22:57:54 50.7.74.172 9001 9030 +a [2001:49f0:d002:2::53]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7710 +p reject 1-65535 +r NEWYORKNEWYORK2 a7Sb6PXiDD2gd2CEgz98nkgn9JQ OWW3SlznxI3d/OhvDHdGWaxNdf4 2020-04-20 01:52:43 198.98.50.201 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,11371,19294,19638,50002,64738 +r Casper02 a7qMLGFx0zc024RSsvChxOuBYxI r0OP2+XM5/wemTRkb89+olulPbE 2020-04-19 21:18:18 178.170.58.2 995 110 +a [2a00:c70:1:178:170:58:2:b50d]:995 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2570 +p reject 1-65535 +r snap277 a8ofrQAPUQVtd1C1RU6UF4AXKHU a+Itm6B4jTH/DpuTUuV48ZR7jio 2020-04-19 21:45:48 82.213.188.21 35919 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=621 +p reject 1-65535 +r F3Netze a8uWSrdOI/iYa9qQVpfTpr4Iryg KDmZ0MJ559s6k2ThMkNUDlfYJ2U 2020-04-20 06:34:27 185.220.100.252 9100 9101 +a [2a0b:f4c0:16c:4::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=91800 +p reject 25 +r tormaumauhosting a+WqNKXDkXJGd6P9wqp3s3aPbiY K4vjQswYOMwnOnBxZpfmSN4CDQ0 2020-04-19 23:49:23 212.47.254.70 9001 9030 +a [2001:bc8:608:252f::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14300 +p reject 1-65535 +r OrcaTor2 a+f37KUxtUEYjyAeer/vK4Mf3NI 2Mze3gsTE0aEy55xBI1tH690EUo 2020-04-20 12:01:05 81.202.155.93 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=631 +p reject 1-65535 +r tor4que a+n8iil9iWsjRg8vsV74VN/NyYs HyuJn2kgxNAqGe+3KrUqs65cRLQ 2020-04-20 09:16:49 64.225.33.130 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2400 +p reject 1-65535 +r tptor a/rtbW3ew5sDxMkfnFcz5bIeFIk zEt4OBYJ7XuVACmtz4dGFt/YIm4 2020-04-20 11:10:32 79.111.14.230 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4310 +p reject 1-65535 +r CalyxInstitute11 bBQ3IP/4Rp72pcW0BmNmNAz2wNE QF9YDstvwK6xbBew13zXL2fGcTA 2020-04-20 01:15:24 162.247.74.27 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r vahShei7Eeth bBqMvliZBu7G5z9PKGrCmvdSHh0 pKFMFDCXck+lWxbdigttLM+St2k 2020-04-20 05:39:54 5.9.37.162 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=657 +p reject 1-65535 +r OctoTor bB0SRLxf+WysUTqj9I8+r02EBCc 3LLCnQcyBq4O5wnBv0sbxiKTroc 2020-04-20 02:54:05 94.142.244.11 9001 9030 +a [2001:678:688::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8790 +p reject 1-65535 +r twinky bCUfp/Rene319puj0Wf2unNvSc0 X4uYT7xeSkuAFT3QGzf/cRl5kj4 2020-04-20 04:23:42 46.20.35.116 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20900 +p reject 1-65535 +r Schneewittchen bCgtNcZ0oDa3m18w6Q0Zs2PT2rI MxGhtKexSM07Uk3/wOYm0VGIlK4 2020-04-20 01:15:46 37.252.191.41 443 80 +a [2a00:63c1:10:41::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24700 +p reject 1-65535 +r czechmate bDM7W9uj3+enguQMuXDCcav+0Rk FOixLtmPKSZDc/90FHmwGqE1pmo 2020-04-20 09:10:58 85.17.127.129 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=61100 +p reject 1-65535 +r cebolin05nl1a bE1jKO2IrARLcTLb7PPy5cZt2v0 7EXfiPuHlTChhBrkka7EMpHFb1k 2020-04-20 01:21:24 51.15.70.32 9001 9030 +a [2001:bc8:1824:f27::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38900 +p reject 1-65535 +r CHRISTOPHERSOFTGEM bE65HJS30ZTLEXCTo2Wh0G+pvwM yytV9612zk9Wp/pfRyfEjrrea/s 2020-04-20 09:18:32 62.12.118.116 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=461 +p reject 1-65535 +r niftyguard27 bFzMexcb/iWMG6LV3B+g+ljbGEA TPPFPKQgf4XnCDn/3Nsbzm6ft+Q 2020-04-20 12:46:22 185.220.101.236 1236 2236 +a [2a0b:f4c2:2::236]:1236 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r Cerberus bGIMNcDqFmV5YIgt6Isolo68hok PHFY0zkYVNtcvox2oa4M+ePvuzo 2020-04-19 21:26:38 205.185.119.222 443 9030 +a [2605:6400:20:ae6:e6c6:d90:fee8:5ad5]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p reject 1-65535 +r niftyhornedgopher bGSubX79pSpGP7atza4tLd4Gd8M j2ivciLD5fVqNwxHqgOXENVu80A 2020-04-19 20:00:19 185.220.101.120 40020 40021 +a [2a0b:f4c2::120]:40120 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r n0torRelay1 bGS6uf3re7duJBRQJftoDagmrbo KLrUkhhhIrV/nwzeXjnnq2eO8mU 2020-04-19 22:08:52 139.162.151.86 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=287 +p reject 1-65535 +r maxlrainerbier5 bGdT01JlOsY8AVYphPJgiFAqfk4 G2igXwZOPILf0uBJVq4DBvYaLzU 2020-04-20 08:14:29 92.117.134.157 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2930 +p reject 1-65535 +r heavymetalnode bISgfEQXpq3mNhjWsDuYIsU26Vo NOlV5H5J+PvpjcrO+vV0Cm3+GLo 2020-04-20 03:09:52 94.134.43.110 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=986 +p reject 1-65535 +r csustueckscheisse bJDwZeRJzVE4x+CLS8L/D+3H6QE 9vjXR7bOmtiHRUWiltKQmBHIa6Q 2020-04-20 05:12:16 92.223.109.49 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1910 +p reject 1-65535 +r AmishTorRelay bKHlIHGxWddK81rTsNzhKKGzKuk hlCsyaUYpnZQ16061YbBEmSb81I 2020-04-19 21:39:12 174.54.26.91 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4390 +p reject 1-65535 +r GeorgeIV bK1qtszLWAqzRbLXiXNrgOmqAvQ auYMsmJ1nSkFw1OqyhUmmkZ9Fdw 2020-04-20 01:00:04 37.153.16.170 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5400 +p reject 1-65535 +r Unnamed bK8hTPKhROfrI8pmwpZusCPvnnU Doar4CSVpFM85pwcMKdnCZkQkpo 2020-04-20 11:16:57 95.216.197.214 9001 0 +a [2a01:4f9:c010:3661::]:9001 +s Fast Running Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=535 +p reject 1-65535 +r niftyguard56 bLfQ81W2DvFmQ56Wh2vN6/j9jg8 t0pd7pqaQuluubjFV8JptEoCqaA 2020-04-19 22:16:33 185.220.101.175 1175 2175 +a [2a0b:f4c2:1::175]:1175 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 25 +r nm2048 bMJe8be6jmq1tPYrPX0bbC5dtvM VeGT9fVjh6NuRsGz2WfwYqoROXc 2020-04-20 00:00:57 104.244.77.203 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14400 +p reject 1-65535 +r ORLY bOAraQ4flQMtOOP684DZBxNcnho x6uv6E+fa9P3UXTzwWKeJquUjPU 2020-04-19 21:55:23 85.166.253.69 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=300 +p reject 1-65535 +r nondeterministic bOPd+qnlb1aJAjXMnCOFst2T4UY bh3emN3FKqm20cA6CO66cJJanUc 2020-04-20 01:59:56 23.129.64.203 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p accept 1-65535 +r cebolin04nl1a bOaU+lV+4YRBUIse+m5Cr7RdHNg aBzNIFqc0Ir7aMc8YDZ+EkH9nY0 2020-04-20 08:20:39 51.15.95.107 9001 9030 +a [2001:bc8:1820:1d01::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24200 +p reject 1-65535 +r kobayashiMaru bO5w0zsYeQZXwEOdlMHzF5muyPM H0qFNjdfHMyI7bQP1myk5ok7I0w 2020-04-19 19:13:17 81.157.142.9 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r sanyalnetcloudvps2 bPpNnPoJsGM6FQ8W3sLQVe0kNTU OAKyGeZMwQIKIxLnJGUQTHqwLuY 2020-04-20 11:05:41 45.62.253.138 65443 0 +s Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=53 +p reject 1-65535 +r charpini bPxHtG5CqddtR7kR+3GeZTCAFO4 7pBPc9lGbJiNPg7RoI2LL0QnAdk 2020-04-20 12:07:10 89.187.143.31 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p accept 194,220,389,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r gandalf bQUECRpvnBSBxizqvuo3gziu5iU BLESL+2CvUBorSu4Ab71GizOwmQ 2020-04-19 19:30:42 38.109.217.146 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2230 +p reject 1-65535 +r novalue bTTt7oI67CSSgac546KstcfqwzU LjAQ4wTnCu6Cw2kfYs/zakfmjb0 2020-04-20 00:07:03 64.149.142.161 443 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9350 +p reject 1-65535 +r niftywabbit15 bUW/eZq5ib59jwRaSJzN3zjU0go 8+ZTl1E45BQQ57d00X93E9xoLiM 2020-04-20 10:53:13 185.220.101.245 10245 20245 +a [2a0b:f4c2:2::245]:10245 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26500 +p reject 25 +r lukechilds bUh+ujCAMLBEEFFUJ2Xp3BkvlUk JSqdu8G8bba4AoOnN61JwJKAcfY 2020-04-20 09:10:26 159.65.2.204 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=911 +p reject 1-65535 +r Assange026fi bU1Rk6DikMAn/mtmcxEz9wlGoVU bsRjUh5ZCv/vSQg8vCNuQSXV8CE 2020-04-19 19:28:37 185.103.110.14 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p reject 1-65535 +r marodere bVorQrEGluKUAB+6nT6quXFnvbY Mjaij8Pn4VKKE7e/Vqazjo1gcTM 2020-04-20 05:41:31 46.188.44.51 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r TorOrDie4privacyNET bW7CouLti/8tSDT41mnYL8Kp+o0 jrV7bsqXy5pSQ9adV9Pess0+89o 2020-04-19 22:07:40 217.79.184.72 9001 9030 +a [2001:4ba0:ffff:c4::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39700 +p reject 1-65535 +r argus bXLpcOtSGHAshUviUOwGY8wU2b0 fgPa+c8IUeM0NeDELZ1nI7eo8f0 2020-04-19 19:31:22 147.135.209.234 443 80 +a [2001:41d0:601:1100::9de]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r SysadmAtNbg bZNQPhUElrsypJEvkExOLbIFJ40 Rk/pb1dq1VWvZ7eVaXWwYDy796s 2020-04-20 10:06:21 91.39.144.59 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=853 +p reject 1-65535 +r king bZS6MOKg2lRpFCKGBAqamqJJQdg 7fe/uJ1wQ3eI7DLnG9cqBSeZ4PE 2020-04-20 06:48:35 51.89.213.86 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ApeSthGw1 bafesDe7FjmRs9unSxrsSLtJfHo HBqYlTZM4Xx9+qJGUVKlKZMRKvo 2020-04-20 02:57:47 94.140.114.122 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r ididnteditheconfig beUQKCDBkBVN9BQB93Dj0mYN9mk WtjCoKOXILQJ5nHgvP5VPEqPjpo 2020-04-20 05:21:51 87.123.93.127 9002 9031 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r Bl4ckh4wk beyQ0tMif9azgGnV0x9wGdG1Ins VVmVpjvwob0rHYEvrI/6wRwVbVQ 2020-04-19 19:16:12 77.20.115.193 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1750 +p reject 1-65535 +r TotallyNotATorRelay bfPLUeGchWK1rqTFetwTYqeT6nA 4ylUll3KmXxZFWevKKgpr1B92f4 2020-04-19 22:17:29 87.138.131.58 9001 9030 +a [2003:a:d23:1701::701]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2490 +p reject 1-65535 +r GIGAWATT bftKyLXnsa0LP19GX3dKQhxmy7o kKj6rfoBI88UEcvxzoDc3fXR9JQ 2020-04-20 10:05:44 71.252.137.246 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=5890 +p reject 1-65535 +r snIP3r bfvw/1BFYSWtmN5mXMYAMYY/65g d9GxT+vkjbDLzBEuJ6S8EA/Vjb0 2020-04-20 01:46:43 93.239.181.229 9123 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46 +p reject 1-65535 +r Onyx bf60HATM6EaHEzjoXdWs9c+2wd0 4c3SpZPJvH/kXsPwY8VDoRZGRTk 2020-04-20 11:42:19 192.42.115.102 9004 80 +a [2001:610:510:115:192:42:115:102]:9004 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46400 +p reject 1-65535 +r PlanetBob bh2kwLDAX7chtCMpxHog2iKQius WVqVVFeSKT/+ddBWqo0UOD2GYbs 2020-04-20 06:10:01 176.252.177.192 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=482 +p reject 1-65535 +r nightie biFBKbyU8m5I+bjH9jEwQVTW720 nQx9ERNBwi2eDYp0KDhZuGsuj5g 2020-04-20 09:27:21 45.141.156.228 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3870 +p reject 1-65535 +r Gihkal biJWom3UoxdG3ztw8iPlo84D+S4 ZlWERXB8kPJtnmqEmOG8FBSWTVI 2020-04-20 09:51:21 62.210.108.137 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16900 +p reject 1-65535 +r mirra biW/StfBRuJDmpaN1MKc4PVpqrU pckwy5Pp21VoyiYGkBoHWvANHHA 2020-04-20 09:09:21 94.102.51.78 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087 +r Unnamed bjPUEB3cY2a+R3ElBo49XS8ix0c yyU23S7WQMeOlBWdRoncKjrDDPE 2020-04-20 02:02:57 54.36.165.170 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=75200 +p reject 1-65535 +r libertynewsrelay blYzuoHWXUjeSNoY9zCcp9GePKI 1jeS/rm/BIfZECG9pn0zwKTWfnc 2020-04-20 00:01:00 188.166.93.163 443 0 +s Fast Running Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1470 +p reject 1-65535 +r torricelli bmQr0IpdaHssVeNZNuMnJjapA2I n7g2YtkQww9etTorQsYJxBdqzm4 2020-04-19 22:26:06 90.110.168.143 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=350 +p reject 1-65535 +r SatoshiNakamoto bmbZeFFP+Gze8B/jDCOhACklqgI +ztGt1H8OUgkvuTl9Fst+RvAYpk 2020-04-20 00:41:28 51.77.108.33 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r powerloadnetrelay bmcwJT9Brgz/flWfvcSlk9Ydfjo poeYkJYGyx0cevJw1JS7MS8uAbo 2020-04-20 06:39:11 46.223.21.191 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=226 +p reject 1-65535 +r UnstableDebbie bmcy4Aw/iRK9yoDPzyPQ0mhqw4s 3cgQd6skq9OL8mQCd2TpoW8Tu+Y 2020-04-20 08:15:06 198.46.248.36 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120 +p reject 1-65535 +r khaua bn29CeCwCw1IkDzbHcx6P3y7QIs wag8qmtLGC8KV4SvSp6nLjSGoho 2020-04-20 08:20:15 217.12.221.196 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=953 +p accept 43,53,79-81,443,531,873,981,8008,8080-8082,8888 +r canary bn/H1AU7ax6KDb2fLHtHDwEEsjk 3BIPlDQOLcW21vimS3DSoxnHPOI 2020-04-20 08:59:53 84.141.145.3 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=289 +p reject 1-65535 +r BraveMenkaure bo5cqbb1Z0Fq2iHpkOd0a8IjsMA PCkTCRZGUeZt8YjMjR4gfzMdviw 2020-04-19 20:25:15 65.49.20.12 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r niftybeaver bpSGbtjKCYus39NtTo4rRZuKc04 +vtjkOptOkI2GuY8a9R8tfoveJM 2020-04-20 03:13:53 185.220.101.131 1131 2131 +a [2a0b:f4c2:1::131]:1131 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43100 +p reject 22,25 +r Elenore2 bpZC3bNT0ESTECnANtHK2DLz39c +1mQ72vjYCeo6z90JzsMLQNCmck 2020-04-20 00:57:10 37.187.105.207 9001 0 +a [2001:41d0:a:39cf::1]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4400 +p reject 1-65535 +r spongebobness bphOL8I4LBKONmhUTIjW8OibH+k iw97xz1o2fOvJdWt57QkgmwkkDA 2020-04-20 08:05:05 89.142.75.60 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3980 +p reject 1-65535 +r X5CXVAGY665MGJW brfx7kSOWigtzOasb3yn704urEw hROixOudodVltoMabMuSCeJI9fQ 2020-04-20 11:18:33 144.217.108.11 443 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6590 +p accept 80,443 +r BLEPTOR1 bs5wO1eBwXjXIL5OJ1XMUy31CUU EZ/PWDOC/mHX1oPkK904ZMaxvyk 2020-04-19 22:10:09 145.239.214.38 9001 9030 +a [2001:41d0:2:8042:0:6::]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r lambda btLTB/Nvnkk9HUZb+3tJVD+/EhQ djYEjqg2WxJm4wLvFjotuGO/bgM 2020-04-20 03:51:43 95.179.203.206 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=88 +p reject 1-65535 +r swlt1 btO+IrImElgBez8FhHBiZZhdeuk UUh0SgtEneWIZc+MlLbs/58U1bA 2020-04-19 21:56:57 212.227.164.108 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74400 +p reject 1-65535 +r KGBumbrella btRFyFRQmFaUFQ+Su3QCUI2GH4Y 8Ub6MjpXvMepQGCmd6ZlVobE58g 2020-04-19 21:18:52 69.112.102.19 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=230 +p reject 1-65535 +r shufflingmadness btviCJe9AqLY1lTQRA/bKjsGQ+E 5/nShohSGqy6eGBeQhE78KEZfdY 2020-04-19 22:27:10 69.172.229.160 22833 2438 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2910 +p reject 1-65535 +r PikPikMikMik bt6zLQue6i6FwxC2etZGaDmEAvs 3i0WfX4OZGuxFo5M0hC3lyLrlP0 2020-04-20 10:27:53 194.67.202.204 443 80 +a [2a02:f680:1:1100::8af2]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5000 +p reject 1-65535 +r Tor1 buG3aFwtQt54l094yOpko07sz7A BmGefV1+DScb0YynN98Qy09/ZPk 2020-04-20 01:07:55 195.24.56.248 40001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r Unnamed bueJoIkt24ko1B9Dn2OeSUBfW7U hF+WP7sUuTNuIBIFH1UYV4WPQNk 2020-04-20 06:37:15 51.79.86.177 9001 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 25,119,135-139,445,1214,4661-4666,6346-6429,6699,6881-6999 +r LANETRelay bueur8JFQr9Ntuck4LSdhd+VFvo Y8wlu63Ygz2O5sqntKUI4tnH10g 2020-04-19 20:33:10 183.96.178.9 9001 9002 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=180 +p reject 1-65535 +r cyndaquil bu+ERr+dQ9p/fYUFvfxJu+ZL+CI iFOPoK/zB2ugv3X2SYAvukXuPaw 2020-04-19 22:58:11 23.129.64.205 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8400 +p accept 1-65535 +r biggie bvVJACc73/yzrHCDxj3q9x93ciw ydVc7LGWNi/rp3dIdTKChgRvETE 2020-04-19 22:29:08 41.77.137.114 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=72 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r VegaIT bveLsTHaM/nSZrxLtZciYeNNvRM XlcPmrz5z2CslFmDeRkmxJRGQVw 2020-04-20 10:32:54 178.239.176.73 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p reject 1-65535 +r d6relay bviXZFt5tss16FOzJQY3UBTeNiE UuFt/79b9+VSIt+CD97ayHzHO9g 2020-04-20 11:41:32 80.127.137.19 443 80 +a [2001:981:47c1:1::6]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1880 +p reject 1-65535 +r dsier bwbjVYbojveL2mmMYqx4HqjYDEo UIkGpF71PBlI21hZ8XJ+WVmgqdU 2020-04-20 04:41:16 158.174.54.8 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21100 +p reject 1-65535 +r snap277 bwlWOm3eo2Vkt8y8RIGYreXxOxg CKsTC3/4n5G09T9+zphvo1WrWO4 2020-04-20 12:25:11 70.21.204.61 36053 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4760 +p reject 1-65535 +r snap277 bws1hhSeu6nLFDmJ7rpBThqN/70 3ht39S/tP4sPG04fsmkl3SnOmWY 2020-04-20 06:32:15 2.152.72.188 45955 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=244 +p reject 1-65535 +r Petibonum bwz/Y5pp8y6UH51RU28xDghyqrc AFmx3K/oGppiio2evFu0WDaPwp8 2020-04-20 02:00:05 92.137.3.58 443 8080 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 +p reject 1-65535 +r leysen bxojFMShre37fUGba7ENe8QBGfY qMwQMYZxZk/xBheMF0Kos6yq40Q 2020-04-20 05:17:58 45.125.166.58 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=520 +p reject 1-65535 +r Unnamed bzerkbSeLuwEZjZxOiT2of6qEr4 ytT7tVSSh/a/aCtAW6Cv5v7WtcY 2020-04-19 19:34:42 167.114.89.193 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed b0nhae9AeuZmeSSDiLHDwgCyro8 K+fDP3N4OeMD0zuwZTyI5eKU9yk 2020-04-20 11:26:00 191.234.162.235 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=260 +p reject 1-65535 +r CalyxInstitute06 b06f0A1CUdmL6W+xqlRv40Z2qVs 7MLEqMTZ2cDPPsmwAaRes5OHgkE 2020-04-20 01:28:25 162.247.74.206 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Otixaava b1QNNb7OvGYaQvl9XwFrPC8mYik sQIDx6EtPT67thtdXbTH+yzDD4M 2020-04-20 10:09:11 37.187.39.53 9091 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16800 +p reject 1-65535 +r Grexit b1uh08Xedh1HQlGd9TntK4myM88 ZzrRio5EPizTlwBSiXWFKxyOcgE 2020-04-20 05:18:08 185.4.132.183 1194 6669 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17000 +p accept 80,443,554,873,1194,1723,1755,3690,5228,8082,8232-8233,8332-8333,11371,19294,50002 +r Vreeken b15ebGVEFXYaJTVInMXVCwG2ymI f2lPbwCRF9jsySGyr3MiFo+TK+4 2020-04-20 00:26:54 44.137.25.56 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=55 +p reject 1-65535 +r torturing b2R4MQNc24kbMxA6BzrrkCgSISk Wk15fDylRKiKikIqkcW77MNkCsg 2020-04-20 03:45:54 51.15.117.50 443 80 +a [2001:bc8:4728:1203::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50400 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r brotherjacob b2WG8WMcrBEVuVYWVudmTThrf0s kjIk8/bHDjdxupNVj/RW5XEZhXM 2020-04-20 12:47:24 46.4.55.177 1723 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=301 +p reject 1-65535 +r kennis b35gLXnRbIcfiYS5hljyyZKPL9k fn3gmpa4yI+oY3vWtpAb11P2Myg 2020-04-20 07:53:47 95.156.95.8 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=989 +p reject 1-65535 +r Unnamed b5AQaTVqeJ8CKU8YpNX+E2gjlwI jcMjm+xX1rJ4Wl+sqd+K92enNfE 2020-04-20 12:28:03 80.85.154.59 9090 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1840 +p reject 1-65535 +r holl b577vQPxqWXFmt1zu6RgB4Ydfyw k9eYc+4cZZbmVARG29rBXf+sVZE 2020-04-20 01:21:30 91.219.28.211 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5040 +p reject 1-65535 +r mj1 b7ILsFqEHN2zCOhaTRF/z8kR9eo MDkCvXFcItiH/B5JMjB+N13eDS0 2020-04-19 20:58:41 93.115.86.9 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17400 +p accept 53,79,88,143,194,220,389,464,543-544,563,636,706,749,853,873,902-904,992-995,1194,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed b7Qe0daPzDmdzoFgDOMDYNz/4mM TpOFIJ2dFWiJFFEXe2Q2JeoPj0g 2020-04-19 23:51:56 62.210.37.82 443 80 +a [2001:bc8:3c96:100::82]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftyleastgerbil b71lwiwplrIDigkL9eVap67e4SA kaqOb9VT48XcLaFD6d/dJ959YLY 2020-04-19 23:16:32 137.74.19.202 80 443 +a [2001:41d0:203:1c74::e5c:10e6]:80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=51900 +p reject 1-65535 +r jubei b8jTsVIFSQZBfLHuBkImV0fH9ok sMT18Ou0EM7ollRou3gilj79Tdw 2020-04-19 20:03:08 141.156.161.112 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6300 +p reject 1-65535 +r S01PIMODELB b+ePP7OWo3hlavLFv2obQ4RSU9w mA50V+bb5jr8ALumTeH37Ld41rs 2020-04-19 23:51:57 217.208.185.99 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=688 +p reject 1-65535 +r atlantis b/RA37HQaXuUI1fXR5AMwwjdV8w xtwCJquJzbDfNc/ANQTQ1nOtOwM 2020-04-20 03:19:31 85.25.43.31 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=94300 +p reject 1-65535 +r OatMeal99 cAkOn4X74ATuv1hGH9bt1b+KUj4 rIavde9PiVuOjIFFg8BlWxFuQKw 2020-04-19 19:08:05 80.66.135.13 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4250 +p reject 1-65535 +r shadowlink cAqb7LNzX02ojxHMfb4ThmUippU tm1xOIxDodfTo5HGNnkbn34vwtg 2020-04-20 09:56:48 209.250.235.197 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=870 +p reject 1-65535 +r smell cAwdo/sM9dNWSdolaqOnUDq4wHo ZOnpLrKnsfSVSzqOjFY/68E3jy0 2020-04-20 01:22:20 205.185.121.212 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5700 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r AkashaShrooms cBDvXR9h7Jy2Vlgjm43aBDnniss uaFp7XX0IGr4lneelJQrxcQz460 2020-04-20 04:40:37 37.187.104.111 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r lostinnetwork96 cB+N+Cfzj4Ia50YKBCQcTLM0u/o IH6Igwr3uGTggctKruZalfVXzho 2020-04-20 07:14:19 192.40.56.233 9001 0 +s Running Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16 +p reject 1-65535 +r L29Ah cESVWk17BM9wAR1ztGexPOXmnUE Fx9yAn5h6jawl2rM2IVzheK4CIc 2020-04-20 03:06:47 94.242.59.47 443 80 +a [2a00:1838:35:100::e928]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4610 +p reject 1-65535 +r LLXnonexit01 cE1jjNZo7RKwG9mZevD+4zMx/wc 2vrpejJmAoqW+irD/xauPkSUke0 2020-04-20 07:04:00 51.158.23.91 8443 8080 +a [2001:bc8:2db9:299::dead:beef]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22100 +p reject 1-65535 +r snap277 cFEwT+UCzOrqWRdxlICAX22q+og vA9tsRr8i1ua8CfjMsoB7mUCTVg 2020-04-20 09:49:39 78.213.247.7 39295 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r rofltor04 cGp2dKIXupBf5nfoIja3uWiiPbc PZjfIg1jQGXQiJLZN0qUWzCgboQ 2020-04-20 08:59:10 83.136.107.114 9001 9030 +a [2a02:29e0:2:6:1:1:7760:bbd6]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p reject 1-65535 +r SSA8MyBZYXduYm94 cGse2a9cyskK1IiuJpGzWPpZjLs NngFyJsdXiYYsoNvMCzO0M3Lwq4 2020-04-19 23:01:06 23.129.64.181 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8420 +p accept 1-65535 +r snap277 cIQzeehviEzRVA3YGkAZ8GO84oY nIbZwF4ivCVoL7FTU+RUjkjqpNc 2020-04-20 02:27:23 121.52.142.74 35917 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=88 +p reject 1-65535 +r Basil cIjUhZNOikA7gVMfjJC9x1+kPJg ipnMI2aYUcGjizzeMqX6KNou0jI 2020-04-20 12:28:32 37.139.8.104 9001 9030 +a [2a03:b0c0:0:1010::24c:1001]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r LittleFoxRahja cIqWjzZE+KVHFWNo/qPbZkEQ5jE pxfl6w25Mf1W9nwhpIHipIS9KZ4 2020-04-20 07:06:55 178.63.72.24 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=148000 +p reject 1-65535 +r FRANCKENSTEIN cIwFUnfWwRgJR0hDonhZCby2Dkw vWHZIIveqX/tetyxIZV65HNcQtE 2020-04-20 00:52:20 185.225.17.151 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5320 +p reject 1-65535 +r SleepJeep3 cJMMz44v/VwPimPI8rwvfM+Lpwo SvtqUqC+whPFGim99sjEqSe74c0 2020-04-20 05:48:54 31.220.2.131 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59000 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed cJT2Om7hoTatmdSD9FVLiIju63g 55goc++lPTdXrdiQjy6E50M0eOw 2020-04-20 10:30:02 128.199.221.35 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=512 +p reject 1-65535 +r Hydra11 cKQ3Ltj13eO6BaF0kbtgMurAJpI 4nmoUQiOx8tqacbC7ITJaoAruMU 2020-04-20 10:33:29 89.34.27.43 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p accept 53,80,443,1194 +r CalyxInstitute21 cKygfZJ2J3uC6QnBQ54ZzKL7Fsw amF4o3J0k5WhagxkG0RYdhoSAT8 2020-04-20 03:42:34 185.220.103.9 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Hostbank cK/uVE9agMLCnT8K6THuq4HB4yU p9heDAFJ8GLVe+09TGc8ebYCO6Q 2020-04-20 08:12:24 66.70.212.3 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r torpidsFRplusserver cMVaEUwO89xXhKT67mQ4hDSjOY8 fe6hcj7usBO3MNAXEHmDqoM2rJQ 2020-04-20 00:29:05 188.138.88.42 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9020 +p reject 1-65535 +r Magic cOP7MVdWVq1nUTJXGkkYEPXzvRI 1a0Umo/uPe5grgAB93XPVY6sKr0 2020-04-19 23:31:05 131.255.4.188 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=98 +p accept 20-23,43,53,79-81,88,110,143,194,220,443,464,531,543-544,554,563,636,706,749,853,873,981,991-992,994,1194,1220,1293,1500,1533,1677,1723,1755,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19638,50002,64738 +r nha cPCemB1tSjSjXySPDIc8ujVqBhI Y/vp6TTOHEGJdc958Q591+iPjBM 2020-04-20 03:07:39 81.17.17.130 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r 92022ff27ab6 cQB0Hs8hnLdKzhnx3vqOmotEKvo CYKZRexYW8MV/uAtG69Kbjptsh8 2020-04-20 08:13:17 51.81.254.23 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r hviv122 cQJrmZ4V7MC8yla5cuIQzKdq2Wo 6Bhz0nNLSFoNQ/vyjlnpNYnZlnk 2020-04-20 07:40:27 192.42.116.22 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r snap277 cRn5iJMVS8o/fmjTF1WwJt6BzOw xi/hVqdO6GMihEQjfJgQSEXHgOA 2020-04-20 06:59:45 92.189.126.95 45675 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1840 +p reject 1-65535 +r hamburgo cSsKrbG3jVQBF8BViqK7Iq6gP7I htEcJG6m4Baw7pKbKSnzNJ5kQBc 2020-04-20 00:20:12 95.116.154.78 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28 +p reject 1-65535 +r snap277 cTB2IFio0sPTic/8EZhfJK3LwOU s5UxPCZC2wH4cHVtjRfLG4075yc 2020-04-20 06:11:32 90.41.238.233 43807 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8 +p reject 1-65535 +r Goetze cTUultitIi4Dr0BMoO1qKsBW99g SpeZbMnGgaTyfQUagxBywZw4JrY 2020-04-20 02:21:17 136.243.247.88 443 80 +a [2a01:4f8:211:115a::188:2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35100 +p reject 1-65535 +r vps603203 cUGLailM3EjpqdsNqZ4Xi1Wv90o oM+T2YhbHSyCqENI5kMXSxLxYbw 2020-04-19 21:52:11 51.75.125.241 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=990 +p reject 1-65535 +r mullbinde9 cUQlQY7u36zIbYdUSyZYkumPoys lbH2W2hS8prIEk/Ifu9AaWZkNe8 2020-04-19 18:54:10 109.238.11.114 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3770 +p reject 1-65535 +r AnonKorea01 cUXjJHzeF5f95aGgR2zYoAAAg10 OKeiv55EEvbyliURK02UwGITZ5M 2020-04-20 08:06:37 52.231.11.34 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=186 +p reject 1-65535 +r rs cUbLs/+wQcRGOnr2gjhObGMXHqE 8Srde9Q2cHlWT3udcA7XCKM7FNw 2020-04-19 20:33:46 91.90.193.8 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=979 +p reject 1-65535 +r hereIsANode cUcktdchWLNqwUcnDVsK6RX8H+k KrU3nGQC8OQ4jUw8qN+BOqlIs08 2020-04-19 23:16:31 75.164.208.199 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3500 +p reject 1-65535 +r Fission05 cVOdGRHsuCYGmk0VZ3GsT59GMqc JgxtWsnykjywy1qlMb0V097CbU8 2020-04-20 09:25:22 37.59.76.252 443 80 +a [2001:470:c91a::4]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33400 +p reject 1-65535 +r maltimore cVjR4Nn5D3mZrLOwc9p2LJssMnU KEAhEWlTykZIF/0R3C46IRLhjXM 2020-04-20 04:19:58 207.180.224.17 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16200 +p accept 6660-6667 +r Air7jyl cW7pKi6T7WkRPY+B6YUwupow3DE nJ3rKFobQeW2zGA0epYv2MJqE5E 2020-04-20 08:27:20 95.154.24.73 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r niftyentry79 cXMPG+tTcsmm/zZwT/GmpIrueBM h2Te4PWyK+FHJE/HZkT1gulnMWg 2020-04-20 10:51:25 185.220.101.219 10079 20079 +a [2a0b:f4c2:2::219]:10079 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r Apollo cYQPRcJHg0e4cjIQZvmAXRobef0 k62Gf9wkUETuVZjiQILoZb2gN8g 2020-04-19 21:38:23 162.213.3.221 443 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4760 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r FalkensteinTor03 cYW2njJn5x0OTL4wIJZ3IF3qXmc VfgNnm8i+ZOwdhCCCKDcX6N39L4 2020-04-19 19:22:18 144.76.236.14 9001 0 +a [2a01:4f8:201:120d::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=50000 +p reject 1-65535 +r Mahesha cYl9QRZnf0hb523i5e6SURb9d2w 7QtvDesmfQAABv8QC1behfxHjIs 2020-04-20 01:11:45 51.158.152.30 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17700 +p reject 1-65535 +r F3Netze cZ/Q+jJ/PMvNoNTqdMFeoRAziUI +4IgwHxM6AocBAe2+OC+wfVcCvM 2020-04-20 01:30:52 185.220.100.252 9000 9001 +a [2a0b:f4c0:16c:4::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=97000 +p reject 25 +r niftycottontail catHJtgw+ud210rveQzwTY4BUbQ BhS6oQBEnbY+IiAayUH+W7uW3LA 2020-04-19 22:15:29 185.220.101.138 1138 2138 +a [2a0b:f4c2:1::138]:1138 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54000 +p reject 22,25 +r NeelTorExitC cax8Vp6yyVa91bPU7Moeyhvqaao q90w6YeyBlHD34yZuZt6VE6eAp4 2020-04-19 22:36:27 51.89.226.199 143 110 +a [2001:41d0:801:1000::db2]:143 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 53,80,443,8080 +r Unnamed cbXwsyUl16ZQlD0JaIkMFtcsMIc L0rOywOy4GcyHkc0uWAFt3GBBUM 2020-04-20 04:53:25 116.203.104.192 443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15 +p reject 1-65535 +r DailyStormerSupport ccWMTu6pV2dAB/VsbK8Mu6H2tT0 2BYxaOt8fiv0QmrgyA6Zb1W/YXk 2020-04-19 23:26:05 14.99.38.109 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1630 +p accept 22,80,443,6660-6667 +r merula ccfSrFwDRq43V/482zg2l2uF6Ww +7CuQhTPce+PlIYZHiXIdoj9cYs 2020-04-20 09:56:01 187.247.234.93 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r Unnamed cckkp3L2lFH+l/5akCXe3e89tmQ J5nkfwgBAc8MEEgj49yaKvGrbUI 2020-04-20 10:51:57 24.49.67.120 9001 9030 +a [2001:470:8a85::42]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3520 +p reject 1-65535 +r nodebyCyper ccoKjDQ1v0jR+5ZCQO/AeWNtvl0 7NioxtLW5fcPSPh8PV9L0lq9irY 2020-04-20 05:18:05 78.46.162.123 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p reject 1-65535 +r niftypedetidae cc/etNngDMw+MexOiinhCbvB+zY YcqmCynrwv2fPnpxIkV8F6LEwRU 2020-04-19 20:27:43 185.220.101.14 10014 20014 +a [2a0b:f4c2::14]:10014 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47800 +p reject 22,25 +r nionyn cdFbSn3Z+3Cw4UOffTULj6zPwwY XCDXwe6ia3atwOsCoGyvlVe+XC4 2020-04-20 10:33:40 95.216.192.22 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r FreeHK cdMJXBzegsS9ohsaTmN9Zuwd0zw kadDE4ipZmhPlZuKVU4Qf3rEWPg 2020-04-20 09:43:57 73.193.43.25 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=270 +p reject 1-65535 +r formica1 cdQWPTY+g60E8v9SWU0knitbpLI BknncX/UG67rRqRV37q80Gc3K8Y 2020-04-19 21:23:04 147.139.139.154 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=282 +p reject 1-65535 +r ULayerEllsberg cd+BdNgJ2GJEW/y4n1oJgAmZR+w BfyK9kiea0xkcXYCvi+KvdgkHpo 2020-04-20 04:19:11 198.98.60.13 443 80 +a [2605:6400:10:2b1:44b9:6ec1:8ede:4dad]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8800 +p reject 1-65535 +r Unnamed ceNqIpcXXMbV37+HOVB09EKlkU8 JEz1ubyMIY4Zdv+JzVWVCF7uEtY 2020-04-20 02:38:46 52.156.128.64 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3490 +p reject 1-65535 +r Cosworth01 ce/kMUZGxGE4lVCXI7/TVNjqvK8 lmL1T4Gek4ZrlJtYQqVxKgPqZEw 2020-04-20 10:27:22 51.68.140.94 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12200 +p reject 1-65535 +r greenoak4 cfi5WMxfglwV8BsGki0LyyzujhA DG83HRZHHR04n8sqAEBr393ZQoc 2020-04-20 03:46:58 81.217.225.96 443 8080 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2450 +p reject 1-65535 +r Unnamed chxQ2FsTvcZPujy+0AiAIBdIV1E l8R8OlEN0dpBxS/Z0yAHklCKs24 2020-04-20 10:12:01 88.74.144.209 9002 0 +s Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p reject 1-65535 +r desync ch5JSw4GVU2Pmhab2/FygsB7JYg Ell1danOKcbcA0p0CpK4H8v6DxU 2020-04-19 23:35:40 66.230.230.230 443 80 +a [2607:f178:0:3::2]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 25 +r niftyentry103 cia+CbeoEAC799lZ42Cy/kHMxjk myADSXZeYvMaNAdqQSS/FURO+Mc 2020-04-19 20:25:41 185.220.101.103 10103 20103 +a [2a0b:f4c2::103]:10103 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16800 +p reject 1-65535 +r giesskanne cicOtY7evnJ6op5nQXYo286In64 AfKEom1T01DLXO2jZ+iVPotZrzQ 2020-04-20 05:32:48 95.216.146.117 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7740 +p reject 1-65535 +r Unnamed cidU1Y5VHEPR9u8Mojrn/Pz0RB4 LVw+Nw+zGbogeqs87ppo35OV+ok 2020-04-20 11:06:56 49.12.78.122 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=35700 +p reject 1-65535 +r Unnamed cipCOP/VR7mbmb1LlpeG6CKR+WQ o4RRRurCFJauHH6OkaC6OpaJQ1s 2020-04-19 20:08:20 167.114.89.194 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6610 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r BraveTeotihuacan cj4h/W+RkF6E5YPUYZotHigrgYA fRIN2OPoFWQTzPnbS145sAAWgXY 2020-04-20 12:26:15 65.49.20.12 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r ToeClipper703 cj6bKd8DV+GbLRyGuGoBZTNb+qk 4TyU+K9dsBn85+h8OQXYhM2r7Y0 2020-04-20 12:09:44 193.22.133.92 9090 9091 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6460 +p reject 1-65535 +r Unnamed ckEaLObrJNjNqGiKazpVzBKQ1EE u0aEbxUhDdGVwjP0NlFPQxFAdU0 2020-04-19 23:59:58 5.146.220.20 9998 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120 +p reject 1-65535 +r besttorrelay ck6G5/XacVUp3A7KoBOuS9xoDkw yyNo+axs5tV5VDRxoO/9POoKln4 2020-04-20 12:31:21 5.9.29.183 9002 4080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84900 +p reject 1-65535 +r snap277 clEDL5QXwCa8dZVgH4tzd3EnW2Q OK1U0NdnzJ2rPY1SQ8WWKZz3K1I 2020-04-20 10:13:50 86.245.84.124 46569 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5380 +p reject 1-65535 +r w2jul19 clIt0oBnz8nPTz6EyWpXQ8bpmHA NN4ntYHKcuGwJO/jSUB72uKsgmU 2020-04-20 00:24:31 81.170.155.6 33333 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=510 +p reject 1-65535 +r Segezhye clOXEYtERbZM+o6lB8/j3oEAW0Q t4VW2+rQfxvBTK+upcMJLCfR1U0 2020-04-20 01:29:49 157.245.86.215 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=1970 +p reject 1-65535 +r ANormalDay clvbOHUquGzJ8gSsmFfCkwa74tY 49rASnN5UTKNAqVf6gKw1auq4fE 2020-04-20 08:20:20 81.90.180.161 443 80 +a [2a00:ab00:1103:7::9]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1770 +p reject 1-65535 +r Unnamed clzlZuBjEqXgkddx6Z8mH43E0OY WYOVCPyjl/9/BrA/jzJynY6RhOM 2020-04-20 09:37:08 13.88.182.24 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4300 +p reject 1-65535 +r SkynetRenegade cmK50u3gtqJmxLQ9YgIgm/a7qIg NOkWsBoW53vfBRlizuuexa5f9eI 2020-04-20 05:29:58 78.156.110.135 9092 9093 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r torexitrendrag cmV7lr+Zso+9nysDalkKqKRTVCI XavvgbhjdPu4yCXvuOhJ4vLO430 2020-04-20 05:03:18 221.121.153.184 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=192 +p reject 1-65535 +r snap277 cmddOoepwQ+tMRO7gY8E7f0fAeU 3KfCGX6xdTZHA0i6kYQxlq/BLQA 2020-04-20 09:23:16 5.252.173.253 42073 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2620 +p reject 1-65535 +r xXxOnionKittenxXx cnL6J6f5nojVm+IBjj8U+4i/l4Y z9q10/2Frn6NEhrzI7NLWKzma8c 2020-04-20 03:06:31 46.38.255.165 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r chieftain cnSaU46ayhMRSzjS5t3Gr94YWbU o8nO2d+f87/0h4m3ZfI22CiW5do 2020-04-20 00:49:48 54.80.24.96 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64 +p reject 1-65535 +r Unnamed cnqgxjD19Ui7SPNgafIXlJZoKHU U5exKEiiicbb4FBRJogx0v8j+bY 2020-04-20 04:42:40 51.75.144.43 443 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=134000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r semechki cpLvWHQsx5P3qzhG2HABF4Mo+aI WJM1EHNWC4mQlmOIaJNO032aWmI 2020-04-20 06:39:19 193.218.118.140 9001 9030 +a [2a0f:e586:f:1e00::3]:9001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4350 +p accept 1-65535 +r Unnamed cprWWVnlmz1tcWDWW2tm27zkChk fuEjMRciFqBhaR7Q2TcrC2HO++Q 2020-04-20 09:55:34 104.211.166.22 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=511 +p reject 1-65535 +r zai3Pheevoa4oiWooz1 cp2qCfHiJduq8vQvPIL9O7561d4 36DHdRZ4j+mSRZi9VHAO5p8XwRQ 2020-04-20 06:57:07 93.184.27.3 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4570 +p reject 1-65535 +r Zimmer42019 cqG1HZn6mYweyvNvWCJ/TfMI+DU NDzy0EZDKaclmzKoUcaqDbc2Fps 2020-04-20 03:25:02 178.17.174.229 9001 80 +a [2a00:1dc0:caff:159::4d79]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4010 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Byte01 cqiLo6RbYH5HXO6BzpctSED04HU 0rp4+vzXRkbFYhFRpVnmF/gEpPI 2020-04-20 01:35:29 167.86.114.102 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19500 +p reject 1-65535 +r Unnamed cq6bgG4QiT9tadspoCGDpc9z/0k CW8BRvtGKuTlgIsZXqt1IU09ab8 2020-04-20 11:12:23 51.254.87.75 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r xoFelix cq7JitLczhUQbwfzXRsNAqFTBSE H0G0oyevXALOkVte6ZwPo9ca034 2020-04-20 03:21:00 2.200.23.141 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2900 +p reject 1-65535 +r TykRelay01 crKxKj9gQIvbyYxt9TmI06Cz8O4 rchAWsMBZaY5RNv3pV/QNQqWUqw 2020-04-20 08:37:19 85.235.250.88 443 80 +a [2a01:3a0:1:1900:85:235:250:88]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p reject 1-65535 +r katharina cs9USSyi9X8SuEk5Rsm/kTLrCro VDzj/RHcihkz5zrRFdcmAyv0tiI 2020-04-20 03:58:23 45.125.65.45 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3560 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,5222-5223,5228,5900,6660-6669,6679,6697,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r guisseppi cvhfFQd3Zl4UWWO4hfxPTKZDS14 NmjMG83XwzZDCPvSTXxZc1C4too 2020-04-20 05:39:11 91.228.53.86 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=940 +p reject 1-65535 +r Ozigbo cwENnFozDH0+ZQV+iLhxxNXSM9U kZXhRP+n6ESZs3LhdMgokZaFuUY 2020-04-20 03:18:26 202.165.228.161 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=309 +p accept 53,79-81,88,443,464,531,543-544,554,563,706,749,853,902-904,981,991-992,994,1194,2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,5900,6660-6669,6679,6697,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999 +r ilikepoop cyAAGIMLhtMYLtBbRK11vanOU7E fO3iPVkMD5uDfU3/hU9cpAlyHO8 2020-04-20 02:16:03 81.34.17.240 9001 9003 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 1-65535 +r F3Netze cyeHauecmX3+MRp7FbT6h1c2u9E K9+pxsVz6hs66nj78pEsN7s8qtE 2020-04-20 06:33:52 185.220.100.255 9100 9101 +a [2a0b:f4c0:16c:1::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=102000 +p reject 25 +r angeltest29 cyg8TevAHT5KX9G7HytQ2Sc3n1k VuEY/lAVhQbsfNFJ857yk15HF3c 2020-04-19 19:26:10 87.106.152.102 443 9030 +a [2001:8d8:1801:8086::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2400 +p reject 1-65535 +r MoldEraTor czKgawDWr1SqgE8DxiTfu8nmYXI sw2DONAp/OBVt+EBh5pgbK6MiBs 2020-04-20 02:15:39 178.17.173.26 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4250 +p reject 1-65535 +r torlesnet1 c07dwsBLHAGEF4Fnq9I66FQTIS8 0ysdj2XhW3j+TrGh9BdLPETo1OM 2020-04-20 10:23:53 199.87.154.255 9001 9030 +a [2605:e200:d111:1:225:90ff:fe24:3f9e]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r hacktheplanet c1WkogukwIPJIUZDAhCMEhusfvI vydH+cvCMjHlYo0Wr5cGNztwjGY 2020-04-20 00:00:00 116.203.61.45 9001 0 +s Fast Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=55300 +p reject 1-65535 +r marisa c1Z4qNPeIwXXvEVX5MzPu2hvYzk 3SqJTlbQsUQwkKVQLFtQkhYrB5c 2020-04-20 03:10:50 188.134.71.147 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11900 +p reject 1-65535 +r beneficentsoot c3E1GOi9cRDQxthPBoLB4LdUH3k manQvIRsmfL6RoVv5rSQK+czr2c 2020-04-19 22:59:07 116.203.149.9 9001 0 +a [2a01:4f8:c2c:3a88::1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r 9eec30762e3e c3aJJaW1YdfcvoOtGjMqBJDScyc EpqdezDdLs78bBfOehuT2ytaDUI 2020-04-20 08:50:56 51.81.254.16 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r king c4MNE1j4EuHtSWZ01q4H8rdgdhY 4pWspG3ngSFl/6nSXUXJXfi3f4g 2020-04-20 05:29:32 51.89.213.80 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r terratorserver c5E1YlIVR7pZ7re5yKlQaSlI09U Di4g2lyPmZ2WrwQ10FAbX5Q3Dtg 2020-04-20 11:17:37 78.43.12.83 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1430 +p reject 1-65535 +r Freebird33 c6WoFoi9U2v7q+GGMPW9YwbJrI4 88m5kGPnouu2ifP74B2IzRrPPY0 2020-04-20 02:13:39 5.44.101.190 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r torcow c6YrWQzE8pDQaPogoS1kCKDYtgw sq2hKc+w/H4GsXQLr1qXoOlQqdk 2020-04-20 02:06:15 174.89.81.140 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21600 +p reject 1-65535 +r Babaorum c7HT7fC9a6Y4IM78T9fZ/vrVE9c R8cl1NRSOruPthZSpQnX34pD6cQ 2020-04-20 04:03:33 92.137.3.58 9001 880 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r icytorr c8W0gHezet+L/d2sAB5xfpyNl8M dBvNJOHPe3eq8nNeRbh8tzTwM10 2020-04-19 19:35:34 185.112.146.80 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37 +p reject 1-65535 +r ehtejab c8xlIZiJRDwG4GoLbUJ7H+HDc3k dNjqs/i7xokYvbl3wqG7uO3zcNE 2020-04-20 02:03:05 193.42.156.106 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6980 +p reject 1-65535 +r notem2 c9ylZCSRL2nxR41mMN8nz+j0FDk oiC9ymzKT3blE3ZIeDoXt7mZagw 2020-04-20 01:00:26 129.21.187.10 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20200 +p reject 1-65535 +r negatoraligator c+Dq18Kp6WA8DbfuR0PM75NerD0 HcMnGpK+dwUDXq+ZI0IcZGVQoEk 2020-04-20 07:11:47 81.7.11.253 443 80 +a [2a02:180:2:4e::c0de:f001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p reject 1-65535 +r Torild c+IEah5/DpXTbD+XnOX6w2CaxhA p29XL7J/HRBI7njaXb1uEx5VKzs 2020-04-20 01:55:31 207.180.198.88 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p accept 8332-8333,30303 +r n4lksask972137tor c+ilWxWP51Cq9xG0AtNwLj/Dle4 wscneacVW+ze9KwLK+kMiUbYO3I 2020-04-19 19:41:48 62.168.3.212 9999 9998 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=440 +p reject 1-65535 +r pkswitchtorronto c/a/ReFMcsR7iz01aPb/GVuWehU NaPeQNySCEeq55hNGUYuNb/8l9U 2020-04-20 04:01:11 159.203.27.5 2568 1403 +a [2604:a880:cad:d0::4f:4009]:5201 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2 +p reject 1-65535 +r kraksrvr c/gReKwp+00p8tEUuHe++VwGcrw SpDtdLStRiPrCg6NaQNcIIbAB+M 2020-04-20 07:03:24 172.73.49.125 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=500 +p reject 1-65535 +r bbtrotro c/ie8u4PXFQGSsUr6cERNJzZ6MQ 8bXqg26sFe6esJe2d9PUr1B7ivY 2020-04-20 03:02:32 62.210.251.97 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=23300 +p reject 1-65535 +r ididnteditheconfig c/wLIi+Eh/Xv/jl7Jq85UP07nto KrLD8I+XJerSZIxr8Alf8tfIebA 2020-04-19 21:26:31 31.146.31.130 443 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24 +p reject 1-65535 +r niftyguard21 dATcTmsX1bdRvzQ+UJ9tS5QPwQQ Zhg9Vh0Cv0ZUklci5Rj27GDKrAg 2020-04-20 12:47:06 185.220.101.230 1230 2230 +a [2a0b:f4c2:2::230]:1230 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20200 +p accept 80,443 +r kbeb6vqsa93r dAbZZyL7/h2bGrQyu71wXYHKdzg F9wPFFhS9LCCOADOTO5EbSeirT8 2020-04-19 18:57:08 80.143.25.240 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=836 +p reject 1-65535 +r Unnamed dA5MSELkwZDf7CeOwf11T9JhqGQ xF+QtmSAy9d+zTMg9GSI9bUFuA0 2020-04-20 02:18:42 46.9.195.72 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3700 +p reject 1-65535 +r effiorgoulu dCCRSG0Ec0xX2XvO+1PSLtC3eIE L+GJ0XkVmS8O2pG/M3czgfB67u4 2020-04-20 01:46:24 185.67.82.114 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r handsomecurtain dCJItUkgmVSkS2eZpGHl8jkJqU8 CsUwO4AFFXvAP8PTdQGk5y3o/o0 2020-04-20 10:11:44 45.76.5.24 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=2960 +p reject 1-65535 +r TorExitMoldova2 dCxF8tkASq3gB35SikQYpqgbwro ACUrEgzmw+xnh3Qzn+PPZ9frDT4 2020-04-20 01:08:25 178.17.170.23 9001 9030 +a [2a00:1dc0:caff:7d::8254]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6540 +p reject 22,25,135-139,445,465,563,587,1214,4661-4666,6346-6429,6699,6881-6999 +r hviv126 dDD2axyry1LVg8nDA17hmj6Hoj4 BOcjTSWmc171tkoDYa/0UVG5GAU 2020-04-20 10:40:38 192.42.116.26 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r g00dplain dDEu9XbeHncQ1UIHkea9tBgIQ54 C44E+FGt/RRleet1VHDVeb/XTqs 2020-04-20 06:02:26 37.187.113.218 9001 9030 +a [2001:41d0:a:66da::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p reject 1-65535 +r CharlottenburgerTOR dEvuvgYDtmlDHiW6bNKFMcU3Ph4 PWlCkPIiWQAlWCivnvq726a7M3U 2020-04-20 01:26:28 85.212.112.87 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=472 +p reject 1-65535 +r shalazarthewizard dFBI9RqDT6kVL2ICFZPyzWLDGro gNlwXsG4pg0RKv6T2S/CjYkWQhk 2020-04-20 01:12:00 23.239.22.248 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=530 +p reject 25,119,135-139,445,465,587,1214,4661-4666,6346-6429,6699,6881-6999 +r Unnamed dFLn0ZrNLDneEMAgcDLmvAXbePI fYbwMPQ6oJXVQiUnc514GORxOKQ 2020-04-20 06:48:13 46.29.248.238 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r theia5 dFNpMydJAhxvrxANMnvDvx30cHs WnBy7SRNi1GZwoh/UG2z8e4AY/c 2020-04-19 22:57:55 50.7.74.173 9001 9030 +a [2001:49f0:d002:2::55]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4600 +p reject 1-65535 +r pizzapie dGs8S63MoJAD3Qka8ChWCmHgpI4 XshfT77LfiYU+6cLhXEUMs1TSO4 2020-04-20 10:15:01 185.244.148.237 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r DIEPARTEIistsehrgut dIdqSWLhtFAWrVn1lHD4zSrRXXM 7adtP3hXbgGMD63Cs1EsyxIFcVo 2020-04-20 05:12:26 79.237.161.212 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=604 +p reject 1-65535 +r niftyguard28 dI6tDR4D/g+vWKgMde8v2f0Lj5w kw2ZRrmWwoKrrS+CL+txyvaisqU 2020-04-20 12:46:22 185.220.101.237 1237 2237 +a [2a0b:f4c2:2::237]:1237 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p reject 1-65535 +r s2chrgrde dJTLa1yCcluvtsEITcChvnZZG1E 6EizLxVW+yJFQHnQlNHVqhr9S64 2020-04-19 20:39:55 173.212.192.162 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6980 +p reject 1-65535 +r avksenyovsk dJnBIfTp4PATVxvTNMdvCrY2G4c V9XpRp370fi2LNj32CF0vSOjUC0 2020-04-20 04:32:46 45.32.29.195 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=137 +p reject 1-65535 +r ExitNinja dJ70pDTf0A2rMek96GIz+5FtMeM o8r62n9jxXpivp9y/3NtO4WGY+8 2020-04-19 20:25:05 46.165.245.154 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=134000 +p reject 22,25,109-110,119,143,465,563,587,2710,6881-6889,6969-6970,55000 +r Unnamed dKGdht32PxEztBS4Hzbh9EZAgR8 NVXqpZimByIaNpwmBx3K275SK4M 2020-04-20 12:06:58 62.210.105.116 443 80 +a [2001:bc8:3c96:200::74]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Crows dKVeEvap/RcWWjVsAEB/TSBug2g H5nudllLDZoNUPEjp3N7faxGsB4 2020-04-19 21:17:42 178.62.86.206 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22700 +p reject 1-65535 +r longclaw dKkQZGvO77zS6HT8HcmXQw+WgUU DK2nJFSa7urQ8NPsUXvuSBk/TQg 2020-04-19 20:51:37 199.58.81.140 443 80 +s Authority Running Stable V2Dir Valid +v Tor 0.4.2.6-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r collapse dKmThbbslgNAnKhM2j2B0ksFTA0 bduyhO7L8eYZJOhlOKaOLDEPyIM 2020-04-20 10:53:56 188.138.72.10 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r NineX dKwQypTkALpNaeOXViWXygT8U1I /bn75V/54Ee9HGXEoBAWi/VA/mg 2020-04-20 09:40:43 185.233.25.162 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r godse dLQd7VBc+rx6jUOTYvybZYneRZE wYk96ePQh3DbEdQlAzHngVJWBqY 2020-04-20 02:58:52 91.132.60.9 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20700 +p reject 1-65535 +r tiflin dLiyKvlQsL4R2KIo+wnS9Seft1c hO6bv/AZX+3ZWtP1MSeXnBvQZQE 2020-04-20 03:57:38 163.172.21.117 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=52100 +p reject 1-65535 +r sabotage dMDCcF2xGSwD8Z980bsjSEOxqB8 ArQvegqSw4dklo4ek0aeFj9OVhY 2020-04-19 21:33:23 45.66.35.35 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9280 +p accept 80,443 +r czrpYOL8Pp dMoW9Gh6jWGbCBbFIbBeTz82URM SGflobjkSDRNlV8kyRBsDs9i0X0 2020-04-19 22:44:40 78.43.152.56 9001 0 +a [2a02:8071:41a2:b300:e77a:2cd3:9de9:5d4e]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61 +p reject 1-65535 +r NimbusReaper dM1OpqunWxptfCIthWeqtgpumUw Fle/TgUxi9JmDwKdyy31pEsad6w 2020-04-19 21:47:55 139.162.96.82 9001 9030 +a [2400:8902:e002:200::c0f:c0f]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=370 +p reject 1-65535 +r Sifon dPIylnTyfLgWmjKkHZcWKWI7dTU 9R2VFTb0GfANupkFbois4odnywA 2020-04-20 06:35:46 95.27.246.252 1485 1490 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1120 +p reject 1-65535 +r SebnemKorurFincanci dPt3fyXn+Aumv4uAjfhzoXCIIac n7wPghgi34H/VcYwM/43yH4ytB4 2020-04-20 08:25:26 144.217.60.211 444 81 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6920 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 dQkTRsB3/jRSKw8IScgRRWu3o3U lGqRM3VsYjZ90BFZ/KYzS52N16A 2020-04-20 12:00:04 109.242.200.47 35491 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r Basalt dQmvh6DI1qt/ewP9TmUG9VlRob4 1DfYWnlSFg9Y/QJH7sixYZh6dAM 2020-04-19 21:31:40 185.166.220.41 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56 +p reject 1-65535 +r GoingNowhere dRV90LmtL2kOraY6dMX+DK9eD+g vMNkEwgNPQHZFGz8ZdUEnyUjj8E 2020-04-20 08:23:32 69.164.210.142 9001 0 +s Running Stable Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=41 +p reject 1-65535 +r Unnamed dSWOdVBkqiQSvGuriFdWoyAfjHM g1lt5YqDZZ6VuqApQpRYVSAcQc0 2020-04-20 07:41:43 108.161.133.189 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=653 +p reject 1-65535 +r snap277 dTLhhR3izamXINpGUV5TPSoYTG8 H2rObYw+nnKw84t+FDdjZNKQQhE 2020-04-20 03:10:20 92.9.151.237 33707 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r FissionMasq04 dTOr2pAn9Az4f7YYmuux9DoTKgs CMfQJrXECdH3JMYBaKi8P1+wDeA 2020-04-20 05:27:01 193.32.126.160 10750 20753 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r benefactor dUy5kRfm7VcN/Pt9nxJnS5ek4o4 NslyaohKh4bFr4WxUpKbZoHQB8E 2020-04-19 20:56:03 90.94.83.26 3690 8888 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22900 +p accept 23,43,53,79,88,110,123,143,220,389,543-544,636,749,873,992-995,1194,3690,5900,8332-8333,9418,11371,12350,23456,33033 +r nodeXY dVnUvOiF80lPd8DzoN0/Jfaw6qU wN7F9+f09HslRRs9iSy393ZRZzY 2020-04-20 08:39:53 213.202.232.19 8550 8050 +a [2001:4ba0:ffa6:12f:213:202:232:19]:8555 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19500 +p reject 1-65535 +r spookybird dWw0u9x3FqX+g4UH2LX9HPJPMDs TGxCZVo0AYemESRhxiQbAVRe3jg 2020-04-20 00:00:00 167.172.237.203 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=960 +p reject 1-65535 +r snap277 dXGzuNo/tzDw3IyJfD5+vL6LsbU Dh4XGJwheLZKD4GaFzV5WD/EGh0 2020-04-20 07:06:41 92.247.119.34 44881 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4880 +p reject 1-65535 +r smurfix dXSXW6dt4HJiMfyRbdcLCbOCTOU uz9lJiIlINeXbPBgdDdOUTIrJfU 2020-04-20 04:06:34 213.95.149.22 9001 0 +a [2001:780:107:b::85]:9001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=868 +p reject 22,25,119,135-139,194,445,465,563,587,994,1214,4661-4666,6346-6429,6657,6660-6670,6697,6699,6881-7005,7070,8000-8004,9000-9001,9998-9999 +r w000000h000002 dXePguBlcxiUKdVT69i9PO2Al8Y ADIMwnuwsZjaXs8J356nxgA++aw 2020-04-19 20:14:14 38.68.37.77 443 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1250 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6660-6669,6699,6881-7000,49002-60632 +r TORxyz dXhN0ry3DOE87JPP4kzWnGbixns u24eCN2vvpTZe41wHLj5HizUNf4 2020-04-20 10:48:10 198.245.50.175 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p reject 1-65535 +r chickenlegs dYFJ3PVYoeMUGbd4kLZbok8QTNw WR1oqaEZ5tNNGLFiwV+DxJv4c1A 2020-04-20 06:31:14 106.51.33.217 9099 9100 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=269 +p reject 1-65535 +r losangetor dYJwuQMV/NCkHgWVBN0PGHfISNY QtYjW1hgubGUdSBKZ5KzhSFHbmo 2020-04-20 10:13:09 82.65.29.121 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r gapcoinclub1 dYQxnQ4Z2uhWISI+KiL5ISPquBU E53Ulfv4raSqY+rEWa3t7djan+c 2020-04-20 09:34:11 172.104.85.43 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=366 +p reject 1-65535 +r TorHammerTut dYcjMUCTgYPmpFFMYKXhOgvtbDs 6LspLuJA4jixAnjt78EhcNO+Jgc 2020-04-20 10:08:44 173.208.179.155 9002 0 +a [2604:4300:a:258::2001]:9003 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9100 +p reject 1-65535 +r StrictlyUselessPi dYeaYH22Ya4u6OJw+8vKZq33TnM eAEjWydI3/1J40DNckdCXvl53mI 2020-04-20 02:06:03 92.249.143.119 9005 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5 +p reject 1-65535 +r Unnamed dZfTlUCXlrql1tzDBameyz+PIvc fo4h6QMc0wj5R7xK+mf3zY0x+oY 2020-04-19 20:32:04 20.36.45.94 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=317 +p reject 1-65535 +r PNTURelay daQpXt1S3YoKN+o0VB8vTEgCpNc t7SQDL8RiFC5FlKCUxpPA52SWWU 2020-04-20 08:22:56 139.59.213.101 9001 9030 +s Exit Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 25,119,135-139,445,1214,4661-4666,6346-6429,6699,6881-6999 +r wsod42 daZB/PW2Rs2EkK3SkZUYkbYvpXg 6LtCSoaTiT4tE8nHoCuQdld6gjU 2020-04-19 21:18:27 185.95.29.165 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3230 +p reject 1-65535 +r Tiberius dakxQERTAwghxUek+qkJSgbEjHo 8xt4C049hKmhybECv2OnzquduG4 2020-04-19 19:18:33 46.101.183.160 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23500 +p reject 1-65535 +r snap277 db9VOXRQOGF1e2zWyYHuRF+GLn0 BKzSzb91eq5gvF/TSvEx9xGXu7M 2020-04-19 21:28:07 203.221.85.204 43241 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=54 +p reject 1-65535 +r hrck dc8PZv4YwxFqq3tniJkVHbdit5U cGhEpdoL5HB8kalXrd9c0hzBr4g 2020-04-19 22:48:06 138.197.150.159 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=535 +p reject 1-65535 +r deceptiveSimplicity de40MM73dE6h41YHiBsnWB6xWIA FdGM8/AeAQemIQ8dSzHlnf36qUc 2020-04-20 04:48:56 217.237.112.149 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8900 +p reject 1-65535 +r NervousEnergy dfuaRGkZnyUVgQYTkSFKz9xoLvQ Bmj5r9XNGRPC4S3G0S56SE5ve1c 2020-04-20 10:18:31 51.15.249.137 9030 9010 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13800 +p reject 1-65535 +r ES12 dfz6EiW1tLNeJdpTyLp1RUY7Z54 hDNIwauVMqLcG7VYJ4NNM+I1JGI 2020-04-20 03:08:21 134.101.177.101 9920 9921 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2100 +p reject 1-65535 +r herukkahillo df2xsDFk7O0rN86Lkl6nYpwc2sM rub9r1va3uw20S0JKI2y7NpRhOg 2020-04-20 01:07:55 84.251.163.151 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=850 +p reject 1-65535 +r ipunchsharks df5SNuZ/+kpEwRUsNeqzY2Dk198 9biL3Hz+r5Z0qlMMVAOOYcZmK/M 2020-04-19 18:53:38 89.239.212.124 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34000 +p reject 1-65535 +r Ichotolot62 dgBoAkmiIIDsxhc/u/ZNb88zCmE 0KCB0Ec1PmkRLqxRD6Po+Ypqkuk 2020-04-20 11:45:39 81.7.14.31 443 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3360 +p reject 1-65535 +r blademaw dgCJnlT6KKq7F2RUjtKM3slmc7E PquNPfbjgWio1jDiRHDaTzG6ZA8 2020-04-20 06:17:00 188.214.128.181 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29800 +p accept 1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223 +r BadUncleSam dgDkaAVcWSAtTlw9ysp64NydSc0 jIFTbC4HGVGz32BYMtAXbcJA6AA 2020-04-20 11:38:00 192.99.183.59 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7350 +p reject 1-65535 +r turing dhHaw8WaQzItd0QA9X/aTSrA7uI JAv3VZq7ekCiJhWIs4EihP+d6T8 2020-04-19 22:12:26 88.198.12.66 993 995 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=59 +p reject 1-65535 +r Nicenstein dhTvMmY12oEGOOL11EnRCuK7cVg 3Lct112bsBdi1+qksXZuayij6I4 2020-04-20 08:01:58 62.171.144.155 443 80 +a [2a02:c207:3004:8874::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r tortestyoda dhnWSebZHSEv9HifQotaSd2qyb4 GdazRjzZ7oeMIpvrbl/1Yag1t0c 2020-04-20 01:33:14 185.26.156.86 49201 0 +s Running Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45 +p reject 1-65535 +r WorldCLTrustDDNPPE dh1DI7az1llYLkTIg+0XdryFzvk RNV9qKRn2F7rkqtVgy3mDLZAb7I 2020-04-20 03:01:24 94.237.76.207 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2040 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Unnamed diTF+vgTitsfiiBYgkV79ZBAvug 6pfOZCAQQ3nIW/0D1gFHOcWesMo 2020-04-20 10:26:07 107.189.11.219 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Panier2 diZ0pwI8LCBqjbsGftsnhtw6IfU WjnnsHCMdJuyPatSXSUXMFJp9CU 2020-04-19 23:35:22 35.178.59.186 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=104 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r RESIST di7Bz+/C++mszlv4fF6Wo1G9em8 aj6r0MVSFfq9msRO1anKXXC9R7A 2020-04-20 02:22:26 95.154.24.156 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r FictionEndevour djmHfhPouk6o/COjgkuaArw+1OA WH921CnbJYgG0o2yPxuiNYWyozQ 2020-04-20 09:58:20 47.254.134.8 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2260 +p reject 1-65535 +r fenchel djt9Z6ay0Zs+nqV9H73EjzuFtVk kpvPha8AMeCvrFEdAJ5EX258kfc 2020-04-20 00:16:41 109.70.100.12 443 80 +a [2a03:e600:100::c]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84200 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r Quintex45 dkv4oDho+EyPMjwaZ2qiVLgNw78 XINF+H7QudOEODOJSVDGh4Wvcak 2020-04-20 06:50:03 199.249.230.68 443 80 +a [2620:7:6001::ffff:c759:e644]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14500 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r TORfrance dlQ3SVEM0Ayxbh3UlAyqj6xyf1g cb6dwZLAns3T7m8YL8DUvoaeLfM 2020-04-20 10:13:47 94.23.29.204 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r DevelopeKR dl+PZG6u2vwUqnuSJ3FZXOWsuGA +/UEGOOaJXNz6hFks5VTz6aCGcA 2020-04-20 09:18:23 108.61.223.153 443 0 +a [2001:19f0:7001:5284:5400:2ff:fe96:34b]:9001 +s Fast Running Stable Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1060 +p reject 1-65535 +r tatsuya dmElqHmsYuNYZHNtCad8sJF/hvk JQiAi+b5ODvsya3YLRfvE9i6jB0 2020-04-20 06:39:30 37.110.66.21 9001 9002 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23 +p reject 1-65535 +r lamomiesinistre dnTDg/f1UeBl4+lbvPwGcVdUahc FecWLfUykhHVdsduW6CDgQCpWpQ 2020-04-19 22:17:30 62.210.99.162 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61100 +p reject 1-65535 +r Unnamed dnm1fCFnx99y1ziaJN+IqXcp/CQ W1aGINf2otkix09FcZPNP0n1ET4 2020-04-20 12:14:19 209.126.76.249 443 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52 +p reject 1-65535 +r qtornado dn5ETh+h2nXzt3R521ri+j//dcw fAkb92toIzLa1OUbb1gvTFyVJ/U 2020-04-19 19:49:04 95.216.35.84 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29000 +p reject 1-65535 +r eludemailrelay dotIiuLGG2+oN+OrjbdgHhoLhJI KV9oT6hOklsjREIgMArdcNonFlo 2020-04-20 05:41:48 109.236.86.109 110 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p reject 1-65535 +r TorDotTeitelNet dpWZAThujJCPUCNdmJQAeIa2fC4 kXiQ1oRHZvYMtTayjCAW7aKWtAE 2020-04-20 09:42:02 198.50.158.140 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p accept 20-21,43,53,80-81,88,110,143,194,220,443,531,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,6660-6669,6679,6697,9333,9418,11371,30303,50002,64738 +r sosa dpopcBe7XpKppaPXZyXKEtaUqjA JxmUwRR+XIEy61uXF/+YBtJQ2+A 2020-04-19 19:30:30 179.43.156.214 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24000 +p reject 1-65535 +r snap277 dqVle9LQB2yH5D23xdHmAn1aok8 iyFwVn5iXYHoD1+PjWEBEKEefAI 2020-04-19 18:49:36 185.7.93.26 39965 0 +s Running StaleDesc V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18 +p reject 1-65535 +r niftylolth dqtQw+wEcqY6+5qDOlNfpr1pFHg y+c4LR1XZcr1quSt86oUi4x2w0w 2020-04-20 08:51:48 185.220.100.251 9100 9101 +a [2a0b:f4c0:16c:8::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58200 +p reject 25 +r vladimir drT+3QaW2SSkB8+rULbldLKMzco SHmbNJ9NgW4d2lBf73WdevEnhic 2020-04-20 00:22:05 158.255.1.112 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3470 +p reject 1-65535 +r loedgreem dro6P02lzf1VMJmi12yx1fPBegA rj4PmSXotAkxH2jxtVN4W1E6IEg 2020-04-20 03:21:56 79.214.234.110 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4680 +p reject 1-65535 +r Unnamed dsDGE7Y9g+hOyHCn9J/V4Mu5yOA pU9RZG+h6hCaQVk5SZcDKwYSs4E 2020-04-20 00:43:34 34.249.24.135 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=946 +p reject 1-65535 +r pinselohrkatze00 dtLrqCu8yj358lSpqDcqEKJvPRQ AaCDThjgNTi7W10bJGW7lTiq/OA 2020-04-19 20:18:11 134.130.172.229 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52300 +p reject 1-65535 +r MarysSister dtPMGpBnMsi3+Q6bWg/zvkpKUt8 aLPMSBdkdKCtuTuqwDWHaSWs3hk 2020-04-19 23:08:57 185.225.69.59 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p reject 1-65535 +r xabbu dt0YS8JYIgukZX6IJVly0nuEuhA Uv1RwWwTP9l1aJlBkc7fUa6rp78 2020-04-20 07:19:16 207.180.221.73 9002 9030 +a [2a02:c207:3003:4471:96:97:98:99]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r snap278 dt/G8sgOcWSFRHji1Ds4w873aCk 6HkpCjF3re5bhWYvC3ZUjhUPFJM 2020-04-20 09:53:42 92.167.236.39 42908 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=123 +p reject 1-65535 +r ECHELON dvNVjLJvQfid7GhbrmZgGLargIs mcGAOma9HlS9LwvyuLfzxex60Fk 2020-04-19 22:42:20 5.254.66.111 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r stalkr dvOoGgeE3PU29t4Z+Y6usfid7M8 wa6QXk4DLRIJkjdDKJyD8lc8Klw 2020-04-19 19:43:42 51.38.54.48 9001 9030 +a [2001:41d0:403:1830:14::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1640 +p reject 1-65535 +r TheCaveRelay dvZpimJN0XYqXKzIMkYOyeijR3Q CgjqhUdQJx8SEMgOEyY+WSOySc0 2020-04-20 02:39:55 70.57.124.3 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3390 +p reject 1-65535 +r cat1435 dvifaG7cWZwUWNXrQvZh0q3xQz0 6F7njvhOsVaW28g96ZepgvW862s 2020-04-19 20:02:02 100.15.249.55 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4860 +p reject 1-65535 +r 2501 dv/fPMFYhzZDlCrqn3olINMIaEI wJG/6uxEHpXj8w1b1S12h4M8JGo 2020-04-20 02:24:19 89.12.56.197 9001 0 +s Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=29 +p reject 1-65535 +r CriticalMass dxMdfi7BypuNc3UCJW2pEDWZzlE /eXE/kf2iHOeXyFvY9ZEu9n0BIw 2020-04-20 04:50:50 77.247.181.166 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79000 +p reject 25 +r Hydra8 dxbegDClaoAIBEbgy8WXOGBUVOY /lJJmRgqwZQfXphfRHEdNcCXtN4 2020-04-20 03:22:03 89.34.27.48 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 53,80,443,1194 +r Weazel dxjpYyqxIx3rOi7tELJLccn2CXo DmZWbcAwVAn72YAscmfsC51AwtI 2020-04-20 02:06:48 88.130.92.64 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r ntfshard dx4IJO+C2F4E2AEWVUER439+t5Y P3m3m3KO13snuqNV3iNQ4BduzqA 2020-04-20 05:29:43 46.251.93.54 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2320 +p reject 1-65535 +r frankovich dzekAwUTGti15gz7kSbku+Htf3Y 8DQrlmA8XZ6zCONkgr9XhjaoQDc 2020-04-19 23:11:30 46.23.72.81 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p reject 1-65535 +r NMary dzh/AA50cX35LBbF1KowrJtbjjs 00jgqsOX88IhdDnLoGAZKub7klU 2020-04-19 23:29:38 45.63.7.96 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=471 +p reject 1-65535 +r TrumpTower d0Tj0fbch+MSXUaz2FRJAptw/lk 2cXWIUSm3qxCfyHhPdNNtW6WW1M 2020-04-19 23:53:04 73.61.161.136 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=181 +p reject 1-65535 +r Aerodynamik01 d1sPr95xqtwj/8h4K3vrHVqScz4 c/KMPoshN2gvbvmgNQpw+Z9t94g 2020-04-20 04:26:00 5.196.23.64 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r CalyxInstitute09 d2Hdx+sb4m1BVfdKFfEsMqNv4PI KohEJGV4RoIzjLYB45TEjV6ZXSk 2020-04-20 02:20:29 162.247.74.217 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r BrightfieldRelay d2/Lj3P42EQH9a8kYKdfnuyYLrM NVANJiXVt1E0qGlnM3PdKTARsW4 2020-04-20 04:39:52 51.175.121.67 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8110 +p reject 1-65535 +r Politkowskaja d3st7NZ8YH2IV61g6XbuPh6KUr8 4L1CEG74jV89YKQXI0Z7lHQInAk 2020-04-20 01:42:21 144.217.60.239 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6900 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r blueberryTORnode1 d36eO7Nxz7Q2y5k8+Mf2MRN77rI hTCf3Lh/d6ntOJP/vm34QC0iwYI 2020-04-20 11:59:11 178.62.205.137 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=358 +p reject 1-65535 +r MEGArelays d4X9KZvSfB/6y1AIUAfzkJzhp00 mqdf45LJmHKmVxIOw8qKDquK96k 2020-04-20 12:45:10 45.142.212.174 9001 0 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p accept 80,110,143 +r BNode d480nkOULAoHZ46ZLJta/W0hgKE vXa4QKQG4U8OAvJVnvbi5xvgveg 2020-04-20 07:10:42 84.118.60.117 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=99 +p reject 1-65535 +r snap278 d5WRlHJmeoyVjrhnGQzoXJ8pxmU XaeBSD5jkd0p/BebYfFqSd2xtPc 2020-04-20 08:04:36 181.91.138.214 41167 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=269 +p reject 1-65535 +r TheEpTicZeus d6Vssjd0DiSuotYcjIk2Iyr8G9g BsRsN4tVtCQGpppTXSgoSklV+mI 2020-04-19 21:05:52 54.36.227.247 443 80 +a [2001:41d0:800:3a7::]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=38900 +p reject 1-65535 +r IKEA d7RWKXT11xVibreEYMeaLRP7cAY NJnuij3uL5rPSgrXmuUEOhVVv7Y 2020-04-20 00:56:32 188.68.33.224 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=42700 +p reject 1-65535 +r BienwaldKA01 d7glXNKmCLli2kQjuM9JrP0eIf4 op7Vptf30vkO2oUlUpNkbT409NA 2020-04-19 19:30:34 217.81.81.31 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=400 +p reject 1-65535 +r LeonNet d7iPdI5AZ90Zi8D6Mx4RjaIRM40 NV/253XQtxZEmFcBLtfvdrydwzo 2020-04-20 04:19:40 95.188.89.206 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2160 +p reject 1-65535 +r Unnamed d7kHToprGRsJ4kkpzr9AieMyHrQ jGMsh4dQmynEAk7aZ0YFb/R0ajw 2020-04-20 11:33:14 167.114.92.50 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 d8ZAMjaHDUURplnwEjKUh/Q/O6w cwi/Iebknwy69Ed6CIm/gmAVR9k 2020-04-20 08:33:13 74.78.27.171 40457 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=54 +p reject 1-65535 +r Assange027es d8dQDMVzZD5LPn9gLQE3+Mic4Lg bjtmi2hwDPzzDltyZMPLarVuy7s 2020-04-20 12:32:06 31.207.89.76 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6590 +p reject 1-65535 +r bff914041c9a d9MyDIyt9JDcg/lZ423qCDIm1g0 UpDR3/Ak7++Ye4Z/X7caWZMygMY 2020-04-20 08:23:35 51.81.253.202 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tie2ooK5 d90ljw1YeS4Ny9qgvGah3F+NhK0 kvXY/fLnxk5jDwub3WesnjNQvjQ 2020-04-19 19:50:50 37.120.179.169 9002 9091 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4520 +p reject 1-65535 +r linode12300423 d+AaXTF0hHTE9fCGwkYeBKJrNPE ojREBdJaLLMMQX77TLemhCajSi4 2020-04-20 08:42:16 23.239.9.92 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4800 +p reject 1-65535 +r keith d/izVzAcaN6pa7qmDAdnbj4WH1Q vVs1FtxkNv+lozMMRC5nqSm8A/g 2020-04-20 03:35:02 51.68.205.181 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=81100 +p reject 1-65535 +r jeweet d/6YRFBIxXdmYbtUrsqnoRroXXg 0XLy0RFkPjz+IpybrTEIwKk6JLk 2020-04-20 02:43:08 82.197.218.152 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=891 +p reject 1-65535 +r delrovio eAco0+0vEoQx38O7Lb4h6AwgdY8 PosvD9KAG7nDJk9V8viPCXfe6ZU 2020-04-20 12:11:36 192.195.80.10 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r heyieditedconfig eAouRwH2xEhbW5iLyUgMGmf2Mxc DI91Wl4mH7jOhG9O7ZJ6PVyC64U 2020-04-20 02:24:01 51.68.106.162 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=148 +p reject 1-65535 +r BarrySylvia eBbe3dfNePkf63Ljl6yxi4gTKKw ba6rWjk3iIb2IbBDUFkj4unwuDM 2020-04-20 00:04:02 3.20.179.249 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r mischief eCk2wWv4dvX1mheTrbHFslHbZec /nDTf6VZ6FE509JVH3xDlK0BJvc 2020-04-20 10:25:18 185.2.43.84 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8300 +p reject 1-65535 +r spotyor eDajiICg/j9DNbi/PZ4IObOWnqY 7GjGsaHYzZwwIZ1WLMYyXK5FKgk 2020-04-20 11:13:56 209.141.40.46 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=763 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r VSIFweb eDeN3QFcThySQqXsQRWK8eJM9D4 rc+seNV2486Gjh+AVznr2IgmQws 2020-04-20 07:14:29 163.172.147.53 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20200 +p reject 1-65535 +r Bierpipeline eGpt14sXAG3AlC4XFBw04Dhj7C0 yObrWAZ5lOxTqRZ9ytBGLlWugOw 2020-04-20 01:16:26 91.39.58.237 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3110 +p reject 1-65535 +r Kitana0x00 eG7KCmbdxQdnK/WYeYXZ9ugR554 KypOiDd/d1LQOH9+tZPvnqjenm8 2020-04-20 08:25:34 213.141.129.246 1984 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2860 +p reject 1-65535 +r WYSWYG2 eIoopKNJs/488buiDJD8RP+9fZA 7Wx9dpGtgx1j0nxn8NXD2xhoYrI 2020-04-20 04:33:20 46.194.46.65 65533 65532 +s Exit Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r machinesarepeople eLj717u+0tv1aN5c6QNFwxAhUuo iAyuQd3rjnX23mtpdS0uUbjKgFo 2020-04-20 09:54:00 37.75.227.17 9999 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3960 +p reject 1-65535 +r grobosolforte eLmNEpl+3WMPamdMv0LyBxHerBE /FQz3YQmWf3G1wbIan8hlbp0mD8 2020-04-20 11:23:16 217.144.138.249 443 0 +a [2a02:a00:1009:d990:8af9::]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25700 +p reject 1-65535 +r dc6jgk9barm64 eLwiVNOzHNhl92gmM6pDghITJTI BioguZAxOvmY6zCCitoPPSVDxJY 2020-04-20 06:28:48 51.15.80.7 443 9030 +a [2001:bc8:4700:2500::174d]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7100 +p reject 1-65535 +r MartinLutherKing eN8rk3hJ5rdjbpATd9sIoVtRUlw wMy/L1QC1ORA8GvZ5HWceUL95XI 2020-04-20 10:07:25 144.91.106.71 9002 9031 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9400 +p accept 53,80,443 +r COMRAT eOIujQFouGOT5WAKr/D/iyX5bgg R7TG8LZ3AD6OqQReSEiCUAHAOcs 2020-04-19 20:20:37 185.222.202.10 9001 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1430 +p reject 1-65535 +r bynumlaw eOK+dEpTYxtKq3gUaOlMUqtzlos MeNkc+shl6T+qEkrAJauxeYzwkI 2020-04-19 19:22:49 104.200.20.46 9001 80 +a [2600:3c00::f03c:91ff:fee2:4963]:9001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=1150 +p accept 80,443 +r PolishHuntingDog eOQsXqP8TFYGs6z1Yj3iX+a18Wc yqBiB/q+TdZAzcl2p5FDnC7orYA 2020-04-19 16:53:03 46.41.137.28 9001 0 +s Fast Running StaleDesc V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r Unnamed eOua0Y5PQilIRDDK4r6F4quUSS0 zEIQsRmcfehr5aKpiX3sNm5/EVs 2020-04-20 10:34:43 107.189.10.190 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tor03k eOuj+JM6D1lrQ6fb15TFYw9bWH0 9SRwE/RSNaHt+H4lKr43o71kTC8 2020-04-20 04:33:14 164.132.51.91 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Blockwart eO2EXVAt/6RmbuqQmYPegd4aP54 gAZTCiG76kBI/d0tx2/DrujZ4pk 2020-04-20 04:04:20 83.135.237.170 443 80 +s Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36 +p reject 1-65535 +r snap277 ePoVqx3mQwXBwddufpE59h/e7t4 NjK0QV+Isd6eOYtPY1PB49Q/aM0 2020-04-20 10:25:24 73.157.203.222 45055 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r chaoscode eQCSPu7OR9nDye0VqfXLc3+wNDc nLjehbqli2+Fh9A+oy1tyC7pXq8 2020-04-20 04:11:55 89.245.242.150 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=643 +p reject 1-65535 +r dockstader eQ6z5UTnCAn6dg3Hk0afxauvHig qr2Phgy6DD3xlcbgC57OWENAWBI 2020-04-20 08:34:34 209.58.180.90 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=370 +p reject 1-65535 +r 4istheloneliestnum eQ+r1RhOmPiZCEBCMzZMlApIgew X0W6/k+9lJ+eafzhuMliRNBMHvE 2020-04-19 20:10:39 185.189.183.143 10901 10930 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3150 +p reject 1-65535 +r torar eSoBX780ONOljIfQAx2e3cJvIpg jG+V5lY+m/goU5WkZ+P8Zg24N/w 2020-04-20 09:28:36 83.56.112.221 9001 9030 +s Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r dragon eTSab3SsDU7yk5iUsSJwLld4b1o AOBal5Uzj4KmEvav+fDcfyEDnXo 2020-04-20 10:51:43 81.17.16.149 9001 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 eUQFxd+EH9sdGoQhppm1IGGKcFQ vqM+YLnNmRcihokqnq6AE87O57g 2020-04-20 08:34:57 5.158.55.160 35629 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=707 +p reject 1-65535 +r DerDickeReloaded eVCWg6tMjdr5ChIMaaQXnGzVo4c d9r5oXQd00yLvu43mks1s5Xm8K8 2020-04-20 04:13:56 185.244.193.141 9001 9030 +a [2a03:4000:27:192:24:12:1984:4]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p reject 1-65535 +r fakename eVeQwlveg0uDbqVN2W2yYQgpVzs V3h1k3heWaUUal7egmMwwkIHL3s 2020-04-20 11:02:45 51.255.75.3 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32100 +p reject 1-65535 +r ZEN6 eVsuzuWiivqVk3ukHkIadai9q/c 8KGVm1OFfWpJosCtOtgcNrOPnn4 2020-04-20 06:42:14 202.239.38.249 443 80 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r Unnamed eWHJmR8CLIo2P9RAyjldR9tdRNU iiB+FNj02PFygaDWbEkUDvtFRTI 2020-04-20 02:03:35 51.254.35.151 9000 9001 +a [2001:41d0:401:3000::436]:9000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16200 +p reject 1-65535 +r TripleBfifty eWIdPzags3dnC0ZHwzcGNc0lIa0 o7GR3zyY1u5u9ysOkGCXnIom8cE 2020-04-20 08:50:03 18.220.20.115 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Piraattiklubi201810 eWM4mZp+NMpMDyxgkmGMgsDTNdk FxoFSBaGgWu8z5AlkYNi7cQtCOw 2020-04-20 01:56:40 82.181.47.70 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50 +p reject 1-65535 +r torfan eWi7aU0FwDNyJ4YsyiIH1m16rxA PxSj2nwQVQsGoksJm9RjDZnRMUk 2020-04-20 10:20:39 79.127.150.75 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=470 +p reject 1-65535 +r Unnamed eYpXtOEpaZpSGgPn9yvA/ewx9NY LIsZSSZi/ob0QWuK0GuGAT9oQNs 2020-04-19 18:53:34 185.90.60.73 443 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17100 +p reject 1-65535 +r unic eZH903KouOUwGrKojf2BgLknXAc 1kMefXHvGkm/+v87j3bLiondzAY 2020-04-20 05:45:31 94.227.13.244 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=182 +p reject 1-65535 +r NeoETor eZfXMnIpXBMi8w/9HzLQk+Hhl5U q7/cgupNBbEoFTbaWDvztawbTjI 2020-04-19 20:18:13 86.210.4.33 8001 8030 +a [2a01:cb1d:8adf:2a00:200a:884f:9827:d443]:8050 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r LaTorretta eZgOulZxTSM1THLBGyKbZ2yeyEQ mFRo3rU21PPoQMlLhRWjbBdPq0M 2020-04-20 03:45:00 145.239.86.245 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7750 +p reject 1-65535 +r secunet eZ1OZHcc+je7McgjcUGlbqfZqwI c4ocPRqakAf4afh3PT2obPH7MrA 2020-04-20 00:42:00 13.229.152.50 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=568 +p reject 1-65535 +r VariantRocket12 eaCNJhvAtpriHa0G6rUK8GDpbgE zORnYB5LQYN1yer7Skfndk5ghfw 2020-04-19 19:56:31 194.99.22.195 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p reject 1-65535 +r yuggeit3 eaYJN1wNrPgqivDkcvFJSeGMW+c AUHeRmLeNUmmdD2plqU46RNeMxQ 2020-04-20 01:44:30 139.162.10.72 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=130 +p accept 20-21,23,43,53,79-81,443,1194,3600,5190,5222-5223,6660-6667,6679,6697,8008,8080,8332-8333,9418,11371 +r 1d1dchang3th3c0nf1g ebIHrVGEL6IV2Va5MHs9Ac00c2g T5TEyjBqzfTDrM/KaFHLw2lDt4c 2020-04-20 04:48:14 37.252.187.129 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9940 +p reject 1-65535 +r grocock ebOfjVPazJpjl1+8NGMB2NDTYDQ /oaoxjG6Ox8q+FHVZx8bki8aeys 2020-04-20 01:56:57 178.32.220.61 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7980 +p reject 1-65535 +r gorlock ecZ05sGskGh8zPZE0kwXrB5TWjw RGPjK5cTBA6Az9t+XGCiUrwOSA4 2020-04-20 02:19:23 81.7.16.177 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23200 +p reject 1-65535 +r friendlyminsky edEQQZcJxLPR+S/DzhIbUxfb6LM kaOtgmUXzwqUrNQeq4c1l65OY14 2020-04-20 12:09:48 51.158.165.212 9001 9030 +a [2001:bc8:1824:608::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30800 +p reject 1-65535 +r BeastieJoy65 ednma7L9vyXoRrY12CSP4RlM/SY 9PX//9CHtxmnZS5EHPWIfNjJ8NM 2020-04-19 23:58:04 81.7.11.33 80 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r Mundl ed604C/QiuGutNhZSqsII3XpBi0 cECv/+R6kEkb5uWJKLgRo0W3h4w 2020-04-20 10:34:11 195.230.168.83 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4160 +p reject 1-65535 +r bittorrelay ed+w4dedEwavA6SwlMVaV2mJq9E 43aTsfLdgh/3W8daRn+9R40Z0P8 2020-04-19 21:48:26 187.73.18.43 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=237 +p reject 1-65535 +r Unnamed eeSKMkLbNRVwD4kl+o5jI/jVHX0 7Vi8kWTHtxW1F/dwnLGw7yz0Avg 2020-04-20 10:11:22 37.191.196.246 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12500 +p reject 1-65535 +r TorGwTga efHkblnr/PygVr3Awc94o2eIqDU kEw7Kvfycgzm2w0Us/RImjMKeUw 2020-04-19 21:12:51 101.100.141.137 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=176 +p reject 1-65535 +r lptr01ORFzF4Zq egxWPbh2CN02KKCw0hZk8UyYkgg /74PIBZbzy8YMgCjSbwubRCOefU 2020-04-20 01:05:51 213.188.235.229 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54 +p reject 1-65535 +r framboise eh5Vv2MByPn/lnf2sH0EwKYydmc IwARLNROY2xgXytT9daz6wGkiXo 2020-04-20 03:45:06 216.6.27.12 9001 9030 +a [2a09:8740:3:42::12]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p reject 1-65535 +r thardes27415 eipvOfSFxPyV+4hf/zfENv0rt+U UORLnoZU9bF8i3lfdEXDT6czTzI 2020-04-20 11:21:16 217.160.57.194 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34300 +p reject 1-65535 +r silentrocket ejLJUZ2AykWPyLA0oo9faBVkmpg /jhOuIr0ZF9VRvfgPehcRlGxA2A 2020-04-20 10:22:17 82.223.21.74 9001 9030 +a [2001:ba0:1800:6c::1]:9001 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3200 +p reject 1-65535 +r Quintex39 ej3SgOpM1N0W74xnuT2b3hhNGoE /0HF7PAb9KQiJhnAkCSalbzOyc4 2020-04-19 21:43:52 199.249.230.88 443 80 +a [2620:7:6001::ffff:c759:e658]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Unnamed ej5TTAM+ODa9WvIjtkKFPFAqszo JfATHMxBW0Na7wHXeh/thir65Yo 2020-04-20 11:00:29 5.39.69.166 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=126000 +p reject 1-65535 +r myrelay ekwpagH62gvF3k2nQ+7tFoKClJY j49ZWJNBzSFw6eTWbgiZiZtmyls 2020-04-20 11:45:25 137.74.198.250 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3010 +p reject 1-65535 +r shokupanman566 elNRgBxgzTADnz74g7onBNBtMFo QwdXbIgy1nyj0xsVIfwi/B8ea8M 2020-04-19 21:55:02 27.120.90.181 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=44 +p reject 1-65535 +r dorin emhzuG2CvItPDnkIKGJhB4IPe54 a1scABuTU2uiP0+3rHDeeiEwsAc 2020-04-20 10:37:54 146.0.77.50 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16100 +p reject 1-65535 +r cryzrelay03 em7EP9TNWZAjD85I7DevxXjjbOY bA0/rL+RVOiXFE5RLhCWxKWgTkA 2020-04-20 05:44:41 82.149.227.124 8080 8443 +a [2a01:440:108:11:82:149:227:124]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r GibblyInTokyo enBwz/sMiC5QeXEpj6je0F7wOUU KNypBqvTJwXDa2hMPs/eb6PHGwI 2020-04-19 22:38:54 107.191.53.201 9001 9030 +a [2001:19f0:7001:33ab:5400:1ff:fe51:b2fc]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=644 +p reject 1-65535 +r Unnamed eoeRZQFok0/36gTl4Cs9pzWhie0 zwX9+vx2Lz6Hvr41gF9s6NQ7/u0 2020-04-20 02:25:38 82.207.167.86 9001 0 +s Exit Running Stable V2Dir Valid +v Tor 0.2.9.9 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3 +p accept 1-65535 +r ITBURNSWHENIP eofyPdJ4XHd8cDKkdbh6yIyi3jo AaRtzfG0cj8vYLXuTv7/MlhsLWk 2020-04-20 12:40:43 66.85.95.43 1337 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3750 +p reject 1-65535 +r druid eotvB42Fro3o0bz9jhtutYlsQxw EQvt16BN2f+z0PGG8CA9xhwov1I 2020-04-20 12:00:11 51.38.162.232 9100 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r steinpilz eqf8gOPg0y6SnSzAlOrPUpyVJkw ZFnGNYSBHKAksQH6OUsypNdPbJU 2020-04-20 03:08:29 193.31.26.18 8080 9030 +a [2a03:4000:2b:1731::2]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r angeltest8 eq9Vl7GNgsyQypX7eXahzqSjLgY jNC+e1DKO5CezsO2tl7Yr64+ew0 2020-04-19 20:17:32 185.112.82.50 443 9030 +a [2a0c:f040::dcd2:faff:fe8f:70f3]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p reject 1-65535 +r reihl eriwjfi5DRCO/DfXTKkKe5OaAj0 5M1Br+BoOIynQAvPFRXGpo3zZE8 2020-04-20 12:10:18 87.121.98.43 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6670 +p reject 1-65535 +r snap277 esVK/SfRtv3jcYRsyT0E2qITcOQ W6fbQVnPq9HAtpromJGcpKnpon0 2020-04-20 08:07:41 109.221.142.241 40815 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4350 +p reject 1-65535 +r torex essqhVoOXtr2gJeuJ3ETuO2poLs lWxlt4snawNVJOidyP8+K9ao7nk 2020-04-20 03:15:32 202.125.21.31 9010 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=314 +p reject 1-65535 +r massrelay euFX5QCEAEPB60MVdUU9G2DWJ48 LYI0ekHrcJQHDGa1mYc+kxJtEmA 2020-04-20 06:50:08 178.62.244.168 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=560 +p reject 1-65535 +r citizen17 euVz4No84q8mOgZ4A6xfN9ALHsw Awc8Yq7EhEyTPyN0MMIYh8hF4S0 2020-04-19 18:53:10 83.97.20.245 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=740 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r torly4relay ev5zQmPJR63YjQlMbjy3GjQGJyQ /wA+TELy8JNgPiY7U6VEZbj8FjQ 2020-04-19 19:55:18 62.113.211.114 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=195 +p reject 1-65535 +r snap277 ewGSFj/yyZ5YLzCexjJneYuIjx4 pm0MUf/CImYTSLUpn4fUn9iqZQE 2020-04-20 09:19:13 71.38.183.183 43649 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=170 +p reject 1-65535 +r snap278 ew7GQFHszuOCebERZdxdHWvNyRg YskW0Xmj7AoeroAbAxRH2Olh18c 2020-04-20 05:22:58 176.110.34.244 40139 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=540 +p reject 1-65535 +r godtfred exkEY+czzCkqpAENGU0XmM2OuaA iL5tEUtuPu+jGQzUChy356A84Vg 2020-04-20 00:01:00 104.131.72.61 9001 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5990 +p reject 1-65535 +r megalama eyN+brU4PI0IUgl7ZjO6w/q16jk 585E5pocCp/MahA1qtAZRpVMTMw 2020-04-19 22:19:36 141.98.254.225 14655 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p accept 1-65535 +r torified eyiXHUopmVeE4wZrnYfkLpxoXzo BK/G7F2Fr4S70uLr129AaVJj7iw 2020-04-20 06:04:32 80.219.48.52 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6850 +p reject 1-65535 +r ClubCryptique eykE/oqhLkXqPWVljtjOykpR9/g NQY5OYtSuqJZRKLCbq1jFapoEwE 2020-04-19 20:05:11 51.77.62.52 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4670 +p accept 563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 ey1FbFf3PRMZ+slBLlbpzU8/lQQ L2nT4+hSeoD7jSE8uTdSNbYYXGM 2020-04-20 12:34:56 71.226.11.169 43775 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29 +p reject 1-65535 +r DrNefarius ey/U/9VlmTy0xDNKwKDEKYXr6ts f3q9qjSQOus/J7QoxTgHmAHSun4 2020-04-20 01:31:53 37.120.169.252 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r Unnamed e0hOg7qtd/kVmgncNKjelJX/PAM W+rWQfSgPyF1jXa1flC6ni5F+vw 2020-04-19 21:06:26 185.125.33.242 4351 26185 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=779 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r YoungRelay e0h25sm/sGBepoFnsw+t2EnFmkc cEomWUcfKBH6F3Ep0qsMLl1hlvI 2020-04-20 11:17:02 128.199.196.137 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=710 +p reject 1-65535 +r TorRelay268 e1MtYEppCewh670KCRExlSFEdXI NEiyIBo9Ip8pIpds+AZ7c7WUY6A 2020-04-19 22:00:00 51.254.39.39 9001 0 +s Fast Running Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5090 +p reject 1-65535 +r iscariote e1PaKIEyWKIDNcjomFwF0NCJtEE 4TsbUlGOlWR/23lkySlHTWvhRZ4 2020-04-20 07:09:23 51.15.142.0 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7050 +p reject 1-65535 +r sandman1 e1eTPinVIEcdfmerSLBrYoMoKPk uoOPsK5Soa7k1Vjt34XZCWXyYas 2020-04-19 23:33:57 51.75.82.166 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r emubeard e2ytGmI5efDOhvwULjwuuyb785k /JjlDOUnqNVYDwDUyU8f/0aA/+0 2020-04-20 06:10:41 91.240.229.195 9001 0 +a [2001:67c:2a4c:1337::195]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=450 +p reject 1-65535 +r dc6jgk11barm64 e3AMDCB+vQAC4A9Jm+JlUZrDwlo 5YnDNtcxaUD+Bq1T6mKqBVbv62U 2020-04-20 06:30:32 51.15.75.120 443 9030 +a [2001:bc8:4700:2500::2115]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5600 +p reject 1-65535 +r king e3WsW6x5qe+zIkbBgA67KFt3SoY w4x1lvbcvZ7MxEkqL22oBesapKM 2020-04-20 05:18:41 51.89.200.97 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 e3pKQhGGpKIT75Gr+G3s4FV7zOg 9YBSvxbnPs9IH7G6FTqxYXZIFHY 2020-04-20 11:27:09 179.34.64.113 37015 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=124 +p reject 1-65535 +r geay e3vmVsMW7tVVzpz2jUTLUBR2eIE 623c44vW6uqDYEt/cEAuzC5i1q0 2020-04-20 05:54:19 93.115.241.50 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9910 +p reject 1-65535 +r niftyentrynice e3x/MSBdeutd/+2gjgAoKnjNduA efiIQu722Cg2RkmMJQgfW05gORg 2020-04-20 10:51:08 185.220.101.209 10069 20069 +a [2a0b:f4c2:2::209]:10069 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20400 +p reject 1-65535 +r SRTorRelay e30KI1deZJzWESpelTuhpvL2K1M wfNiBBcQGVRIZEUrNeZcWkbqSrs 2020-04-20 11:14:41 121.122.127.134 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=446 +p reject 1-65535 +r 6ba405a10c25 e4TmZ3AYUmXyh2wNNJzsmOPSpyM YdsIbmUDapiuSGfD8Cia+8qj99A 2020-04-20 08:03:53 51.81.254.3 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed e4fvV9rDMtcBbASuggY+k7UWLEQ Xla02bJKZZrdEizU8RDCYcfzfjc 2020-04-20 04:15:17 51.158.65.243 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r bigtits e5jR08NORFqnJq6ZuS/NmaFeTsU PGtoyoXGWDIJsALZ4M6Ja+DLWIA 2020-04-19 21:25:15 178.18.94.247 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=90 +p reject 1-65535 +r eceakwer e7JwRUrm5UXqJUY6AX7ppAUsmrU GVIxh+LTpTUVO/EreoJ8V/hJ8H8 2020-04-20 07:26:26 139.162.23.53 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=722 +p reject 1-65535 +r torproxy02 e7cPhYXfwn511pKXDA7rDyKYOmM fXLw8Y4BQViH5slEkRjVs/rRI4w 2020-04-19 21:06:41 51.254.136.195 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r heartbeet e+R1KHdVOpbNQDXQxSa80J6BzGQ Wkx/8pEW8QHzeli3mrPf+RJ6e30 2020-04-19 20:58:19 51.75.153.17 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13500 +p reject 1-65535 +r dannenberg e+aD5l1IFBMhxe2S8HXFU2SscSM lWlkMhSLf0SadvOLSV8toILM3os 2020-04-19 23:27:26 193.23.244.244 443 80 +a [2001:678:558:1000::244]:443 +s Authority Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r ididntedittheconfig e+ezC0wQ58Pd8urR1rYqGCY9ajY 0g7ulKbrUbSZXjD8tvp78ViOgok 2020-04-20 03:19:32 83.254.12.1 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80 +p reject 1-65535 +r WYSWYG e+ni7yu0G7Zi2aPNaCibnj2/igg pCoML4P2KtDjWZcu69d0vJrNTrE 2020-04-20 04:37:43 46.194.46.65 65534 65535 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=181 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Thornode4 e/MDFl105ix+a6uqB0YLNoQJ+Jo AtU7rjT1L46zlh7ZRScuZfPmmxs 2020-04-20 09:17:54 5.42.136.114 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r sofia e/uQijqltJHaTKcsy+4OHyqTm1U tcyaebs48twC0yfLITIiiunJNfM 2020-04-20 04:50:49 77.247.181.162 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=72800 +p reject 25 +r Dimmer fAQW2KvWP058R8NfKx7fn2ZCSQA SAGp6roq8VhnbpRHsMOQ80F0Qhk 2020-04-20 08:37:24 178.254.43.123 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7160 +p reject 1-65535 +r ibibUNC0 fAqk47c+QH6fX+sZEvi+JtiqEk0 BGiP4Jw5EMlmZP8e6GtTmsN2U5s 2020-04-20 03:45:17 204.85.191.8 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4290 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r ZKP1984 fCLomrYg533xtKM3h6XsPyq0qNE IpRP6YLtiQ2vlupiExhw0USNrCU 2020-04-20 01:19:15 190.2.145.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=73700 +p reject 1-65535 +r Stargazer fCknYHWSrfJjExBXknFN5Aiu0Ls zpozxr3fXSO8prgFMRkJGRFiw1I 2020-04-20 08:53:05 92.223.65.31 9001 9030 +a [2a03:90c0:154::30]:9050 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p reject 1-65535 +r leenuts fCsaH7Ul0y7uUJPI6QrpFufuyrA lb0Cm2l22MNioifPn+Ys8UU1efU 2020-04-20 00:41:58 185.17.178.132 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r anonymous fEbALxdbSuioyMXdmxQH6hz3Km8 FW4eZaf/gaogbuFOK/a+j3xLkIg 2020-04-20 10:44:24 163.158.13.177 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=46 +p reject 1-65535 +r ES1 fElLW7wVWDA9sc+4QNmAoLS8wyQ bnw+Ao54zu6GwWjAV0/0mCjmt1M 2020-04-20 03:09:07 134.101.177.101 9910 9911 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2030 +p reject 1-65535 +r DefiantDaveRelay02 fEmazWD7ZR3UhrbYAikKPrvszYQ El77YM1bOf8if2iaB1Zd2/VvI+Q 2020-04-19 20:36:03 174.141.200.41 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r snap277 fFrEcBKIALneFanIGKe+NiTwW58 BcJ5mIOKX2xQHri8N/LEyjd8zBM 2020-04-20 08:42:15 59.166.192.158 40087 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=65 +p reject 1-65535 +r Gu1nn3zzRelay fFwOg8opD/9tXjDZ4OP/ybrg0MU AwOsbI2zlnnyDYeDUqYZJnbutpk 2020-04-20 06:06:27 212.47.236.95 443 80 +a [2001:bc8:47a0:201f::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23600 +p reject 1-65535 +r snap277 fF/4GUMyXW9Oi+Y3GO0nVIuZQR0 jC8K03Eh7nTpLowQdcEnQbT1TwQ 2020-04-19 20:24:56 195.62.15.26 44839 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4470 +p reject 1-65535 +r niftywabbit6 fH/7HEi34MXJs9Ef7C+FAPRkeGo 9E+/9eF3SotyQ7Cd5r1++Y0vx9I 2020-04-20 10:52:53 185.220.101.198 1198 2198 +a [2a0b:f4c2:2::198]:1198 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57000 +p reject 25 +r Unnamed fIZ/UpByZ/ZYhn+HSw0+WvzJCb4 tqbZMzqrCyCdn4JU0a17rwZl8jQ 2020-04-20 11:19:47 97.103.190.156 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=215 +p reject 1-65535 +r toomanynodesDE01 fIbHPbF84gzSZTfJ4+wP16VeXG0 1eUPJnXAA+kqk3G4zkIluEKKiOk 2020-04-20 00:10:11 79.143.181.221 2010 2015 +a [2a02:c205:2021:2617:2000::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17000 +p reject 1-65535 +r Unnamed fIiJC2bIx++wokQUIZ057Yf6JOo msMMLAwZEJ55Lzuc3AXKckeG6yI 2020-04-20 05:02:57 209.141.58.114 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=9170 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r snap277 fKL3OiSyqNhGmPaPkYO25gFNe7Q cyijA+xuFoRqfCZTpaziZc1YM8M 2020-04-20 12:03:24 49.244.147.223 34015 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2 +p reject 1-65535 +r CloudRelay1 fKU8NNjHA3ahY47nqTSnywOZa+I 4oO6DAUieWdWTQ7Zfl4P1N4CLqQ 2020-04-20 09:17:48 80.211.53.44 9001 0 +a [2a00:6d40:72:992c::1]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6010 +p reject 1-65535 +r Rigel2IT fLwdR1TvOmLBXLSMCAKcmQCeLs8 MhlC5CpPkaNHPmUMeXkwJJ6YV+Q 2020-04-19 21:52:54 193.183.98.224 443 80 +a [2a00:dcc0:dead:b2e0::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6600 +p reject 1-65535 +r KD8HLN fNI03+/o8hXsmuK8HSyvyeDRzAA Oq3OvUSVmwpyKBZMOqxZdl8dZN8 2020-04-20 01:37:45 158.69.222.218 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10400 +p reject 1-65535 +r torrnado0339 fOlUztuYJ8NHgqPxcu4B29xoOsg 7h78AtxuKFxUXGIrCEMAkrJTb/U 2020-04-19 19:27:49 172.104.79.222 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=418 +p reject 1-65535 +r DEDI44 fPPlui9Vr3t1Sxfc1lmGRGfh7SQ Ap5pdLwaPqit6TEG60OHzr6gRaM 2020-04-20 09:15:01 178.175.138.58 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24800 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r 21b fTHVEY1Hv4bFUKu3nt3oZewxtn8 GmeiHv1JY7/3+90JEVlGlboxA3k 2020-04-20 12:47:07 51.15.74.130 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29500 +p reject 1-65535 +r Unnamed fTK6lMMcQLDti69/wobq4axsNjU u4+VjFABKVmAIcjZqMlA5/B38JU 2020-04-20 04:24:09 85.212.133.221 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p reject 1-65535 +r lemontime fUH+1YSBoOWUxkLnQXbIEXeNkaY /VQZdscEMGRjbo25SdaZTfbWDFE 2020-04-20 04:56:29 5.135.181.213 9222 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9230 +p reject 1-65535 +r Unnamed fVX4ea3h56xJvNQNf2gpMwgjPxg 1bc7pas3Fqm2Q9B5lS9zM44Z1hs 2020-04-19 20:02:27 51.77.140.69 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=13300 +p reject 1-65535 +r omgididadoodoo fVqmmnb/Y0izanx1A2vhFd+IBcE 7/TRbs1q/NGI315viQb/env1P1k 2020-04-19 21:49:45 122.59.117.254 9001 9030 +s Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r Pagkaki fWk8Kpw7Cy1p9HOvHA4cvgXq1BI dBBlRD6I4cHwgCYXJZ8M8y0Zhp8 2020-04-20 05:27:33 83.212.96.120 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1130 +p reject 1-65535 +r Unnamed fWm/dgY5+9HZD5zKgIYNaIN0W2Q 6wdpwPJ7686uVXY/5EZv31yOEfU 2020-04-20 12:42:12 108.20.80.107 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1560 +p reject 1-65535 +r Celestia fW3JK6918d4oEsLhSJ6RKSOFjjM IUD0aV9H1u9mQGsSy845BlZIauk 2020-04-19 21:06:50 188.165.211.164 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9850 +p reject 1-65535 +r smell fW6Wy1+wsEPNqjiG6ghBD22ZU1w TKgKzhV65Z9Ddocby39dUVVpo48 2020-04-20 01:24:14 209.141.35.14 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5880 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r TakeBackYourPrivacy fYX3lNOzrmUTQ2O2Vq45ImXtcNU ESt+6KZDaWu6dpJd2SxwAHlQ0VI 2020-04-20 09:17:11 185.193.125.155 443 0 +a [2a0a:3840:1337:125:0:b9c1:7d9b:1337]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5380 +p accept 22,53,80-81,443,853,873,5190,5222-5223,5228,8082,8232-8233,8332-8333,11371,19294,50002,64738 +r PinkmansRelay4TOR01 fY67hs8utWD5OL7wGOHY/Ws2syc J99U2+K+EDs1JakVQM0ggwdymXY 2020-04-20 06:26:41 82.165.74.130 62734 62735 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=46900 +p reject 1-65535 +r niftymuskrat fZITY4F76Ja1Ri6QAz2pN773zj8 FyhXNFFMcQM3cuT0yRoPvT5WHmw 2020-04-19 20:26:41 185.220.101.11 10011 20011 +a [2a0b:f4c2::11]:10011 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p reject 22,25 +r Anagramix fZTYStjxUbr9zXZU9EbD2VY0qAE gCU6W/2iDpEnhHiLD+2LDalmWvM 2020-04-19 19:57:16 84.215.198.76 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=352 +p reject 1-65535 +r Undertaker fZwD+BIkHbCK2pZjXnJ6LveHk4Q 5fw/zwQTXR4Mfxk9OMZWBm8JsXA 2020-04-20 09:51:40 77.120.113.64 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p accept 443,464,531,543-544,554,563,636,706,749,853,873,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,6660-6669,6679,6697,8000,8008,8232-8233,8332-8333,19638,50002,64738 +r FritzWilhelm007 faMdeeUtEmhbvoVE48VX8Xaw/IQ 2wT0klk98P/jovEIEKcxZ/WLsm4 2020-04-20 06:59:18 37.221.193.44 9001 0 +a [2a03:4000:8:3c1::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6880 +p reject 1-65535 +r Assange006us faNGC3wcE9yrO0nt1sN2yoVis8k IEwc7Pa4z0pHgnUNqU0FUbrhedk 2020-04-20 04:11:37 198.23.221.16 9001 9011 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Songino2 fbGK7jQQVgoDllz8XpcXYHdsFkk DxyMAeUmT/A2Z4G4nCa0v1S3tsQ 2020-04-20 04:13:07 180.149.125.150 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=590 +p reject 1-65535 +r 1chandotus fbhEOuKfvEUNNOVfqRT0K/kp7kk hX2H8wzNMFhiafgJN9DNpA/vvu8 2020-04-20 00:44:20 147.135.36.62 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r DeepThought42Bridge fcCZ6ErYrMEt6S7vKxqQUrFdCvE jbgup8p2wiCE2/wpcoGvIUepaN0 2020-04-20 01:02:00 5.226.148.44 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=692 +p reject 1-65535 +r niftyllipika fcUq5mZ6MFNrojg80QLPwk8grXE 5SSmGP0YPcdR6B0rz7xXyfai7T8 2020-04-20 06:25:34 185.220.101.9 10009 20009 +a [2a0b:f4c2::9]:10009 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37500 +p reject 22,25 +r dreamatorium fdKaZcNwuGtb5wbqOxQXdFcUyK8 L1lm//NBq+Mus5h3mjWJvLrQpsc 2020-04-20 04:24:14 89.31.57.58 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79200 +p accept 80,443 +r snap277 fdmrSthDiLz8OM9II11vQW5SpwU 1z8g8HCRbArjS7ymarSGKs7MRII 2020-04-20 09:22:00 108.185.223.157 43047 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p reject 1-65535 +r Symphony feHozy/CMQU645SV9HpgnaA0da0 72A32L76FBqU/9UiuP5yvYLD/vY 2020-04-19 22:19:51 51.15.206.48 9001 9030 +a [2001:bc8:47a4:1f52::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r celerity fevQk+JQOSbDAnrrDAMKGohWKlg 4jUmW9RcuItf7fsz9qBCjxnmjK0 2020-04-20 05:33:10 90.65.152.93 9001 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7530 +p reject 1-65535 +r niftyentry91 fe5W2UZGCAjwrAc7/InZvgL60Rk RNeRKG71BaA4F9tdTmETKfmkhdM 2020-04-20 10:51:48 185.220.101.231 10091 20091 +a [2a0b:f4c2:2::231]:10091 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6800 +p reject 1-65535 +r ZurichDistrict4 fe8C1ssFk3ofaikjhAyMbNJmtMI 1hfbp6JqBa3HJrnQwSlwMBWylu4 2020-04-19 21:08:56 213.160.38.238 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=480 +p reject 1-65535 +r AccessNow008 fgBqRqIizkL4S0oXVpiztZOns7c M+xxQGGzGBE8GZkmJVZ5ACmn25s 2020-04-20 10:32:15 176.10.99.208 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25300 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r ididnteditheconfig fgeNE8OpS0NIai+KKB7tYAenrSg yYIBvIem5q2f8UirYgEQhLKqHoU 2020-04-20 08:54:52 217.76.158.244 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22 +p reject 1-65535 +r baroni fghzSQk3jX84/o/clCncwVIe61c UDfo/4M1udPlyfgRfY7vlAsJElg 2020-04-19 18:52:25 160.119.249.239 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=359 +p reject 1-65535 +r niftyporcupine figc0sMVxPeoS8fIchw7yXTdv6M boiYedZrtRGsPNUPXYLOtYKfRlE 2020-04-19 20:26:46 185.220.101.16 10016 20016 +a [2a0b:f4c2::16]:10016 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35100 +p reject 22,25 +r 15T01 fjF8+kTntgE95Lxfg3w3ancXnHI +HwtL8GVJc6dR4I/MOaHkcTYqkk 2020-04-20 01:16:56 92.60.37.105 9001 9030 +a [2a03:4000:33:1c8::13]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3420 +p reject 1-65535 +r CONNECTICUT fjX5dBT9zGFQhj9S9r220SF61sU ILe+WJT51rA0ZzEcUz8vP9Tp0R4 2020-04-19 18:59:35 209.141.37.231 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3710 +p reject 21-25,119,135-139,445,465,563,4661-4666,6346-6429,6660-6667,6697,6699,6881-6999 +r mentsomedle fjbot1qA7qk1nZtGLe6uHuF4Zm0 chi+AxTM4e7t58boTCkgcKJqE/g 2020-04-20 09:23:09 140.82.51.196 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=854 +p reject 1-65535 +r ChaosKnight fj1rv4XtGie0J120Y7BEoLffaRs xc0hfTzyU6PxISHcebsEgsqrwIo 2020-04-20 05:30:13 205.185.122.208 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=130 +p accept 1-65535 +r torexit42 fkTg05zoZmqY6l3ry7jhKzkGQQ8 DnaASjYmU5DTB3MMFrnmyOl2eYY 2020-04-20 00:06:33 185.31.136.244 8181 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30300 +p accept 53,1194,1723,8082,8332-8333,9333,18080,50002 +r ARCNetWork fkfSjwdEO1f4Ji4UEpNrPiWGlKM 4WmFvgQiVu9jYE4zqPcsPMZdCfM 2020-04-19 20:20:05 173.249.29.137 9001 9030 +a [2a02:c207:3002:6974::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r cn1akatala fm2ua9y962k2EnBLv78WTFD2XlM zKZXbjSU6/Y1ckze8xUDNgtwXBs 2020-04-20 08:13:50 103.73.67.198 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r Quintex48 fm6ab9243HyS8M/MPL52wp8GF5k JtiTaUPiTqQ+75HnqiyKqzRQyVw 2020-04-20 06:50:51 199.249.230.71 443 80 +a [2620:7:6001::ffff:c759:e647]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r torjockel fnRh+LTEGuYXJARj5cyDkFXpgQc 1EfApZiMKuXvoSYDnJuCI1ayFDo 2020-04-20 08:30:07 149.56.44.47 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r pitfall fnfMlNlMCGCdcLUX/5OMxhyfgjI Jbeeahjh53APTn8GzN+x1H0PywA 2020-04-20 05:52:20 185.100.87.241 9000 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SoftPower fnhpgpvyAHi+ALzqO0KXH1vY1YU s2P1M+aqRxNb+3UlLamrwVIWgLk 2020-04-20 07:35:17 206.63.229.144 4031 0 +a [2002:ce3f:e590:1:1::15]:4031 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3 +p reject 1-65535 +r Carrie foWXuznUx+3Eq/dTi2UxZVotozQ K1EaJXjdl3eUQO5ofXckxz24q4I 2020-04-20 00:52:56 15.188.107.107 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74500 +p reject 1-65535 +r minotorus fovEOuderhbX7EZ29KXDVfRUuAk gxmIDnr2LVdJYOZZuX8gWLUZJqw 2020-04-20 07:49:52 94.23.194.134 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r dizum fqbq1v2DCDxTj0QDi7+gd1h911U uhPxE1UgJqaxBge93hScWaY44rw 2020-04-20 08:12:19 45.66.33.45 443 80 +s Authority Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r BobDobbs fqqpqaGwuDS3TGDNu84wbKf5FCM P5uxk1zJtB5vkhXBs6VZtlvvHJY 2020-04-19 23:11:16 190.246.222.162 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=160 +p reject 1-65535 +r rulistan fqs4ySV7XqqrtVHGqj7s8vRtqmI h3WpucpJN/35BZ2ZPsjwxzzmce8 2020-04-19 22:01:00 185.183.159.157 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=812 +p reject 1-65535 +r jbone fq+eVbm0BTKvLbW3A5LzDlqhxZY Ufp/aAwnp3yCMhbBb3dzc7jftHU 2020-04-20 05:45:04 188.168.34.90 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2290 +p reject 1-65535 +r moonraptor frhrBXp2GwhScwSWQoY++drK5ug M0J6b+B4cdql5GWbmtELVCDSM4Y 2020-04-20 02:04:18 109.74.206.21 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1120 +p reject 1-65535 +r falared frkf22jq06E4CNk1bagmBXcyFfU 3rcw4Obo2atNpZYIcvD0pZM9UxY 2020-04-19 21:41:15 148.251.81.16 110 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p reject 1-65535 +r nuruve frw3WoLRG8pVSQKrkhiI2M/Yquo 4O4BccBp2vysXr/5pOuWtegIsQQ 2020-04-20 12:30:48 181.43.208.239 9019 0 +s Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=34 +p reject 1-65535 +r TorBerryPi01 fsohXVsGEdWmEx92Fse2AAN4G3g 7ax9jpFlNIG975TS7bGFSHlmS84 2020-04-20 01:14:59 93.198.218.48 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=760 +p reject 1-65535 +r Unnamed fsuyKinqkL07/fW6UqX2ETQlI2g 2nr7OkCuJFzXg9c6ILmjTw6nF74 2020-04-20 06:43:03 213.219.37.205 9010 0 +s Exit Running V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62 +p accept 22,53,80,443,1190-1200 +r brattastic3 fs8pTEPblZvcDn78kTw6wjHedEI 1+iaBokEECHa5y28PCjrb5yVsjI 2020-04-20 05:33:05 209.240.109.238 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r niftyentry100 ftPYr6x1D4zAvfjIf+O8uiu+Igk XKqkBPuD1bsEVUAJJ1+lLLF/GZY 2020-04-19 20:25:33 185.220.101.100 10100 20100 +a [2a0b:f4c2::100]:10100 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p reject 1-65535 +r nanas fuu/7r63D5lJX7+fUyGj4vemKOA TjeR08Lln7iEmMOGFNuHJdunLSI 2020-04-20 08:15:21 85.17.88.177 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=32000 +p reject 1-65535 +r MaiaAlston fvbpmFZCEfuGiB/qJieqkRm9mEI OANj4zXecYhfu2S8qdvCshwhUwg 2020-04-19 22:50:28 31.13.195.248 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2090 +p reject 1-65535 +r captain fwTgica+2D4E+yrhlr3jS4CAlPU f0FhZIUNK2JO3tlhbxsuOFUPW7g 2020-04-19 19:00:02 142.11.201.90 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5500 +p reject 1-65535 +r DevOops fwzz2WwckQAgFJ7qWhApQRfcZ6o nHCgAypHUYjo2JfhxlHJBXXvX3Q 2020-04-19 22:59:08 23.129.64.184 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8480 +p accept 1-65535 +r ToRRTHoRToRRRR fywPsQqMlyUIn0AVCPbT9vU0R1s EVbMjMi//JNfLxTTcxfqtXRJ2hs 2020-04-20 00:44:01 24.118.12.208 9011 9040 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=72 +p reject 1-65535 +r PolishTatraSheepdog fz0g5yok7S69kqqcQwuAW6OJ0Cs rhBq3AIvI7TqygdcxWub/MheU+0 2020-04-19 23:15:36 31.6.70.71 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r anonymous f06eyCFUlJmRHIchoqRHz568Gqg 3a6sCpdbjnyI7kFiMShSdooko4U 2020-04-20 04:19:01 182.171.233.68 9001 0 +s Fast Running Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=790 +p reject 1-65535 +r tor4ever17 f09G5OhW80Whsh8yvEitxtwNJno fr5JllgnwfwJNGeHkbftwfh0T/g 2020-04-19 20:34:45 45.62.227.10 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=505 +p reject 1-65535 +r TheWindyOnion f1OJjYXBhABjsv5WeyM8CYQC91g rUSNYQi5ub+F6OCpzq7yNNvxInM 2020-04-20 11:31:46 167.88.7.134 9001 9030 +a [2602:ffc8:1:18::1337]:9001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3060 +p reject 22,25,119,135-139,445,465,563,587 +r Unnamed f1jNGb959yD+541oR0oiTkBQWZI WkrG200XQ/X2X+qlRc3XcN6+A1o 2020-04-19 19:23:38 193.176.85.183 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6300 +p reject 1-65535 +r sharkwire f1lA99ZbB65cLHoV/opj53CLlQ4 ZDt956wcTMqcsl/xazHXqixCuII 2020-04-20 10:17:54 2.205.196.120 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1510 +p reject 1-65535 +r DKrelayasa3 f1viZqvbPnBFEVidqsaNOxsLf7I WWcQtuxIBXhP/gKhHZY1F/NwC/Q 2020-04-20 03:49:47 81.161.163.140 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8610 +p reject 1-65535 +r Coatltor673412 f11acu4FZYbzdDdR75Cw/fQu+cc YG5FIRDxSghRvVTqQdd36nt24nc 2020-04-20 01:27:19 84.142.203.177 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2610 +p reject 1-65535 +r OONITestHelper f2S4T6eIlogEHSQTrWDqP5ymgB0 YBhq2vK8JnlfwoVLdhryJtcfQOg 2020-04-20 11:55:57 103.104.244.76 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=570 +p reject 1-65535 +r Hmmmmmmm f3RdIS/SgXVrElSzuEouil/YmpQ 5AG2YOzz45wdAlB4VE5EDaKAYVo 2020-04-20 04:10:07 116.202.179.148 443 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1150 +p reject 1-65535 +r niftyguard02 f3vnkmr3GNaj3tJNaU2UwdX6zyg Fhyk3loyHDCtEBMYIytQ9nL3gXc 2020-04-20 12:45:26 185.220.101.211 1211 2211 +a [2a0b:f4c2:2::211]:1211 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40300 +p reject 25 +r EpicOnionDefender f4MkSJZTtj9IiGS3rke5vmCRvZU 7nxZV+8M5Qv3oan2JwtOgo5HXTE 2020-04-20 12:44:37 190.130.151.29 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=590 +p reject 1-65535 +r king f4fRQrqRsOIKO3CODDnijo7roD8 tqC6zMbxqa7ccihJpU3pN3JmUiE 2020-04-20 08:20:24 51.89.200.122 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r pewpewfaaast f5+2vYfZ4hYhc/T5WkE5nWKoQRQ NCTAnxvcGQFClPJLo4Wt7ALgiUw 2020-04-20 03:24:36 104.244.77.95 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Nisos f6P6UlkBqRoTELgXlDZovCwWKJ4 EUlQvMr+zhpWokp/MDZmAFaG+pY 2020-04-20 02:45:56 138.201.87.38 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62000 +p reject 1-65535 +r Quintex20 f6jn5E8TkqTkD/w7ads7AAkbf9M gzIFCTmZ+SWePM9ACCe4evbzMI8 2020-04-20 10:53:41 199.249.230.110 443 80 +a [2620:7:6001::110]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r km6p31yo f9bJq4OXYbMzS8m6joVDJhuTu4g 2sVr5XB9Xv8cOB+sTtGseQER1V4 2020-04-20 10:20:39 81.182.119.76 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=600 +p reject 1-65535 +r Unnamed f+E+xSOv13IK513heh867l0odEc aO3Ulzp1XOa+vQ7BLb1vjEe0jsY 2020-04-20 00:01:00 185.112.144.53 443 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1290 +p reject 1-65535 +r webbsonTor01 f+gGW8HIyrz0mpqMnccClhN5mac zJPMEd95VvBWtL0ux7Xw/cA/rF4 2020-04-20 10:19:46 51.158.191.0 443 80 +a [2001:bc8:1830:140b::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10100 +p reject 1-65535 +r MiamiHeat f/Gmc6Xh9+nSSVo2wYW4kNvZZVM oKZFAtHhI2cGA67M2xtEZWnhkWQ 2020-04-19 21:22:11 51.83.236.121 7777 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12200 +p reject 1-65535 +r edxred f/I+jQq5naeMgdQeUabiDrhL/Wk cEqiaK/MldpyAV6csFw90xUZvfE 2020-04-20 02:20:48 45.63.116.104 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=268 +p reject 1-65535 +r lebreton f/lDIJY7XNr5oHLOm+6bTx8rODw Fi85bUODG8W9mi6BqvVHprggtEE 2020-04-19 19:07:56 50.7.186.38 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5700 +p reject 1-65535 +r greluc0 gAJnclrws0Jl+2onlas/dDpj3ZY wupXXziJlzCTdAoOIt2RUYrFebM 2020-04-19 20:53:38 217.233.93.239 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4800 +p reject 1-65535 +r snap277 gBejk58JVPV32ZMTHO9oOsduVf8 prnWZa6veytyLQ70P2gP7KV4wPQ 2020-04-20 12:15:18 201.82.102.218 33427 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=81 +p reject 1-65535 +r anyname gB/FRofjgMIm01zX279z/NRC6ms mFFJRM0LeI5UyCKj8608xWJ+uTc 2020-04-20 09:21:44 82.146.47.17 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5620 +p reject 1-65535 +r limitedhangout gC7KnWIyLSFSqh1LsyX7mxaaf6k GeI1uTxRE56vBkY91HlecvzzABs 2020-04-20 05:09:27 145.249.106.102 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1280 +p accept 53,8333,9999 +r GKrvrs gDoK9IIQpjE8mMZQ9N2acWzkV0o H4Oa5VSnfGpfFgfm4eD0oNqwCN0 2020-04-20 10:04:36 174.127.172.185 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6800 +p reject 1-65535 +r Damnation gD+5i6D+FwnAh+kTjMYJbyIIPKU coHlr+KDI+3bO03d6gquSYZ0W5c 2020-04-20 10:45:44 123.255.62.137 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=113 +p reject 1-65535 +r niftyguard57 gFTxBYKUOLAp5yZbsQcPklhwURI 509agn9mGh7soeRRLT9i9TR+eeI 2020-04-19 22:16:25 185.220.101.176 1176 2176 +a [2a0b:f4c2:1::176]:1176 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 25 +r rohtidanoshis gFYIDugitcoaj/9StyQqgsXkL7s OfrQcq+YzL1u9/9UTvM1y9ER4xk 2020-04-20 03:34:42 185.246.128.161 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p accept 88,110,143,194,543-544,554,749,981,989-995,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 gGc/S+CyW7tDTQemcmCYSYlpIEo DqB0vYtLVyt4SUNe/cDpxYoHKSE 2020-04-20 00:45:56 149.200.160.156 39353 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2360 +p reject 1-65535 +r weiner gH6mSnYdGh/jy9Pq1DIoPJoNUjw mnn4u/u5+1jaY/F9lfRFFtRYF7s 2020-04-20 00:44:24 50.7.178.98 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5910 +p reject 1-65535 +r torayne gIEuOzgNbZpugcfh0ifzY+bLX+Q vwCMk2jqfeX5DhrZV6qbluPqcj8 2020-04-20 11:34:29 208.110.97.231 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r camus gJRA/9V1aWI531P0XUlYDk5hM5U 3+zIZ++KKJuKjJ8ew136kCyd5xg 2020-04-19 21:49:22 24.7.200.130 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=164 +p reject 1-65535 +r bavarianOnion gJRvL2kWowRnaTqZwDojB8SqYbI jiKScxl+Bs2p2JNaQf5ZhR9yFQk 2020-04-20 03:15:34 89.247.161.22 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=548 +p reject 1-65535 +r Unnamed gJeeyTbkjxviKXXzLxLgaogW5Mo YmncDfK19lRGGdnpBG63EUXGFb4 2020-04-19 19:37:40 167.114.89.192 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r mdfnet2 gKr41ZVqQ8GXEEzvJVDNQtFlxvs ewK7345fX9Ev4z4MfpLr3iOzHjw 2020-04-19 21:21:53 193.11.114.45 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14300 +p reject 1-65535 +r TOR01JKL5Group gKsWfkY9yXfwsC1ogOY9wpgCmHU sf4jkLzX9Lf10AlJzSorXvtRzJs 2020-04-19 22:37:47 172.105.98.201 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8060 +p reject 1-65535 +r ScarletTitan gLLdrjriNX0RhXjIJ0jvVVs5lAk NAaCfZiM+/HlzLXi1ItphCdj2UM 2020-04-19 22:24:47 41.215.242.42 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=166 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r bambam gLj1rXn1YW7/gWa04hKJJPkN6PA XWMzl+aKsbdlZfkhyIOOzZ+bV/Y 2020-04-19 22:18:07 178.202.249.204 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r dizzy gMETvOk1a03s+U589KjAvTFe6Og so1mBswYuWbgV1drTQ+fruVLObI 2020-04-20 06:19:08 80.90.39.25 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r Oxygen gMXWf+E+Ol7b9N1C44Frdj1dQ0s KUvpXhnNIFhILBfF++fkk0za/XA 2020-04-19 23:01:52 94.130.129.15 9001 0 +s Running Stable Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6 +p reject 1-65535 +r Aequinoctium gMf9OWTIyzY9idhf6lhWtv2Mu5g kXC+yExInvz/o8o8ClvXt0EYaBA 2020-04-19 20:44:51 62.251.100.171 9001 9030 +a [2001:985:c344:1:ba27:ebff:fe33:9eee]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=99 +p reject 1-65535 +r default gOPK1pqqnentnLZTHKPXP2+5/lI PBYfkbQ232r+gF6sbL6rpkY85Gk 2020-04-19 22:27:33 94.19.217.76 444 9030 +a [2001:470:dfc4::1]:444 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r snap277 gOYrLLq0Ht+cJrhqOjdzZyxqmp0 86uUDxis5E1DaMea0woruhwA+X4 2020-04-20 11:18:09 201.158.136.152 39125 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17 +p reject 1-65535 +r snap277 gPZYboEZphvVoKJSXfWC68kiLyg 6BtGLvlnl4dtrWaCf2KlI8PvR1E 2020-04-20 06:33:53 177.98.158.237 46635 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=232 +p reject 1-65535 +r STANSTORNODE1337 gPcvl5Z4Bq1a1MHmHIi0PcR/Zgk PAAyI2O6+8dIb00Cy669z/mtDWM 2020-04-20 11:46:40 66.85.92.15 1337 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3190 +p reject 1-65535 +r Powerballs gPictCoSV6YUXBsdZGPHlcuZpqQ AB81nT/pbAUTcPqlF6/C1FFWE20 2020-04-19 20:07:46 173.249.63.227 9001 0 +a [2a02:c207:2026:3509::2]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8120 +p reject 1-65535 +r Unnamed gPmsgeDGTGz+viZFIsVFYE8sQ2E 8B0r4gcUDlGvRNpr2P1FLNwK764 2020-04-20 09:21:05 46.127.38.176 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=560 +p reject 1-65535 +r rofltor01 gQFCG+/M9MJx1Ug8WqvKrSRbu50 OFviIOK/DniOehiylFCld0PW+AY 2020-04-19 19:16:46 51.254.96.208 9001 9030 +a [2001:41d0:401:3100::30dc]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16900 +p reject 1-65535 +r Unnamed gQFh78YMdA16bvYlQ7SMA682gMg u+gTLc7a5Nf9lgncoDM9qs8BYsM 2020-04-20 00:59:07 46.229.55.13 45869 57069 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=239 +p reject 1-65535 +r thardes3 gQHAfMnn8AHM1/Ox0MrtArwmPYw wZep4HQnqu0JJ3jmDK4uefY79qo 2020-04-20 01:14:07 78.54.213.231 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=97 +p reject 1-65535 +r TugaOnionMR3 gRH+tF7ylQ64+Ev9j/Bwqweu6d0 X4mBgqfJ1Wbh93n4gmfi+0eNfZk 2020-04-19 22:50:29 152.89.106.147 9001 9030 +a [2a03:4000:39:605:c4f2:c9ff:fe64:c215]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58800 +p reject 1-65535 +r jitter gRb2IZR67lIqVrPrzgB2KrjPa4U EuX9Uw4qFmlr/H6fktnetpvQbLk 2020-04-20 09:03:17 95.81.20.188 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=653 +p reject 1-65535 +r wilfong gRj0wOYMhKRTrM0WQfOnMoy+YoA D60wZ1fm+2XtbTYZm0yO3Ea69UE 2020-04-20 02:55:58 178.32.189.88 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p reject 1-65535 +r shelob gS0X+XTyzNeq5YWoeXg8Lvlmh94 9TQIQiDaLUNlZv3cdEGY50gMYtM 2020-04-19 22:58:03 23.129.64.211 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p accept 1-65535 +r capeaturtraffic gS+JpK0FlGR9fhpYpQhwUE48TEg BuzpUSpWpQwe0or5czqE1/5kizU 2020-04-20 06:43:58 45.33.47.218 443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p reject 1-65535 +r king gTjbTxJWnQOjV3HkyBoVCnADE1w vdyP7Y3u2XO4mFPVfQeEC93Pd8c 2020-04-20 05:18:44 51.89.200.110 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12600 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Tor4eghaineebe gUh6TIkoTCmbH8EzHaORDChbbsY z+FlonE7vexPOpmXYPmmD+1JIUg 2020-04-19 23:56:55 91.121.67.146 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=68 +p reject 1-65535 +r salus gXhFYMYTxfgbPCe2iiNOGgxCqYE 4xg3+csbiV/LAzVJbRwQs5VnK5s 2020-04-19 22:34:23 97.107.141.130 4731 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1560 +p reject 1-65535 +r Unnamed gYWkPhF29iHc2VqgS919GzzOt1w EHNC1sED3tE3M02Tt9Qk4pCULzs 2020-04-20 11:59:48 199.19.225.15 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1820 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed gYhIEHoRPTRCw3rRPyIOhXs5FKU f8nqRdVOiYghe/6Baz37N4kaniU 2020-04-20 00:06:37 176.158.155.120 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p reject 1-65535 +r ieditedtheconfig gZGXVVQ/5y26Ra9OsK/7/OGPbVI DVCi1MmUxEo5yKEEAINjj6PqQ+U 2020-04-19 19:41:11 132.216.54.2 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2350 +p reject 1-65535 +r Unnamed gaF5PUM49s1EjoZNcJD26RQk5ec vZGLpANYAibfA2vWHacLfmZlGEk 2020-04-20 12:00:06 83.220.174.80 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=76 +p reject 1-65535 +r evudalhessempos gaHXd8Aj67He6ef6hzVim6j3SXw +cyPWpudTHqyOAO/hlWxVDbaMUY 2020-04-19 23:39:09 185.225.69.91 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15100 +p reject 1-65535 +r chutney gaWXZicolNJ/6DdcT4OmukU2ce8 QLIKR7w8kE4GfrMF0XPq3wslcwo 2020-04-20 03:19:03 37.252.190.176 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r espinoza gaWwLCy+IqhHD79u7u5X1UZKr5g 1W9LD4C19mKrK36djzHt2hpQX9g 2020-04-20 07:44:30 62.113.209.110 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2480 +p reject 1-65535 +r Unnamed ga2cInb9cff2s1ijHp4qqd71/Bk upitvU4FmtWqXmww0ipQgV3MccI 2020-04-20 12:11:15 81.205.147.109 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1250 +p reject 1-65535 +r bing gbI0hcixONJyeR2vC6+o0VYV0eM uC4qISosSyk69PGujn0Yql7w4zU 2020-04-19 20:32:52 142.93.210.1 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=318 +p reject 1-65535 +r hviv104 gbddU0+Rv7fFerZ9oQvO9iJYKug E6w12eMvzY+EtUKvMEDAr3MZ65Q 2020-04-20 07:10:47 192.42.116.16 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r InMemoryOfJohnKerr gcVdQDqCv258P729QdECtwiJANk ExV+BFm3XbXM7nFnuEClpB8sKt8 2020-04-20 09:57:28 162.255.84.248 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9660 +p reject 1-65535 +r GoElephantGoGoGo gdi9rrhuFqrsLrSjlaeR5Dpzw1E eVcCJXoXAQdSbsKR6x31o6h40t4 2020-04-20 09:43:41 31.208.8.132 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=120 +p reject 1-65535 +r snap277 gdxu/D9G7DdDacWc6N4TtSIGRtY ydy6XGaJAjK8+4O41gr3OMR46dE 2020-04-20 11:03:02 85.225.75.230 35385 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2640 +p reject 1-65535 +r Stinkyfeet geD2L/Joepah6cTJHg8GdidjONs KPsv5wU7kY01od2G875tCFKrUH4 2020-04-20 10:49:30 104.244.72.99 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8500 +p reject 21-25,119,135-139,445,465,563,4661-4666,6346-6429,6660-6667,6697,6699,6881-6999 +r rosskemp geGHJTl9Yg2lSKu+JNnNJj3vL9w Z8g8ineUJNaW1IXYnloOSU8P+w4 2020-04-20 04:43:29 176.9.119.40 9002 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=91500 +p reject 1-65535 +r acab161 gefVrqR9ohAwEYKXR13FmgHCkeE ESrQb74p736rZDWStAK/7TyHWF0 2020-04-20 06:23:50 176.123.6.10 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p accept 80,443 +r CalyxInstitute17 ge37yPb1x88K3V+OCLyPq6BAicY 0kSidcm0p2msJwjDgjphTcP+i0Q 2020-04-20 03:43:46 185.220.103.5 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r frantz gfWeiTbQshBRguS4IArAfZJ0lh8 vmcvj846emafLpslDd2sFoQ5fJs 2020-04-20 12:26:56 37.220.36.240 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p accept 43,220,389,636,706,749,853,873,902-904,981,989-990,994-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r mirinska gjGDzrdUzejnajci14PKAx5+Fgo 849DiiWuuKSpdN+p4nYUTBWJ8/s 2020-04-20 00:24:54 95.141.35.15 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p accept 1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,50002,64738 +r DefiantDaveRelay01 gjcB1cTF1yw/9TMRPyWhki3tYwM 4vqMNHSD0pUcSwHZ1ybs9cLAVA4 2020-04-19 21:21:19 174.141.200.41 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r noonesland2 gjdcKxrx09O4vOib+uzWLEs6dXc eZzOe9oiq/1Zhk6EUDjAwx3hx+w 2020-04-20 07:34:55 91.65.86.238 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r RasticTor gjnG/c/by5QfMWDoGmowcqN3uyw LPXHQF73AoGpdMGli5Jq7zEXsO4 2020-04-20 02:38:27 85.92.42.43 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=126 +p reject 1-65535 +r snowfall gjqoHid/NmUFVFUiztwvUpzk3D8 YJFLRDpuwpO/l7epIMfookDeXn0 2020-04-19 21:28:57 192.160.102.164 9001 80 +a [2620:132:300c:c01d::4]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r maddyTor gkBWeeHyriWPuo3UW7KlJzXu7ZE 9hsRRgzjNpSdv/kAWaiXbXl0I4I 2020-04-20 08:15:29 173.212.194.102 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r smell gkjkvB5vzpq9fnxJ21CnMOGTPs0 qVSxTfL96BRox+xTHqVzjR80V+4 2020-04-20 01:24:05 199.19.224.84 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Unnamed glrV0zsqXEG8ZHBH1rY6xBxMUCE IlCXv5yx/7U1GaxiixwMA7D13Ic 2020-04-19 21:02:20 78.94.253.253 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=219 +p reject 1-65535 +r schlafschaf gnXOIMU9eexRyocpLn/FjyOPEAw Rrb6fISa3LxowzsyMCuDYuLH65E 2020-04-20 02:56:58 130.180.63.150 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1450 +p reject 1-65535 +r ZapekVixen gnnkR5+uteUy2uU/MXYKoalEcEQ b34kJPGqaVKbXQaJvXavSe5WF+8 2020-04-19 19:08:24 37.187.117.123 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21 +p reject 1-65535 +r noisygerman goESuA0oqSMRqMbHzPNpsxbEB0Q vFtHnFNpCqGnueXIC91Qe44inSM 2020-04-20 10:46:51 95.217.97.138 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r snap277 goQUHoQrfMdZeox/Vl6jIC26kZk 3Hn39UwbQANvcjYzvE2Iy7AIFq8 2020-04-20 06:32:03 122.175.75.130 46285 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=337 +p reject 1-65535 +r Unnamed gonVlwcACYbs09iEPdyxy+zzUps aeH3ep7l81ggmM6KnannhqhGcs8 2020-04-19 23:06:53 77.110.173.117 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=430 +p reject 1-65535 +r Unnamed gpaeq3yU121ixOSPNHGgjXGIlpI RTZxru4gYfH9M11ISX+uHfHL96I 2020-04-20 12:14:38 134.3.131.126 9001 0 +a [2a02:8071:3ec2:b00:ba27:ebff:fe64:6704]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r snap277 gp4L1eRrOH5uDvDG7sd2oz5Yfbw UrxiIHHgmGW84rR+AglWidi+WeU 2020-04-20 02:28:29 47.156.21.67 45161 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r AbseitsTOR gp5L2YA50j6Cb+uCLzWpO1TFFi4 B96agWMBr08MQoGQREU28icJtBE 2020-04-20 04:07:43 86.103.8.161 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=25 +p reject 1-65535 +r snap277 gqQKLOS3h8cbKSvTjNAjjobbMHc RSHWHWjI7uVxiHq9mzVyut9kvsk 2020-04-20 04:24:07 5.167.67.108 41277 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1470 +p reject 1-65535 +r Unnamed grMtoVpf5/0bFG5A3D2ymTmVCDc OCuCeb3trK2lT+H5lQev0rgTIlI 2020-04-20 04:55:44 163.172.42.4 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24600 +p reject 1-65535 +r skydiver grlGY/FBl4+yJSoWan/P8Lo6FwE ZKxhMhIR2gf+DYRiPGlvH05oNiY 2020-04-19 20:37:56 93.104.209.61 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p reject 1-65535 +r busyspinRelay gsvh5wvJOahk6fue+Mea7viBgo4 dnEzU0ZynE60mpat3ig05+JH+4c 2020-04-19 19:27:27 173.192.213.234 443 0 +s Fast Running Stable Valid +v Tor 0.2.9.15 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=11800 +p reject 1-65535 +r hacktheplanet gtOfy8Rq6QSxysBafrTEyPq//eA MocFKf3rY52kLb/108qqLTBAiFU 2020-04-20 05:29:45 87.71.139.47 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1610 +p reject 1-65535 +r eunyeunrouting gtVEpyoQfkGSo8odZJppbrH9AqU QYzhh6gyyDIQVTLWLlWXtwGlbiA 2020-04-19 21:51:33 85.10.200.109 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=90400 +p reject 1-65535 +r Ichotolot63 gtqWeKC65gCHqmij4dbmosQkbW0 1QejYA+QV+9npkgvvrrXJ4TrVvQ 2020-04-20 04:33:09 91.143.80.147 995 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p reject 1-65535 +r EVANGELIYA gudRSXwMuSS1b0EuhpKnPjBR29M OX9reppCaDj1AuI39bxtY5vqz3g 2020-04-20 09:07:45 87.121.52.47 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5010 +p reject 1-65535 +r solnettor gumI2t+DBR7OadZK/EdmJ4jYqh8 oXIwFHFGdFzJgWbvEV9RYNUrkiw 2020-04-20 10:30:24 134.3.19.128 9020 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1980 +p reject 1-65535 +r tarf1 gu2a7JQYTsbdKZpc2zN4sEuxdIk iJy8H8dksXVBeQcxPvYl3gRnLmk 2020-04-20 09:15:18 176.9.156.202 9001 9030 +a [2a01:4f8:160:42d3::2]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=139000 +p reject 1-65535 +r rwa9xgn gu7cMeLnhlnt0azro9wPHZi9Kss PfIcc49DicK7KAAqp7Q0ZmmoF8E 2020-04-19 23:43:47 45.79.192.87 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2670 +p reject 1-65535 +r citizen17 gvORKSFfocTmUGOwYMY373vbmfo BqVNqvCkLvVVyMZc5xaflaKuEIk 2020-04-20 04:52:48 83.97.20.101 9001 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=390 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TUSIEK gzgbn3LXU/P1elOA9sbS6wekg38 AtygGrAdfo2QiBnogtk+Fkg80xw 2020-04-20 02:00:40 45.137.155.56 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2640 +p reject 1-65535 +r malekalcom g0yR3usv5P785VqZw3iWj7ZZEVw 6fU8dOIEk8/I6/I7TG2Z2QHmNcs 2020-04-19 19:34:55 37.187.12.100 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p accept 6660-6667 +r Unnamed g1i92pyaaAtOOigJ5cJPWzYk1cI qKfq0Rm4g42z55MXXeq+yk1FSiE 2020-04-20 05:11:08 51.91.73.194 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68100 +p reject 1-65535 +r UristMcDerpsNode g12IrpkMo6M6SfgA9krOWA9MIf4 jgjkaO/IqJwjum13DwMLrkzJSY4 2020-04-19 22:22:28 144.217.92.215 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10500 +p reject 1-65535 +r Unnamed g1/+ZC76O7eTZmPSNloV0xn7YiY IAFw/8OZY29IWKUq5n1FzW5W2c0 2020-04-20 00:40:28 109.87.25.148 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r nidermegator g2RgxyFXeHOtH/irAAESqTYOs6A 5POB5Hyfgr37X6D4XeDRlOoLrP0 2020-04-20 08:41:21 51.158.170.79 1277 0 +a [2001:bc8:1820:507::1]:1277 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19600 +p reject 1-65535 +r McCormickRecipes g3D8TBkNACD6WU2CMt/jS1swrwU YcJU9Osqtq6g9OxkrpagtgeKM00 2020-04-20 11:18:09 18.27.197.252 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Brexit g31epRPff92ja+VpxkYVHNpLmTU du/6U0DEqkelU3fNSWsyPTytH4I 2020-04-20 05:07:13 31.13.188.43 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34000 +p reject 1-65535 +r aldabrachelys g4dJ4AZbeQhtErXB14abme7+HbA hckODsnZzGtMSatC4cqlRIKT8tg 2020-04-19 22:50:55 141.20.33.69 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2580 +p reject 1-65535 +r Unnamed g5TzhIbp1ezCN+2EPk5aD5Tsg7c /HEQ6hu/SWgzvh7nFs1X0yoKsCk 2020-04-20 11:51:42 104.210.15.27 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3800 +p reject 1-65535 +r smaug g7SOaMMcE6oS4qn5wcvh2bP04Do u6uuX5DAaDO2IeyRuwhVfioF4Y4 2020-04-20 11:05:22 130.180.51.242 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=380 +p reject 1-65535 +r Champions g7XblApxm2f1v2Fv7snY1Pdk0as WrIwGnN1JkFVL5hEky7fxj4dv6s 2020-04-20 08:02:25 68.14.177.196 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1320 +p reject 1-65535 +r tor4ever6 g7kcL9LtUunWh/MvaOLlQwU9YmY IJIrFMrZGf1TTwgtaKlS6gCjSFU 2020-04-20 03:32:03 45.62.230.82 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1270 +p reject 1-65535 +r snap277 g8zVb3ULpcoE1mK7XkeaG/bPRe0 ZiBizqIEiLMh1fU0pBDIouFF/uo 2020-04-20 09:13:12 94.46.224.140 35703 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=61 +p reject 1-65535 +r PIAnycexit g9D8i2eRBW+u0B/ScXppnT2Xzr8 GubWXXGWNDXhtrtzzK67dTK0Gx0 2020-04-20 07:16:29 209.95.51.11 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r justinian g9v9A7naR2e/WzIIGKqAMYKdkXc IyAIjCb9/DZ6VPvi5+ZPHTatiuM 2020-04-20 04:47:30 104.236.151.160 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=140 +p reject 1-65535 +r snap277 g+3aZO531eMoWNITcZixwCLGGB8 NPQpM2eZ1ylXsQPNaCm2YF7r2ak 2020-04-20 00:24:25 82.225.92.178 41901 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r zhuknode45 g/dbxXiTI8qftVgTp6zWEpHjESM PDQS+p8PR0dTDLIEFX4OSCudpE4 2020-04-20 10:50:28 77.232.149.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=760 +p reject 1-65535 +r ParceNode hAAeijdqOwtkXub4B9ByzI1j6gk pKx/9YxO+yyyraf07dhsC59V/1Y 2020-04-20 00:01:09 185.82.126.190 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p reject 1-65535 +r 8rijgto8 hATouKq5ggj677Fye2NxM62cb68 mQwGVPHHD2PdGT65uDWTjP0zB4w 2020-04-20 03:21:52 66.206.0.82 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=54000 +p reject 1-65535 +r digitalResistanceRu hB3h4GW8qMHr3EpxQGRvR6Yle9g EJWPYBzjigdf0DMwqRU2Jvo6R3c 2020-04-20 04:55:42 195.201.113.193 9001 9030 +a [2a01:4f8:1c0c:7b3b::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r befree hCTy7aufm9FtieHqVktpkj2VGSE c1Lh5wKKXRMjiX/TgxkL4vY8AW0 2020-04-20 00:34:09 108.14.82.24 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r TheNewOil hClOcKX9Y94GfljNBHL69G48JZ8 z9livFA6sRX46VRsnUTAG+CLEZM 2020-04-20 08:38:52 136.49.189.109 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3750 +p reject 1-65535 +r Precious hCsfbEueQfyQWd9nXF31vanw/HM 7E0XzZILMYpyiaHIV90Y7roMKvQ 2020-04-20 10:32:31 95.215.45.188 443 80 +a [2a02:7aa0:1619::ed92:293d]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26900 +p reject 1-65535 +r DidItLateButNow42 hDxPd02iZT2tuluEejPMZGmV9qE +Dp9bFnIo3L4pKhv+YMIVIyxpVE 2020-04-20 00:08:01 62.72.82.222 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1770 +p reject 1-65535 +r Smeerboel hErpytBDJelV4r4VIVY7ef5wlLc bcyObfk+yTIHrLloe41mX2euPJA 2020-04-20 05:32:50 192.87.28.82 9001 9030 +a [2001:678:230:3028:192:87:28:82]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38300 +p reject 1-65535 +r cloudy hFghzY494CPANIO460Kg9aVYLdo kWvCT7EQHl4OR1rV5yuI4z0leRg 2020-04-20 06:17:02 167.71.141.243 443 9030 +a [2a03:b0c0:1:e0::472:a001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1560 +p reject 1-65535 +r CanineGift hF6d8dM9s2Yvdp6Gg5DCWMTm67k kOOh1gk32H3KpPAQzJNXJDaRUag 2020-04-20 07:52:18 172.86.144.59 443 80 +a [2001:19f0:1604:3ede::3:59]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2630 +p reject 1-65535 +r xinchaovit hGQGJSIaTpYwmv4IELOGRrxg9Fg qPyeHZrCcaDctY6Ky2Rgg3fSWqQ 2020-04-20 03:03:48 125.212.241.131 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ULayerDoe hGXr4BVdSQfEH7C3YhbH9n/bUps 1KCxGfBWSFqgu1zx3bzanXU1DUk 2020-04-19 21:17:30 152.89.244.134 443 80 +a [2a01:367:c1f2::647]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r dc6jgk5b hGs+qvDAf/cvx5rrsR+jrcWPJA8 3Jf69dta2AiTRt84CDmta0QVv7g 2020-04-20 05:45:04 62.141.48.177 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3740 +p reject 1-65535 +r tor26 hHsfhQNE14dkkaVIkvkEk05OuF0 WfxAs/No9ZPCa0nbdHTCBapfPFE 2020-04-19 21:08:14 86.59.21.38 443 80 +a [2001:858:2:2:aabb:0:563b:1526]:443 +s Authority Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r greppo hIUbYXNBqBFjx0vzrY/3AOOVohs 1mtvzurnTOxuU5ENakhL0YiTy1E 2020-04-20 04:05:50 217.133.59.137 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60 +p reject 1-65535 +r Mellisa hIsaBQ3DX8iY6z+lYtgmcDlE/Fs L9nbDb4OjAGZ1tOSZAkfwSCPlo0 2020-04-20 06:14:17 185.174.100.47 18854 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2750 +p reject 1-65535 +r Unnamed hKdXnjhkCAY+q8Lb2uEnjg3V9qM Fd/EKQBqJm67EIktGwv0ENL6IXE 2020-04-20 00:53:42 178.62.49.147 44807 0 +a [2a03:b0c0:1:d0::102:1]:1100 +s Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r RandomRelay hKjkHQOGWCInL2R9N4r/Sscxh/I 6w/obMX7wV+sTsavdBVGrx0bVjg 2020-04-19 21:01:38 46.182.18.245 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r TorNull hKv2OB/Q+WuIJ2TxdrhZgOvDH+E +oG/hHPDs1T4Z6sowt1W5m3dZa4 2020-04-20 04:12:03 138.197.168.41 20 21 +a [2604:a880:cad:d0::5e2d:d001]:20 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1770 +p reject 1-65535 +r Grexit hK0dshU9lT5n9tiMP7QJnfyMj5o xcuJIwIJgWn9lNymcI5majc2+ho 2020-04-20 04:44:07 185.4.132.183 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16500 +p accept 80,443,554,873,1194,1723,1755,3690,5228,8082,8232-8233,8332-8333,11371,19294,50002 +r CriticDelighted hK+uGSRFQaQE92O6Di8MrYo/rPA 9lX/g5v7rt1Azi/GMCYY/l0EAIA 2020-04-19 22:28:50 47.56.212.27 22528 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=345 +p reject 1-65535 +r bitch hLqi8sO4tJx3FTBmM09dCK02T1Q BPgWdR5QR9zU7CJdO/4jh/nuHxc 2020-04-20 03:25:23 5.39.217.214 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r snap277 hLxjx5Rypg1Ns3kuai70/GBgdpQ RNkHeRm5a1THEU80q3UH99MtNu0 2020-04-20 11:11:11 190.182.210.117 32773 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=60 +p reject 1-65535 +r nalca hMAHJ2fuVZtU+sjr5WybgOt3Qbo jEsAOoYxd51cekVnMHY5+oFP+Ao 2020-04-20 01:35:41 51.254.48.93 9001 9030 +s Exit Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6660-6667,6699,6881-6999 +r Neryl hMF/TsV6F9DEoTuZgFp9oyWsEP8 mD66gh2r4Eui3FVnB/pnny22bqw 2020-04-19 22:16:34 178.64.55.45 22711 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1290 +p reject 1-65535 +r Pistis hMsHgsjKgacmPuhvMh7f7MYRNpo gNC3Aujy/ktA/Zk2bdEbkrFpBvk 2020-04-20 08:45:13 51.254.136.6 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19600 +p reject 1-65535 +r Unnamed hNFkqQbNFlx39qScl+L0yhfDqz8 e8AL7WojcOR8W2jTWPN35Y162Gw 2020-04-20 11:18:21 94.27.133.198 60395 61288 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8190 +p reject 1-65535 +r CalyxInstitute03 hNNhtzaozR6IGND8GGiS6Rq3aIE Loe90mbWbi90Nmr9H0W7en1sdMA 2020-04-20 00:38:47 162.247.74.213 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r kleptoman hNfqQEaCbjErMvgipZJlESGJDq4 41u5FpTYELevQtQa3tQc9jsVS9o 2020-04-19 21:17:33 193.0.213.42 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2230 +p reject 1-65535 +r EnimEtMollitia hN95jFHONnQ1lVYUsx5DKJ4T334 2FQ2PwWvU7O4BEIXrugB2Hb5bd0 2020-04-20 02:21:05 89.65.45.215 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=564 +p reject 1-65535 +r Taeuschland hP8FmDx1N+i89v3PbRaIxGtoRHE JfiAdZqJ+ljUzl/BJFEtRn8WesA 2020-04-19 22:16:27 95.90.110.98 9292 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=775 +p reject 1-65535 +r bartleby02 hQQefF3wQ7A/LBlCGZjxdRwALkk 3dZ6orTqFh5qeadDigpc2NnBYFY 2020-04-20 10:08:04 93.176.184.141 19001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8380 +p reject 1-65535 +r Unnamed hQsMDfwF7kK7Fy3bLzFtdy5clyo WqTP5sMzSnDHpIOukkA8EZsQMys 2020-04-20 11:43:48 185.67.161.99 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r justtesting hRPFCO3eD0hbL5WlV72tc8flkP0 kM7uSZGe1DCtQMAWGFHQvExqv24 2020-04-19 20:21:32 109.238.92.84 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r snap277 hRfPcxjRVyl237qcha4xtN6CVDw Xr6HyKmO8Wq9lHSqE31hkgDK3IA 2020-04-20 04:33:50 220.253.12.223 41289 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=35 +p reject 1-65535 +r xanaduregio hTALJqjtTRRb0t9awZl4+APtA4A N1kXDyCPxyyH6+fqA50ZEf9sFp0 2020-04-19 22:59:20 23.129.64.191 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9010 +p accept 1-65535 +r Unnamed hTrFGNCF+xRXD0axJi6ZA0nBjWk HGvyeu0J2dz2kFYeq7wgtltolTk 2020-04-19 20:48:17 173.249.32.194 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17900 +p reject 1-65535 +r torseedslu hT0xKkCXhFNZsuOJIL1spHI9OPU QjV/3AFAFrfcaXUfJQ3SgEmRRlE 2020-04-20 06:36:51 104.244.74.78 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4530 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,18080-18081,19294,19638,50002,64738 +r TorRelayOSTF hT3beLFD1nTKw5nh039Yc0MfS+c f2xRXihoPtP+hx8gquo1ZOVsso8 2020-04-20 09:30:36 90.153.87.71 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=413 +p reject 1-65535 +r KnightKnight hVI5DUPQ/uZ321TGUBGBQpOSAiA j56YWuhVUKK0UFxgCSgrVLsu8So 2020-04-19 19:33:29 2.25.225.42 19001 19030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r Logforme hVvC2r4kyGHNiH25sulQQktJ/DQ ryEPCnx4FW3uw6rOMHTQ84KVsg4 2020-04-19 22:24:34 85.228.136.92 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59300 +p reject 1-65535 +r Norway01 hWH6fYRrVuD4LLwMeYUy2+nH+DQ m+ppht5bUDLBbIsIuoHIFHPSkiQ 2020-04-19 19:42:38 82.164.239.130 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3340 +p reject 1-65535 +r Hasle hW2rL9ye7Yiie+ImX6a9VInvF44 48GUkqX2DojeWWg3Q52950HoUd0 2020-04-20 06:06:32 185.109.64.191 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r BobsHouseRO05 hXTU929E69KidNqUcyvVeRwIZ1s 6AF6l4FPdgnAViOA3PJXEz8S6ec 2020-04-19 19:12:10 45.14.148.97 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p reject 22,25,109-110,119,143,465,563,587,2710,6881-6889,6969-6970,55000 +r TubularRelayPiersGB hYvsedc1XsBjHpjUfPFLV2v9bQ8 GGSJsDsKk7cQBtZhu4Y+gRiAKYQ 2020-04-20 07:31:21 82.4.8.138 443 81 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=1600 +p reject 1-65535 +r ip7 haLbFI8VEQpvcJr1bqAvNsuzmws BpyRYV1hsNNt76fe/dVHg8iWK+o 2020-04-20 01:21:43 193.218.118.30 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8090 +p reject 25,111,119,135-139,445,563 +r niftycongogerbil haOsBB4/zXlq9dZTlT1eJ6VuNxk WTJwO11TIBBBcxlHRoZWVOLhyww 2020-04-19 23:32:16 51.38.164.157 80 443 +a [2001:41d0:8:d077:0:1:305b:fdd2]:80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63000 +p reject 1-65535 +r wr3ck3d0ni0n01 haiFQz5QsYdPEc7JvphFHiRmCXY +WjfcenuRoM1QPg7J5ElEEaPYgc 2020-04-20 00:51:33 178.254.7.88 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r torproxy05 hcjYncMD3Y8NVmZ3/Ki6aliirK0 9vrcoOEpSIEaOX2n0FjNF1cjeLI 2020-04-20 05:23:04 193.169.145.66 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13500 +p accept 20-21,43,53,80,443,873,989-990,992,1194,1293,4321,5222-5223,5228,11371,64738 +r mailboxorg hdQIgUixppVMm//8oBDoXgqoj/A Y/0e2Fu9JrA/wnHMBC1zMg7TTyY 2020-04-20 03:55:20 80.241.60.207 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p accept 80,110,143,443,465,587,993,995,5222 +r larissa hesfcjZUlg1qjuuWF0lOIqUv0EQ cQNhhnHQ591Zd3Vq8M1qMUvq4DA 2020-04-20 11:19:00 185.236.202.140 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7100 +p reject 1-65535 +r smalltalk2 hgUVZ23x3zaxIS5zPlEpoOt1QjA DOZER9DOAfhQNiHRLmFHpyCDcSk 2020-04-19 19:11:48 82.165.68.165 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r TugaOnionMR2 hgcyc7Pa5K6nsfj5zDcDXCdpX90 9G5riYBq8mfY8XnhVaIkHmib7y8 2020-04-20 10:01:56 95.217.129.29 9001 9030 +a [2a01:4f9:c010:68b5::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r acidp hg+81tCaCEMIj4hSe/vTjxvHDwo cRr1fjiskkAh+9mKMaaDsK1K1LQ 2020-04-19 23:03:08 46.245.187.156 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=311 +p reject 1-65535 +r itomori hhvP3RSJc5hef+l8dFXJ5KxOE74 xb2SdJLS3sXII3hg2QXd7JDHk1U 2020-04-20 05:37:46 148.251.22.104 443 80 +a [2a01:4f8:201:8367::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=87000 +p reject 1-65535 +r strutzRelay hiP34XVfLVEeVpxS70nXDVcfeiI KQg7wHRIqiIWdZkizcikWDWefco 2020-04-20 08:09:07 81.169.210.56 9001 9030 +a [2a01:238:42e7:9000:ed20:da9:58e:c194]:9006 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31800 +p reject 1-65535 +r FissionMasq03 hijSrMocm+WW3tHfnQCZu9sTUrM RS+rPpv7TypNm2Wo+XVehaTRpAo 2020-04-20 05:27:08 193.32.126.160 5753 6068 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r meinegte hit3/QtQ1+xljjeXvbk62O93g+0 uSwHaLvcySx5xcYNXf5B8qaFmZ0 2020-04-19 21:18:01 87.181.92.92 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r Manheim hj191l9k8Gk0qM+yKGU+OKBh/c0 fqCH2HP3GBG9azp8ZUr8GkCQE3w 2020-04-19 19:51:20 159.203.85.88 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=193 +p reject 1-65535 +r niftyentry95 hj/do8pTfOA2RrOuvT/RzGsHf74 Hg2tY5iiSejHT+h78++jk8d8edU 2020-04-20 10:51:56 185.220.101.235 10095 20095 +a [2a0b:f4c2:2::235]:10095 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16200 +p reject 1-65535 +r anonkaisx hkYiZpDB1PLdwwIfiZCaJqjDKic KCrU11ZRvRI5BV01F6mJUTerZFA 2020-04-20 06:55:48 151.80.115.180 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6770 +p reject 1-65535 +r Deviant hlYheJoULfwkSqYRabF7vBy+E1o 6NvGqzhoUULND8jATftkXhSvgy4 2020-04-20 01:15:36 77.20.194.126 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r Unnamed hlc1jdMHZmSlmJAozrGpL1+TwCo XgIkcjHXYuPBcJhP5z1MnKBf4fY 2020-04-20 01:46:27 94.130.69.171 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12000 +p reject 1-65535 +r privacytoolsIOalpha hmJShSdYQTb+5xNcq331ptfV/zA dwtq6bTxyPJpph2Gva0uTC1y7k0 2020-04-20 05:00:58 145.239.169.62 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8330 +p reject 1-65535 +r osipetz hmNUTSEQfE6sQ36ASYueAu7FwaI lsmQuI4m1mn56btrKtYBFMym3O8 2020-04-20 01:04:09 195.189.96.147 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82900 +p reject 1-65535 +r snap277 hmx+51utlnJetEB7Qgt/BseH/Rc zex9gBjVv0yHakVFPDOJArEzSm0 2020-04-19 22:03:14 76.99.240.42 38995 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1170 +p reject 1-65535 +r Thales1973 hm+z4u6DqvKaMJ1iVCcExmVrFrs eXV8mwGx0Ar9v0qSb1vlFmnn6Zk 2020-04-20 10:08:57 136.53.97.175 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=420 +p reject 1-65535 +r frickySpeed hnZj0Yj9pY7rgoUOb0xPgtK2Z70 qNh95GFF3WW0RKAb9qyWd2SUhNk 2020-04-20 06:02:33 185.205.210.245 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p accept 53,80,443,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r roTor hnmCrc++VewcAKWzTImR/4dgWQY JJHZ9bdV7Hcaw1pLMcWmFyHLHp4 2020-04-20 02:07:53 82.254.147.227 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=70 +p reject 1-65535 +r trans hnnLr9P0R/npzQWlcBUBJIwkqk8 APdbV6QmuIyN9DnhIC3bDbpxaMc 2020-04-20 09:19:06 144.91.106.72 9001 0 +s Fast Running Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31000 +p reject 1-65535 +r bitmessage hnrffU6FWfNPs5IOJWsuyFjRG+k sF/mupy95gxTd6kcrG/crqcOl9M 2020-04-20 00:13:41 146.228.112.252 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=426 +p reject 1-65535 +r patatilla hoOZOwibUIyDrBFTeK76IqKXM+Q N5EqlaiS6Al1WLRVR2MBm/QE5mU 2020-04-20 11:31:12 79.148.210.184 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r dc6jgk4 hoolPDMPQPvkNdkyCEk5f4WCPoY 7WoZ7QbLpRRyB2JMYD7kBu3/rYU 2020-04-20 05:59:02 195.234.152.86 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=370 +p reject 1-65535 +r snap277 hpB9Na4RR6HpYQKTcdGiOCOFmlQ C1/6O4Frcu192kbFNJSMUHy5kXM 2020-04-20 05:59:44 85.72.105.25 33681 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r torrorist hpk3FBXcBSpgvKOq1o5V2bdZyuA PVWB4K5gOK3Cu2m2x3Pg4FX7go0 2020-04-19 19:11:54 193.138.118.3 50001 50030 +a [2a02:2928:a::3]:50001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=380 +p reject 1-65535 +r RentonTor hpmbveV3CDvKb+TuIim8Ox1YvQc 19e5UVDCqqh2FwR4EyOtfa44AWs 2020-04-20 02:35:12 94.114.155.242 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=480 +p reject 1-65535 +r hjkoiuyt hp4EZ6qHSRm8p/VphMdCLvsy9qY d1lvgCxlEaMQrOjRlfifEleCNn8 2020-04-20 04:24:57 93.104.208.119 143 20 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=732 +p reject 1-65535 +r electricdreams3 hr8ytgbxMxqk3SCV1UmDiqFDVUU 1b3cA6dciWkVJADJk6R0EmVTffY 2020-04-20 11:36:33 80.211.24.208 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=740 +p reject 1-65535 +r TykRelay05 hsKBrRNQWCONejN9VGyQK+hQXd4 kfe0HSP9Ho3GqwHN1tKfVIwGiZI 2020-04-20 10:09:15 185.96.88.29 443 80 +a [2a00:4020::185:96:88:29]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47400 +p reject 1-65535 +r Unnamed hsf4rQNkiM0nwjNYxFyltb3Zclg 83t0Y1my/n08v+N9tOTRvhp5Yl4 2020-04-19 21:04:15 87.121.98.65 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5710 +p reject 1-65535 +r RyderIII hs3Q2Sq5clOEFqOC2ZZmc2zd8UE ZlZLS3VlsDEkaFcCodTfDtvuvCA 2020-04-20 01:45:49 88.196.252.84 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14600 +p reject 1-65535 +r mnesys1 htkk7eFJi04d0I0iYPPp/kVAEuE V9yeyxgXm0/2vQWi/X5CTSz76jY 2020-04-20 08:43:00 193.30.123.113 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20900 +p reject 1-65535 +r uovobw hvKCjLSwh1UVYH9OIJeVFUK3E+8 kD7y4XbQikvxNGWAozcInZFLsP4 2020-04-20 12:06:22 188.40.49.86 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=915 +p reject 1-65535 +r Tor4tuequeeg hvoCPGdqU2N6OPzHihDXO0p5gDs 5P5jh2Xsw0gQIWltQJdhsakjLrs 2020-04-20 00:19:50 139.99.194.157 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=37 +p reject 1-65535 +r Potatoe hvunU8jSVlPghrmP/4qghPhi22c nHCsKP8xDZYLfbUyexFnLPauJzk 2020-04-20 01:30:11 139.162.232.28 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=789 +p reject 1-65535 +r brokolimc2 hwHnCsTAyeH+R+qFP8mX0pvl1lw AJcFHQ+VunVpIeAPcyeuby48ips 2020-04-19 23:38:53 95.217.0.139 9001 0 +a [2a01:4f9:c010:4eca::1]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13500 +p reject 1-65535 +r garin hw2RSKJfhME49y3GR6vDkO00ODs TfHpacUiF/4NqscqHpBsXzGyZxo 2020-04-19 19:40:14 45.123.118.101 443 80 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6100 +p reject 1-65535 +r griffin hw6X5YRtgwjqRppbtaUNKDhQPb4 mE06rCOUNhESZdP7sbZSfDi/nAI 2020-04-19 18:53:24 184.145.159.237 27015 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13400 +p reject 1-65535 +r snap277 hw+U/g4oclNONj5+lNCbFVhsq8Q QXk9Uq1LxE3HrCqP8I7HMrgSgGI 2020-04-20 11:50:47 89.115.43.188 46273 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=539 +p reject 1-65535 +r tulsi hxV30FK9QaWuZ81jsMHcCHX2Od0 cZioGzz0dDYL06HQtowfcxHv3ZY 2020-04-19 21:18:55 178.128.239.129 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=522 +p reject 1-65535 +r TykRelay03 hysYdhlTJUkU93xxhG6KJiPFJZE C8KA4jYTTV3YvklVXjdvlo0ra6E 2020-04-20 02:37:47 89.233.43.74 443 80 +a [2a01:3a0:1:1900:89:233:43:74]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 1-65535 +r FissionMasq06 hzV/zCvywh8GlxQ4G8psPn78vV0 8bfDHTz9aQNkVxTmWudq1wi9TjY 2020-04-20 09:27:02 185.213.155.172 10750 20753 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Tor0x800 hzcwfehMJiHmOZ6ZEjlnqVkCl/I ild4KtiTCs6ICfowDEf0bC2hPmI 2020-04-20 06:38:37 95.168.216.152 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24500 +p reject 1-65535 +r Unnamed hzgytKdHDtI7AL8RoUaW3VW75+k UbV/PiVuIROW2jLSqRih64FnzCE 2020-04-20 11:51:44 198.98.61.103 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6770 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r glenda0 h0zn5zKjYoow7ku3E/pF+L4/MsM l55mhezgzRj3rdbu+VX5jdTkZN8 2020-04-20 09:33:42 88.198.101.33 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 FlowCtrl=1 +w Bandwidth=54 +p reject 1-65535 +r Pacbert h0z2PJmotGqlQ0JUWDsKgIbNW5U jrv2o+AwRnu80/MN2jCgqReeCMA 2020-04-20 03:06:03 93.210.7.164 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2780 +p reject 1-65535 +r Spigen h02EOCyJLz9hzJ4Qa/CIQ94Lhlo 5mbGPsDxOjdo19Zrew9A+kKlz7U 2020-04-20 11:29:27 192.42.113.102 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110000 +p reject 1-65535 +r Marsu h1CpRt1askrnGkCxunZyA08kZj8 VyF5sw014cw7BF9OXDpqjlX8yO4 2020-04-20 10:59:49 173.212.199.160 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8300 +p reject 1-65535 +r Babylonian h190o9wUc3vsoG+LUAAiFU0aKdE xwVKcxtFxExTGWp5Ak+WzN4QdFI 2020-04-19 21:27:03 78.82.251.153 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37000 +p reject 1-65535 +r rainbowland h2x85Dd0NmJQ0+do5pDaudS11aM tNkYHPiCKfZh+BFt/gf/OUxonLM 2020-04-20 02:01:07 37.218.242.26 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Unnamed h4Z2ctcM/ap6IlQyaGG3bGMskmk lziof/avEvj/UTtINoBGBrnc/Cg 2020-04-19 19:54:50 68.149.43.226 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18 +p reject 1-65535 +r TrinityDDh39 h5Oa3t64kQpDCXCOr9s5SpgzUxA Ds83+6sjnwMnhlxGKLGrYJpM4mA 2020-04-19 22:06:10 79.254.19.190 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=722 +p reject 1-65535 +r CourtesyOfBigCorp h5UL4OapspRMdKbFytSGEDhKezo 2PWcsLJ0y0CvyMMv+s+ncGIR+wA 2020-04-19 23:35:31 132.145.48.73 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=49 +p reject 1-65535 +r UnicornRelay h5h8i4WutzqGamesaWEUz+J+fnc A9CPg9uclS6kzP9/sn9Bp8kyAKU 2020-04-20 02:25:36 84.138.55.15 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3000 +p reject 1-65535 +r cp1 h6LqvqsNfk6wAqQtJgAPXLjVuTc q+soh7njacUVpKZRRLvpkKOX+uQ 2020-04-20 12:34:33 54.37.200.157 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6920 +p reject 1-65535 +r Unnamed h6S3qFRCnCuBeW+qAaAbx8Eh8SE s/3JdgGiC2XOGeaV6tH9z8padUQ 2020-04-20 12:25:35 198.98.54.61 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5450 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r PythonRep h6nT3nQgw4aExAKjI7XwpCD/3YI Fm4SYCtrPkoVNdBM2Owzc7shiTM 2020-04-20 01:56:03 51.83.217.201 443 0 +a [2001:41d0:602:e33:d6ba:abb1:755:1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5630 +p reject 1-65535 +r BarryBen h6ob5KOVKd2GGUc437WdxpjzE2s 4Ikh2h+pMZkx4e/Cl8pl2oEfAJ4 2020-04-20 00:53:43 52.205.15.239 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r f89g65f21 h7NVfz55IhfivE6ZI+rKSuxbqcM 6mTSrqvc3mavYATeNuHMqCPjmYg 2020-04-20 07:51:04 82.131.65.94 9001 0 +a [2001:470:28:872::44]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=880 +p reject 1-65535 +r FreeSpeech61001 h7uVlc3GxFPp6iNcadESQhotDpQ 0e5iShJRCwWbRZxooVAUlATZ8ak 2020-04-20 05:09:58 87.177.73.175 61001 61011 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=508 +p accept 22,563,636,873,989-990,993,995,1194,5222-5223,8332-8333,11371,50002 +r Unnamed h8CN39MsYvPFbTcfl3TSe/27gHs ZeZ6vtQWhnaw4rbNfSWnHub7leA 2020-04-20 11:40:53 23.81.66.90 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33100 +p reject 1-65535 +r mbdy345 h9JintZk72nrVCCU88yXPT4KZTA CtsEed6ZUfe5hgvznrctogS72Lc 2020-04-19 22:15:46 216.126.228.62 53001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=75 +p reject 1-65535 +r Hack2G2 h9KO4MmTslDvk9vk0ssOMCRNdXw znHyDncd+AaPAa+jb6ftVOgIIj0 2020-04-20 09:13:49 91.121.82.132 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r niftyphoberomys h9c0cf3GS9nO34RDXSDKTrXDb+g jDBQBYVKZGwmyIF1/f7CJ4uZ1Nw 2020-04-19 22:16:32 137.74.19.201 20 21 +a [2001:41d0:203:1c74::911:c78a]:20 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67000 +p reject 1-65535 +r FreeSnowden h+o3zC8VcOtQDEamkeUFpwMmvTY XunKJN9+XH+xbVCxlRRuGtF4nEE 2020-04-19 20:04:22 139.162.19.233 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=328 +p reject 1-65535 +r wakka h+qGIKE2jxnEOgNxFfFUYclIezE jpzqYqjbC6qFl/slsRlAl1pPu58 2020-04-19 21:25:23 194.88.105.97 443 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r wheel h+qLQhNtH5AUvjd7K5hUWdGebnA OuRjqjZZlBG253SxdNuxvIlr0+c 2020-04-19 19:46:18 50.7.117.115 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p reject 1-65535 +r TarpNL h/BZYVT+Mb7vAz74oMBUyDJ5+l8 jcNXWgqKzju4LLaYi0GxqSqkQp8 2020-04-20 03:39:32 188.166.8.152 9001 9030 +a [2a03:b0c0:2:d0::4cd:8001]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=574 +p reject 1-65535 +r Unnamed iAxaMKrgA0Og/t2alyyuFrAmWK8 zx8/hoY+Gah1VQULLQEADoyH3Sk 2020-04-20 11:10:19 51.83.171.238 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 iBR9wTSJ1I1aVuN3UE4Cp2Y/F0k fjMSbg+xz5fJRDjFwF25CtTQhow 2020-04-20 09:56:59 83.134.227.221 38321 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=416 +p reject 1-65535 +r relay2 iCSfGHNzedrIcYXl7HVibrH0FOs Yws4Sb7dTMQjbkce8S9xRQ5mC7Q 2020-04-20 00:43:34 23.157.160.195 9050 9051 +a [2602:fe2e:2:2:18:11ff:febd:583d]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p reject 1-65535 +r sexytiem iCaYssocPMizR1FHi/uQzoTHLzY DWsFPOvI3W1KkpPOf7DFdlXo+rY 2020-04-20 03:42:29 95.216.107.148 19731 39030 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11 +p accept 80,443 +r DROPINJEEP iDRonxYiRcXiLdY/Wmuzq2b54fo qO4D1B/Wyx1sDBJBed27KLskifM 2020-04-20 05:49:14 31.220.2.132 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Anbarocrator iDi56PcOELWJVCfTcKZbVVTD8l0 3QgZ7K7zLLDea4tWbgzyg60V2eY 2020-04-20 08:23:19 78.36.32.17 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3710 +p reject 1-65535 +r niftyguard49 iDno++KCGbhTku6lpNvEHTFfS4M qv0HRiPA7cAOHZCpXuvQKEJQrGc 2020-04-19 22:16:22 185.220.101.168 1168 2168 +a [2a0b:f4c2:1::168]:1168 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p reject 25 +r 0c364ea2bbd1 iFdtbS6zWPPGW/vZAmwLvqJrV/Y QWxr7Nq1qv5zxgXEr1uEaZWrtCE 2020-04-20 08:16:11 51.81.253.207 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18500 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Ui iFnminyVvVq0A/FtrZJoHhhNNxA lJ4BSdgU1Q5L+B89SMXrJU0LTxQ 2020-04-20 10:26:16 195.154.226.135 80 443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=30500 +p reject 1-65535 +r 42e7b73f33ff22cfc9c iFz7aSHm53FrtkeDNI3bBuF+W1o IVDvGQYLRLz2Tae7uAnmmJ4NRwM 2020-04-20 10:33:11 51.38.98.5 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r function2 iHKFeuraiPXeAlw62mTCJFdtkPE uFuOt+BnDpBzhLaPfgj2aKeqsYE 2020-04-20 01:41:10 87.239.204.111 12001 12002 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=79 +p reject 1-65535 +r autsch iHRhoz/ysCt27RKQX9lb8NhhZjg 4EJZfyS3RdYrZ5vBUwVzFAMbf94 2020-04-20 04:28:07 87.193.208.14 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1850 +p reject 1-65535 +r PowerRelay iHSAUoQ8yToCvh2em1s1irOhBKo gxUfYfd+ub9MqbW90rcBgT0quu0 2020-04-20 01:23:49 178.254.40.158 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=63400 +p reject 1-65535 +r TruthSeeker iHVK+baoIGFOFP6PH+pCMXnoCX4 AcnjW4Z5r44EEkvMy3zDmp5hEKQ 2020-04-20 10:58:15 8.42.76.68 9443 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=310 +p reject 1-65535 +r niftykostchtchie iHyrUBqdtoosRO35i/ULAwTu2LY MvM4vPVJ5rZoRCSU3cQNl65CBOE 2020-04-20 08:55:15 185.220.100.249 9100 9101 +a [2a0b:f4c0:16c:6::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40300 +p reject 25 +r Karadoc iH4rc+2hCcCa3r1rHniP32IGRrc ISg4sSU2RD/Yk76YU4KMLBNC4bM 2020-04-20 04:52:47 137.74.169.241 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21600 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r KchRelay01 iITrqEAdBvAUOZ9IWiyqDP+oUw0 0B9Vk9JlOqK0PDa5aA3Bbmt7ERI 2020-04-20 02:23:32 185.193.125.140 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r Unnamed iIXqb3SmlIJbE7inCA9s8WTfdPs +htBvpJn38zJncj7eMkuh6PfaLY 2020-04-19 23:48:56 144.217.95.12 9001 9030 +a [2607:5300:201:3000::49be]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r eclipse10 iIyRECM0f1DL4lc4yJPjV8LJK6I +fntfK1/iPSZnKGLpYF4m//pzb8 2020-04-20 10:37:53 51.83.217.207 9001 0 +a [2001:41d0:602:e33:eea2:156a:3eef:1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4630 +p reject 1-65535 +r king iI4+ZJZi2xh+jTFW7Xjxp0++WYk p/5FPyFieEPqkUFlBgPMljVN5JM 2020-04-20 05:28:54 51.89.213.94 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16800 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r wyxtpthllRelay iJeN4HEWp6xEMV0kLhZ/YM+JKPk 2E6G12czvKj08bOm8ncpJzRCkEw 2020-04-20 09:34:48 87.239.87.142 43617 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p reject 1-65535 +r snap277 iJ4nOF48FROh3Pv0gok9FXw0vJU NuoHiYHUrkFcs3cyD80MLQc1f3c 2020-04-19 19:39:21 60.153.229.69 41963 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=269 +p reject 1-65535 +r Koshaq iKGJYK93Nf1EiTdKxBH7v+l0OiA e5V40pmkxkfjF2M4MlZbmm9Qhhw 2020-04-20 09:20:42 77.37.218.221 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r snap277 iKdv4czAO1DR5vJd5NjCb9yJ8X0 spMOGjmXAozxnKs756rrvlm7vWM 2020-04-20 10:56:17 181.84.151.108 37295 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=141 +p reject 1-65535 +r niftytamiasaristus iK47wIg5bx0/zE8vWIwNyDdZnSA UTLPhaXcS5i2HbMVkSLYEwm0LC0 2020-04-19 20:27:10 185.220.101.33 10033 20033 +a [2a0b:f4c2::33]:10033 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34500 +p reject 22,25 +r RasBifrost iMYVrF+Vkb/UjbV4slK4mnL1w6s EcjWvSku5Rxa1MATThifc6vVcRo 2020-04-20 02:08:00 84.170.26.131 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=580 +p reject 1-65535 +r cryzrelay02 iM+NQtSbfI6dA6vl2uevJemQIAg 9Wae3ZIrhHhhOQMNZCSmhZHCwww 2020-04-20 07:39:39 82.149.227.125 9001 8443 +a [2a01:440:108:11:82:149:227:125]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r DiraE2yhvB iNXwvYf5vBqW/L/c7bHA5rqx0U4 8zUNRIA7TEUHHAW8xouvPsPOyV4 2020-04-20 07:00:59 98.128.239.73 1025 1026 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r Privacyignr iOCKMrZ1pyVtsaGLyAAe8mvy2YE zk62mZr5yd+HtsY3kvJW9mxKpUs 2020-04-19 20:38:00 174.19.106.27 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=226 +p reject 1-65535 +r goesta iOLSWmbtYwMPJYGfStt9GvDlvXc U6WKGeolc6KXof4CjIVKff60bSA 2020-04-19 22:08:21 31.184.198.152 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6650 +p reject 1-65535 +r Unnamed iOnZO11v5LFQv3IdjjbbHC/5Lyk TJTNFMZKkvVNyvVy6M7etseiMUw 2020-04-19 20:46:21 80.211.172.119 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p reject 1-65535 +r smell iO9IdWoki6vrXJnrkZN+x01KdV4 VWHEQBiTxGZ81eKd83XNUtH08y0 2020-04-20 08:18:18 209.141.52.203 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r snap277 iPEwIfVF8lANrjBh1QA0jDEGHs0 wf0RooNyPvJrPd18avlxfwFoZGI 2020-04-20 11:22:54 71.199.212.141 43529 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=231 +p reject 1-65535 +r sprockets iPc73b6HgOLsfSjS9DH1fsj9m1s bKOCFLvJdawUlABzV9ZYYtU7gkE 2020-04-20 10:29:49 137.26.220.250 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=820 +p reject 1-65535 +r raspitor iP19WBCJPnLnNU0O7cp6fkeQx2g V6kfAvwao5XJnNxQTDKSyWBkq44 2020-04-19 21:57:48 83.163.255.139 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=491 +p reject 1-65535 +r AnonBrasil00 iQCTsOAQKSbsteifAyvc+bJ4GQE 8jVr7/JuokZZ/ZK5iU9dLFud46o 2020-04-20 06:14:01 191.235.95.166 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=380 +p reject 1-65535 +r ilovecreampies iQSA4U5jTItEZ8R141Wm+/PZnNU LFH3EvPa3GXwkIHExvqDtpPlFkk 2020-04-20 05:10:13 79.172.193.32 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39100 +p accept 53,80,110,143 +r outbreak iQUwxbUQpQb1zyBu/sFZX5bnJ6U H4m4BQkLTHjv0ZZgNdWijC3EAao 2020-04-19 22:22:56 51.15.230.39 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15100 +p reject 1-65535 +r TheWindyOnion iQlN+kFYx6FYPsOjMs3Lx0oozA4 8/SQ39zFW76YhqywM6nLSPNEaVo 2020-04-20 11:31:49 167.88.7.134 443 80 +a [2602:ffc8:1:18::1337]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42000 +p reject 22,25,119,135-139,445,465,563,587 +r frolix8 iQ8yuNz8Bw5Y9dUK6Owr3gEBNGk xbJzksXE//pAGEMxkUOJF8xTBpo 2020-04-19 20:56:18 153.120.42.137 110 143 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r yomi iSqCe/Z9snDjA2d6M/5XcGnd5Vg ICByk92dN3q4qh1ePzorLmMvJ2I 2020-04-20 09:37:46 104.244.74.97 443 80 +a [2605:6400:30:f8b5:620c:dc25:c624:aafd]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14500 +p accept 43,53,80,443,554,1194,1293,1723,1935,3690,4321,5222-5223,8080,8233,8333,9333,9418,11371,18080,50001-50002 +r BlackBoxx iTn+32+3RP2Oaf9s5HMxjyG33a8 iPO0ikUZqvbRYdcYYCaR6+/qdvc 2020-04-20 08:21:48 118.127.108.136 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80 +p reject 1-65535 +r Venom96669 iTuuQ+rBUHxfvQRsMlND1Y/ARYg NqrfL0o9EX8Yq8jnJKzLtf+KwlU 2020-04-19 22:07:03 62.173.139.157 5091 5092 +a [2001:470:6e:80d::2]:5091 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5160 +p reject 1-65535 +r GreenHostVDSL iVHwDk8b8g7kg+MLzz+N5+IppG4 UfmqUAuoAFT25iXFv8yudWS3H4M 2020-04-20 12:13:55 79.229.223.254 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1400 +p reject 1-65535 +r a0cator iVxDP8GPomow7pjlBAHieCxAFZM 47bKlBTtiaMIHQV4k3lwQDlLh6g 2020-04-20 07:04:41 174.89.48.229 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r blackmamba iWNkt5lvXfug4V0aLgbQuYtVXdY LQk9Q1I/o5MNMgfNFHTh1Xk6QOo 2020-04-20 12:05:39 195.135.194.134 443 80 +a [2001:678:7dc:134::dead:beef]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=7740 +p reject 1-65535 +r Fuller iWfXtzN33bB2LLdHs/iJd787PTM GjBCmStMkLmmJcgApXbB4MyUoT8 2020-04-19 22:36:34 41.77.136.114 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=140 +p accept 23,43,53,80-81,88,143,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,991-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap278 iW/SmUxIM67DfL1D3IXEQVcxm/Q z7irxLY2uny7TBfr6a0SMUg9yxI 2020-04-20 06:29:56 90.21.229.206 39077 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r heims iXpn281+nVw7X9GTSUM+ImOgHQg OgA0S5VyTDcoCzKWt8pxCYwFLeM 2020-04-20 04:47:51 78.130.128.106 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p accept 20-23,43,53,79,81,88,110,143,194,220,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r TorMonkeyRelay iXqO3yC/EnN/2CduwJGemfBGMEU qA3nFSxXxYmBLyr1rnoiSLkUG9o 2020-04-19 21:23:47 188.173.170.16 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p reject 1-65535 +r lavillederobots iX671bUyVVng42UHkvaM4GjaaeU rblOmmJ7h3Scmokd9G6P7O6FdgA 2020-04-19 21:30:15 41.215.241.146 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=223 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r DangerZone iYqpoX7LsF/qT+dBi9HGT0XZphQ k4qRBO73ufNU8jzKdJMf2oA5BvU 2020-04-20 04:25:12 172.104.138.137 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r wsantos iZCuqRmsvBbmnVvGFqKfj4Kl4no +fg5k5Xxbw9zb8PO/xEz0G7B47c 2020-04-20 10:42:54 62.210.149.16 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=82600 +p reject 1-65535 +r Unnamed iZIzigPfksUxi5kkOee/lZyW1vY oFhAOcn8rWSlrC+4Kbi/01SgwIc 2020-04-20 11:38:12 51.79.53.134 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 25 +r OldMug iZfkX9h0NA05PYcY6S9D4UsqP/4 lUvwHpatbMl06HjyL7uyTMMbhdI 2020-04-20 08:18:35 212.111.41.143 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=480 +p reject 1-65535 +r piratecantina ia5flsuXkZ7xOxcuDk4stQzDPxo itlIE98eWQE80CenrW7R9PCIo4Y 2020-04-20 09:31:02 195.144.21.182 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3920 +p reject 1-65535 +r Unnamed ibLjiNEU36PoLOg+FJaJLcnxVH0 DS/fpN4EV4UTxC6BFeDXcjuqDfM 2020-04-19 20:09:38 173.88.171.180 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=437 +p reject 1-65535 +r king ieV8bMNm2vBIVISX2smFFAsGXA0 sFeebI0AzmsVh/12FHgdP1S4Gi4 2020-04-20 08:22:17 51.89.200.125 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20500 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tormb6 iem1tcquTjiAFGyK/kdm8Vpx7lU +M0O0Fk1xlq2B2sh8QnhErQOy08 2020-04-19 21:48:07 3.134.247.200 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=734 +p reject 1-65535 +r UDunGoofed ifviGmgBKSz96ON9NggUYWIpxWE xu6HlrgLwUWOruSwO6K8p6W2xoQ 2020-04-20 10:01:36 167.172.238.42 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=224 +p reject 1-65535 +r VisitFrance if1PsqX9c7UPLl2FxHB4g/jNUTA ILjhK2AW42lHUxtqi5L3g4vetso 2020-04-20 01:29:42 51.159.59.174 8081 28192 +a [2001:bc8:1200:8:208:a2ff:fe0c:73c4]:7712 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r ddetor3 if9KCBjYvp+LcTONlqa4VPd/n+w yJ7wwbPUiyVGebGUcL1h64YSf2E 2020-04-20 01:27:36 5.9.18.2 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1500 +p reject 1-65535 +r FreeAssange igDOlji9tGhrkfHwsinbP4ybhBU iqN69e60X49JsixHZxYqwyV2tzY 2020-04-19 23:17:39 82.251.167.192 443 53 +a [2a01:e35:2fba:7c00::33]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48000 +p reject 1-65535 +r delpin ighmqsqN4pJvQEm9fwoQGRj6Y8g E7nY9qDr5eOAcdPTCyOBCuJ5J4Q 2020-04-19 22:16:04 81.191.94.162 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1770 +p reject 1-65535 +r kyu ihZ5cbrmktscyruSY1FprnnJl1M BkI2IexwvXg6ALBpjIJDbMBgG/I 2020-04-20 00:09:44 188.240.210.20 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=580 +p accept 110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r idideditheconfig iizPmjVO+JwIywri3X9+hBit9xM WiU9V/af+77ONYNAf4jX72t5oys 2020-04-20 10:37:08 139.178.49.166 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5620 +p reject 1-65535 +r weizenbaum2 ii1xy8oz8To+qWFN4orj9mnYSYc aIi0mEuqwoUctBPdNcDf+E2312U 2020-04-20 05:15:58 62.102.148.68 53 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53300 +p reject 25 +r snap277 ijRhtiGuMgF/M7wZ8h9xD59ULrU DN4sduRvUYfAPsxlk5IXkw6I0Bw 2020-04-20 12:28:06 86.254.115.164 45881 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=235 +p reject 1-65535 +r zwiebelkuchen01 ikyPxtYzZeBOy0sY72GppSk26K4 /lmtcoLKIPztoOhpjwnyNJxmvZ8 2020-04-20 11:30:46 193.80.234.214 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3 +p reject 1-65535 +r Michelangelo ik19NftNNhPfDSZMrxbPDaJwZ2M r2LhQP8n0ztT2C20c94e2jFfBrE 2020-04-20 12:33:19 200.122.181.2 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=89 +p reject 1-65535 +r king ilR/LzbkQFJYbIhWBI9ybORPa/c hODOd0n8DS6RmJQacWfgH59dA/Q 2020-04-20 08:40:44 51.75.175.28 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r treesofmossspa ilfaL/tbpJwEHt4aCV4z6G6nVsw Ll2s09lCXsajHdSY2YBvp+Kotzk 2020-04-20 04:39:38 46.227.68.106 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p accept 3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8232-8233,8332-8333,8443,8888,9418,9999-10000 +r prudelta il58LQmDWXS01YJSutUf2K1U+c4 62xQzo5HpFsh6zw9ajF12oKx/8s 2020-04-20 12:20:45 85.214.160.49 9001 9030 +a [2a01:238:42a9:c100:44f0:bb64:a1fd:835e]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15100 +p reject 1-65535 +r WonderLights in7SoVvlWFUt9ayVwtvcDeBiGvY SKFu81wHKb2qWzEqvk6uB0O49tA 2020-04-20 08:00:44 193.118.34.130 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed iptb1bNWoB26tnbj1BKLjb470f0 WAldlMRnwWoK2uR5+RgramcjEKo 2020-04-20 09:18:39 102.37.15.222 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=354 +p reject 1-65535 +r UDEtor irxNX2GCx+ebCH0e2eXPZSyD5Sw spp8W+TAhTxDVv4qvXcfAtATeME 2020-04-19 19:28:25 132.252.186.185 443 80 +a [2001:638:501:4185:250:56ff:fe85:bc64]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=70400 +p reject 1-65535 +r 3bb3b705758b isNwpOw4oTnUDCdiscTXVxchISs rJNYn1xiP6Z/XZ4S9wP4utG/niY 2020-04-20 08:07:55 51.81.254.15 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r KleinesZwiebelchen isWX34BuxpZOa6BHyP2/R/fV01s ADLx+JuXphS34I101YCUR+gFKus 2020-04-20 09:53:04 95.216.190.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1820 +p reject 1-65535 +r netShelter03 ivxvx8mH5M6UvQHK5/upMzOQeHk 26U+0edIweY7lxUFNAu+qb5gu8w 2020-04-19 19:20:22 185.121.69.37 9001 80 +a [2001:678:a00::17]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37600 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,25565-25580,27000-27040,50002,64738 +r CheenaTorRelay1 iv/q4qkX01xOmDlfXzvcOlVHJjI GsKzH3exyFKmb7E2coHo/tzWoCw 2020-04-20 05:49:14 178.17.174.188 9001 9030 +a [2a00:1dc0:caff:4c::38e7]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2420 +p reject 1-65535 +r anongoth iwKUNEAa/ci5eTpJAF4rw692wCw vOJM77nExAcuY3moX1RE3dpSras 2020-04-20 00:44:21 46.248.164.24 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2720 +p reject 1-65535 +r Unnamed iw2NNeyb6QZ14dBU3X9S9VXIAIU H6F/zIZNsAB92QLWrwO7ua3oXrc 2020-04-19 23:15:01 163.172.42.52 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22900 +p reject 1-65535 +r soberness ixzHbW0TcKZyY2KNTLwBtikD0L8 OJA1emfbJGrAqne0mbVLL3Vo9OQ 2020-04-20 00:41:48 86.105.5.133 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13100 +p reject 1-65535 +r snap277 iysRLm1L9yk00wnvjzo/hC8bDQ0 UreTIVqbJ6M+L38N+TaRaTnE4uA 2020-04-20 11:10:16 77.38.17.190 41851 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=79 +p reject 1-65535 +r Unnamed iy6yu1OdC4enukvhZ3plAaBLiJs sE+j68CqK04/e7x+FN+tYUFucm4 2020-04-20 02:07:46 109.201.142.53 48794 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32 +p reject 1-65535 +r sonnetor izSlPBGkX4UaZ/OPHPgFZk4EobY UK5jbmo75+/EIUnmFrMh4hoTGpw 2020-04-20 11:55:48 155.4.73.125 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=713 +p reject 1-65535 +r nick0815 izhDZ+5if6Y97x06GEwOOdK2bpo 9TfyMRybpYdC/WCjzAkxdggc+6o 2020-04-20 11:00:09 79.235.126.112 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3000 +p reject 1-65535 +r bektarGenesis iz1N7azUpqQ3LQpLapLmtKyPqJQ UHp3qCWKcy0LUjaIfO9Vwepg1D4 2020-04-20 03:38:23 81.170.244.50 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r mobileitdept iz2M89cQCkAv9EFSUuJJ1sUe/O8 MKD3jpNnmxyFwELdnGNlD0HjEU0 2020-04-20 01:56:25 45.76.114.160 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=150 +p reject 1-65535 +r Freiheit i0lvPvO/XMMqTCDs2+wqBufqQ1c QMsb883/6qLrla8WugZQXjSXwT4 2020-04-20 07:59:06 217.79.178.53 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47400 +p accept 53,80,443 +r Feidhlim3 i1oZsVltrUyJ4CW+LLo0JK6UNpM +CCkUbdY6Xck++lsTqwz8Yo59w8 2020-04-19 23:33:01 178.27.106.21 9029 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5080 +p reject 1-65535 +r hina210143 i1tJZPyLzyxhWePI+O7A7bT+h8M rOeP+lELRkit/ve+Hiw262mNbW4 2020-04-19 21:39:52 3.113.210.143 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=363 +p reject 1-65535 +r F4AxFree4AllxTOR i2T1k8rC7QXA+nA671D/cZJbVpw CTpPHzsJAuhgPkL+2pc1tSVgTy8 2020-04-19 23:46:26 193.30.123.176 9001 9030 +a [2a03:4000:2a:3fd:ea7:dead:beef:ca1f]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56000 +p reject 1-65535 +r Unnamed i2euEDNbnUTTFQm5qUq+jtdp8Xo RrE676IS2t5eXLFGAsFXXoD/YII 2020-04-20 03:00:01 94.242.57.164 9001 0 +a [2a00:1838:20:1::cf70:bd57]:9001 +s Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5920 +p reject 1-65535 +r snap277 i2i2de3UDaN9JCf5JuuizOEfeLo cmBBpsVL+2ENemOfm0GZW8WEusU 2020-04-20 09:11:36 109.28.32.147 37089 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r laurita i2sQoK7YlAjlCdRCLskmyJx5M9A Hfi2m09dHah48iLJm/s0ovABuyY 2020-04-20 05:06:19 95.211.205.138 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23700 +p reject 1-65535 +r UndesiredSand i3NAEpbiUEbzdOtuDOJwLe0EtWE DLGCUvx8mBF+iSvIDS7SDmBnaWE 2020-04-20 08:33:20 144.139.62.165 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=169 +p reject 1-65535 +r axiomaticlinux i3xk7J2CCcFCUws0iAULhdVdadY G8qhR2Xirn32VCh+zICg7lO+d/Y 2020-04-20 08:57:33 208.113.200.103 443 0 +a [2607:f298:5:101d:f816:3eff:fe83:5cb1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p reject 1-65535 +r Quintex35 i4AWm+9xRQ/EBpoZCFNSO3rqReE /C46AdfSeXFwJ4qnRs7pSgtENS4 2020-04-19 22:39:48 199.249.230.84 443 80 +a [2620:7:6001::ffff:c759:e654]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r bobtail i4ieBMYOMNURATGJ08KtzlIuHzw jXtsBbBu+FF9/bJJTKBZ0iSVPRU 2020-04-19 23:41:07 190.2.133.227 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20800 +p reject 1-65535 +r snap277 i4zlZ1Tg1wsHtZNQpB/8yTgcrog I95UnU8e9wnqUbCCvcdppLypveI 2020-04-19 22:54:08 144.202.30.46 40371 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4380 +p reject 1-65535 +r LordNikon i5ty2WE+G2dKF9qmoR/jNsNCcZE LjD2Bqa5fkG0EZiIVmQTLC4Xx54 2020-04-20 01:59:14 23.129.64.216 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8510 +p accept 1-65535 +r FrenchFries i6Hm2KoI9CW4Hc9AMQq9v6VLCV8 CaNEn5Cm2MvCAziJsSqfP3FfMHc 2020-04-19 23:05:00 136.61.223.102 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2040 +p reject 1-65535 +r Kackfass i6X0vSREn51ZG7vKVhQuAH1kIzs 4CypygfEnmPxzeeKHjHJjDK43EQ 2020-04-20 01:31:28 82.207.213.189 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22 +p reject 1-65535 +r MidgarSector7 i6/6ol+jemkoaeUi9eTICzev7ZA R1C3ZYPuWCXwtz5O6+/jrBvBGfg 2020-04-20 07:21:15 45.76.177.51 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=709 +p reject 1-65535 +r notatorserver i7Fx2C3ewsx1HFtjulQ5+0SKJLI pft4KUbHEYWOHuC7o0/sqebvQyI 2020-04-20 10:19:11 185.107.81.194 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r Unnamed i756kNwDqVRnOpn/tteTCK1PZDw wD3Q7PsGcLQl0ZC6lga6hGMjNGs 2020-04-20 06:38:15 95.211.186.80 20188 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=74 +p reject 1-65535 +r torrelay0x7io i8O7+QEQFQD1j+udpAG2cl+3iqY 2exCQychzEuJvi+50e4fmMswIxk 2020-04-20 08:51:35 54.38.239.109 9922 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14500 +p reject 1-65535 +r Sao i8VU9/kxaxLewXGBX8tFKeigHUk BRoqQfXsHkDvccnOLZ1waw9sTr8 2020-04-19 22:06:22 92.211.41.119 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5190 +p reject 1-65535 +r snap277 i8bTiMJ2j2u5n7FcEupEAdeKxnU nFfGIsZ44XGdJUcB+g1a7sIMV5Q 2020-04-20 04:12:58 67.165.133.17 44401 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1200 +p reject 1-65535 +r snap277 i9+h2o0i9jm+NpsVDh6qZQn2j2U bwEdaPFkLa47od8L/sXWD4mtTy4 2020-04-20 12:14:50 190.131.169.94 40747 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=360 +p reject 1-65535 +r niftyentry80 i+WLp6KNxrTyEc6O6GeDuFEzSI0 Xz+lK/F9JugacufJub0ckRjuGHY 2020-04-20 10:51:28 185.220.101.220 10080 20080 +a [2a0b:f4c2:2::220]:10080 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p reject 1-65535 +r cookie i+ec4yYcAnzpT4TWy+RfA76bi1k nu7MYSMSKj/UJFoDsd6ZI9a1XHo 2020-04-20 05:01:42 5.9.37.214 4443 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=77100 +p reject 1-65535 +r TulipBaroo2 i+zY/4uMmj28SlRbqGwWiXOTl6g e2I90iLpi9Ix4FN2UhFBIq79kEc 2020-04-20 10:41:53 198.98.50.112 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r GrmmlLitavis jAD6c2mnowj2oTdgDw+geZDZ1FE NRZ/GWlpodeGmzormtvgSLO6CyQ 2020-04-20 01:56:07 163.172.194.53 9001 9030 +a [2001:bc8:225f:142:6c69:7461:7669:73]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33300 +p reject 1-65535 +r DigiGesTor5e4 jCW6E01Xm4qvQg4BIV6yzwaq6Qc MFGWVPLPL8u5ifJcTUo2g+BrrGQ 2020-04-20 06:43:25 195.176.3.24 8443 8080 +a [2001:620:20d0::24]:8443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28500 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r ssrv jCoQ0ZMX+297tClUprX+YkSImvU 7V2W4ZO9sMrJt6fkDEuAXK+P0eQ 2020-04-19 23:58:44 83.32.47.118 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26 +p reject 1-65535 +r HappyNode11 jDWxXB8Ti95NUKl1Ep5Hc7RKUD0 sLQnXf3fEPKxYP9NiFlUjfAy3ok 2020-04-20 09:35:18 45.79.138.8 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p reject 1-65535 +r sqrrm jDrSwqr397fpK4HxPBqSZ7OUFto n1oCXFdTI+Xhl8UoDsvGwk81MyM 2020-04-20 05:54:51 185.25.50.199 9100 9101 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r houmgabot jD5gWOdnyxH5zSBf3w4pBsg7qSM +IvcljUiLjmslQ+Qpfs2xWMIjFk 2020-04-20 02:07:31 82.253.194.252 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=360 +p reject 1-65535 +r ALBANIX jEL8GHblHVyN5jcse3rVlflebcA ppKbWdpBHQijsUMczzOBn8uZT3E 2020-04-20 08:28:03 68.203.87.86 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=490 +p reject 1-65535 +r Unnamed jEPgJsPG8eIXxRvh1H7Rv2g/MSI OLeWH1jNjtQfg927Z2P3qlNHFnU 2020-04-19 19:40:46 111.90.140.143 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=585 +p reject 1-65535 +r AnonJapan00 jE2VvOZMbZ2nX3KOog3C2LQfU/o aRPPoNLsedGeb5lHGkrRsGJAMbc 2020-04-20 05:39:02 40.115.158.160 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=209 +p reject 1-65535 +r covex2020 jE7PyEiviH2phkH9ZJCH2GUWEZU fzoiJBZFHqv2OcPzLAVoSDzkwo0 2020-04-20 05:49:15 192.144.37.127 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=661 +p reject 1-65535 +r Waldmeister2 jFsxbtcwGEhHZcPglE5FCNyuCUQ lUZhXRe43TlG7z9RgbwY1tKd0Ag 2020-04-20 02:57:54 145.239.7.169 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53000 +p reject 1-65535 +r davy jGEiE8S1wVT6kIR/NvvzbbeKsaw nNxDOv1l68sxRKeV6dyzujnpG5A 2020-04-20 06:56:32 185.225.69.90 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p reject 1-65535 +r Unnamed jHMOrxSQOAO6EFUgK+ZcVBBeXE8 Af4J/NMM8esnDBv6f3Rd42jrNH4 2020-04-20 00:10:12 172.104.131.38 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=708 +p reject 1-65535 +r LetBitsBeFree jIWNVYMQ1NXqs96vM87jVqygGBA LWm6PyfHhltZu/mNNAacKp5jPNY 2020-04-20 02:41:20 68.69.166.145 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r vaseduva jJT6tzPI8ebBgolG23dpndmsY9c 6RXl7XKn65bVbJ1qaxqKRNgkpxk 2020-04-20 00:39:00 185.156.173.148 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6510 +p reject 1-65535 +r KienjochDE1 jJcEqAaORs2RKH3jwzLv4uIcaFo +leLdEjdaYk0wj5/XaupM5aQ/oA 2020-04-20 06:18:52 81.169.167.88 443 9030 +a [2a01:238:42c8:8600:b5ed:da10:386:9f16]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11500 +p reject 1-65535 +r rynsin jJkHiPgrOgTNgZNulvJBxrtXyq8 IlRC37ZRjJ2KN88kWGmmJKL7xdw 2020-04-20 04:46:32 45.79.144.112 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=365 +p reject 1-65535 +r niftyguard51 jJ33/ixsjiUwSNB+sfOYaEHPJAc 65xv7NsBVRuxK7Xs1673pzc88bA 2020-04-19 22:16:24 185.220.101.170 1170 2170 +a [2a0b:f4c2:1::170]:1170 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29300 +p reject 25 +r FlashSalmon jJ5CdzmcYSwgMs08mMBS8NbqSWE w1KL0VDr14VuyXe9xQmni+smoBs 2020-04-20 08:51:03 185.244.39.91 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3750 +p reject 1-65535 +r Auroch jKFuh4KT0R8OCAPl/An5OlxmaIk MHIGUtJUaQWFBs2f2rG8aINSeKY 2020-04-20 10:57:55 178.17.174.198 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p accept 43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8082,8087-8088,8232-8233,8332-8333,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r king jKKS/1crm5nRlvVgXqAo90/etSE Kp6U3x8D8BAK6HD/wnO3LWp9wjg 2020-04-20 05:40:59 51.89.200.109 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftyentry99 jKc28zKTfk+g9fSEiLgj8xiDEjw LuvG1j+p3cILXZRmzJiQZ7K3BnY 2020-04-20 10:53:04 185.220.101.239 10099 20099 +a [2a0b:f4c2:2::239]:10099 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15900 +p reject 1-65535 +r BeastieJoy64 jKpHC5BXWHQiA+PrRZQXGfyp/uw QaS8QK1qcDRJlm24HXaOb+xJ/W4 2020-04-20 10:16:48 188.138.102.98 443 465 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r VergeDealer jLU3FI1mPbXuRmOkYhjG72vIAVk /zQAvecX/Wsvki/FMede4ptWQYY 2020-04-19 20:57:00 165.22.212.101 9001 0 +a [2400:6180:100:d0::80e:7001]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=810 +p reject 1-65535 +r Kepler62e jLpHCIdFhcRdORcnhV5iOEiwq2U /gIAHsVqAi8wq4PM/FbCw6I0wlc 2020-04-19 21:00:04 86.29.208.115 5724 47125 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=42 +p reject 1-65535 +r philzdifference jM5XSQ+XUhAPmxfiGSotrl0GHgY qyNRIhIfK1vgGdzeJ2KpyGhl/hA 2020-04-20 05:27:58 188.226.107.203 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1490 +p reject 1-65535 +r MarkTwain jM7TkdLhtu0eeHafvc+3DlyRhJ0 px6oWyuzsiwKoNtEh8dvQvwK1Yw 2020-04-19 13:53:28 141.14.220.177 443 80 +s Fast Guard Running Stable StaleDesc V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5150 +p reject 1-65535 +r Hydra13 jN8vOoq9g0z58+j8IC32RiW/tEM bN1bJKfTGKPWWoJ3+Thac4oHkQ0 2020-04-20 07:03:55 51.15.99.182 9001 9030 +a [2001:bc8:1824:103f::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11700 +p reject 1-65535 +r ParadiseTorRelay4 jOsevQm9voMOJXxnVKiJzWhpsD8 sqSqGMwVK2BYRr53oCazWSY6w3Q 2020-04-20 01:47:32 193.182.111.133 80 110 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6770 +p reject 1-65535 +r lg2l jO/ZGSZZ1Gs5OMpMjzRZ35o6PRA QUQbJ1J3XCErQkGQxVQCqAHTI8s 2020-04-20 10:20:46 80.238.124.3 4431 0 +s Running Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r Nusswurst jPAj192IxxQ1UulMaSuQNA/c/NQ rPG3BQfBI01zRmB2TrTQwJBqKGs 2020-04-19 21:40:02 212.227.8.137 9001 0 +s Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=34 +p reject 1-65535 +r zucchini jPmH/0P7fz2apMTz2W/98keppsI 3tpr2r6yOr9hfGnD18sWJbzP33I 2020-04-20 02:20:11 109.70.100.6 443 80 +a [2a03:e600:100::6]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79200 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r crypt0Dude jQaX1i6ZcJAbTsZNUR3fOZzRnbk HgkCZaBSXuFT64b9Cjf9rUscft0 2020-04-19 18:55:04 78.47.125.48 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r AccessNow009 jQk8nCtCvCJKUxmmYKbPXt7+g58 tLZDST3+jgBRbNs5KSUcSprHrNE 2020-04-20 10:33:10 176.10.99.209 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31400 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Raptor jRCF6BjQRz7Gk+OwkR/xh0Hx8t8 Yaj+tGTozVlsI3/z/3zr/oKky6w 2020-04-20 00:02:52 91.203.145.116 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2870 +p accept 20-21,23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed jSDg08ep1yNTNOHCzKa6omw/Rck 4hdaI3egzKFABXqCj6bXvIGj+tA 2020-04-20 04:41:20 51.75.52.118 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61100 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r ECHELON jSMrcfzDVTfPUVJVdRyXKX1RwdQ RzwoHRxjlkE+71V5sD+x4RXkCO8 2020-04-20 04:46:30 138.59.19.17 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r bsg jT1gI8Adc9WnrWReIJN3vFrMa4I HoldYviLJye1/81zo7z2T8M2OnU 2020-04-20 09:10:25 178.78.201.192 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1170 +p reject 1-65535 +r psYchotic jUGZTR0Y6UQDw/Z9BpnkydIkjUo i+YHQMcPL5DQkY+KjRaZlwp4kqo 2020-04-20 09:12:06 5.9.42.230 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r YetAnotherTorNode jUV7OIfvsXorqOoBVZ4WzudOJIk hfnrHehJACbPxxgtFtXGCgtrs5k 2020-04-20 12:04:25 217.91.68.107 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=560 +p reject 1-65535 +r MyHeroEdSnowden jUXm923zKobvMlae36FbanOaWiw tFbfm2fvV4GTdfo1me6XA+5SsK8 2020-04-20 10:20:51 163.172.159.135 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=20000 +p reject 1-65535 +r rortor3 jWLD3Cqt5DMkMppfX/2XcQI03Qs 6qRfXjH69gNejfS3LhpFfgH7o+I 2020-04-20 12:31:58 172.104.49.140 9001 9030 +a [2400:8901::f03c:91ff:fea3:eda]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=438 +p reject 1-65535 +r fucksociety jXP8/zHfNEqsMvMytXWIcyhjuFU avBpj1woR+qcDLpwW0GJpfhTzR8 2020-04-19 20:12:09 185.172.115.137 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=494 +p reject 1-65535 +r thanatosDE jXn3Pc2R/E9QF0IvrHAHTW243YE HXo2DxZwd64MLE9WP7XkbUgsozE 2020-04-20 09:56:28 5.189.169.190 8080 8030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4400 +p reject 1-65535 +r IISPRO jXoSznLd2aH8axi8NwTBNv0URMA gif4JLQYASlyG+MVzupHHpmHq/4 2020-04-20 06:37:32 151.52.195.3 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1530 +p reject 1-65535 +r snap277 jYaJV4Y3n5tOYgg9hrzbduhtSRs vMuWYDM/LjTv9jjIILjiXklg0WY 2020-04-20 10:31:20 78.251.150.4 39853 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r BOOM jY4JCDL8r+oIO6FQ2m0VTjZaWQw ZpCe37KAvwLgtIH5Nml8IiPWoRo 2020-04-20 07:11:00 51.38.51.194 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p reject 1-65535 +r NowyTorSerwer jZEhJvpAvWfufVdZvRlFlFCuvqE FtkxoyOhkra+3lVp5EYCraTol3c 2020-04-19 21:51:02 46.41.148.75 9001 9016 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2950 +p reject 1-65535 +r rtkNetService jZMkjXe7FSw9FPbWNBZklu7gR2c mzHgz0Uznkw84gsRmzOWG/wRjKg 2020-04-20 09:40:05 84.53.225.118 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 25,119 +r BarryJames jZqcIWk23hb+bKejPXtSDXO3zAs aAtnq8HiLg1EQIHfGY2afriT5MM 2020-04-19 23:44:06 52.8.68.153 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7910 +p reject 1-65535 +r vianullorumunorumq jZ9KN13op9yXTAn/3XG1zXqdh40 Pfs8skQk3FItRo0Di8hZg86JjO8 2020-04-19 22:45:12 130.255.78.2 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3240 +p reject 1-65535 +r BeGood jZ/LMIgDHFIZjn0jRLlULj0bCBA xwMWllKRmY0wAWEmSzj6K+aGP0I 2020-04-20 03:24:32 31.193.139.14 8080 9031 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=447 +p reject 1-65535 +r flymylittlepretties jaI1xG1a/EEFj6No9c+MTsdTmx8 gZZdzW+iDfKIve7NRpyyB12c11A 2020-04-20 01:41:39 83.165.35.13 20576 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r TheAvenger jaqAA4dsifLkwqr3cLdy4JsdnzY 9xVaRmtrT7WbnWaRX85vZc1I2+c 2020-04-20 08:07:54 185.248.160.21 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3720 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r J0nxy javwQokkNcm9La6sZ29ru1AY/xg 8kkKJNc8SLupHuYz6VFGnOI3LmQ 2020-04-20 02:34:12 88.153.243.58 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1730 +p reject 1-65535 +r TVISION01 ja8sr0v7DdVrUZVaF1man7DpM9M ZKgIkQVq03TTc+xyK8NO1BzEal8 2020-04-20 12:10:53 82.94.132.34 443 80 +a [2001:981:5b21:c::34]:443 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r TorExit2XYZ jbT34jDBre91IZIc/3PY5UzN04Y Kd98ja3AFaAdAoBXDrwCuXjz/Gg 2020-04-20 02:37:31 62.141.54.199 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9950 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ContinuumRelay jb742CRDd3AmG0x0U/KBXbf8kWU FhrVQdeHeURWUhY2n3sV3GgNi4g 2020-04-20 09:46:53 71.126.130.144 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8270 +p reject 1-65535 +r alnutt jcgyq9ycl7i3H3SrBB08s/qVeKo iBjBGnLRbnMENI9q9ossV5NXW8Q 2020-04-19 19:45:19 95.153.31.8 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r torpidsDEnetcup2 jctSZyL74rP0wM6dAgsFiRcPi9o bD44MzQCNIChEooy5tPysFeamSQ 2020-04-19 23:03:24 193.30.123.70 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49400 +p reject 1-65535 +r powertoyou jdCVZFfPdaSeefjkNOLciYGC3nk qVlg97rDxSX96D1FV1Qe4HEZpGo 2020-04-19 21:20:12 83.57.222.112 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r AngelWater jeEhGQHDM3m7nFfie+02j/bUUSc J0+lordVAwfTTfHXTNiHPBWxPmA 2020-04-20 05:28:35 85.214.117.185 9001 9030 +a [2a01:238:43e7:7500:6d2c:778b:1ff:f2eb]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p reject 1-65535 +r 543da97e8ec8 jetJYn6ANKmL6iQmU0yROvYCKTM Ca2tkA/OuHYsq48dAEW0aNa7Lm8 2020-04-20 08:21:45 51.81.253.201 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r PfpNetworks jfIu6q4kg1eD4FgfssfP/oClwHA P62PDZ5vnb/gst2j1OmVPV3sngo 2020-04-19 23:18:41 93.180.178.216 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2800 +p reject 1-65535 +r smell jgKPBCKhCVOZTFHTxfqO3sGPaTE G7F9SjIeS9VjoG7tLZR/l3uO7k8 2020-04-20 01:14:15 209.141.54.27 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r H3Nr7C4uLT jgUG5/05ufPJB7/H6o7WW9VaBto okEaUbH1mhQ+r0EPmr5bWq+LBZ8 2020-04-20 02:11:29 24.157.140.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=680 +p reject 1-65535 +r 80b74d070419 jhRNkFXO8TVc0iKrlMS/UzHNd18 3aEVCVlKy05R3HuWy8xs5Wzewgs 2020-04-20 07:18:26 51.81.254.25 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16600 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 jhhXYtEZxUrCNxu2ox+WDCte7VQ riqkryfJLEaa5ol7uK5TRut4Rkk 2020-04-20 06:37:35 83.237.22.140 34701 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1940 +p reject 1-65535 +r Inferno jjOksZhQBOX7pfi/Ya46I6K/eOg 6CYbYnzqDlMPwQCihfL6ISxype4 2020-04-20 03:54:24 104.223.94.66 22528 44929 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=414 +p reject 1-65535 +r F3Netze jjixHoSTNtYqtiZPuumwPHDweGM 7QQpg+EbSItfDNbvi8/PXxjQ7i4 2020-04-20 07:05:14 185.220.100.240 9100 9101 +a [2a0b:f4c0:16c:13::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=81000 +p reject 25 +r don jjmIFHKUbVu+QXZUcNnjCZoOtMc qQgXuMaYzpIgIUpn+GDE/lewgz4 2020-04-20 09:36:23 51.68.185.141 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r 1d1dnt3d1th3c0nf1g jj08W2So2tkVJofJPNzh2YzF4yU 0nz8+rHYnl3r22g4Z46cci45fLI 2020-04-19 20:00:41 82.161.210.87 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=274 +p accept 53,554,873,1194,1755,3690,9418,11371,23456,33033 +r colinsullivandotme jlHiueybSJJWg8FocMcnimb+H30 5UvBVj0sJx4FbyDxPmjvhE64Fyo 2020-04-20 04:41:48 174.138.59.100 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11 +p reject 1-65535 +r kingyetwewillsee7 jl6pCijoiNMG+kO5IQoelGe6OuA lg2uIqXBQzoQPdBbMU0ApoLPruc 2020-04-19 18:59:06 178.62.24.212 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=141 +p reject 1-65535 +r DuesseldorfTor02 jl9O5F4GMaYOWcqkLhRk/XEgRZ0 To/Z7Hxk4M7bXb+Zk0YVX5s5FGg 2020-04-20 04:19:49 146.0.40.73 443 0 +a [2001:4ba0:cafe:ecf::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=43000 +p reject 1-65535 +r AlGrothendieck jm7aeNjjq6iNh3w+N9bU8JOMe58 rSisi/AstEtqLLnGCLyUyFaNp7o 2020-04-20 01:45:08 80.67.172.162 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r JimmyBulanik jnbx9uhJnM6XXEUVYFhqX4vwv9s M1f5S6XNhuT0xEVk6boWrU9LJno 2020-04-20 07:18:07 185.86.150.58 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18200 +p reject 1-65535 +r snap277 jnsaracWV8XcNlVaGNHxxVGppy8 Py4MVwjEzcx/urJiWXidyQNH3sM 2020-04-20 06:32:36 90.216.121.218 40297 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r dipulseIT2 jo6dP9HyWBTNtXp9uqKQEU6t574 ZHSudLjb1/LaQHaK7XitcvQFNZ8 2020-04-19 19:00:41 62.210.207.144 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p reject 1-65535 +r NietAanraken jpgxVkcOkebvQQzYC7QRD3EmALI B4kTx7D1qHtA7UsPziB+m6OtV3Y 2020-04-20 05:39:59 176.9.92.138 9001 9030 +a [2a01:4f8:151:3388::2]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4070 +p reject 1-65535 +r way2Sanjose jpwRJR+ozlBuDJInUlLS/bQ06vQ V18kkiwhvri/lvEGN2LZyl1YARY 2020-04-20 05:38:15 61.92.22.235 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=471 +p reject 1-65535 +r noname jqWPKNymD1bG8hMb3+m/X68iM84 goplvCIzSemXt8JPgpiQwJVDkr4 2020-04-19 21:03:23 195.67.191.210 9100 9101 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Enos jrci+hrp3eGRS8If6iKBnU3pnbQ 0XUSoWuqU7T7doEmMEKhVKHxzTU 2020-04-20 02:35:30 195.189.96.148 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=65700 +p reject 1-65535 +r kansaiNURO jsUDyaEycbkTTsiJn1Z5oxjayP0 jT/eTTjhUrGMZDtoq0d2GDsiROo 2020-04-20 11:49:44 92.202.22.130 9001 0 +a [240d:1e:11c:8000::5]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=806 +p reject 1-65535 +r PolishWingedHussars jsf+fyoRiet5oHwC+z8f1XEy5C0 GupJWfnoJVd/q4gBfjmN5ArwzrA 2020-04-19 21:23:07 85.89.172.150 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1430 +p reject 1-65535 +r niftyjerboa juBTRTLqMapRcrGJL1Oy8lx26wI RyEza7gGZIToOQIfbIM9QFJszt0 2020-04-19 19:25:27 185.220.101.25 10025 20025 +a [2a0b:f4c2::5]:10005 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35300 +p reject 22,25 +r Thalassa juKOrwh0r5sD6715tetQWeJUc1U zWtJTT3E6M7SO3qFMc+VYpHaQjQ 2020-04-20 11:56:44 198.16.70.10 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=50000 +p reject 1-65535 +r TorOrDie4privacyNET juRHF/pVcFwSCG8+zR+NnIZ2/QU QlaJfH13eTfEqnB5gRC+3O860/Q 2020-04-19 19:51:45 217.79.181.23 9001 9030 +a [2001:4ba0:ffff:15::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32600 +p reject 1-65535 +r astronomy juyzK0IwgwGiVlLdxfij1AGrwhM occ4TNx399pzpP7L92aKmaOgDvk 2020-04-19 21:00:07 142.93.114.226 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r nels94 jvBSAzMJ2FTWIGpMMPF60nyHiT4 ZsmwHZ9WkNTJfJpUNp8i8vZLoZQ 2020-04-19 21:00:07 91.155.242.145 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=79 +p reject 1-65535 +r TormyyrFI jvdI/M8aniuWUdxqvZIfjusk+nM DgNvW8W0/5DwnpEuQqBdr/2pJ2A 2020-04-19 21:19:13 91.221.66.21 444 8000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13100 +p reject 1-65535 +r 22c7676e678bb03519 jvd/0AkbQiGrWcYmMMXVT2bkx84 6VJ+hWcTqzHx1AA4P0bXOrPkgoU 2020-04-20 07:35:54 190.216.2.136 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r amartysen jvh2bhZFpBoq4VZetnOklXyNWtI uZJfoUcBqE6oiMoEB03UBysvsLo 2020-04-19 19:06:07 77.247.181.163 22 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44000 +p reject 25 +r scenics1 jwL+XiM3MKarTJguGKITbmYqC1k y/3HH68VHcN6fdGLeScI3zEbrlg 2020-04-20 07:20:28 85.228.26.215 7070 7030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p reject 1-65535 +r snap277 jwRigXoOLNPdlW6fkmvw0rCzrUU vBD3TbVN2Sczj8vjsFcXwvoCw/w 2020-04-20 11:19:23 109.136.209.83 37699 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=865 +p reject 1-65535 +r whitsun jw9J8jQcf3BtW0dYFdvT5XYTNLM WonpUd/PhJR/uJKBAyt8Nk/TdnA 2020-04-20 07:57:05 91.219.29.188 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56 +p reject 1-65535 +r pointderupture jxYinVQld03KVm13N1lheBU9uDg U7j2hXlhcmTNNhru8zTKfU4WsX8 2020-04-19 20:37:50 195.80.151.30 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r bee1 jyCNGsWPvYl1zOTL70DGgCIBpRw f6wHON2ilL7HYHBWuVd092znLTk 2020-04-20 06:49:47 62.219.3.47 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4280 +p reject 119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r danby jyKv3QaqQjit2TqOpvvCu5xlJxE VpqgTAhMnjr829M5SRu0rMoying 2020-04-20 02:16:49 93.115.84.143 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27200 +p reject 1-65535 +r BitchCoinRulz j1jY3GqWr+YmL77/h0H9QmLrrLQ q5j9ycwFf7lhoxd9jEjXWiJSdjk 2020-04-20 05:05:16 93.132.67.84 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2030 +p reject 1-65535 +r Martell j1rLQLQmKARebYykyxA82usRKj4 ACWr3fs/R5nIvQdJtnoohIuVrU4 2020-04-20 00:46:24 3.121.167.65 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63400 +p reject 1-65535 +r Unnamed j2GYN1vY4zlSFDkfHO8G9fwO7mQ 22LTrGrWM/MtkmatEAw7jv4dXB8 2020-04-20 09:49:29 188.40.166.146 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=62900 +p reject 1-65535 +r king j2VKgxZicsoF0AdrF3g8wd5dDFM 4Tt6WTQZzms/5PCQxHRkERv5HWE 2020-04-20 07:09:55 51.89.147.68 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 j2z0hZTFeX4tnPrcvEbYubqi3SY pfvmEbkufnSqxVks0xqTXFUig1s 2020-04-20 06:50:08 92.158.2.251 46369 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5320 +p reject 1-65535 +r ChanaTorRelay j24hv614gSPjwEzpWzVszyovupk wva11LCtG63w3YMx59UNzS/uPTY 2020-04-20 09:44:56 27.145.235.28 9001 8081 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r orwell3 j34SDB1Dcf6hnjwVjBgNfeTuUFw yhpNh5Q4xldq8vuut+KW+oYTSK4 2020-04-20 04:17:57 91.204.6.195 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7330 +p reject 1-65535 +r duke j4kHhXX+5XZ1qSLp4IiRj2OsdQw tiWMtDijX+WGiKf4TNE/HzvICoE 2020-04-20 03:31:28 158.58.173.78 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p reject 1-65535 +r fiedlerRelay09 j4kzmcjKKEWD46UmprTl/XVEnoc GNjkZrYVVy4bTbX9EZhmYlgZ6EE 2020-04-20 10:07:55 46.232.251.29 9001 0 +a [2a03:4000:2b:610::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7700 +p reject 1-65535 +r smell j4ld1x1vh5D1YbAEQi6PMTtuaHY 4dv4Sebnxg8exZ0Iy7MrahS1lT0 2020-04-19 22:23:22 45.9.148.221 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6930 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r nibiru j4vLBFFo1Z0NdEOpH9yiLAEh+vY Fknuu4B/r+mTQFZwPQIHOk90Sic 2020-04-20 07:12:15 37.247.49.139 9000 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=713 +p reject 1-65535 +r snap277 j4zim7Ri95EC7QXgrf4pTCpT3S8 7injiIUn/t47aP82wAto2TA/m7M 2020-04-20 09:16:18 46.149.86.127 37785 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2020 +p reject 1-65535 +r Doedel22 j6N7kzlwFbK8WlJckISFJgvp9CI myJmTvHuWyPbUbKqYG8VFukzE8w 2020-04-20 00:06:47 81.7.11.96 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r NeelTorRelayA j6v00mbflSFvbGRsbW1GEdPc9IQ mFc8GVzlHQbr631N8ZhIaCGkxi8 2020-04-20 11:02:27 174.127.242.253 143 110 +a [2001:470:b:1e8:af1:eaff:fe86:ad09]:143 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r snap277 j7rntFsL5ZSp4kUeC2rwPPXkT4w 8+a0GYHunt/XCaZX1XkclDhJbtw 2020-04-20 01:20:23 88.26.122.2 42463 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4840 +p reject 1-65535 +r SharingIsCaring j8I/QStZy0uyaSB7EQFh+G5yPRk tVZ7VDjV43bisZLzx63+V7zQGkM 2020-04-20 10:54:28 23.92.138.206 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=323 +p reject 1-65535 +r TOR2DFN02a j9O69eFOvhEk1iU9WYgq/hwrm44 9qSEIqH33jnGyR7RkMnBciVxfS4 2020-04-20 09:39:13 217.182.196.65 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56000 +p reject 1-65535 +r UAyyyy j96udZqQxkiGO+2F0HET0/oqpv8 xyofDhXkIhZaNXL5jKoW3bkvM2w 2020-04-19 18:54:35 193.218.118.131 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=271 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed j+/80tv6CHnKJflgBIxV6IbOJSU CXUq5pu+IVJBf9aoktwK6XA2M2A 2020-04-20 11:31:46 205.185.113.211 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4060 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r rortor1 j/JNxh6jNcr91Wmak3rZbVlOWQQ 5oNfY0QyNZPMeLGHIi0dCI3sdws 2020-04-20 12:38:36 97.107.132.24 9001 9030 +a [2600:3c03::f03c:91ff:fe93:f4e0]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p reject 1-65535 +r niftyentry74 j/KJapS8ql8KfFpWrWWGSSzUSK8 JACbbEF/oip3TC2+jEN94OWYtSg 2020-04-20 10:51:18 185.220.101.214 10074 20074 +a [2a0b:f4c2:2::214]:10074 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r leghorn j/Lnt79MEh0fSdZgaYfFgC3blXc vhCcAPE82zw8hhz5XoxwjJiSY8o 2020-04-19 23:06:40 192.165.67.254 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=556 +p reject 1-65535 +r TheLichNode j/PK9gaz1tSBlGqzpZ3O8VmcW8s FoOt3kSpeom3g0+y6lewAdJfOVo 2020-04-20 04:37:11 45.79.138.171 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 +p reject 1-65535 +r h4x0rs j/ro5nS7q71twDss+lOJdhIBSYc jUPLZ/iZIg4aybP3gg3CgBdk8XM 2020-04-19 19:28:28 144.76.143.137 443 80 +a [2a01:4f8:161:92a7:b03e::17]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p reject 1-65535 +r SilloCybin kAUmHBp2gWvpgMT4J5ImPb98wPs AiLSEVfrxsy6CVBrqWFtjD97MdM 2020-04-20 10:25:19 94.238.113.19 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2600 +p reject 1-65535 +r myNiceRelay kAd39uEwcyjVw5gmNWkl/eyweQs sFCEp/ubYkLTUwBR6gAWLIM4Ak8 2020-04-19 21:50:01 62.171.180.6 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=37300 +p reject 1-65535 +r SillyRelay kBWS++KiM19dw6VDRgC5pPnZxo4 +p832uHX7BGaEhRV6WdS9rWwjrM 2020-04-20 01:36:15 147.92.88.67 9001 9030 +a [2604:21c0:100:1::cafe]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5860 +p reject 1-65535 +r freep3p3 kBy6b/O5BhjT/+/wQDU8Jn9pDfg kVD5WnbAuhiiHDeAK33TT16NRMw 2020-04-20 11:35:24 94.23.222.72 8080 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33600 +p reject 1-65535 +r niftywabbit12 kC4hvAWnseyM6F14xHw9jq1e/m8 9zSGQigW9FeA+sabjF+NOdW4MPE 2020-04-20 10:53:38 185.220.101.242 10242 20242 +a [2a0b:f4c2:2::242]:10242 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45100 +p reject 25 +r engee kDBEsYXSkzF6DLTn63/4mLB248s iCscVgfFbFIBi7NM2FiZsLRdlDQ 2020-04-19 22:19:52 116.203.22.86 9001 9030 +a [2a01:4f8:1c0c:5812::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r torelka kDoqeZHIOOcP9aWGzTh3SbNYlmk hEWDoCm53dFzsULDUUtNXFPlQZI 2020-04-19 20:54:01 51.15.219.22 9111 0 +a [2001:bc8:4400:2c00::1a:40b]:9111 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29300 +p reject 1-65535 +r nottryingtobelame kDymfQ3rdM+7AUMoQKJsuMbBj98 Bxz1trn1qe0FZa0rKQNFF9+PMRs 2020-04-20 01:08:55 24.154.185.56 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3110 +p reject 1-65535 +r tschunkdidmedoit kFR+f7MbaUpCaMWrAqCGZwPE/4M hhJMhmtKSs4lOjwWVE+PDAQ71dc 2020-04-19 19:14:55 152.66.35.72 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p accept 53,80,443 +r LeoR kF63emOFfm788E1zSlR7CZXYXDs T0nk+z1dTgxAOtyPJNNi4VrHTTE 2020-04-19 19:45:47 3.225.115.238 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20800 +p reject 1-65535 +r AlphaRelay kGMwEqGnUtjQL+yDdKS/mJQaGQA znsXq3t07clMWUNfZ4Yj2cyX4xA 2020-04-20 10:43:12 116.203.40.245 9001 9030 +a [2a01:4f8:c2c:1192::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22600 +p reject 1-65535 +r mj3 kGPH7Eoyc0RtwF6TEKXFsvQjVpY jX26Kyws3jtOyEYPOeRKALhNVX4 2020-04-19 21:26:36 93.115.86.8 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24900 +p reject 1-65535 +r Unnamed kGkzownxXXzzeRJweKZ5Hfmwx2M v3MrkjnAUc1iKKSD2H4PBQp2MyE 2020-04-20 04:31:55 91.121.82.25 443 80 +a [2001:41d0:1:8719::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8330 +p reject 1-65535 +r thanosdidnowrong kGpC3YgKLL7dUvPyj+n5Qqhl9xU aL97JM7QvuJaWsrml17Z2Io7MGA 2020-04-19 22:57:14 173.255.250.219 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=4000 +p reject 1-65535 +r niftyquokka kG3LOQ8rqYeuJY10XmC6qrrTHeg T8lTqOVt910tmFZYkJi5KVNExro 2020-04-19 20:26:53 185.220.101.18 10018 20018 +a [2a0b:f4c2::18]:10018 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52000 +p reject 22,25 +r zzzapz kIQj/oxyIrKslQwDRHDSEn3oeG8 iwDbndy1y3wTteRAtZzLQlQQYvQ 2020-04-20 00:01:04 77.164.90.95 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=117 +p reject 1-65535 +r LittleTorRelay kI1QsXyBrXlKP7EkNzxtRYQ3xn8 xCzZZAHyqrSHJ9OPjloBjUWABiA 2020-04-20 08:15:44 130.255.78.232 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27 +p reject 1-65535 +r deadbeefbbq kKQOr2CQvSYCN73+k5Gi7/NehzM QTKxUx2w/oH67ziQCNxVSFR0y1w 2020-04-19 19:28:20 199.195.144.111 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16500 +p reject 1-65535 +r rofltor09 kKXRNVxLWEDpUOth5nOGOmrjrKE T+wwS5sfGUgoTGwKDtXdHNgPLt4 2020-04-20 06:18:48 54.37.139.118 9001 9030 +a [2001:41d0:601:1100::1b8]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15100 +p reject 1-65535 +r LeaveMeAlone kKuNVCisKWarbUm5Nn7VcB1vtNg ygU0EreWeYe2LQ27Z3cTHkMV8iE 2020-04-20 08:12:51 82.169.77.109 9001 9030 +a [2001:470:7c21:28:a074:d1ff:fe26:62d4]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=765 +p reject 1-65535 +r Unnamed kL0GE3pb43pyvWeTzfBXaRtxjo0 Js8zFfnwTyDPlLAu5NDWkDoyoEI 2020-04-20 11:55:37 205.185.119.126 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1850 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r KhorntestFGUP kL1eOlLuOYfBm43IxA+Oi/qdnhk f+1XOlL6qdX0aK+0uYB4XbnhpME 2020-04-20 02:21:13 188.254.32.237 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5600 +p reject 1-65535 +r MegaRobotMecha kMG8EN8IGgHVDjgtcnGVXgH89sk CSIqszx9OJMydy0j0p1OLZTDNKQ 2020-04-20 02:53:19 45.79.92.94 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r coTor kMHo3dM+retnraiMDhNpj/h4rlE J1B3Q8x6sfQa6PQHvq0u8NcML44 2020-04-19 19:28:30 95.179.247.88 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p reject 1-65535 +r iamd3vilrelay kMcXKzXRGNM30QZfuDMG6BffrXM GJ2GUxPhHXWfIppv28nuKTDXg0w 2020-04-20 09:19:07 51.158.108.61 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19800 +p reject 1-65535 +r Legolas kMvD8/E9Xg1b/zsRN6SsZNOJzwk uaI50vcCl2iwQe8o/3jHNX2R7vQ 2020-04-20 08:37:15 37.187.1.29 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3100 +p reject 1-65535 +r marylou2 kP2DDDV6UQmrPFBSh3E/GsgRF0w hJLgIoqxag7BHHaLGQquyHNGkyY 2020-04-19 22:54:29 89.234.157.254 9001 9030 +a [2001:67c:2608::1]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r tor0kryptonit kQQbNKC5F1lHWyzsCrMGP/I8dY0 qkFXcdBvUAhEnZSr2vu5w2PShqo 2020-04-20 07:34:07 188.114.140.245 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p reject 1-65535 +r dipulseIT1 kQhCICVyu7iQaSlxYUdYrZ8/69c 4AWxLA70LJ799vlBxeefyhLEKC8 2020-04-19 18:59:45 62.210.207.144 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r windeck kRjXt3Cq35id2cJtbUUSfvDzsto vS/0IH7YzP++JMlgPvTA1W9QrRY 2020-04-20 07:46:54 185.72.244.24 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8050 +p accept 20-23,43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r siotor1 kSBW6uhBDBdorS78AHzl0iYlvCM jVWkdDyfyBR/lVt8RSxmISMpb9U 2020-04-20 07:39:17 51.158.70.1 443 80 +a [2001:bc8:4400:2b00::1e:c11]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21600 +p reject 1-65535 +r landev kSWPDtsf+Sz3bm3Di/6YBVp02/g 2Mb9Vlrtl+Az/3IMeS/GfWXi29w 2020-04-20 10:07:28 178.82.215.219 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7370 +p reject 1-65535 +r TorroncinoDE kScJx/VgzD6f6WBLWNWYsb+u2Mc ZZ/wYsB0fT72ptWkbPKuWSY7LOA 2020-04-19 20:10:48 62.171.185.179 443 80 +a [2a02:c207:2036:9748::1]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r 0x3d009 kSp8V+BWBq9gLsY9HQa71ceq5RY nwZTQCinw0zrRKs9aQPnLyQQ0hk 2020-04-20 02:23:16 188.165.220.34 8001 8030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r trex kSt1lzRqdKRK1LYGjGRXcrdY3Lc wsPyWzp1mXfmJHC8zhRsPwwn6As 2020-04-20 11:42:46 46.4.124.165 9001 0 +a [2a01:4f8:140:71f5::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39400 +p reject 1-65535 +r Unnamed kTjd8/IR0g/2Ea/wmbZwcEWcbUU 9zkqc1h5qo7HBlV7RdRVT3YmpiE 2020-04-20 03:08:26 18.176.51.176 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=994 +p reject 1-65535 +r dakkartor kTkx7F8fnMuWTX6sGt2YaWhEpSo RSPXgJ4ZCwnk7XC8aSdgvfnjAYA 2020-04-19 18:57:53 5.79.85.53 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r F00F00 kVF/IZ92SOS4u/PBYsd93FUxVhI 7aKoZ6GFPSYCSFMdH7TE+zvvFh8 2020-04-20 06:32:54 46.4.88.92 9002 9100 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98500 +p reject 1-65535 +r cyberspace1 kVXb8RyiRpCKVBDtp5/PAdpEkBs zDM/bszWeMrzeuslTvc/+Rhd/64 2020-04-20 00:24:26 94.114.86.53 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=141 +p reject 1-65535 +r elektrobier1 kXEQHnCa3liB9eLKEQDUBEtEJj4 v2NLFOYPOd23hak/2iJlykumAfY 2020-04-20 10:27:13 95.211.138.51 9001 0 +s Fast Running Stable Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r EyRonsRelay kXma0JcBj9X4O3C5eAaPuD9yk08 YyjsQBs2uiwXdqtgXy8ezuJ6nGI 2020-04-20 03:14:04 178.254.6.4 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39900 +p reject 1-65535 +r timcinel kYJJVt+kMMBxv2uUtiPfEJMdHUA IA/JMteXCcAERhY/J2YQHYI0sbg 2020-04-20 12:17:53 37.187.105.104 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r eficommander kZWCfqT9z7fQBB0sn75Vr1sfOj8 A7gtcR5QizBRakoaezz0sRvSDrY 2020-04-20 04:14:27 73.202.4.42 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=220 +p reject 1-65535 +r NikitaEclair kZaAt5GYrk2AoGmZqT68kJrU3dw 2ZFNrYyiCbnyigTsafkYe87xYOg 2020-04-20 12:49:36 144.76.24.130 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4220 +p reject 1-65535 +r Unnamed ka3N/KgwobutOhA3eyXWlakr8lE idOsQmnrlcnaRkZHGQxtvYH2t1I 2020-04-19 20:31:48 145.239.158.234 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=710 +p reject 1-65535 +r 324partyvan kboZP7Ni+3tmeaeoOjBQ88RKVGg U+7aNE6mUcL9H6r4XP/LmrXtUPg 2020-04-20 08:46:41 45.35.192.34 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13800 +p reject 1-65535 +r valkosipuli kcaudKNSCuiQ8FHpkvXH9tOR5h8 fNWBDfO4Wdinuj9SBWpxsTPZauM 2020-04-20 01:51:14 95.217.23.60 9001 9030 +a [2a01:4f9:c010:6734::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r IWorshipHisShadow keQBXh+C2vASHWImflSh9mGrbcc Mvqc7ZZE6glxLoPTVjeSt8/UGC4 2020-04-20 04:26:07 173.255.245.116 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=800 +p reject 1-65535 +r Fission06 kefKa40KrXfHz7j+olv09G2hBCo qz24Wd59ZXSjxYSwNVTRyo7Ayr0 2020-04-20 11:25:19 37.59.76.253 443 80 +a [2001:470:c91a::5]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 1-65535 +r bamse kfdCLrxw9HkyOEQUliu2SIvbKwo U4evuNPK2pX7g3LR4VDRtvyV7z4 2020-04-20 04:45:27 95.216.220.19 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=9600 +p reject 1-65535 +r TorchFlak kfuuipLzvfv4bYhgzH/xibag0WU DyQPnLVQwRXprc4/gOWa4lwwjaI 2020-04-20 11:01:54 83.139.143.131 9010 9040 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2190 +p reject 1-65535 +r bgsv khc8nxCBl0YDB5adNTMz2s6bnwk lZQ2bHL0MenQUpZYunYGxGlguYM 2020-04-20 02:11:37 62.141.39.8 9001 9030 +a [2001:4ba0:cafe:5e4::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48100 +p reject 1-65535 +r thardes2 kiBdbRG3GAzZHHiYl7VdC2LSLDo h1MBXTYbJukmrr4AOI+LlpabAMI 2020-04-20 02:20:13 77.190.119.198 9001 9030 +s Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=63 +p reject 1-65535 +r mediterranean83 kix4DWoylEiQqcK9sogDfrLwY5I uoH16Aqp9RjleVv6cp2VEdUKKuE 2020-04-20 02:22:50 46.101.192.230 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2500 +p reject 1-65535 +r mayonez kkKbtLb+GxZq4DR9A7PcOs9Xi8w UzfZ40fGWM89ZAEUhHA1PjE1uPU 2020-04-19 21:12:57 95.216.181.15 9001 9050 +a [2a01:4f9:c010:622c::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=34100 +p reject 1-65535 +r NSDFreedom kkskr6fwddBZ6O6yhMxACzPT0DY lGm95BFVYZzYa95BBkD+yrg60q0 2020-04-20 10:08:18 96.253.78.108 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8160 +p reject 1-65535 +r snap277 kk6sunUvVOqzFXKg9onhL4qQ60Q g34I1mXdl3EuEPl+Rq2VfQQj4+E 2020-04-20 09:09:47 83.192.237.17 44383 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2 +p reject 1-65535 +r king klkb/tFGrQ3tZdQm52ZasftDppk eDfcEd/Z6KzlngWHY/CwSoe+8mk 2020-04-20 04:48:28 51.68.201.118 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nothaas kl+Cz60N24ORYfq55zVed0xzA3g oq82Jwmm3iLsSPV5LAkRjCPV69I 2020-04-20 02:32:32 91.219.29.238 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=161 +p reject 1-65535 +r 0x3d008 kmlVJ3x722zR4VYakYR8vNWweeU zB5j9DrnP4tTrNOe09d9nb9aqYU 2020-04-20 02:22:33 188.165.220.34 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29000 +p reject 1-65535 +r angeltest9 koi3W1/4hh7/Mqa+iCXMOKT5+MI eLMdVVJ+JRJJgN2gu+kFjq1W0XU 2020-04-19 21:29:49 92.38.163.21 443 9030 +a [2a03:90c0:83:2908::101]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48600 +p reject 1-65535 +r BexleyRecipes koxHCeZjsP8VL9Hxy91qr6O1SNk /yVu+rowHDp3LDvhyl4mpmNmf40 2020-04-20 07:25:08 18.27.197.252 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r desnaturado ko+hxoBIRWmRcHETl1cB/XXLMRs PQv6dDTzV0YXUjnA6zdFatX/G20 2020-04-20 07:33:00 45.232.132.193 20044 20045 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r Fission11 kpu4SmgZjONeLygogShAr1wsvEo OAiWX0gk2AvOpLQn3x1YUMb6ksA 2020-04-20 02:25:18 54.38.219.250 443 80 +a [2001:470:73f7::6]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33200 +p reject 1-65535 +r Ichotolot65 kpvzfGV9T2nHYyTl/qdgpiSDgTs 4pDklFOpbvdbZtozd3+Ith/z8HM 2020-04-20 04:39:15 91.143.87.51 1080 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p reject 1-65535 +r mpan11 kqEluatJGvwITkJXtVLQ+1YJDLM brOyEMJs+l9P25cCANqopX2Tvhw 2020-04-19 20:05:24 89.74.84.213 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r niftypedetes kqYIXquq3ZKLb46HFUChpBy8CLo 13+PcwXYxofeGQQYeFzNr+oxoWg 2020-04-20 03:25:42 185.220.101.13 10013 20013 +a [2a0b:f4c2::13]:10013 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40700 +p reject 22,25 +r Unnamed kqxDgalhK5WjrugwjfKUugkEfsE P5dRXofa8J2oIb6tTYDdMlkJcLk 2020-04-19 21:46:01 185.51.134.186 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6830 +p reject 1-65535 +r Fivedollahboomboom kq/6Pg8aI2wXW8Zkros1btptDI0 7dTwnQHKJvVzLfy2YjhUQaDCPyM 2020-04-20 10:49:17 162.216.242.122 31337 29030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2370 +p reject 1-65535 +r ecrehd2 krqm9B/SjCLxgrRGflQzxLU4nFE F33TnZPSnMGuSce7a9rHuD3ITfE 2020-04-20 12:29:41 217.230.99.52 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1340 +p reject 1-65535 +r Unnamed krutywaX9esXksYH7i3BwpGpitw U1+a+YOUne8pQxI0IwKea3A5FKg 2020-04-20 08:43:24 78.31.64.201 443 9030 +a [2001:4ba0:cafe:477::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49000 +p reject 1-65535 +r Unnamed ksP6vD1aNchZeCAPc8CQsJVADPc y3vYdWDpwbIDpR6tpXBOtbR1CrA 2020-04-20 10:31:22 107.189.11.233 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40900 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r angrydance ktGTpVnQt8pVU5KPB5wSvPw3Hbg NUgXGp8iwiZHZIJTgQ9tCXhWEks 2020-04-20 10:05:24 45.91.93.231 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r Unnamed kt7dc3aA6o+brSl5efSBeNvdON0 XEhdmpgyZk4MsunNHuOcZ18vgyk 2020-04-20 02:47:23 95.216.0.158 38574 49735 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=96 +p reject 1-65535 +r bel kuWnNQNfSAEgdojk9zDCWnpQh/Y hfa7EzTdpmsmOd+DWr3klihbGLc 2020-04-20 07:36:05 142.196.194.103 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=963 +p reject 1-65535 +r mamba kugHrF4jzNn+Yj6k3AILFieg0Js sOAMFzXRbeUM+HtqQnedeEDlXVk 2020-04-20 08:43:38 45.95.235.197 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8900 +p reject 1-65535 +r rouleau kugrbXHIBzx0i6dOgYxHi0tceTs cOINDTtszxnhU0k3piWlcYFoXlE 2020-04-20 00:08:41 103.28.53.138 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Aleantlar kvEGSsGiode0qXUGSEt3mAFviLY vm+ue0ezWPHHjUCVYjPs0eeEzVA 2020-04-19 23:18:21 185.244.192.119 9002 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1860 +p reject 1-65535 +r sipe kwVRoJFk6rGuqoTzKrPyIN6VI8I FJNC8ZRbexRtVyBOXg1WTyWZb7Y 2020-04-20 12:20:23 188.213.134.60 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=139 +p reject 1-65535 +r Quintex50 kxS9lQO5AUJhplwiHXflc4nbzME IAn6z1o/YlvKeLQt+Nwzp9xv2no 2020-04-19 18:54:36 199.249.230.73 443 80 +a [2620:7:6001::ffff:c759:e649]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r TheLeonardNimoy kxx2LfpxzgUXasHzQC2GayoMke4 fkicFE23hOB1pkEu2aYkPebyIq0 2020-04-20 08:23:06 198.74.61.51 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=14 +p reject 1-65535 +r bauruine65 kx99exAsh9ArCQ0DBnrrHePQLJQ KmeN+yxI6JSK8gonxBN61WKN6rc 2020-04-20 01:56:35 158.58.170.183 4443 5580 +a [2a02:29e0:2:5::7]:4443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p reject 1-65535 +r fdpstueckscheisse kyHQTpU8oJS2Nk+jSVraUrHbSp8 fTf9y62oZbu0I8x58/JieQtx51k 2020-04-20 10:18:26 140.238.228.95 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1230 +p reject 1-65535 +r snap277 kygB1iKyRSMwHy2kLSB8VIWvem4 JFnq9NUcPCLI9JICdTR7L4Okoas 2020-04-20 12:34:22 37.6.77.0 44731 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=92 +p reject 1-65535 +r dust2dust k0jpJ84ofzWuBvH3TGe01rx2aQE IlXlyTkJ7g1fBaMDms1sHxgiJh8 2020-04-19 19:40:53 158.69.207.137 8081 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14800 +p reject 1-65535 +r snap277 k1jmeyTcoN3uF+77yljGiayH7Mk 0HFLKUWX09fcEixjtqnSjPEkPTM 2020-04-19 19:44:14 155.133.57.209 33037 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1240 +p reject 1-65535 +r hiddenPUMA k24VcDNlFnwHDeORdx+btgIARGA 4HTD35DFacYOR759SJjw1yiWJ2o 2020-04-20 10:13:17 213.170.216.111 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=723 +p reject 1-65535 +r FFtor k3KqhebELzNMuR+f6bWbURjFZig ULgB85kBNxKzB0Yb3k7svLDzlQw 2020-04-20 09:36:43 87.231.29.62 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=813 +p reject 1-65535 +r Fission02 k38gHSeXMUlT8mjSUvXJjT+p9x4 Re7Mr8d3wcM+tM5sMhq0sSSYBfQ 2020-04-20 12:25:48 149.56.94.217 443 80 +a [2001:470:b14a::5]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r Unnamed k4eigJGnksTgG6RQsKQXLc999rA l3EDnOm14D0cFcHRDY0pZ/c3fyI 2020-04-20 01:03:39 213.179.54.190 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23500 +p accept 80,443 +r BravoRelay k4jSJI20jLrCPtEyZHtwG52be6c x/Rq9GTe7NDF1/ahwCrCmaNuwHA 2020-04-20 03:40:37 49.12.3.171 9001 9030 +a [2a01:4f8:c17:52c7::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24700 +p reject 1-65535 +r ididntedittheconfig k4wnL0C1e3DLvXmlWViMy9cPPDs 7Bx4ineUi3w6FTZew6BMaj5NL1g 2020-04-20 11:39:07 100.15.139.123 443 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1240 +p reject 1-65535 +r snap277 k45TXFpxchWapYTNlOXOKi5Vnvw NoezaQps1tdPnNNxDz/yNZNEJvk 2020-04-20 09:26:21 62.194.68.33 42267 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=311 +p reject 1-65535 +r pricklyshirt k495Kvl9/IFUzaw09kbY9H1wQ+s A1UeK5qHDhSCgGOBv5RbSjcxd3A 2020-04-19 22:33:51 167.172.111.100 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=1720 +p reject 1-65535 +r F3Netze k5Em6k0lyyEqeXRsEzGU+KJMQ1s qH6BCNiIZSenBG0SEilkYfrrkYg 2020-04-20 06:34:09 185.220.100.253 9100 9101 +a [2a0b:f4c0:16c:3::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=85000 +p reject 25 +r snap277 k5L4aIT7fLdJmWBN7NpgCrTqMS0 IQswkcGEBZpICLwitVxuvIQtXbA 2020-04-20 09:19:07 94.34.129.103 33095 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2220 +p reject 1-65535 +r Unnamed k5UpJqXyWS5+jB3Uee1hWIgErAQ tmh53AayXMVYcAFEc4BTt6RswSI 2020-04-20 10:30:01 91.219.236.53 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SixRelay22 k70CCb8i5Vih6L592q0kfPt2jVA dj6gTxHqZl6LB8/81pdVWO0e8RQ 2020-04-20 06:47:54 5.51.254.248 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5030 +p reject 1-65535 +r tpzzs k8HhTNYAz1GxF95zZ0HnQAoGmvw KFn0vO4HViv3GcJUsSJ0FOKF4sM 2020-04-20 00:48:49 188.134.83.100 9001 9030 +a [2001:470:28:3d3:b62e:99ff:fe5f:334a]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9510 +p reject 1-65535 +r bosabosa1 k8vB5BREBqtnYeAxT0uzU/g4zQo WxhgolEe/lsP1SPdHY5b4QYBUZg 2020-04-20 02:41:27 45.79.73.22 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r hougeMiddleRelay k+TGa3Y/GduaFM0AgICLfSk7VbY Ixe6PWZ3U9sGbNHgrBY/kKJfs50 2020-04-20 12:31:42 51.83.217.199 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16800 +p reject 1-65535 +r Lotor k/Ta9PDeXmhnziCg+cfAWYNNrK4 I16/k/6XA0cwARpmbU2e4wUbeFE 2020-04-20 11:34:37 94.16.115.123 9001 9030 +a [2a03:4000:28:5cd::c001:d00d]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28600 +p reject 1-65535 +r 3728effcaf4e lAG7YIgPgE10h2a1TYlB2JtolzA gc8OFvffhD1D7YzAgvix+/bru74 2020-04-20 08:11:02 51.81.254.1 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8760 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r kogis lBmFzeLcnWf+wHA6j/0GHjtLqKk TlJxLCAEhDsrNoqJw8MNRGiAP78 2020-04-20 09:32:36 188.165.236.18 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=5100 +p reject 1-65535 +r Unnamed lB3dDUxJw8OXhyJ1Un3EsZIHG2k Yz+qXYlGnbX/eYxZVyEOH4CQhHk 2020-04-20 09:07:55 212.237.96.162 9091 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2280 +p reject 1-65535 +r TorOrDie4privacyNET lCOnK7yLXGrJ3p9Xc16ysI5BVug G3dK+3yZZCfadjuneTXG+YM/Evw 2020-04-20 00:44:51 37.157.254.37 9002 9031 +a [2001:4ba0:ffff:11a::3]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34000 +p reject 1-65535 +r AutomaticArrestLine lCUWTkfnuPKqZpRPvcOM+vs+C3w pUX3zSy9EdYjCiMsEOYmmrl7EkU 2020-04-20 00:31:15 23.129.64.195 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6650 +p accept 1-65535 +r paranoidAndroid lCX66iyEShIFNMXW3KUIyR0x0y8 jb3FdwjMq/Mow6u+hlfy5uqg5tg 2020-04-20 05:47:25 100.18.29.69 42901 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=268 +p reject 1-65535 +r byrdeman lDGMwimaOCbYGJnrI8JaK31rH/4 BvklmaGIMae7RYXx4emSkYzYlDg 2020-04-20 10:56:25 213.227.133.129 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=42300 +p reject 1-65535 +r rs1 lDSUs4z3T73THSbZLWbVNYJFTis Djp5SPc2AlfHRPsiajhUmj7TdY0 2020-04-20 05:25:56 37.35.107.238 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 1-65535 +r harmony lEbuKDQqi0UCtNok2hiFG8nlFuA LLhJKE+/PboOfO+dIKe2p6k40wI 2020-04-20 05:51:20 185.100.87.243 9000 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed lE8fn3nUPp5In0Pz/grKLBK61DA WrkU645GAvxs9Avv8cqKql8dzuE 2020-04-20 06:44:59 185.38.149.27 60376 44183 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r F3Netze lFT4LUfroMsMKkv+eWYYHb8QgUc 4+4HubKYi3/72Xd1MYLiF/MqsmI 2020-04-20 07:02:56 185.220.100.242 9100 9101 +a [2a0b:f4c0:16c:15::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68000 +p reject 25 +r Totonicapanp5 lFa7s/uSPdHN7FyLRdlhW8k33EI NSUD+6j5uztpyu5v+/w3Y7WS/fM 2020-04-20 01:18:34 163.172.14.221 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=37000 +p reject 1-65535 +r snap277 lFiN7bujGkAOk2ukLgiSBnkxoh8 D/Z9fnEqQrTEBpuMvuMTk2p28tI 2020-04-19 22:35:29 181.114.149.190 45403 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=28 +p reject 1-65535 +r Unnamed lFqi9sLsZEtTPQSMeeA1ps8JLE8 Imkdsj970oViVNn3eA5owK9zAKQ 2020-04-20 05:49:07 51.255.39.110 9001 0 +a [2001:41d0:302:2100::78f3]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18500 +p reject 1-65535 +r Aframberi lG37RhaGcIJewacl0XjUvgh79uE JxlPTna4QeRMfTtNpIrN1gxLGlU 2020-04-20 10:37:17 157.97.23.177 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3600 +p reject 1-65535 +r privacypro2 lHjMRqxi6WoAMfgy9UjDoVOhoco o0SXo5D5cDL9vi5oETxvGNb9/c0 2020-04-19 23:48:45 172.104.136.137 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=990 +p reject 1-65535 +r SPFCFutebol lH//RWz8713KsJQi4ZRajSGu7GI mjpyYAGTdU+x4udH067pp7sEREs 2020-04-20 03:35:47 81.17.60.24 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1170 +p reject 1-65535 +r PrivacyNow05 lIkPN84M1dAgdzynoOOXqlkuWvM mT0zhB5sBt9ZwktcUQ09w0hqsiU 2020-04-19 20:18:44 88.99.189.40 9001 9030 +a [2a01:4f8:c0c:6075::1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=25000 +p reject 1-65535 +r tor4ever12 lI2rhzWWIcuN99NopMRsf5BayEs OXWjmjAm64ZDYxCHk0ejICoTjtg 2020-04-20 12:32:17 45.62.228.131 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2880 +p reject 1-65535 +r koubtor lJKqKir3c+48lcbswlJtgi6/Tjc W9FH/+hbWdTnItGLRN4eUMOIGr0 2020-04-20 02:03:53 86.239.217.252 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=145 +p reject 1-65535 +r myfirsttorrelay lJLMBGoLsBY4wjMgc6oGALPzElI QSZeMv5bwyg5QUtWzRj53mmzIJc 2020-04-20 05:23:33 86.80.224.202 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10300 +p reject 1-65535 +r effilochures lJVFlgZVwXom9lJfZ8VUIzz+Fj8 7KKtfjNyLPWIPiYNg37Jk4mhUd0 2020-04-19 19:06:52 172.105.116.230 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=340 +p reject 1-65535 +r torrelay lLcQxBuej7WS0JFucbWon/SZWZY zqn8kPwNlHIlUaDlW3YHHhktRIE 2020-04-20 03:25:37 138.201.35.6 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=150 +p reject 1-65535 +r BostonUCompSci lMS3uMUMhqkraiAQdTnuJnjPmig 0IVIsYm5wpLmlyzbLTfsujTNEHc 2020-04-20 12:34:04 204.8.156.142 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=4930 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r snap277 lMaAOyKL0VheKHHfAbYq3uxshxc ymc4DRHDm9exxPw+h1r57Qw55BU 2020-04-20 11:59:35 62.99.32.125 37743 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3900 +p reject 1-65535 +r snap277 lOnDDDwW/q6dx1NA8Ztc0f9BYkk rCn6TuINxaV4KTnThjAMNgJKRNk 2020-04-20 08:18:33 5.58.235.157 38913 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1020 +p reject 1-65535 +r unix4lyfe lOw0uHGTZQS+cGcbRHYLyZJC4fM yAyTerA8HsVftqiQSZB2b4ZZiSQ 2020-04-20 01:23:00 71.19.155.121 9001 9030 +a [2605:2700:0:17:a800:ff:fe3e:bcf8]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r RealityLeighWinner lPFtor3boJKVT/jsKfkjSmmUlAM gE1I90IMJoj5Ptr1Mn+SrnA6lcI 2020-04-20 02:54:51 77.162.229.73 443 80 +a [2a02:a446:5ef1:20:d072:53ff:fef4:ea59]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13300 +p reject 1-65535 +r FreeZion lPNnoTApbJ65K+MuJarrfyJ94NY bQcOeUBWQx09WihcRCg61mtb+sY 2020-04-19 23:55:31 87.15.107.71 9443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1130 +p reject 1-65535 +r FakeVolleyball lQE09KujKR7uTnovJlRttwcHdqQ kfGW5ZoIh//RXl2xWHizHGK5XkI 2020-04-19 23:12:00 195.123.212.228 9001 9030 +a [2a02:27ac::245]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7500 +p reject 1-65535 +r snap278 lQFSe77eHPN6MOr+xDNcyLZAjeg 5VGHsLv1jZNPWRJVczz4WlAV3hw 2020-04-20 11:34:01 197.204.199.160 45647 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3 +p reject 1-65535 +r angeltest5test lRMHunTkSpycIIsvE0zaJAmUQHU LGmJfS5AOZiDs5MeUaqd/BHGBNY 2020-04-19 19:29:29 51.38.147.96 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2460 +p reject 1-65535 +r snap277 lRkhYqyopnE0+wh8AWTr3dNM6xg fOWGoRzIudZt8hAjSFLUavC5ZVg 2020-04-20 05:58:08 86.242.101.169 44809 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r Unnamed lRkt8BpvNYq9qROFjUkowAiOT1s I/OG4xhWPY/EtNxtWqoG7R6Gf4s 2020-04-20 01:27:34 151.24.223.92 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2370 +p reject 1-65535 +r ragelafu lTZUe1+Xz4dowGehfE0B8agmpm0 FjMNxWFw+1+CO1HfvqtQOXBxg4s 2020-04-20 00:00:00 173.212.218.165 9931 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3910 +p reject 1-65535 +r chopin lT23CfKi3syNdWBmH5NOZEEURPc q8pDgfQSO4OUbV1+1hEETyuMd3A 2020-04-20 12:07:37 93.115.96.15 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r Unnamed lUsiHP3D9WoV/jwp+F1f40uxRLI 9fFgqOJeczzHD/ZlCj4rLr6F1gE 2020-04-19 22:45:23 50.116.47.139 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=823 +p reject 1-65535 +r MrRobotLives lUsq6o/c8N9wGi7JKFZAuSlUbfc nSkEDF+quZtyvoRyBmxxycQySsc 2020-04-19 21:05:46 68.196.184.151 8443 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1030 +p reject 1-65535 +r FiveBoxingWizards lVT8DPmlIAVC4zdciuTpOcRZQig q4EBsCueVZRR5QAQgsLrhWZEy8U 2020-04-19 20:14:08 83.58.209.215 80 81 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3300 +p reject 1-65535 +r jaine lVbCxiypqaKWwEm6e9wQq9P/AXA K7DKbZ05EQG1mjqvD+yYTDUllbE 2020-04-20 12:28:28 5.249.145.164 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1390 +p reject 1-65535 +r Tor4oomehief lWoDt18Y5OepVClGlOwQAeXFgmo neonEBLP+CQcza8PDy8MsG8GJzo 2020-04-20 10:31:15 51.68.77.241 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=17500 +p reject 1-65535 +r Unnamed lWxNk8jYpokLUr92N0qKBTIjmgk BfSuowf9PSrTyTa5WOKznQVBtyM 2020-04-20 12:27:59 92.118.47.206 43471 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=8130 +p reject 1-65535 +r BlueMonkey lWzVM7fDMcZ10wpQkAoul3fUJ4I FXhIKhqECWaqC7/bRd5fZhhU6Ac 2020-04-20 11:36:52 13.211.32.165 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=122 +p reject 1-65535 +r niftytamiasatsali lXNU1yBCcZwxCpB/v+QqMjLHh1c Q7vEXvjOIvxwHiYdQO7TEiJKHKM 2020-04-19 21:26:13 185.220.101.26 10026 20026 +a [2a0b:f4c2::26]:10026 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34200 +p reject 22,25 +r snap277 lYWL7oeKDMM3xgIA+YuHdc2ac/U UvutLKPB1wID3cN9pCRSLzk73VA 2020-04-20 06:39:21 151.66.15.240 41891 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=611 +p reject 1-65535 +r f095 lYnaTIFhD575RMmpNFYH+JtvNoA hLlAQMp6LYsR2hx4ajed/KUQTg8 2020-04-20 10:08:36 176.119.158.31 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1830 +p reject 1-65535 +r FiveBillionEyes lZcuzQbZyupl2KfFzSYDnmOyKsQ DlqLKJqTG/QGn1RqjvoUqnzVlTA 2020-04-20 11:30:02 203.206.5.96 2501 2502 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p reject 1-65535 +r snap277 laG4KqX+sIqn7zmq3hoQNEpgofo l4WLEEfD0cl+PgWJxAOmg8BV6mo 2020-04-20 09:11:01 62.57.144.115 43951 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r Unnamed laMPWOPeO+ddXLr3Qmu/V4byweM G79fluiV2HVUrMDeoT07k9WMfuY 2020-04-20 12:21:47 47.49.35.242 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=227 +p reject 1-65535 +r kriefukegtai laXdSJLol3kHDeb9z10YYTkGGf4 dkDTZHXzDdR7r+Kn2/jna/fBga8 2020-04-20 00:40:12 82.221.131.102 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7720 +p accept 20-23,43,53,79,88,194,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftyentry92 lbkFLuzbS4M/Ewq9Vk5yBkO6eVI IiGC2Pqh62uZEGTSOLFGIjNMGak 2020-04-20 10:52:51 185.220.101.232 10092 20092 +a [2a0b:f4c2:2::232]:10092 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21700 +p reject 1-65535 +r DontTrustVerify lbzNAxDOgp4xRYrxVCmEfn9dJNI r3NaSKc1/+7xgbhtP8hH3EtxZmE 2020-04-20 05:14:11 5.181.50.172 80 3000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9200 +p reject 1-65535 +r Menggengges lcFqWzM6kGz5yGzeuLYuuKSC/lw StSzSelHcyWtG2Xoo1MD/tOYPQc 2020-04-19 22:06:08 77.57.197.124 12007 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=830 +p reject 1-65535 +r KuroNeko lcTvN4cGmjoaO1/UBXo0ypfBccM WJJuTAVpjWCaPL5k8cAXpLGT9mc 2020-04-20 05:55:48 64.237.51.46 443 80 +a [2001:19f0:200:3006::10]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=1380 +p reject 1-65535 +r FelixIO lcbF9lv8fAbd12UBXmF4U7qZPJQ ICk0U45pV2eaz+i8POno9ZBNjS8 2020-04-20 06:56:36 87.118.92.43 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20700 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,543-544,554,636,706,749,873,902-904,981,989-990,992-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r angeltest27 lci5QY508/+A5cPTr38DFW/7v74 RLlNjSp455nGHnTUq/1qIISRLrQ 2020-04-19 19:06:18 185.173.177.153 443 9030 +a [2a0b:6900:0:1::1d7]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6370 +p reject 1-65535 +r Unnamed lc/ZDfF3IiJljVzyi2G5dZ1dHWg SwqPO7EpTFvtzG2JIK3KUiiG+ec 2020-04-19 23:31:38 85.228.42.16 9001 9031 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=18600 +p reject 1-65535 +r boomshop1 ldCzRezIT9K/J6M7J2XfXgd6zb0 c2DPmj/rmZMMNFCbOunh4tVIoN4 2020-04-20 03:47:17 176.9.50.240 9901 0 +s Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r torzone ldeKBGpNMhThxbQhTi0Qn89Cvd8 whE4KFKTN6hOSHqif7aWV/+d2Zk 2020-04-19 19:56:29 81.167.185.151 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8500 +p reject 1-65535 +r pikachu le+soY40wmDd90lZa5d0AllOZzk y3FrlL0p0kctd4fln7edqGZRXmA 2020-04-20 06:46:17 178.17.170.149 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1510 +p accept 20,43,53,79,81,88,110,143,194,220,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r jl2238 lfPqXSrK6KWo7HJ1+awZWpNUYCk vANN8vJWoqcLbAmbH82VlPt4m6g 2020-04-20 01:26:13 92.200.190.134 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=79 +p reject 1-65535 +r flowjob01 lfp1hxfRhcvB1e6ZKq4IStBBkn0 fJeaptlZD6+aCNNY2koQdrkNa8Q 2020-04-20 02:03:48 195.128.103.192 9001 9030 +a [2a03:4000:35:4b8:b82c:86ff:fe72:8091]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=51000 +p reject 1-65535 +r FabulousMonkey lfzXGXSYX4y1RoIePcTYNHlPd/k pp8PIF/6HkjoF1utvnNSkAOpYqs 2020-04-20 01:23:11 142.167.34.174 26303 9032 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9770 +p reject 1-65535 +r Unnamed lgYjpFy0/QUq7s7eiSsX8xdh9Pw xObMhYNY6yWMyIPCXZdPyduaZic 2020-04-19 23:40:07 80.250.235.81 9002 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r upsuperRelay2 lgcGmHFNwHris3eGRiW372TjO/U SMJdzy5IBJ1LtKqJBgXu09GKEdU 2020-04-20 03:30:10 212.24.100.138 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11800 +p reject 1-65535 +r snap278 lghQeq+r9N47Z6RmIlQXkNK50Yc SSNXP1O3jvpvVq9vLzUFIxCbLYA 2020-04-20 12:38:54 84.71.48.228 35949 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=759 +p reject 1-65535 +r Unnamed lhMaA1LYEoMRG2O9xCcMIo+QzF8 GGrH5z6x+Z++eAE9zr387OrDSgU 2020-04-19 20:13:41 91.121.50.14 51605 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r castellum liEfV/oKOZ7EjRlyuj+O5uTWl4w CseZMiO7eD8jPmXnRGyQocClFwo 2020-04-20 07:58:18 185.163.46.138 9054 9030 +a [2001:67c:2db8:301:138:0:108:1]:9054 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=694 +p reject 1-65535 +r Assange015lt lidZIRBdwtQbea11gEowFzi1Hkc Yyct1Tf/XqsyyQa46JL3xjEV5+Q 2020-04-20 12:25:24 213.252.245.202 9001 9011 +a [2a04:2180:0:1::e308:9180]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r niftyguard71 ljTp9T60aCiufgaDn+5ZWVAoax0 QFHD620J+MuCDlcsApp4sPUlQJo 2020-04-19 22:16:43 185.220.101.190 1190 2190 +a [2a0b:f4c2:1::190]:1190 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r w1d3p33p0 ljh5u0JNmmN6YxBdXCaiRTwsInI aa40vKL5HW+vCPbx+i4pDirhrkU 2020-04-20 02:40:50 178.63.87.165 8443 9090 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46500 +p reject 1-65535 +r inktankmedia ljjYpG2Munn4Ei134Djtmev9rq0 DTbAp8gKMmi4EdTQM1OMYNteQjc 2020-04-20 05:02:52 213.243.138.19 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5820 +p reject 1-65535 +r sichermannac lkQAvXL4Xk7zVB3YV46RMepijdg G93qogsgmkLvqCW250p/7rWayjU 2020-04-19 21:10:41 94.134.36.91 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=956 +p reject 1-65535 +r MHcXthX9Eb34WYyEN7H lktOinUmOml2lUHydkVj2r3ZldI rfls9kRXNw28yqNIy7eu8d4DMLk 2020-04-20 07:26:20 68.67.32.31 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29100 +p reject 1-65535 +r erdapfel lmGslXF3mIhPPjcn02DdmNZnJ8w aFmHrEIF19q725K2bC6+//YPYQE 2020-04-20 02:17:19 109.70.100.5 443 80 +a [2a03:e600:100::5]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=85000 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r niftywabbit16 lmSn77QF9VXzwAefp2GLLubObSo JWpAmDYnJVFIU4YDMMplxrT7v1w 2020-04-19 22:15:38 185.220.101.156 13156 14156 +a [2a0b:f4c2:1::156]:10156 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p accept 80,443 +r Toray lmUkkar+mxiWPAglmhqPqbIt70E KOvXvRVyZTA4oxCr4kLaUZtnURU 2020-04-19 20:01:20 94.224.67.24 9001 9030 +a [2a02:181f:0:4063:c084:b25d:dd16:26cf]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=237 +p reject 1-65535 +r c13chom lnh7EuPDnUt90Htai9GmhDVh8xY h2aahlJcDTY2ZU9YNGYE8DAIV4A 2020-04-20 00:26:09 84.10.80.222 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3970 +p reject 1-65535 +r laeviculus loTE1scRMe7vLlwjw+ojSmhM1QE NN0gjNA54YTRRyJ0SfWlg3f6XYA 2020-04-19 19:43:27 51.15.77.244 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24700 +p reject 1-65535 +r moria1 lpXfw1/+uGEym58asExGOXAgzjE cswPbp4f0UF4IuzMAHCPtgA8VTU 2020-04-20 02:44:04 128.31.0.34 9101 9131 +s Authority Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r puls3r3lay lqCY24yHcTgPP0f7BO3su5HMYtQ nSIo+GuQkOFBV5mPlU8cpyhx6Is 2020-04-20 05:58:33 92.222.91.41 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3140 +p reject 1-65535 +r fiedlerRelay15 lqUWc3HXhOzpeaHkUE0lq/6FPow +6th7WdGDml165ynfUcUevPArVQ 2020-04-20 10:09:22 185.233.107.101 9001 0 +a [2a03:4000:24:82a::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5990 +p reject 1-65535 +r cx10TorServer lrNYdE4dsNbbuW0ywn+R6faVJ14 mQzTYv82O4c21KghGHtEoRZrw5Q 2020-04-20 05:57:30 185.2.31.8 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2920 +p reject 1-65535 +r dragonhoard lrcPhrRWI7TscejpU9zWGgXVuqw QxDq8+l4Hp7BLUoDxfxwERLRulM 2020-04-20 11:23:46 159.69.36.3 8080 8008 +a [2a01:4f8:1c1c:2ca4::1]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r TorRelay01 lsqpF/ZbzWLOzSNvZ2Ur/Xxp5S4 2VcPIfCPSRT6aHqZa9ofjNyR+qc 2020-04-20 08:27:45 104.37.193.102 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4820 +p reject 1-65535 +r niftyalloeumyarion ls/heKHRJInZ1ZoMrhf+hvWjp58 l/aklIMT8gKrwEpa2eepFoyv9oE 2020-04-20 03:25:54 54.38.145.211 80 443 +a [2001:41d0:800:656::3021:c5a0]:21002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45000 +p reject 1-65535 +r winR ltPY2MY61Y2MrqG439U5o6gPBA0 ps7KFY9LrpsyxkGMNS0o+48bwj4 2020-04-20 10:35:41 148.251.169.246 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=705 +p reject 1-65535 +r Dagonet ltTGHbWzjser49ubuHqXqFh7gIc mSJyAAZ4NfkWhpzqYsLklkofOB8 2020-04-19 20:06:44 145.239.91.37 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19700 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r thorship ltr9zpK6lOTMlfgxSuSOJypwL9w j2BvvGNS5hq8Eqkbo2/16keHL68 2020-04-19 22:22:37 91.219.237.117 443 80 +a [2001:4c48:2:8400::5bdb:ed75]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1760 +p reject 1-65535 +r Honkler ltzR0XwfD6Te0gfBSOVMClVVMHY agOYoszfHx+7pfR4lTHKUBzoltU 2020-04-20 04:43:58 108.206.76.242 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12900 +p reject 1-65535 +r karfiol luCV1c2/w5iN63COwVU0ZHJALDI pwPFulzj+YWW/m6m20ov5ScSQac 2020-04-19 19:16:23 109.70.100.11 443 80 +a [2a03:e600:100::b]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=76000 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r FreeFlow luDRnXNdRwOYROqDNyGDu2Bvh7Q nhgBuwiqJzD3bcyS1c2ZGlr1L3E 2020-04-19 22:26:54 149.56.101.31 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14500 +p reject 1-65535 +r gsuk luhslhjtMyCkfhQzYx29WWC0j2A mLWrwgo5LaXvDdyQVQCcWdGRmo0 2020-04-20 02:22:39 85.119.82.151 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=487 +p reject 1-65535 +r Torrr lupOLIfVuZcTIBzKi3Etg5/XbFk 5wdVNPktRfQe8DdUMR1sUCA+F60 2020-04-20 02:00:16 54.180.106.131 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r isnt lwVlkenlgXL/dsyLIYezdRZRHHY 7G37gn+JvxGNbJgtQ/tvW4llVTU 2020-04-20 10:38:23 212.109.3.253 444 9035 +a [2001:470:de5f:bebe::1]:444 +s Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r Unnamed lwzmsXkn8IOr8Vfpv6MF/TngYuU M/wK75RLWK0EXNbgBr95em+j8TU 2020-04-20 03:15:13 185.100.86.154 443 80 +a [2a06:1700:1::7]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5850 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Determinist lw8JZtqn697kTjdyBFUnpoVOmXs K8XLOrB8Hn99lk7PxmumunZeZnE 2020-04-20 11:07:20 5.188.108.82 9001 9030 +a [2a03:90c0:d5::39]:9050 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20300 +p reject 1-65535 +r NeelTorExitD lxERcoXrmifXHAOtWc5G6BbZCyQ EGfb7T1sudnMsT2KgMiR6XTmqd0 2020-04-20 00:32:39 51.89.226.199 70 23 +a [2001:41d0:801:1000::db2]:70 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17100 +p accept 53,80,443,8080 +r Roazhon lxMyHUd/MVtYGKGJuBncl7PkBF0 6qcJtTmkEQmNcZA52uLechPEx8Y 2020-04-20 10:26:59 86.215.252.212 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64 +p reject 1-65535 +r HrmonyNutrient lxUbxuudY8JqZy2VXrbWbjzLm5w mx84LqUWVcQAAw+0h3E3fCrrGP4 2020-04-19 22:57:32 47.254.152.242 9000 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3450 +p reject 1-65535 +r csailmitnoexit lxXIG6jFsMaYiCA191xn1tZD2+M gqekyafCgQLtvQ8hDIUAGUpyx84 2020-04-20 08:03:19 128.31.0.61 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19600 +p reject 1-65535 +r eddy lzYHUmvpyP2gPruvUn1nrm/9Zd0 5bw4Wht9fQYB7nNvBElqfrsmYko 2020-04-20 02:25:16 109.201.133.100 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22100 +p reject 22,25,109-110,119,143,465,563,587,2710,6881-6889,6969-6970,55000 +r atoratvm lze+sC25/mqJ8qAiCB+33ax1Gus wVsI+HIX7yfdLW8gM6y9P39WJnU 2020-04-20 07:30:22 37.218.242.84 8443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r Sandtler lzj49cOGza9XB9Dc7UKPKBPKKF8 7SunqHYt5bCtsKHo4UrcBfcs3tU 2020-04-19 21:25:09 78.46.85.216 9001 9030 +a [2a01:4f8:120:1381:421:5:0:1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=74000 +p reject 1-65535 +r NikowskiThirdNode lzshn9rDCHMhLYZlaLMMRNV7MuU oq43wZufEdO1vJ9It75gfyu+1E4 2020-04-20 05:00:58 51.79.52.15 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10400 +p reject 1-65535 +r wimbakinemar l13yymKIIoBEqRYv8NOLPuFSmM0 D8pv3QQcupp0DPVlZZBPFBperY0 2020-04-20 01:02:07 151.237.185.110 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 25,119,135-139,445,1214,4661-4666,6346-6429,6699,6881-6999 +r nopejustnope l21iN0D5EO/m+X5ULozoVqgs7YU OeKRf3LXxJEUiwTLDPIHOzW0Kzs 2020-04-19 20:08:29 75.127.96.101 9991 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=335 +p reject 1-65535 +r rayonx l3Z7Q+eBGaYTtGzq+Bp4j0XMBdk Q7MW3Umv38/asnaD9vBynOLWX6M 2020-04-20 01:56:07 212.47.253.12 444 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=35800 +p reject 1-65535 +r Unnamed l4Gw7oHpWUEHOvo3VCs27XEBjUk Q8X8g+qovRuWbyb/lUNNbykRIZw 2020-04-20 02:41:14 136.37.102.111 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r Unnamed l4pBsAJBhy1Oqt6WrcG369appWE zkNpxneC1VI/MKb5Q90AQSZYPsM 2020-04-20 12:33:10 163.172.146.92 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 FlowCtrl=1 +w Bandwidth=4020 +p reject 1-65535 +r Octogon l5suZ39tlIIM2NZFYm7Xdtyxy2w ZiQj5FwtMhZuooR62Z9fF2MO4lA 2020-04-20 00:38:36 101.100.144.174 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=133 +p reject 1-65535 +r paprika l67h7vvLtv+PpIICmDDo4QqWGIM aYp7WghMMp6oPLoEZCpZgVGHCC0 2020-04-20 02:17:54 109.70.100.17 443 80 +a [2a03:e600:100::11]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84800 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r niftyredsquirrel l9KibqXJly5m0j9GmOlNvbqPbBg j/TpS0HDVpIqH+y++sEjJBbdOc4 2020-04-19 21:25:52 185.220.101.22 10022 20022 +a [2a0b:f4c2::22]:10022 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49000 +p reject 22,25 +r cebolin01fr1a l9g6TTZUlq5HZ4P4+SeC8Z/hR8M U17bC7ASmlHT6yqZPHMb1smgeMs 2020-04-20 05:58:36 51.15.243.138 9001 9030 +a [2001:bc8:47a4:d51::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24200 +p reject 1-65535 +r insane2 l+CMFfUKc4PgyMVuN9eTE8QwPng esznULpKuj1mbAag14EnsQRypto 2020-04-19 23:56:53 185.248.160.231 9100 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5480 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r sjllndsg38 l+agCRhfzypY2IRUXk4Y/2ErewY v0c7s3wRmebsGrQlvCFLXhCWUC4 2020-04-20 06:44:43 92.244.31.28 29001 29090 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=910 +p reject 1-65535 +r myOnionBox l/wCggkSRBvC3+Os9DPkVXFLCvU orV+M5x+otlvgifGxbrhPgRo4Xw 2020-04-20 03:16:29 89.247.163.201 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=556 +p reject 1-65535 +r WINDSOR mAO1Nu0gPJqq/D5TzUk1uoX/QC8 6Z8eMnwN6q8+jqynF38upnjXM/0 2020-04-20 09:57:03 185.125.206.186 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=602 +p reject 1-65535 +r BobbaSmith mAr7SF0ExWbHTVcEyWz4DSneN5M apJGTba44Q3D0D5fNsVAtrnmnjo 2020-04-20 00:56:49 51.15.58.212 4443 111 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3290 +p reject 1-65535 +r zeus04 mAsooZsKZpSANaP+FD5c9hPIQSI XXd6uB7xPlmHDXdh55NpJtyCCGA 2020-04-19 22:16:24 81.170.142.157 4430 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67700 +p reject 1-65535 +r Fission09 mBON/T4sjInY9asR75tr/yctg7Q sBSwkQeGZGk5wdyxUXSHqST8SGA 2020-04-19 20:25:22 54.38.219.248 443 80 +a [2001:470:73f7::4]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p reject 1-65535 +r snap277 mCJ2uIPNayKOv+GY2aXiXxlJj9Y JsVOEhqmdvVB8fqM48W/J4y74As 2020-04-20 12:27:05 83.113.86.75 39023 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17 +p reject 1-65535 +r anais mCoQNInfhBBYW4B3t/2BMhcJPrQ /ZcU7sVaEj8fmAJyNFQyE95LAEc 2020-04-19 19:22:11 185.77.129.35 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9790 +p reject 1-65535 +r snap277 mCzSWJqTWuGKWEng+b2XB4MpTo0 XicjbhN1F9xSUVO3/l1aBR7gZx0 2020-04-20 12:36:52 86.206.37.26 41101 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=425 +p reject 1-65535 +r 0xDEADBEEF mDJaXrxKvQyUwRtDwlQQK+GcWqs kjy6NA+GASjL1/S/fgpQCIZNfMQ 2020-04-20 02:26:50 93.231.88.42 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r carbons mDULFlUUUqvH80V9BgMs0w9ygM4 YtMq+fraJMBqZSXJEKrisRz0dpE 2020-04-19 19:26:12 81.170.131.138 32000 32001 +a [2001:470:27:704::2]:32000 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p reject 1-65535 +r mfbsd1 mE6dx5IrXMmV6v1Q0jOKUhNuK8E 8SdEgfCwOSWQcw1X97mxwtkW+AQ 2020-04-20 06:35:20 64.137.178.157 9001 9030 +a [2607:8880::478:9d]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6100 +p reject 1-65535 +r lowbwrelay mFtMgpPpT7bs9cPE8SbWh8ztfyc JcDF7L7gAEMMlNokHQLNKYUhqe4 2020-04-20 00:26:02 172.104.179.210 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=184 +p reject 1-65535 +r niftyspinymouse mG4p+xfIx6H+r/ID8BLVkwugeds VBIHcTg23Dz/J+SPvKqJYfFOTLU 2020-04-19 22:27:21 185.220.101.145 43333 43334 +a [2a0b:f4c2:1::145]:21360 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35000 +p reject 1-65535 +r bolard mH0HBtQgcPHiFCqfzLVrOIeAjTQ IV7ILt+OIr0l+HN/NvZofDWd2qg 2020-04-20 11:24:41 31.131.2.17 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3120 +p reject 1-65535 +r ididnteditheconfig mIPzWW9qB5VmfH4aZxNqavYxHwA acg5DeJtqWkiVJqK5DLvK6VSNnA 2020-04-20 06:00:00 176.159.193.163 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=350 +p reject 1-65535 +r blot mIYlv9npsjs1xZAlBAdIbyj/j/w roChOTixHwgA4zLvW57EA/VS0uE 2020-04-20 09:21:00 107.189.10.42 443 80 +a [2605:6400:30:f754::1]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Piratenpartei03 mIZ/UkJQWi3VgchbHOJWCQuH8Tg cLJ6B0Z7M2bvPKUibnNxj9BQ8do 2020-04-20 03:15:25 188.68.43.192 9001 9030 +a [2a03:4000:17:688:b854:7ff:fe48:bdcb]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r PissingAnus mI/vqpk64L67+yS9jmwnJ5jGH78 UoDlf9qfaYNexqMy5WxYK08UdKQ 2020-04-20 08:34:19 78.72.211.34 9001 9002 +a [2001:470:28:365::6]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1220 +p reject 1-65535 +r GrvityImmune mJ0dFetMKPEfxiC2Iv7SId+vK6Y qe/Qv5VrzXTq13y3lPBHxUne5yE 2020-04-20 06:21:02 47.56.94.99 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=159 +p reject 1-65535 +r Walnut mKHM9iteYb1uK+pXNWm8lx/VDqg Cq3iP0vkMDBoXUVPRQ8RQ+AH7ac 2020-04-19 22:47:22 162.200.19.50 9001 9030 +a [2600:1700:581:74d1:ae16:2dff:fe71:8368]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4160 +p reject 1-65535 +r kbtr3lv mKHQvMxdRcfgltdjTI7T/78ZCMY M9sa6SAP8j6ifbo+CMrdG7X10FU 2020-04-20 10:20:22 185.61.148.80 8443 8080 +a [2a02:7aa0:1201::ec41:fa19]:8443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12200 +p reject 1-65535 +r Puhuri mLLJjAVlLkLj/rYhhZk8jofkIXM PlnDpDnQ964Cex/b9rz4JK2w5Qw 2020-04-20 09:35:57 151.236.218.67 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=210 +p reject 1-65535 +r 0x616e6f6e mLyEb7g9HUrtT98PW4UWMmNxHZ8 LiotZzLCZm3hCc5GjN0B9ko3VdQ 2020-04-20 11:11:59 178.17.170.116 443 80 +a [2a00:1dc0:caff:b2::26ac]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8740 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r cCc mLymPdguE6Y3/40OwoE1Zj2wjKE rSahPsrT6cqwvjnZvP66i6ratZc 2020-04-19 18:52:11 54.37.207.82 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r fuckingexitnode mL9OSiL2L1yPFWZQCEspZFhTp7k KyACtAqfRpsP3KOHnrProQpu7s4 2020-04-20 03:40:44 95.216.34.221 9001 0 +s Exit Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p accept 20-23,43,53,79-81,88,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r LoomisTorRelay mM4d6HycVSSTkq7ilsefiiMTBoo 2B2mPC4hqWRN/iGhRcZvM6YJOdg 2020-04-20 06:18:49 192.92.6.32 9001 9030 +a [2001:470:1f05:94c:20c:29ff:fe52:f53c]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=310 +p reject 1-65535 +r OsamaBinError mNv6bcf0ATVm0J493G9sr1EOf9Y kFt/KNaRNeUYBR+kndUZVETkorQ 2020-04-20 01:00:48 95.216.140.239 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26000 +p reject 1-65535 +r VirtualMachineOrg mOZZtbcBB2vkM7RyPyChgRc5WIo bL4FMAWU+Cp7QIrqaSmnCxfniCA 2020-04-20 11:25:34 178.254.30.66 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p reject 1-65535 +r pablobm006 mOrGfqaBQDgoXxoQDXhq2KDNKl4 KGV4OxONOII+kB1WY4FddZyHBmg 2020-04-20 07:41:54 139.59.45.242 9001 9030 +a [2400:6180:100:d0::ffa:8001]:9050 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=847 +p reject 1-65535 +r agrajag mO85gfdm+fh9fDmebdD/w4Z3Ea8 Q1ydpBgqEmLV6fuKQaL8ELhY8dM 2020-04-20 07:59:06 83.255.133.164 11311 11312 +a [2001:470:deb8:a5::2]:11311 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4270 +p reject 1-65535 +r TomaszPi mPDcN0q4FWvRKgPiXevM1duFocQ PrpBfNLJQLP8EQ2pIScFXIGuNLY 2020-04-20 09:10:44 86.147.53.38 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=631 +p reject 1-65535 +r EifoenRelay mPeIIAzGQGBpWwdVXwmo/kdnmsg FJJlHJHQqE9dXmsgj0Xt9mo23ro 2020-04-20 11:43:03 185.244.192.155 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r F3Netze mPeTxzIM48FaRTU6/MFldHpANm0 o9uR0fUtWPxI0oDnjro2qu5mve0 2020-04-20 06:32:58 185.220.100.255 9000 9001 +a [2a0b:f4c0:16c:1::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=99600 +p reject 25 +r glenda2 mPt1dJMtvW/p51FpmC7fulD4YXU MMFh36wYuIABIuTPepQgmR7/iSs 2020-04-20 05:58:12 78.47.117.28 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1630 +p reject 1-65535 +r nacor mPt2fa00OLGH9byJaOyLtXiWAyo Lb7jKqoGZm0/l6KM7GcxqNRR4WY 2020-04-20 02:57:05 185.65.205.10 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1990 +p accept 43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r bartleby mQt6+DMIMbsivelnFBIY6tv0vr8 CXLfvONvwLa2mwB+Dkrx4N5FcAw 2020-04-20 09:17:57 185.105.38.81 19001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2430 +p reject 1-65535 +r torjittertrapnet mQyy+Nq9h1pypaehh299T2X3bl0 1ubTVQvLwd1DIt5P1Q3cCaJj2jg 2020-04-20 00:24:48 52.63.134.148 443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r niftyfoxsquirrel mRDG3uqZB+56784NoHL5T4br/Ug FN/xozqVX1XXRXgY0W1DHNjLN18 2020-04-19 22:15:34 185.220.101.142 1142 2142 +a [2a0b:f4c2:1::142]:1142 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54000 +p reject 22,25 +r BABELFISH mStnOxg7V2c2DdZut+ZGVdZz5UQ MRLSfY1EiWVt22KPYP2cgN6bkc0 2020-04-20 06:19:15 185.248.160.65 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6140 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed mTOfPmi8zBORvxTIIdgHZv4MWVY L+4wE06ilUMKVujmNHCa28TrOfU 2020-04-20 04:22:38 54.36.166.86 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=133000 +p reject 1-65535 +r Bender mTVBqrVSUN09EAVwfMnSRh2pXIo tQ7moBqVjxXw07GnUTOjQxkKU7g 2020-04-20 01:20:24 78.46.141.131 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17500 +p reject 1-65535 +r relay001 mThFo5iB5qHE3Wyac/RVQdsQkq4 Bohu2pRmEmmS4P6+UNRef4v1ZAk 2020-04-19 20:33:49 174.140.227.118 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r WalkAway mTjjqsZM6dVrdD7NiyyiNa+533Q ej3ND2QKbT9tjIblBz4ymRQ9wdc 2020-04-20 00:26:23 31.43.158.11 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=240 +p reject 1-65535 +r fb1610b070e9 mUlq88MlzMchelxxRJ3gZTDGiXA dFd2NulAnw+add3NMH/VJdrARSU 2020-04-20 07:30:01 51.81.253.208 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13100 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r F3Netze mXH1GjJ0dYtcWeHWWA7SwT4Ty+w pRFV0dTORCL+jGkXUpQYsDJmqYk 2020-04-20 06:35:33 185.220.100.254 9100 9101 +a [2a0b:f4c0:16c:2::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=117000 +p reject 25 +r F3Netze mXPh6XMKWP26nhEtKzNC0sDZIbU gpZZ+7K9eEMIb5nvW/ftL49iH18 2020-04-20 06:33:38 185.220.100.253 9000 9001 +a [2a0b:f4c0:16c:3::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120000 +p reject 25 +r bl1nk mXdDV+f9HxE/JCxGnR05nURKpRo 4gvgQwLhfiuqnEdSmu12swc5y3s 2020-04-20 11:58:54 195.154.240.145 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r snap277 mZ4vv1RmE8BkWEagLUKeajjlf6w YHkdIGJb1h+p6RlwqpMu2dP/x00 2020-04-20 09:27:12 90.106.210.237 37945 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r peu max3Zn2NYGJRt0nf2kc7LHgfeNA xt87SAPp3zqE+37FPjTW1zinWEc 2020-04-20 08:17:42 81.17.17.131 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17700 +p reject 1-65535 +r isis mbLL9u/YCs0wPoCJZWZo7yNgFc0 uHMl4gBESIv8wXzo3OxEhyvFb3A 2020-04-20 00:47:21 188.40.159.122 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=314 +p reject 1-65535 +r k0nslNET1945 mbT1dX3CcYLlKC3UTcIYKpu/bpw FPMxCMXITq2RVpXt1R0vFvssAoA 2020-04-20 08:03:33 104.244.76.245 443 80 +a [2605:6400:30:fd17:5f56:ce5b:f14f:e252]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18900 +p accept 1-65535 +r TheDarkLord mbZMZgxCkiDy1dbQ36rTMV1iNqQ 325NlbIK6oxcB+aeVQDIK17g1uc 2020-04-19 19:14:52 185.86.149.139 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=2120 +p accept 1-65535 +r Unnamed mbfpg8rl3/pue/EiO/3F81/bDNM 5S5t8iwpnPqphYyBedU0hE8mxpU 2020-04-20 12:00:31 167.114.92.60 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed mbwc5VYzaat/FQqdKoUfnuHovCA Mc2Io5nlwdJmu4KVg0xms8zgFPQ 2020-04-20 12:38:29 158.69.172.228 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11900 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r prayerfortibet mcWs71rI49PE3nkATzrGSbN1iRw 8lCmYp2wAgbuIqbE86uZEkaG9NU 2020-04-20 06:37:21 91.244.181.85 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3210 +p accept 20-21,23,43,53,79-81,88,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r VccineEffort mdVohf2RYPujOmRouhE0tgg33CE BsV6emHxUD3nsXO86YWF88IC0n0 2020-04-20 02:39:53 47.56.192.35 9001 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=280 +p reject 1-65535 +r arbitraryKenzie0 mdXJpacjiYbR6h13cc+BtKGSxNA Hss8G78UY/sduc0mhXxb7ZMGrlA 2020-04-20 03:21:26 95.216.14.222 443 80 +a [2a01:4f9:2a:f21::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45500 +p reject 1-65535 +r ViDiSrv meJG20gLMTowErwzYwk8wmzSCcc UBWBgbIT60XMeCzbBjS3jJ2hdkY 2020-04-20 09:12:01 173.212.254.192 31337 31336 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5400 +p reject 1-65535 +r snap277 mgN4f6heWVBYva/JEzdc1CdgGyc f7ZKY4VBFFqWtH755c0UmTkyDTY 2020-04-20 07:09:32 92.141.95.110 40351 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3480 +p reject 1-65535 +r westrum mgjjeOo/oYGDywUi12ZVUOG0K7Q vssx/VPqLnvfyhYm3UQVlUA5oT0 2020-04-20 04:36:49 46.38.51.18 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1980 +p reject 1-65535 +r lnag mgqvLkO+N0TNHWzVMshh9aVo96k vfsFz3jYz9QAPCvSZQnM/o5hkH8 2020-04-20 03:32:00 160.119.249.223 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=545 +p reject 1-65535 +r python273 mg7FNwUIivDrKUFSThforGEWxJA RTCpe2C4iRXaz1T7LvukI62ysT4 2020-04-19 20:15:42 188.166.20.124 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r fiedlerRelay14 mjhWX1aP5+VA2cvwxCGxRtFcrZU tGdYLHm3vLD7UJnSTbJfiSxaRN0 2020-04-20 11:06:03 185.170.113.28 9030 0 +a [2a03:4000:15:8cb::3]:9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4350 +p reject 1-65535 +r nodvrelay31 mjh2023mjBESiVNtVGZiFjKmAac ZyMPx//MNJV//bPcPyUD47bkrjg 2020-04-19 19:07:12 45.62.235.112 9001 9000 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r lovelyspam mkL+7LBvvhebLJ/3K4Yo3gdbVlA AdtF0xI+wJYT3OrZy6cegdixCH4 2020-04-19 22:45:30 77.70.28.38 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=806 +p reject 1-65535 +r catmeme5 mkjsiq+y6MniBAhZY4PbdPEZZ0c xoxjq8F+UhvnUp7Lub12xf9+uCU 2020-04-20 00:01:48 148.251.51.94 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=85700 +p reject 1-65535 +r GuavaSpace mlKZpruGVtmI7d27vFFzbt0+9DQ dIpi931e+G061JnHMonyd/kPueM 2020-04-20 01:05:23 86.52.108.22 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1180 +p reject 1-65535 +r Seccom01 mldUzQyYc1XrPYrUvvSiqEF0BSA Vf8hwIFMAH+nlelUEEUVxbruA+I 2020-04-20 04:03:31 217.182.94.58 443 80 +a [2001:41d0:401:2100::80e]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17500 +p reject 1-65535 +r Ichbindoof mmhOxgQ7WlxfuR9wDNMCZhcDJG4 cDOsf6yFkRzFwaySs6KcEbaVYno 2020-04-20 04:53:47 31.16.168.125 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=99 +p reject 1-65535 +r snap277 mnNH51r115T5sAkmWagktF4OCec tZU45s9AFJa4kQ6HoRxqeQYWXis 2020-04-20 10:18:11 77.0.224.227 42807 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=81 +p reject 1-65535 +r tOr mnQXukAbjH794klF4YFFoe2nMOc z+wB3gCvY/8m29XVhQzQYnuW9rg 2020-04-19 22:06:08 163.172.182.147 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29000 +p reject 1-65535 +r D3S4RS1 mnXMAFyg2S/9P5YAOyUkwgsFPig 9+/cjXH8JQYe4pH8pBNmEqwwdQA 2020-04-20 12:06:25 78.47.43.253 6080 6443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=925 +p reject 1-65535 +r hviv123 mozZzWKynbBUnioRfrLwFPWv/vE iRS02w8gcliQccWS+CGGNm8zaJI 2020-04-20 07:40:27 192.42.116.23 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20400 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r jmarshall3 mpvDRGisFnd4Lk5Wsn2UepyZHi4 0WzkOBZkJGLlCgV/3pLiGUzYwQ4 2020-04-20 12:26:55 93.92.203.113 9261 9280 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=10100 +p reject 1-65535 +r Unnamed mp1I89XFcsh955I2o/qTU+COP/I /1K8BD6lVci1IM5Xe5y3z1LNJKA 2020-04-20 11:10:24 54.36.183.48 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=680 +p reject 1-65535 +r DigiGesTor3e1 mqP/NeelSdIzfpYjM9Nm4QL+TVA UnjHAEAT0uY2uDGgO7LJ6s8vSCs 2020-04-20 07:41:56 94.230.208.147 443 80 +a [2a02:418:6017::147]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r atomcats mrk7VCIUnl3/S+ajgU4vbZZI22o GGoiR5cyhJZCZldMzcyh1ps1n7w 2020-04-20 06:10:37 51.68.204.139 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=83700 +p reject 1-65535 +r ingmar msHm1tZdgDakLz9riK3Cvr3hfxc KdF0S0nT9CVw9viE4pnR/t+7J0U 2020-04-20 07:07:28 93.95.100.202 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r UncleEnzo mtEvDjzIcdWayhS7QHbN2Mso3lc Z1LcBDx9WSDg0PeCWtu022791Ek 2020-04-20 12:46:21 18.18.248.40 443 80 +s BadExit Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1170 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,989-995,1293,1723,1755,1863,2102-2104,3128,3690,4321,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8008,8074,8080,8332-8333,8888,9418,11371,19294 +r Torrible mu03O9lBXoO9z8c1/KKIF4gpRZo CUqILaTI95ZlXvrule077K2uTco 2020-04-20 05:57:08 45.79.218.205 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=310 +p reject 1-65535 +r tagos mviyTRc95ogBimvdQk++kGdszMY 8hPoAqF21PQ1inSpkhSAy1YwkM4 2020-04-20 08:22:12 77.68.11.42 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79600 +p reject 1-65535 +r MirasEtrin mwW6Nc7CfAK2BduP3Woz82cGBXE gspMX3XU7SNxCan1rw5G3VQXhuw 2020-04-20 09:23:11 93.238.251.207 9001 0 +s Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2 +p reject 1-65535 +r tor4ever11 mw7fQKAmhHKZIWPv/GrmmKOmkWY NQOm2255VTNUJdS7vrzWAKRIMLM 2020-04-19 20:28:48 45.62.228.146 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1430 +p reject 1-65535 +r TorRelay myJUK6CF+OzMi20PiJe42xxubWU TFUTwNs8eKqo66DCFh22QDk1azY 2020-04-20 07:19:01 139.162.142.120 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=952 +p reject 1-65535 +r horriblefarmhouse myJYZZlGoHhZWZ99NhEpxPkSgk8 KGgKMuVeu+PNnWSbN/hMEiaqrsM 2020-04-20 02:56:23 79.226.146.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=320 +p reject 1-65535 +r mullbinde8 mySyFJYxFncENi4HNWqem/wfDwU cHN8SX3mdX6I/sh13+Ow7FZ6DfM 2020-04-19 18:58:15 95.216.3.166 9001 9030 +a [2a01:4f9:2a:3d9:200::201]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p reject 1-65535 +r MIGHTYWANG myvH79ZhByr63FM76NzxwZ2MLcw yJzqFIrsOD1oUgtMVBet5BqF9FA 2020-04-20 11:57:07 188.127.69.60 443 80 +a [2a02:29d0:8008:c0de:bad:beef::]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=157000 +p reject 1-65535 +r nodvrelay17 myxC+EtOmF1N2n6vqmZrVxF8m4E r5cRmFHXDkgrOnAF62+0bKgz1WY 2020-04-19 22:57:46 104.167.114.201 9001 9000 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2300 +p reject 1-65535 +r snap277 my0/5+PkL8xU4MXajfSKLUwnhxQ +bXZZ0ntZcpvYdptu5VdD7aXf3I 2020-04-19 23:57:24 89.156.108.222 37191 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5160 +p reject 1-65535 +r TorExitFinland mzHx8cFVT5/7NFWRH4LoGO98eIM ibzqUw3K3hwq1o+tp1xIF/FTLJQ 2020-04-20 00:33:18 185.100.86.128 9001 9030 +a [2a06:1700:1::11]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8000 +p reject 22,25,135-139,445,465,563,587,1214,4661-4666,6346-6429,6699,6881-6999 +r fiedlerRelay05 mzPAQ3Bi8S3BN/dXp0X8BM6iYjE tTIuKOAiXYFeYV/4jKsfYi2mRxA 2020-04-20 10:06:38 185.162.251.28 9001 0 +a [2a03:4000:1a:800::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r scaletoer mz56CtmgVJhMyH58qdXBFyAtRdQ m8SG/2dhJYN5EuhEHf5hDk/pTVA 2020-04-20 00:46:44 51.15.36.183 443 80 +a [2001:bc8:1830:e12::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p reject 1-65535 +r snap277 m0Fy89VMvgFHn5C15ijT4lh8o+k 1qo4erh9/M6orN2pevM/+gh5Gvg 2020-04-20 09:22:57 188.240.195.193 41061 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1320 +p reject 1-65535 +r TorTor m0b3vaOVDLAidIfhKCR2Ql6Ha8Q DuzgngkZsJwz5VACvLDAqH78Ka8 2020-04-20 11:56:37 77.254.36.176 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1310 +p reject 1-65535 +r RunningOnFumes0 m0elt8EI8i0a/1ROcNIu2Jl7lqM CFh8JEG5WMy1BKPN6+CDegUGE2s 2020-04-20 12:48:08 185.222.202.104 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2010 +p reject 1-79,81-442,445,563,1214,4661-4666,6346-6429,6699,6881-6999,9001 +r Unnamed m1sA0SQxc7d9W3S7UBvVKTsJ3yI +fKb2f1/tZz4pcbkpWuWzv3S9vY 2020-04-20 11:17:10 80.82.70.227 9001 9030 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=302 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r fleischgewehr m17TNw4AKuuyqbJeMhPBgXzNLYg mC8exXf93cptvLNKRTZtR00HFVI 2020-04-19 23:33:50 51.15.65.243 443 444 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28000 +p reject 1-65535 +r snap277 m2FVgDSAzmEox2JW2oGqnFHwgLw AEtU8nRRXeVhNup7wIkRa24w8x8 2020-04-20 12:46:40 89.185.185.9 32957 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r srcglenn m2NSaR1nfc6VyfSLJd37er3/fgM pJc2fGSeMrTEBREXWXoYb1S9NQM 2020-04-20 10:00:32 142.93.167.85 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17600 +p reject 1-65535 +r literalchaos m3iBfLce2ncYa1QZXjS1pd0apFo mqn8OzrEOdrCTGX4bEG8CfKXfd4 2020-04-20 01:22:34 138.68.172.176 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=170 +p reject 1-65535 +r niftypygmyjerboa m4FqWz6yC45Om50fuimb0/QPAyA Eakqe5nLFo0FlaJCMAL2jGV0W2s 2020-04-19 20:26:50 185.220.101.17 10017 20017 +a [2a0b:f4c2::17]:10017 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45400 +p reject 22,25 +r UenoStation59 m40IJ1yFKmd+jGXh3adEMb5Qm0w TLGtrfbu6S8EeRTMZ3/SYt7EhhQ 2020-04-20 05:58:57 51.89.143.159 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r Pannuba m41H81HZ4MzT/UJzpn3HbKQ4Pa4 tsJZwDqjg8PIEy3FHwnPaGoQ1Wo 2020-04-20 04:38:32 87.15.57.76 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r niftyredrockrat m5SndtosC5dL9OBqNSEz7f5iA2w D/Txf6zX5j0o7wAKtdEVVFIlgo4 2020-04-19 21:25:51 185.220.101.21 10021 20021 +a [2a0b:f4c2::21]:10021 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49700 +p reject 22,25 +r bologniaise m5+F/wmPPmOCoqkz/c8eZdLiX+c WdPv76YRH9ApeJXx4i6mAdEwssg 2020-04-20 03:51:36 89.159.5.44 1713 11010 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r Pivo m6EonNz9kHuNQKirEvNr5iDdQIU l8ztY8gJk119OrHs5dDCbw6CVdM 2020-04-19 22:49:03 207.180.216.146 9001 9030 +a [2a02:c207:3003:1052::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16100 +p reject 1-65535 +r ekumen m6hOjJAINnb4bHQnyNEFkl8TcWw 8up8cipMOEtxIdSYBgEBDslFz7A 2020-04-20 10:14:44 95.142.161.63 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5300 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r huxrelay1 m6nXqekPF59tLsrN0QrFWlBKhqY ootkOf+z3qDmGGZmcUbTCFuh4HM 2020-04-20 04:32:19 46.227.70.220 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6140 +p reject 1-65535 +r calator m6qpy6MQnCyAfy6E1cnAyMFH3OY JraYwJv7Ckeb9AgbmoBE6Qiub1g 2020-04-20 08:22:52 178.17.174.164 443 44935 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3820 +p reject 1-65535 +r Archer m7ZiSi3pX8c8zEbANKg0lBcu5NM b3E7sEURdnkxsXD2I53wfMv6D5k 2020-04-20 12:17:50 149.154.67.50 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7330 +p reject 1-65535 +r FCKNSA m8ZIsYK5Kx89/QIqAKs6ofF4B1A nE+TBHpR8SkKk9YXWTBt89xS3QA 2020-04-20 00:13:59 91.38.47.215 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=758 +p reject 1-65535 +r Lavaeolous m8new3HRcZDwGF182kLzCmF7an8 XKoKrj9duRWCP5lHU+yacrGHTZo 2020-04-20 06:42:44 37.48.120.196 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=94 +p accept 20-23,43,53,79-81,88,110,119,143,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-993,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6679,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r vega m94qiA+YXIDojzrMREboJt6setE 7r13+LHo8Kd1fR8ar+A6IOJLvpc 2020-04-20 11:32:45 185.163.117.147 9001 9030 +a [2a03:4000:3b:367::]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p reject 1-65535 +r stauraum m+GByU6zZ19pvgkZ1IzWfdbQwnc fGZk9rPbhLObMWnxmxnWhQh6Vto 2020-04-20 07:55:37 79.206.243.112 9030 9031 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2760 +p reject 1-65535 +r TheToadHole m+7R4DEBsryTk8Vg/PE6Hkbkk1I CNzCHLEzywsAls5g5J2ZkPEN2CI 2020-04-19 21:11:13 97.93.219.51 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=303 +p reject 1-65535 +r Unnamed m/Pc6qotq5GKbjzUtD3PUQx3UeY 8DCAL/AjiWElm0VqYV8jqQBw5p4 2020-04-20 11:09:52 142.44.133.95 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9700 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r LonelyNeutrino m/ShNzB3SGXvbdcQLZivGjPlTgw 3or3v5nsmoBef+1s4w7V7tiucbo 2020-04-20 03:23:49 46.4.183.104 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29 +p reject 1-65535 +r Malazan m/7b+RoNJPORhuCLwHVwa5wODjA UFjHoYNNpYZL3NJAzjYTmXPc6Ms 2020-04-19 21:45:58 46.226.109.16 443 80 +a [2001:4b98:dc2:41:216:3eff:feda:27ee]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1740 +p reject 1-65535 +r Unnamed nAca+eyaxFpQHCxezY7j5H0bz/g XVd8PoLY390a8JsDYkakedP+sRw 2020-04-19 21:14:27 157.56.164.38 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3620 +p reject 1-65535 +r JanKuciak nBVZxGrQJ57vb9GH4bJ9k5wwMIY lCd8I9OAD9gP3FhU4gCxsOjc7no 2020-04-20 07:59:31 217.79.178.53 444 81 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49900 +p accept 53,80,443 +r Piratenpartei04 nB5H/yBfNJ1p1WmuftFTZqVVSkY kFSLMLxcPmnGXSiotDt277V7604 2020-04-20 04:27:56 185.162.251.94 9001 9030 +a [2a03:4000:1a:5de:6489:b7ff:fe8f:8434]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26800 +p reject 1-65535 +r QuintexAirVPN21 nB59khFdQxOFuMrqanwV+4nOI2s TqN3XykgiQXGtEW6m0yAgnmptvA 2020-04-20 09:57:26 199.249.230.74 443 80 +a [2620:7:6001::ffff:c759:e64a]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16200 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Trimblelink nCLAFTLQMMJJ3joxVcbjorwzs2E bxbQVCyZKM44O81NT9jd5mi3784 2020-04-20 02:30:12 46.246.126.62 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=705 +p reject 1-65535 +r DeepGreenResistance nCv5seMOuxo4NvoEvu6MwZLMHls PCJwXdm+J4cEEJP62GgN5bOf9rg 2020-04-20 02:54:17 185.165.169.138 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=872 +p reject 1-65535 +r Unnamed nE2u1HWapm0Ok+snCTvSHP4sInE 53IqWQNHaPq/z4nHJdQZZYiNwdY 2020-04-20 12:06:09 130.225.254.103 443 80 +a [2001:878:346:1:1::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30100 +p reject 1-65535 +r geonpvr nE4nTzSsjRARpbHw5fMJ5iVWK1U WX1Tr4REcVLxfCkIF+2YxhiTSJg 2020-04-20 10:15:01 65.49.214.254 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2140 +p reject 1-65535 +r coffswifi4 nFr9Sark4CcrrXgMbdcc4aNgEqY MTf0pgth51QkyuzZHNmB2KXyESI 2020-04-19 20:16:46 82.223.14.245 443 80 +a [2001:ba0:1800:91::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22600 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r snap277 nGBLeELdn6fGT7c7dwX3QJ6o6yU WpeQHvwOS2732Jl+lxLnDxVSvSM 2020-04-20 11:29:27 89.113.220.45 44420 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=678 +p reject 1-65535 +r DigiGesTor5e2 nGH8CgFAHt9xxASGZeU5aOgTUfw n2PkdBkTD60gS3CYaBJkteWIS4o 2020-04-20 06:44:24 195.176.3.23 8443 8080 +a [2001:620:20d0::23]:8443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33900 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Sriracha nGarO32d2i6oGq9RurptQzHflZI QmkU+lepf7MeEQWQE3lXhYnvGtc 2020-04-19 18:58:05 195.154.179.3 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r l4ppen nGc/e/Wm1deC05w65TL9/pqTQGk haF0od4GC1TUlda8SQDfr56H2dA 2020-04-20 12:34:55 136.243.38.51 555 666 +s Fast Running V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=296 +p reject 1-65535 +r smell nHDSCkVkdTz7vPTs8pFJ+O3CiGo WG+/XNGt7GkcQ3In32jOPTMCY2U 2020-04-20 02:02:40 54.38.213.66 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7710 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r snap277 nHHBX17ynugvKL7ZkJgUIfXKLV4 mPuum2D0lheRgBzx01vqJwjYLcw 2020-04-20 10:33:06 176.188.241.138 41473 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8 +p reject 1-65535 +r contributionSp nHv/0FOGg09mk1PPSh7PVH5q5BQ p7CqxZLKAcmcwKDiww71brVCcXc 2020-04-20 09:17:56 188.85.129.36 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=534 +p reject 1-65535 +r EmptyNickname nH9LZqTJ8SgARBawLwDBSo6J/E8 /drXPLL1Py1KnsAJkpQu4CZZQ9U 2020-04-19 22:37:51 85.204.116.147 9090 9091 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22 +p reject 1-65535 +r firstor2 nJAKf29d0DTP/RktrsnMqoE9sCI /4GcXNScXXMxAqosjmHtdlG6+cY 2020-04-20 08:59:52 86.105.212.130 443 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39400 +p reject 1-65535 +r snap277 nJLaKXChZG8SPgiX1SHYd2P6Uzk gsG0/XrmoaYSn+JvC0ddoOGXJNI 2020-04-20 11:42:09 213.57.141.128 43655 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=341 +p reject 1-65535 +r santaclaus nJYq75eElmEsUh0JYy5Z7QVdU+0 cAgABBdLlBImzDh60rMVwJmlT7w 2020-04-20 07:01:37 178.17.170.77 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2500 +p reject 1-65535 +r ScarletNao nJflhAV4aXAwq/x3hEQuMu/Y6R0 3/sj2WWsFjLlTqty0VziLmGq+5k 2020-04-20 05:46:53 158.101.168.225 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3180 +p reject 1-65535 +r anonymous nJ7fcKpnG5sCc5Qmic5132DDPlk LnIhwrOl722pzEDDrboOF8qJyy4 2020-04-20 01:58:13 36.228.138.151 21 465 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=527 +p accept 43,53,554,853,873,993,995,1194,5190,5222-5223,5228,8443,9418,11371,19294 +r Unnamed nKSrKwQsFzrFZHnGn19Dbp8eD5Q yxyWEj2k7PYXA03nujetyKHQ1bM 2020-04-19 19:39:52 46.227.67.92 51505 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48 +p reject 1-65535 +r snap277 nKV9piA2kIqkjBUkynBCn1SJyuQ at3YDhlmgS28owyANeh3X9OzqZA 2020-04-20 09:40:47 80.221.155.55 35645 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=530 +p reject 1-65535 +r t0rn0d3 nL1j/D9C8PN3GB8db1seACi5NLY q0YrpmcGFD0fkulLHeJ2GprY7CA 2020-04-20 09:33:20 94.242.58.236 443 0 +a [2a00:1838:35:179::e836]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=25800 +p reject 1-65535 +r Hyperloop nO2aAoRlkrOxzt8NYTdgUB47KSc Qe8sDI3Rh5NUVc0DzH5gCbYNErM 2020-04-20 02:11:05 78.54.60.130 9001 0 +s Running Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=78 +p reject 1-65535 +r snap278 nQOAGWcP22fxnKoU5DZf9xjTzUQ l+g72D+s5ZAOhK/jdzGJWAa44QM 2020-04-20 07:51:58 2.3.19.50 45907 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=979 +p reject 1-65535 +r incircuitryrelay nQffpkcrgCd3mNcyNDSM7wLy59U kGoF9Vz0FM819rTvb0TZ+9CPpQk 2020-04-19 22:03:19 159.89.87.126 143 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=97 +p reject 1-65535 +r Quintex16 nSHwNMO/9OdzfQjPd13BdFcGgB8 XB1Vy+Jwh0wVNWcatD6uGQsRvsU 2020-04-20 10:52:11 199.249.230.106 443 80 +a [2620:7:6001::106]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15900 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r DedlineExperience nS18p9upQcRwxpOV8j64H7kRWtE 41RGUhD3+UVjEDAilfCqGbyn5L4 2020-04-20 10:35:15 47.56.197.246 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r interferometer nUYvtJm6MW5IXtgOAHOALSKD+qs jt0cp7azK9PyrQL/OIZ1xcS4LTE 2020-04-20 02:31:12 209.188.58.234 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r F3Netze nVp6gbxhlFVc51H3X7GW5KOYLMU zZUnwa8KUOn5fjLl21cQPNDkaVE 2020-04-20 07:05:15 185.220.100.243 9000 9001 +a [2a0b:f4c0:16c:16::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82100 +p reject 25 +r AnonymIMXMPPNode nYlGiHeUT/ZWi9iZU7r74W6YkS8 a3RvUt7XZ6Uo6pBdEWG2XsjZzrQ 2020-04-20 12:38:12 185.162.251.249 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r hop1 nZW/oT82WFbb+oZCS5PitZZKcYc YzQMtndGI4H1DmITO3L5wimyIUI 2020-04-20 10:31:16 77.250.134.50 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21 +p reject 1-65535 +r SuperNiftyH nZzp2zu9izfz62WwzpmgnmycAIo 3WsZilJOaBgEHdQAebZARwu19Bg 2020-04-20 01:47:07 49.12.39.6 19001 9030 +a [2a01:4f8:c17:89e1::1]:19001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=46600 +p reject 1-65535 +r Bifrost naUoSlECGnEeyqZ3yB5UCCIrnyo JHblMXtVnxDrt02Zq/L8b7SHEf0 2020-04-19 23:48:27 90.225.65.71 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5460 +p reject 1-65535 +r corvuscornix naZy9G0K2bpZsvpWqPND04x4v0w YJKOO14bA/JVCuwKDlAJ1/3Rj5w 2020-04-20 08:28:21 176.31.180.29 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8400 +p reject 1-65535 +r anonymous naepeJKMSLTdUOOX/i88QRDqNXY qIuWjjJTDo+ht9DfiuW4vn99pk0 2020-04-19 23:12:00 64.137.167.84 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r HungryTREX nafvnp1gcM2LcFm4qMxbQc7AJyY /h+BnJclSi4WcFfLfYlQqJCZk4I 2020-04-20 08:20:35 192.99.151.170 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5950 +p reject 1-65535 +r bachforever nbQAQCtUXcQd40LhRkT3S32k94k M9QqFbf4lIkEV2sY2RPPEj34D9c 2020-04-20 10:43:51 89.22.96.90 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r MaxPower nbUvGnwUrM+imjbcHEDX1kPKz1g AFrnSJnHuvugIWKQ5cWqS18ZzA8 2020-04-19 20:59:14 217.160.65.208 9001 0 +s Fast Running Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23700 +p reject 1-65535 +r StartinIT nb1U0Yle4jHQdWhjEUNaH1VoK44 JzIujHo8afPEFSSU6loWSUxmLS0 2020-04-20 00:56:49 109.156.70.9 9111 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2140 +p reject 1-65535 +r akira nciwKCqNPEUhIWfEVLUDJDvJOVc c2HmXw8iWnY3DB3Ak2pPs/xH+/4 2020-04-19 23:23:04 193.105.73.80 9001 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5800 +p reject 1-65535 +r snap277 ndLnb0yooczdmSbkaO2oA3X3kF4 11KYfsBJQ0XePlMOKbhOzZI22n4 2020-04-20 03:01:56 73.34.28.144 45305 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=650 +p reject 1-65535 +r hviv114 ngBYMAQB9mh+rln5/oLbiSMDRME KxGx0R0K85ghjVx23dafha0ZahA 2020-04-20 11:41:13 192.42.116.14 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r TorScaleB nhJaBfx/twyUWs65wBw6GLfcQc8 8rO9M6RvQZwdqqaGEPfU6D0Fc5g 2020-04-20 09:37:44 51.15.86.162 9001 9031 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46700 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r eclipse09 nhmMxtowSB9C5KIuKeSpIsEvn5Q JalGWp5KRiyyRCUdKn9q2QOOwuw 2020-04-20 06:43:12 46.167.244.60 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1770 +p reject 1-65535 +r torpidsDEhetzner1 nh5PW1+UgS0CxNGMtAhs5xylxhQ ywVaB0LBrPwjGuXPP08X/QWiHYQ 2020-04-19 21:03:52 78.46.217.214 443 80 +a [2a01:4f8:1c17:41b4::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39100 +p reject 1-65535 +r Unnamed nigwHhDzj+JNzgkSUodSjkYT/jo ljc5dJqNsWc9GIvJ7jUvK05Gs+s 2020-04-19 19:46:28 79.220.158.217 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=74 +p reject 1-65535 +r Unnamed nimLlVuR1c4q6uvGyphYZ20JH5M FyhFSaSZAuLndx8HByJXchsLXM0 2020-04-19 23:32:50 176.67.170.192 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=710 +p reject 1-65535 +r Quintex47 ni18aYEmlASqGXC1OJFwGiBCTvg u4yEtQra02j/5q2N1QdR8NrXFx4 2020-04-19 18:52:00 199.249.230.70 443 80 +a [2620:7:6001::ffff:c759:e646]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r snap277 njCz4BGRKRmAuXyctpjSNeYS29Q 0dlH2CtfQDQU3rrc/sC6AYQjt7Y 2020-04-20 00:03:29 187.113.39.160 37913 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=226 +p reject 1-65535 +r TugaOnionMR5 njKNTWSlHfqQdMYVZxMLIujRRks 8+jAVI9PdMQjWvK14u6kmBS7axc 2020-04-20 06:57:30 62.171.172.234 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3910 +p reject 1-65535 +r MaudSuicide nkFEjODd4YbOBdLe1fNEKMmajXA I+rc6E6XFbPiyv9AeBt/VCY1p0k 2020-04-19 22:35:06 139.59.36.56 9000 9001 +a [2400:6180:100:d0::40c:e001]:9000 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=614 +p reject 1-65535 +r ieditedtheconfig nkM0U9M/hbcmqrrQQ93QDhcTKcE RsU2+2687S1Esa1wrC4FWa2otzY 2020-04-19 19:59:58 176.58.110.66 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=762 +p reject 1-65535 +r atoraphobia nkPn0id2rUU0hlyVF6W4livTm10 94mIz5kSx4CKkwx2j1GWJHu0b80 2020-04-19 23:40:01 62.151.180.62 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=15100 +p reject 1-65535 +r marla nkzGTE+Uw1nUPFugkJQyP9vv2XU B5oZApCgVildfgEhGfsaDbo/mPo 2020-04-20 06:51:58 185.117.82.68 9001 9030 +a [2001:67c:21bc:1e::f00f]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59000 +p reject 1-65535 +r hviv127 nmJODl66MVa/2piscDvP+V6aL/Y H4XJ6BC5Ke8NEi2zTdnSZ9UaYzs 2020-04-20 09:40:43 192.42.116.27 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Reichsfunkmast nmVPkvhJCEJ6Lqv/QzSbzDKDjx0 c1Dpd5DlKTzCxhs52O3PPqvTFQA 2020-04-20 00:10:32 144.76.96.6 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=120000 +p reject 1-65535 +r nn2kRPi nmbThLfFqZWYAO9hS6oi4EvLxEU BC/CyrgnUjZ1jadGX2/xD7lS/k4 2020-04-19 23:54:07 24.210.225.85 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r Veil nnwsbe2jqQ7X1DUnEmq2eTb7A44 nyfRY2+9v3GpbKoBOAShkIpmWE4 2020-04-20 09:23:44 69.146.146.55 59001 59030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=790 +p reject 1-65535 +r snap277 nn9/vb67PWLyOtz0MWHF5Xv+0EQ Cujm9KVhcWfRxm7T3cUD/Pi8Ues 2020-04-20 06:28:33 79.12.25.189 42185 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r 420blaze noZvMLeRrLee0oDTGX2ZnLqFpu8 ZAdjG8B/rv8ZGSY85yLREuxNyo8 2020-04-20 02:52:51 51.158.146.218 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r BISMARCK nob0yJMaztJ4+eETPrGW/fm4L4A ghWxdnLAluKEm/1jMESGR9TYzls 2020-04-19 19:51:54 37.120.146.80 9001 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p reject 1-65535 +r nostradamus npvsQprI+5l5Ws3O4JvFYEk0jss VybJMpnLjdfm3shV18Ow85SJrjs 2020-04-20 06:23:34 51.75.143.241 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p reject 1-65535 +r vegms npwiI+oXn1K6c6JL/eLkTcpGju8 GxJEuanJNaE63ByTXzdFV+4VvB4 2020-04-20 10:18:28 92.50.105.150 9001 9030 +s BadExit Exit Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,989-995,1194,1293,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,5050,5190,5222-5223,5900,6660-6669,6679,6697,8000,8008,8074,8080,8332-8333,9418,11371,19294,64738 +r bos nqRklADH014gxzT6c3z2Fekl8eQ Spr3tJvhqM7IMThExZX/2Lkz/f8 2020-04-20 03:02:56 108.61.99.149 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=51000 +p reject 1-65535 +r lumiRelay nqZdG7YHraS5prKli6oslg34veo K1MTD45rtHi+mRsXAyl2EMNG3VU 2020-04-20 08:35:16 140.238.168.214 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9900 +p reject 1-65535 +r melquiadex nqkgwnZSXXOeWHcWkqNdb3r+Tfg 9oSHwCcQICxpMc18s1na32DiB7M 2020-04-20 02:50:06 85.60.157.242 443 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1 +p reject 1-65535 +r Digitalcourage3ip1 nq1bLT29ltvIDc5COww0XpIKdY0 XUFM4j9G9ywMyCaZrDSAqkPQ4aI 2020-04-20 13:09:58 31.185.104.19 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4600 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Zarkon nrP9hAZeViKlfv7xTkGgG1uZoCI Z1a1YKOOh8UnZkLMQZUIQku+M1Q 2020-04-20 05:47:37 116.202.193.60 9001 9030 +a [2a01:4f8:241:1003::dead:beef]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44000 +p reject 1-65535 +r PacketPusher ns7AR7oFlsUe3QmGFsioZpehKCQ OKxgKw8OteSjKcmN3M5NWvk4ePE 2020-04-19 19:32:59 193.218.118.130 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=310 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SpookyMulder ns/WcjDQnl6PNDG9xP2OUkKK/Ak QjwMBDt9Urd4b7LX7tr0a60qMsQ 2020-04-20 06:08:09 89.35.39.185 443 8080 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 1-65535 +r trainmaster nuqgLjOM31kZ+YPzJFqpWnkLm2w INEz7uSx7C3YDGs7sSiz0WUR944 2020-04-19 19:06:28 89.46.100.71 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7390 +p reject 1-65535 +r niftycastoroides nu261+41GZbfyRV46IK+9P5e2/o jgIABijYNSIqgqKns87lmQEVx7E 2020-04-19 20:28:08 185.220.101.121 40080 40443 +a [2a0b:f4c2::121]:40120 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26600 +p reject 1-65535 +r specters nvT0eEZyllAFKALWlsq3CfEWxLg om/Yibc6Gded5VO28YEofD/glho 2020-04-20 04:35:20 79.112.23.103 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=708 +p reject 1-65535 +r Unnamed nvkqEv8GpiDCOnyQP/9AfOBaxdc z/wMrMJ8uge1iDpkaDZxO++u2LQ 2020-04-20 11:50:53 199.19.225.84 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3890 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed nv2icVWD3kmmmI5i2Q20imwj6kI dD6Y0JMKTvcqsGCEgUY7Ima+uDw 2020-04-20 10:27:34 91.219.236.50 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4600 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r torreymerch nv8W6iX/J7xDij+/I8UxXldkZ68 9h0WXj8BXMj2758Bev7BlHj+HRY 2020-04-20 07:49:45 172.104.27.216 9001 9030 +a [2600:3c03::f03c:91ff:fe5f:92f8]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18600 +p reject 1-65535 +r Quintex15 nyhW9tK4mtTvbVcj+rFn21pTUZo IA40x+SHStr/XRZ6HiFvwo4w4Qo 2020-04-20 11:51:15 199.249.230.105 443 80 +a [2620:7:6001::105]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r ViaSEfWgRFE nynQ3UrrYudCva7vLf073XaVNAM cdB1zPhylXzWwmGLOnpGvhV8n9A 2020-04-20 08:55:15 185.22.174.46 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6680 +p reject 1-65535 +r melk nyziQ3oE2K9GPXcK5xbBWVqhZm0 AQcIySSW5/rBKsNOOmxKmOzNUQU 2020-04-19 22:42:19 85.204.246.199 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3990 +p reject 1-65535 +r synfin nzmjXeWRsuh2nory4LgRxHkris0 pHd5qS9Nb/hS7AOu7gtv+vU5wQQ 2020-04-20 10:43:58 45.79.109.55 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=255 +p reject 1-65535 +r QM1Relay n0STQM/nKXDMVklbAXtzyCXbtWY lLQigEk7/f2G8wKTsGcYhMXC+mE 2020-04-20 02:58:11 87.125.123.223 49001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=170 +p reject 1-65535 +r Doedel26 n1BoMQgY7XxwsLxAh6tVyxLLQ3c HmFjz0z2aUmaBWQweR+dSIvVRsQ 2020-04-19 23:52:40 81.7.19.110 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10500 +p reject 1-65535 +r lftor3 n2iMRuAEatLAJsGNk0MlInnkJTU MFJO7rg+WWNiLGtgOrpUxt8kv5s 2020-04-19 19:45:25 51.15.210.243 443 80 +a [2001:470:c85d:32:216:3eff:fe2a:244d]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7910 +p reject 1-65535 +r Unnamed n28p9wqOFDfFA6yKfkFeuSJfc0A 4yfzbO1TFvhxWX5NNFvq+TdUUZw 2020-04-19 19:36:29 167.114.92.59 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Nivrim n31uZCAYPCt2086ZYk68mKIaln4 xH075ySQZQ68mYFHyksrAz8rWQI 2020-04-20 00:00:51 46.28.110.244 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7870 +p reject 1-65535 +r MapMaker n4f46TPh62zLl5F7EQtmQfbsMgY ELgmfb1WwPg5Vpr0OlT8BAmIMXI 2020-04-20 05:31:00 104.192.102.106 31927 0 +s Fast Running Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3150 +p reject 1-65535 +r noa n5B4OmcgFdTUDyKQKWS5KtDqDBc BO5W6hQuR8B5QOBHDb1+bIWp0CQ 2020-04-20 01:53:32 149.154.154.155 9001 0 +a [2a03:f80:ed15:149:154:154:155:1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2180 +p reject 1-65535 +r DeiFlagellum n6+JFeI0LMQxWdvumDDavM1ZtLI y3DhaZBv5WVcttJlgl4IS+6Sy0E 2020-04-19 22:29:08 188.116.42.3 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1410 +p reject 1-65535 +r smell n7JTW7+s7vzIGwFcDHJ+Id6tcmA Q6juAWViYIYLTgw/7CUbZ1dyxPI 2020-04-20 01:25:44 51.178.185.239 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27200 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r devilinside n7KgeGeSnqQEZnJHrullbz33JEc Ma+c2QzEFoKKRyG6uuGTPJf+a0g 2020-04-19 20:34:27 66.175.208.248 9001 80 +a [2600:3c03::f03c:91ff:fefa:755c]:9001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1040 +p accept 80,443 +r Skvatboy n8TULx40AEigpAl79UBsotqtCPg QeyZ1+n4OMWfMd19NozNcMOew1k 2020-04-20 06:00:43 90.184.104.85 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=77 +p reject 1-65535 +r Unnamed n/ofU+QmhRw8XTa+u82DXK7QUsc DdmGONqUUJDWXJwOYCKx/FKkjrw 2020-04-20 12:34:54 167.114.92.54 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r d0m n/wP9JJquOprkuJBll0WX7AdNrE OfrMiXrrnsdCP5bqxoQtzwmEz3Q 2020-04-19 19:35:23 51.158.148.216 9001 9030 +a [2001:bc8:6010:215:208:a2ff:fe0c:6c04]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22100 +p reject 1-65535 +r ForFreedom oA9+BUImfcWLoAmDIlBd9dM668o PGd+gcPfqx9MTRmAWHA5m5rmeWQ 2020-04-20 02:18:32 159.69.69.72 9001 9030 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r niftydiatomys oBYZLQqH/JNUp1I6IRu9nPhZcIs auTCyyN6coogfVmV8210wc6f4/0 2020-04-20 03:25:46 54.38.145.211 20 21 +a [2001:41d0:800:656::6067:9ce3]:21 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36800 +p reject 1-65535 +r Nozel14 oCYcFtFbRPfJi0cPwHPqK5zRDUE nypreX4Yqm7j8PGbhweqzZs9EDA 2020-04-19 21:45:57 163.172.210.193 465 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r niftyentry63 oDq9nVhiVcjDOzonMOZISMqxHtM Vz7afcWkDWUiEXuBCYGOiCkH2ew 2020-04-20 10:50:51 185.220.101.203 10063 20063 +a [2a0b:f4c2:2::203]:10063 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p reject 1-65535 +r Unnamed oD+QJp/cWKVagzEOPCjpJkRqpcA /4xnL10C6iF5OMetP/41R/ukSeY 2020-04-20 01:22:51 83.83.232.20 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1640 +p reject 1-65535 +r snap277 oEMOC66osCtskveqPvkPkX6qfPg WOkiLyrMLVoUoH+l4z/tO+MgvbA 2020-04-20 12:39:42 87.244.162.108 45937 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3810 +p reject 1-65535 +r psilocybin oGTjxr3rvMKLjv6TLlnnzX5/wj4 ud6rhdTUt9sbqmwDyb/fJcNffTY 2020-04-20 03:40:36 24.116.70.175 50000 50002 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=960 +p reject 1-65535 +r vlado oGbnmDdYx8wAl+Fqz097cbr6ROk kwz74dH0UIPVeW99rvkmM8IFwD0 2020-04-20 07:16:06 104.244.76.24 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=33000 +p reject 1-65535 +r zpyramid oHoMx0IhKLdrsYuWWP3ztQZCJD0 stPPtvpVZPKR7rvNr1/hu8hAE1s 2020-04-20 04:59:22 134.209.90.217 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=11000 +p reject 1-65535 +r STUCCOTHUNDER oIs+ZTMfKclgqOtvXZC2agXSbLU gmJUtozvMS6TA/rD4IQVUxy6uzU 2020-04-20 10:28:41 88.198.41.140 9002 9032 +a [2a01:4f8:a0:11c2::2]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57000 +p reject 1-65535 +r Applejack oJ0g2F0KopxHyQq+r9trekv3/Qc 1c+fkXn8bHFl2pXyVdsN9o0AGGA 2020-04-19 21:08:47 78.46.177.87 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8600 +p reject 1-65535 +r inhonourofecho oJ2qrRbj93wu0aASvYoY/8v+tCI krUhb92OF+9kQkpaUNTGqgroHOI 2020-04-20 09:01:12 85.167.122.23 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p reject 1-65535 +r bluediamond oKHaxBzkyQppqgskgLvaZnpgf7Q TQR8+sc8FPMYO21BMYLaEE4UK+4 2020-04-19 22:48:50 45.79.222.13 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=2540 +p reject 1-65535 +r disconnectedtech1 oLBeHYUth07682A8gyRuAK1lryA U9YmbX/v4uSDliE1AmsTaaqNG4A 2020-04-20 10:03:04 85.191.249.24 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10900 +p reject 1-65535 +r GfRzz4HydFJVSIgs oLZ4BZYpvNq7Td/1LlRu8TmacKs yjCRQp+egRQpEHcyhRZAdwdDlxs 2020-04-19 20:42:50 94.237.68.13 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r TerminaTor oMWUELkDCsE4XEykTI2/4Tr0vJs bJY02XNPj0mBTFw0IafNS1OCIQk 2020-04-20 04:56:44 62.171.142.3 9001 9030 +a [2a02:c207:2034:5805::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14700 +p reject 1-65535 +r sccOnion oMXdxVzsr8Mdw5CbyzRGA+alB88 SSTHZYNpMul3ZP2kpqpLgSsb7V8 2020-04-20 02:36:36 216.186.250.53 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1520 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9332-9333,9418,9999-10000,11371,19294,19638,50002,64738 +r gerty oNB04FuK8J0WBaqX4U31wjgy6/w 166sfSd06i1572b6YB89fPyFNmo 2020-04-20 06:37:09 103.31.251.112 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=120 +p reject 1-65535 +r basajaun oNKLRbzxeZ9W5dJF3mRpwQ0fTCU esrjYVQd5bnQtmozLNPY/aiXKrQ 2020-04-20 00:36:21 90.94.236.160 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6 +p accept 64738 +r QuintexAirVPN29 oNuCD+yHwEBfe/Bd7l5K3tK7mQQ E2DUeeGKNZn7BWyI2pCFrBGexmg 2020-04-20 05:33:56 199.249.230.82 443 80 +a [2620:7:6001::ffff:c759:e652]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r isprjr0 oN+zEjHHGIKfoY6rTQzVHe264Iw 1+JPNlXEcNxfl8llXUFjsudh1Vs 2020-04-20 02:53:52 51.15.206.72 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32100 +p reject 1-65535 +r torro oOPTCmYNtwygttCBulTQlN7W8o0 wQ/RuDZG3MS4Ei8CZYlolA+7VIc 2020-04-19 22:04:44 85.204.246.104 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8490 +p reject 1-65535 +r snap277 oOddv7+foAgOOYynpv85IKrFe9s oi6uaXZOUXgzNyH+LDJ382YRA8s 2020-04-19 21:25:16 94.33.52.76 39951 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4680 +p reject 1-65535 +r snap277 oOyUkd/CNf/L3ZKTH90zGM/iH6Q yC1YM/Hv62Rjo15sM1nBCvZly7c 2020-04-20 12:42:29 91.66.44.74 41233 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=64 +p reject 1-65535 +r YeJunPeacemist oO29qPJHV0KdrIKJEYHZaHBiPE4 bqx51ssNBpW/34lWHkKxz03kUKQ 2020-04-20 12:00:58 51.75.71.108 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=615 +p reject 1-65535 +r Dhalgren oPBsL634jTo5qjBytAbwnXCVrJ4 vffZsaBKsscyxaCnwo0gfRADb88 2020-04-20 12:47:27 46.165.230.5 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=90000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r loskiq oPN85j8KiU4C2tMcuoOb0ZPtrDo OXCLHqaEJdgKgqbi3bA5XZqpJ8A 2020-04-20 03:40:35 94.242.55.101 12317 12318 +a [2a00:1838:36:131::38b1]:12317 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r pldtor oPOdMgKM7H81QZ6VcEAd4VsbRWQ OegeJfyaSIZXw6J/ku85/GH7HWQ 2020-04-20 03:21:36 5.196.58.96 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20700 +p reject 1-65535 +r terrance oPWZmaxhIxWAXVCj5J/Ee2AbjTA IRJoJdAh3w2+vVwI/3v5MfJ8W+4 2020-04-20 12:03:33 87.120.36.210 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5400 +p reject 1-65535 +r DFRI1 oQxPZm0nNkA2tWKCPlgwvESOBGo LRM06oYq/B6gpeN9QYgpwf3PduI 2020-04-20 09:48:06 171.25.193.77 443 80 +a [2001:67c:289c:4::77]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r kiwitui oSP0BL2aFdlsx5MMK+KBAzQaxos U8NjxC84KTgNHFdRa77fZAspGwQ 2020-04-20 01:40:08 141.0.153.53 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p reject 1-65535 +r Desperado oTKB29j45ITpXdJzs+5/wUwbCno LNCTKNquKVge+rds7eOCxN79Dos 2020-04-20 07:39:52 78.47.134.196 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=12500 +p reject 1-65535 +r niftywabbit oU+QlTrpRizzqGLEypX3O/lKb4s LJoIx/amSzh742piD+j63rK3kg8 2020-04-20 03:41:05 185.220.101.202 1202 2202 +a [2a0b:f4c2:2::202]:1202 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57000 +p reject 25 +r whatnick2 oWiJcuSqTyTEyaojcs04e4KDTEA xlEy9FVi50rCB82+8As87mA+ix4 2020-04-20 09:00:38 78.47.14.99 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=150 +p reject 1-65535 +r otto oWma9dfgKU5F1C/6aX92K6JjQOk li7MrjmxC/gXWztgnVk/SepLRPI 2020-04-20 01:39:20 193.84.190.54 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r apfelkuchen oXuWGX19iZNltmxkk+NNYWtjrvk r7DTMjhw9WX4tKVOu86jvN4iSNg 2020-04-20 02:12:33 87.162.63.71 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=119 +p reject 1-65535 +r tor4ever19 oXwJOs6a6j/5yr1p7PeT0gle0wQ /+jbidjDoElK1BKayuKQToweip0 2020-04-20 00:55:43 45.62.236.202 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2330 +p reject 1-65535 +r showpen oYv4GFV71sijVGsVe3gAtfJKeac J8txf6s+imsX6aQFsma7uqgZ1HQ 2020-04-20 07:28:04 88.115.61.255 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=230 +p reject 1-65535 +r unnamed42 oZO82VlC3NJUGDW2PlzhcQeI5IU QfFEDE8c07T6VvSpvrqrUWsphdo 2020-04-20 09:51:52 213.138.102.209 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=300 +p reject 1-65535 +r snap277 oauOebvQdQ6tB9F3sbXb57WLWmQ ED9KFCSjXaXyr/rGhpLsiVHhtX4 2020-04-20 07:40:05 84.47.21.73 35875 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1140 +p reject 1-65535 +r camouflage obFupyxd8jNGs4FlgaMJN7Xq/JM lQUToSiFM1iGG2ny50uZeNmTHD8 2020-04-20 10:00:06 185.26.156.186 46523 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=541 +p reject 1-65535 +r bakunin4 obKNY2pWqv/pKtzKk3qkvVMzu0w C/d0hwKgoN2bqfoiL2cG73w7r8w 2020-04-20 01:15:15 193.234.15.55 443 80 +a [2a00:1c20:4089:1234:7b2c:11c5:5221:903e]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r omue obLjLkJvcA033/FCKOG5V6Is8KQ 3ssw1qi6ArYQ5gArkGD1lHa4Is8 2020-04-20 03:11:44 92.116.198.74 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3620 +p reject 1-65535 +r arnall obfB+D5dpDdv0uHbp6wopxqzMq0 T/k2vYCntLoJl2JNauuhDwY1z2Q 2020-04-20 05:57:03 82.103.140.87 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=55400 +p reject 1-65535 +r locotor1 obvL7BE9qsfxfnp+aYqqexR9aRo tEbljCrFRS/7qcnbS3Du/dpDUWo 2020-04-20 12:22:18 82.64.189.117 93 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4980 +p reject 1-65535 +r northwind01 ocrLTDT70O6rl8mayNs0qko7VQk 0gbE9DK7HEKd4NJBnAMYd0kZytI 2020-04-20 01:22:46 87.159.158.209 8082 443 +s Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r reaigauebnap odi+Jks2kYAAbNoDmYh5tJz66Ts XG6HJZ9soekxBIakD3SlcdG+dCQ 2020-04-20 12:30:03 207.180.205.67 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35900 +p reject 1-65535 +r Unnamed od61Kd6G58q8MhJ3g3STPWj7fy8 F6O2p7oVCr7zgI2bsi3S0HnXSVE 2020-04-19 23:24:37 51.38.107.122 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r huxley ofpiPBELnjSJaU6o6FolwkK7sUc rNHAYQJ38K4gRretHlolrPc3yeE 2020-04-20 00:45:44 54.37.16.226 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16800 +p reject 1-65535 +r Galactica ofyOQkFnrXC2+klT2TSLzYLOt4g zUUCffSAA/YVvdwgQgnjb9QERJA 2020-04-20 06:20:47 185.217.95.25 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r Zwiebl0r of7oU3yEfTMPH39ZK+JDYMXWBR8 +w0ZkxICB6NKWqfaTK7fK1er79w 2020-04-19 21:27:35 37.187.98.35 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7500 +p reject 1-65535 +r snap277 ogA4d7RUH84ann0G4zjowRtbsHQ qg7YhbQv09q6tocNy7G2azOsZxI 2020-04-20 06:02:20 37.194.3.42 43559 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=600 +p reject 1-65535 +r snap277 ogLaiwAUdw74JfR21nqOFcJquXY AgwArXhialx8JUIKIVYVGfl+3AQ 2020-04-20 10:28:50 83.31.125.151 39521 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18 +p reject 1-65535 +r kbtr6lv ogyyQWvezGC2gf7iARM2Hbfd5ds uVDyUrYrw/8s6kfFn+db4lxxnRY 2020-04-19 20:40:54 185.61.148.121 8443 0 +a [2a02:7aa0:1201::15a2:6a6]:8443 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12900 +p reject 1-65535 +r ak3812 ohLaXa+UDYymMGSSahsP8DXdzgI MtkKFd855qtDN5obu/2V1llhpbM 2020-04-20 06:48:52 212.47.234.212 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2230 +p reject 1-65535 +r hellyeah ohMU+y1z3JtL1FjOaWaaxl6yZes Aj4gmsU5O1aHvwIMvDXm/zMf5Us 2020-04-19 20:18:23 81.89.112.129 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=370 +p reject 1-65535 +r Init6TorRelay oiscLvIlWYf4q4qgsajiP1Aj7rg SuPA/oAeIl72S+6BFUCo8nFa03k 2020-04-19 21:44:49 178.63.138.17 29001 29030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8200 +p reject 1-65535 +r TorpNetRelay ojpyGbHqnVg+Zt/ybWJXPeZKnCk DgtHLOFcfJkScRp1lXcX4Zec2+A 2020-04-19 21:47:06 81.226.65.243 44443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9960 +p reject 1-65535 +r iVPN olNO8jOQyuB5sVhvD9+c4R9VYGI tJRtB8oPnLK6ZUR6+GssNcp4dMw 2020-04-19 21:30:13 185.220.102.6 80 0 +a [2a0b:f4c1::6]:80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=64700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r noisygerman ol5J6HmyPtoJiC7ZmvuT++a19gU UR9lqwFfIWr2VjjRD75tQlqgNak 2020-04-20 10:46:51 95.217.97.138 444 8080 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10900 +p reject 1-65535 +r LawyersGunsAndMoney ol9r3m5eRVVeL8zE9QRgplVE1h8 aZAt1iIXS5266CF1E5mafGLaV0c 2020-04-20 09:27:34 208.94.242.26 9999 9998 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9530 +p reject 1-65535 +r OgresHaveParfaits omf6tVVG2MovR2GOVWbA8RkTRgo bKHm7/q2/c9D0s2peZFesLXgku0 2020-04-19 20:48:30 23.237.87.201 9001 9030 +a [2001:49f0:d099:2::1d6a:c9e1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6940 +p reject 1-65535 +r RoteServerPaul op0qeKipVIGeIgzvvrzpXS/PpU0 +8rPFjAIuzb+nB0fwxk/tAgKUaM 2020-04-20 03:11:10 92.75.12.181 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=820 +p reject 1-65535 +r Tadeus op/hmGRwUE0zK0NxYQJ8gTFG/ws cbwlyYrj4lqoszvz9y+9k8aHxpU 2020-04-20 12:37:15 62.153.4.151 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=958 +p reject 1-65535 +r Cebola osvscCF4FKnfshBp+FEL5BirsJQ tAdW3gkGx3B8rGJzVppFvkjdj34 2020-04-20 07:57:43 163.172.216.178 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r GIEBELWALD001DE osv1ePLnM4wTcwDvQszbGRBhtRs rBJAtNiHbQfE6h1KPCNnJLEa/Fs 2020-04-19 19:30:37 185.101.92.236 8550 8050 +a [2a06:1c40:3::103]:8555 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p reject 1-65535 +r arbitraryTessa0 os0y2dBmjbdkrWjHRc4paTyoUbk EW2zEw9sJHKglMVeSwPocaJNQjM 2020-04-19 23:23:20 95.216.19.207 443 80 +a [2a01:4f9:2a:1430::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42000 +p reject 1-65535 +r Relay5202 otQ332VMO+VCj9R1o7Qeurx8gyw R49DwSRGBXKoSJkAfcFodr89ftg 2020-04-20 07:12:01 67.7.84.172 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5030 +p reject 1-65535 +r Winding otWisZdPKfQODyw260hwtYUloBI LDjIwnesgp2z2fsINics9R8J5bA 2020-04-20 12:07:27 74.108.39.7 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r RSFPressFreedom otspP/xadqcYhjvxrtvI37HLEJc gh4YvQI1wsFbf/AMqg87QHgcK2s 2020-04-19 21:30:12 185.220.102.6 443 0 +a [2a0b:f4c1::6]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=71100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r king ot55n9GxKlymTUhqnMMQYEjb/NA 9y/91yEYEbkmWlZty1fF7mEX9Us 2020-04-20 08:28:12 51.89.200.121 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17400 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r BeastieJoy62 oua7XDkc1Gs4xVtDKcNTBFQHcfE f9eGrHhCXx3v5p+vQJA9oIZaHO4 2020-04-19 23:49:39 81.7.3.67 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12900 +p reject 1-65535 +r FuckCancer ovWA+T+j0No3N2lhS9mwyKbEYj4 xP6rNTCIyLhaYaljLlbabHl96Dg 2020-04-19 23:01:47 23.129.64.185 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11700 +p accept 1-65535 +r 02d881841883 ov14i6/9RYijfZHqDxHNEcUzcKQ rkru2jmP4wHPYvRii4U0Qe9G78U 2020-04-20 08:15:59 51.81.253.209 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TORFASTER ow9oOOwPAE0sOVZ2Cm7Go5iDXLU kqPn5HMyMKZrAOKvVy7+bfA9XWM 2020-04-20 11:27:33 84.53.192.243 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5590 +p accept 1-65535 +r SecretTrumpPornHub oymfEL+SqI096jwW8sg98YwXsms Bxej5NnGGZ2hBN/Ig8XmNd+JP6k 2020-04-20 11:07:21 73.35.183.117 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=467 +p reject 1-65535 +r Dakar ozJMrJ7ijyBwkNc0jpnIxW9HNI8 aO/5mI3AX3bko3MvnxbTloezbcA 2020-04-20 04:02:14 195.211.143.223 65065 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1610 +p reject 1-65535 +r rainbowfabrelay ozOXVGC0W7EJzG5UEGtbKmJXIfo ypafGlFsOX4aU3kJUsM2V4uXA80 2020-04-20 07:51:13 91.58.8.45 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4250 +p reject 1-65535 +r TorRelayOfRio ozVzyTWzTNB9mI53SBnfDTA1n4s NRx+8YS7wKylnC6rgtmOHPrqF0M 2020-04-19 23:01:47 83.212.103.133 37755 9030 +a [2001:648:2ffc:1225:a800:4ff:fe20:9a67]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3640 +p reject 1-65535 +r bigbrother23470 oz6JOLLSwNEYpa6VoTnY5TaXrDg jBPf5DyZ9hEYZgQ83N2t3OHBOh4 2020-04-20 07:43:34 75.142.113.210 19001 19030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=183 +p reject 1-65535 +r TorVXNDbhs2 o0B8xAPPOd+kDtnh0UqLVEMfYQQ D5KJp3rv7pFenU8YsgXGu6r6uv4 2020-04-20 02:55:18 198.27.81.192 443 0 +a [2607:5300:60:22c0::]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9250 +p reject 1-65535 +r paruchu o1AxTCSipbfOCpFwe341lJXc7KA +KPAc0pjRL3/Ae7nrwUFddchxC8 2020-04-20 04:22:03 118.243.210.81 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=207 +p reject 1-65535 +r Oberhasli o1PnIYL5qWJrEEB23VZ1swFCexI 8GySJZJp8K7Z0plQTwg/SGZONSg 2020-04-19 23:58:43 204.27.60.147 9001 0 +s Exit Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=246 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed o2oZjS4JHJmCnKqInwY6yVZ2kxc BS5MXQXc0olAXPscWzNOKcr3SbM 2020-04-19 22:07:29 77.8.159.46 993 0 +s Fast Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=346 +p reject 1-65535 +r thorion o20TA2dQ5HfgxWKKW+T+y2MobYA WkK0m8ycnwg+ASU9qVglW3u5dzc 2020-04-20 09:54:50 45.91.101.227 443 80 +a [2a0a:51c0::59]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p reject 1-65535 +r Unnamed o3vRm+6C/4HG/GGALE9PymeBRpE BfJAugffneR8FW3Giutw1EQlRaQ 2020-04-20 12:29:12 167.114.89.195 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftysnowshoehare o5Ad23eZoR6bq5C9HdpzTboZYzc +Jb4Ht7jR3UzuK5Zv4I/EIenLr4 2020-04-20 12:06:25 185.220.101.139 8093 47769 +a [2a0b:f4c2:1::139]:31367 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26600 +p reject 1-65535 +r sighif1relay1 o5RZHogOs2EOCdJAq2OYhJGET7Y M1aBYvYjCV9LAfEoV8KxlbvKMGM 2020-04-20 10:16:47 46.101.165.197 443 80 +a [2a03:b0c0:3:d0::dd:a001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=113 +p reject 1-65535 +r niftyshrew o5ch0oSqHtGuh65jUjU1SEqhT7U I4cMwyEvlFk9hijdeRmXXyX9ntY 2020-04-19 19:25:37 54.38.73.16 21002 11002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p reject 1-65535 +r Unnamed o6NSse0zBaHYzIRS2B1yr6v06lY y2TDCiVO6JjjFywIsqjDYPxkBCM 2020-04-19 21:13:37 195.13.50.227 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=423 +p reject 1-65535 +r Gaugor o6bZ19vtAPfmUItV00Sf9rbF35A St0IWHqgE+gxhmrfv4261oCEpWA 2020-04-20 10:59:24 88.3.72.24 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4390 +p reject 1-65535 +r isthisthereallife o6+97jAjjkSJnJ+LdmbRKwnI7jI pOWjAu+oFh1ZSKMpef+2DPiiPUg 2020-04-20 07:02:46 212.51.153.165 9001 9030 +a [2a02:168:4e13::666]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80300 +p reject 1-65535 +r andrethemac o7EQ41z8JQ2p9ARaKnbgEUJNItc adv+P+j0BsVHW+T0uV5F/1a2mVI 2020-04-19 19:10:10 94.226.76.51 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=220 +p reject 1-65535 +r king o7MVkE+STYNdnfBvcVo12sjYTwA elPe5AmPY7XZMXjXqf6skEuJtI8 2020-04-20 05:08:16 51.89.200.100 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r name o7s+ywXCoAxHOMh82Fozm9n1XYQ XmrdXHwgmpy3G597NaSQkULUl7E 2020-04-20 06:31:11 86.57.149.13 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=3600 +p reject 1-65535 +r pangea04 o9JkiV9oXRb8g00GhaCUrmIvIgY 6NXv8wkgKPaCqT+nlHL2y1ePEbs 2020-04-19 23:54:33 46.167.244.56 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1280 +p accept 43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,873,902-904,981,991-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,5900,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 o9MqImOD1fe/lGeLgFsbd2WGnLU xG4bX4HI+G87FOcHhev6HvD8zF0 2020-04-20 03:29:23 109.63.198.120 38791 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1910 +p reject 1-65535 +r VCVLPQ01SRV04 o+ekOV58HzBpIBjk+wmAsQPjhIg cOvXZ7DHXQc/pcNd1VafxAeOHNI 2020-04-20 11:02:13 69.70.221.254 443 80 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r hktlRelay o/iFN2l1VcchdVJveKwDS5gDRWs ZY8f8C2iJGfbvb1c0KJ2fGeLD9I 2020-04-20 12:40:20 1.64.103.119 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=818 +p reject 1-65535 +r mcnulty pADPg22jUa3a2bo1DBq6NQJkpOA xzvh7x0D3fVXz/i4VPBnpj2J1oA 2020-04-20 00:10:50 51.158.165.51 9001 9030 +a [2001:bc8:1824:2202::1]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p reject 1-65535 +r grezer2 pAEmQVRYNjvfYMTQZnJ5grPUHsw xq0zd1jIzn0Zg2FyUwZvkOqBkoE 2020-04-20 10:52:17 82.64.82.111 9001 9031 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12800 +p reject 1-65535 +r snap277 pBKGEuVnAXp6K3NMZMjDv7AXHtU fVxhQ0oyBh+sphPNyXBgqcKV7tg 2020-04-20 11:54:34 47.58.203.24 33297 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=478 +p reject 1-65535 +r Unnamed pB+SwJLJOLA24Iny3mr/bY1b12U DWmXV993qRQgs1nrncXkKu2c1Wk 2020-04-20 02:34:17 84.39.112.110 13147 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29 +p reject 1-65535 +r jo pCRgdfNp9kETGz5dJtl1EUG/MCw yNL68Me4BbM8SmIjxWXMSsI9Gvc 2020-04-20 04:27:38 81.11.235.31 110 0 +s Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=35 +p reject 1-65535 +r Unnamed pDsP0eeqqque8dJ7/XYw1yjQiO0 CMTT6bW1C0pFsKy4oU0631Lx2NU 2020-04-20 10:24:25 71.19.250.147 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3600 +p reject 1-65535 +r Unnamed pE0A4iXj7AnTpI5KjSydVW0jUEM wDpcJtjyvHmI6iNJ+1VrbQbmkHs 2020-04-20 03:45:37 173.230.137.207 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=120 +p reject 1-65535 +r nofun pGYXSsRneGnWomBr4BvyhCeTlMs z8ZgURdfZmsq5W/6JyJFxeEvVNY 2020-04-20 04:30:13 144.76.19.221 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1800 +p reject 1-65535 +r Unnamed pGbcHFRgUwYJQKsnnx6pZxZ+yss KsAVWPnjXhwGYvG+dPTiz5WfNfU 2020-04-19 23:12:36 198.52.245.128 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=105 +p reject 1-65535 +r Koljasagorskidotde pHccuQAk8YcNYilgUZlFo+SbQP4 8gdb6FY3Jp+DHBHlXX12Gz3H0Fs 2020-04-20 00:07:46 136.243.250.124 9001 9030 +a [2a01:4f8:173:2166::6]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=88200 +p reject 1-65535 +r DFRI4 pHjkIfgxlMEU9B6U+VmZZyrtUf4 E+TH0vGHI6cadG9IBJk1xCZ1E4U 2020-04-20 10:13:00 171.25.193.78 443 80 +a [2001:67c:289c:4::78]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r ipenburg pIDYyfmxES5Hwk4z2sBBnK8agho XSa8R7CmHlBs8djktlbEvC788Os 2020-04-20 02:52:33 80.100.157.41 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3900 +p reject 1-65535 +r djrizi pIwd251EmTME5otImC9zx+uL3NY 13gnNaPhLrQ4oyWRh+2i6uoDFlA 2020-04-20 11:21:15 64.137.161.147 9001 9030 +a [2607:8880::461:93]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19100 +p reject 1-65535 +r torrelay3 pJS9QSa38Yh8MF0H2yQGaFDq7u0 CZ8WtewyNJvS6Dki5r4zUeLaY3s 2020-04-20 08:44:02 78.34.207.81 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=371 +p reject 1-65535 +r campsolid pJx5nw7g8c3s885+7jBDFMy6iCU G2Hx94016x+mDgk1MkQUebK+CX8 2020-04-20 12:21:34 167.179.119.143 9050 0 +a [2001:19f0:7001:294d:5400:2ff:feaa:192a]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=598 +p reject 1-65535 +r plan9rijk pKJe2riA/0IA9MITFvO54HLJ9GY E07S0S07D1oGuCpA0WytWnudkeE 2020-04-20 00:10:08 194.126.175.157 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1480 +p reject 1-65535 +r Unnamed pKMOre+6SSGrJGlU4FH0XvhbRZ0 ScVJELzOB7OFIPZ70qYy3aKTRgA 2020-04-20 12:09:19 158.69.172.230 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9120 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Quintex44 pKOT/vSGQJYarOktBBk0tVNIzvk kOHanxMFssLXPQqdG2Tv0+LWOBE 2020-04-20 06:47:09 199.249.230.67 443 80 +a [2620:7:6001::ffff:c759:e643]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r kiwirelay pMg8K+tPGzHUDoDVUkxmoRfXfFA U+eE85efuVScS0VUl4FYt8riw60 2020-04-20 03:23:02 136.24.157.210 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8900 +p reject 1-65535 +r angeltest13 pMw5GErSh9csIkdziDWBHHp+y44 Ulrpllt2qozekTPFVU8+88xmWXQ 2020-04-19 19:39:39 185.225.17.173 443 9030 +a [2a0a:c800:1:5::86]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15100 +p reject 1-65535 +r banghash pM9qw20Y7A+3sXNMP8fZFIDhuM4 R4rDCeg8YS8Ts+fbeYCkgEbdHXg 2020-04-20 00:09:40 46.4.114.111 9832 8160 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=108000 +p reject 1-65535 +r antongervase pOEgNQQlutkgMH/6dEQPldAXIwI xb6LMv65VmU8oszlF1zAPE0VP6A 2020-04-20 06:38:47 51.15.34.165 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30400 +p reject 1-65535 +r Unnamed pOcxgZmjR7cOhbTIWB5gjK7a2Kw GSEt0sn953jfvt9IHb7+c4htBns 2020-04-20 07:58:45 172.104.187.188 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=291 +p reject 1-65535 +r torototela pOdEENg3Be7/JLwmXeKy/zm9pW4 d4VwaTXLze9KiMeKSNd+WnubpB8 2020-04-20 00:48:27 79.40.102.187 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r torrocks pPEdaT+rbpSbK3wYFTw/eYmJYAc eowGUcGRLq6R14jIwzzb/TWlgTw 2020-04-20 09:15:36 194.55.13.49 993 587 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61200 +p reject 1-65535 +r snap277 pPKipolgXbSGIoXXVk2B9iHovBQ n4JDuo3rZyi9iTuf443Byk383Dw 2020-04-20 10:30:05 83.201.75.86 33799 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r bisindia pP4CGotMTjy4hRz8PgFk3t0LSqA 6BADsj3i3q/Q0ltgnUsxXrQ4ZQU 2020-04-20 07:32:32 139.59.94.18 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=371 +p reject 1-65535 +r 550af08a pQ7em117QXrnzf/otO5+AVAAcmY Nxg0fX0xSOuaTmPBHraXJeAFUzk 2020-04-20 08:43:57 85.10.240.138 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=117000 +p reject 1-65535 +r grhtorguido pS6uOMcKd7t+Vk/WxsffaICXrtc 3BVkDrOYiXh7M01K0glTswloT1I 2020-04-19 23:34:07 93.213.146.52 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r BienwaldKA02 pTVpyzM+mJWkSVRwDMB9ITWAFRg BvQj4wvO+7sQGxDnxZyxTH5Ps9Y 2020-04-19 21:02:35 217.81.81.31 9002 9031 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=720 +p reject 1-65535 +r csailmitexit pTxG9bFX3YM2bUWo6ZokSTShTEY hIxOqLMkxb/y0JWc7QE36x5VzC8 2020-04-20 08:03:53 128.31.0.13 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11600 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r Unnamed pUBoQS3DOTldQJHnLUAlUzlgaiM XkXDLt01bDisZoc2RheF1dolQys 2020-04-20 03:49:43 129.232.134.119 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=334 +p reject 1-65535 +r alittlehelper pUJD9jbk/LL/WjIRLxJvvznQvWg m5LqTNsDpc8jAKNA3Az6KyBvKus 2020-04-20 01:28:30 84.143.185.95 443 80 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=56 +p reject 1-65535 +r CheetoGottaGo pVDV+oCBEBu0zKF9vNXWq6u+a9A jGAfYr6exy/YaTja078zgNRStxM 2020-04-19 23:45:42 71.127.173.98 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5350 +p reject 1-65535 +r anontele pVNWGoUb0Rh1C0lq3CsIgZ3RkdU 4TZZBeL3Qn93S2gNSrr8Njmwrdc 2020-04-20 10:54:31 98.128.172.177 1 2 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2320 +p reject 1-65535 +r GENESISPENGUIN pV5ROig98s2J/B3tOWsK9PyPJfQ VOKRAW4Mvea8LoLqpcl+zFzqCMI 2020-04-19 19:28:01 88.198.41.140 9001 9030 +a [2a01:4f8:a0:11c2::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82100 +p reject 1-65535 +r hacktheplanet pWf/XccqIaa3EgYJ5R52xJUX70E I0C3t6IqC+m2+zMfG7AJDzOkeYM 2020-04-20 02:05:01 62.133.157.139 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1840 +p reject 1-65535 +r Unnamed pWoBIKIVV4MgANXGj8194I6Co7A GF1/IPTz8ZuAtZqU2OAKESwXQ/8 2020-04-20 07:15:10 37.191.198.135 38443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r Unnamed pYZuNQXpPS0L85HR+iiTFSeYmCc 4l6ZDRyedqEqxc8aTI29mPmEMKA 2020-04-20 05:21:44 99.176.15.169 8090 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=180 +p reject 1-65535 +r lptr02ORFzF4Zq pZFlfMf+zHle1D/j7yIpDlM7uy0 BOLR3O22Pec1HYAbiunZTRXOU5Q 2020-04-20 07:11:22 173.212.242.110 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120 +p reject 1-65535 +r drizzle pZeshm5AyrWmd1mt5JQhkumd5oQ nX61vejveVPuBCNKkMaDU50sziY 2020-04-20 07:20:06 46.166.151.217 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57300 +p reject 1-65535 +r AutonomyCube pa9dGQRVDdJ7HFCHLZSWxz2Rau4 0WLIIC2xkuthU+0ToqtFLRzocYc 2020-04-20 11:37:34 213.215.202.234 8051 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r demonteal pbFdWQwgdEa/tvc5/KZ96MF29DE jEYO7F73xOWkX9wOxGM9IdNAvBM 2020-04-20 03:42:25 138.59.18.110 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8443,8888,9418,9999,11371,19294,19638,64738 +r MARS pbaC6EZhUIg2Kjsr0Rw1PIR3hlk I9DYA2TssMNw/NIkE7W6+59Dnkc 2020-04-20 00:59:33 31.13.195.130 443 80 +s BadExit Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9160 +p accept 20-23,43,53,80-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Ceedfoptoa pbk/gxMTIHHh5lTrzL/p8fBz2Y8 7Y2AcaWzGIoKLXp5eFAW75htJ6o 2020-04-20 10:47:42 95.217.42.94 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=840 +p reject 1-65535 +r snap277 pe/fh9AIWzf6z0e2ndxwd1Cvcsg Re9lt9jAkuqQQEfoExDV8xWnyIk 2020-04-20 08:02:32 176.154.225.16 36195 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=672 +p reject 1-65535 +r weirdoo pfn5RWA4iIMi4c6WWmZAs+C7FMM 9IbXPWf5i7tzqTHQn/acbTfoflk 2020-04-20 10:56:58 80.71.138.195 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=290 +p reject 1-65535 +r plan9rain pgQIbq6Dh3T4CYEZJaIj3P27HRc YBvZlYaBaNjvYgxVrxPUFNDfkIg 2020-04-20 11:53:12 5.9.56.12 4433 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=840 +p reject 1-65535 +r dc6jgk2 pgaX/zg+7uLohQXdTjBcB78yaxE BrY7xyYVUnaL2gBMagsQubd5U00 2020-04-20 05:43:20 80.147.33.157 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1340 +p reject 1-65535 +r adlon pgr6b/su645KTFMfump4r1hqrLc GiCnKfssBIGOj3ORCVu5grBptaU 2020-04-20 10:41:29 185.73.240.205 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=380 +p reject 1-65535 +r Elias phtWpQ0T3CnbsjxqAz+j8MV0IM8 Z5Qb7oQYuIk/KT8whx6rRGfOx8w 2020-04-20 09:14:26 144.217.80.80 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r TheCube pid6zFXbCkiPYVuWckJ+DdG0+Hw 1Ykec+YmLj/s5ocnHPbI3cxuSMM 2020-04-20 11:47:08 62.78.245.129 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7800 +p reject 1-65535 +r Unnamed pkvW2jPYcPOAfFd13qI/buMiibM oFY/hV/+LozCA+rLsEzEuUxlFGc 2020-04-20 07:24:05 95.216.154.139 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6000 +p reject 1-65535 +r Unnamed pk71yF9Kr3HcXRwqzOfY76r1mYg ZJxwjeknloabiYu87gn6KFDST3k 2020-04-19 19:46:14 5.196.68.213 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15 +p reject 1-65535 +r Unnamed plBPGp+va2FEB+R55GIn+g0SJO8 UzNqu3mi3YXwENzcln5oMf2dyBk 2020-04-20 08:55:00 129.232.133.43 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=420 +p reject 1-65535 +r netcup plJ+K3oy0CuaVHT/Enm4PGKoeBQ 9Gxt8a5LhRvRIuE92kktrg6VyFA 2020-04-19 22:04:23 37.221.196.31 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r pym pl4VI/MTQFu2DkqhNqae+lBMT2A PUljqRBt8GFebKMPNk0sqM/dW7Y 2020-04-20 11:24:50 62.113.216.177 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9050 +p reject 1-65535 +r genericRelayName pmRXfDlGNMe+tgQAYhRDBc5Hhvw vgshLSTwnCtSZwZumrfnbt8ifM8 2020-04-20 00:03:04 89.176.78.62 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4160 +p reject 1-65535 +r alxu2 pm5Xgv5gl9KCQERGZ3b+kSrv2Fs RVPVLVlWwrm35Gs2oHe98Y/h/6g 2020-04-20 04:20:34 209.141.54.168 443 24384 +a [2605:6400:20:274::1]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4210 +p reject 1-65535 +r Unnamed pnD+5ef3cibWw8bU5BKVQbd7Ujo Fu6e/Fnb98nmxsMxLTu6mnemkFE 2020-04-20 06:12:08 81.19.210.148 46300 30530 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=153 +p reject 1-65535 +r cobrakai pnjaYKbHy3RlU0MNhK9FJy7N2pU T4sKjnYKj0euX5bIWw9Mz5KCAeI 2020-04-19 20:20:28 45.79.96.232 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4700 +p reject 1-65535 +r Unnamed pn+YyoxJJ/7ToFKqL3QA0Id8aYU kULfk03V4Mv9wJK94t8D1CgQBi8 2020-04-19 20:29:46 72.188.224.179 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18 +p reject 1-65535 +r olabobamanmu poCX/pfTBlsab0znGH11P4uFE/U I5jJJjUWzMBBT561TJdiVAoEFNk 2020-04-19 19:39:19 212.47.233.86 9101 9130 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3530 +p reject 1-65535 +r mjay42 pocTjCzzg3Tlcn3Uk0t8sPyLhtc 83ugSmxwYiggPGV1sd0+qvMktmw 2020-04-20 04:05:45 149.224.141.48 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=428 +p reject 1-65535 +r PiratenparteiH3rmi ppDGqoECwCfSl680Ab/haRjM96Y 6vrYduOQp3dDexySK7DiwKmOhwU 2020-04-20 10:52:48 78.35.144.81 23 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3700 +p reject 1-65535 +r Truie ppIhp+x0mNL4ig+3lSYQE/o2yq4 9ngxv6W/xgRFEgkibtiJ/l/tyWY 2020-04-20 06:34:27 149.56.185.56 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r FrankWoiTor ppVrKcW5mXB/CvAGcy8vp7PValo vKYwfVGF4jq21F6Pw0pdoqp4iF4 2020-04-19 19:31:29 185.243.9.128 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r Unnamed ppoKu08BNapMOLGXj+UprQQH2t8 vRet6kFhCkJjZC4SOw9c26VqoO8 2020-04-20 10:30:17 46.101.215.42 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14300 +p reject 1-65535 +r dc6jgk6 pqqUtAB6DikZstqOzyz6PKF2GhM frWZ5KoyiMqvfvaE8zTCvzcjJZY 2020-04-20 05:45:51 62.141.48.175 443 9030 +a [2001:1b60:2:32:4104:104:0:1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3540 +p reject 1-65535 +r irish pqr66ru6zHTOsVvpzmnzs6QIeEE q9StKthp8spvmvK+3Z+rZwg3dOc 2020-04-20 02:19:24 185.12.45.115 9090 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r apx2 prBSHEwfuR+2Y5iq1SOtdz6C534 EzQ0WiJ1/CN+XLyayNhCAPPXboA 2020-04-20 00:53:27 185.107.47.171 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=83500 +p reject 22,25,194,465,587,994,6657,6660-6670,6697,7000-7005,7070,8000-8004,9000-9001,9998-9999 +r CretinDesAlpes pseCG+AMmpURgSlu4S61rYt8+hc i/oyclY7WC6ASagBQI8VUIerLFY 2020-04-20 01:48:20 2.7.3.143 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7200 +p reject 1-65535 +r leek psxXfzWs/8ruBu05Mh69VlHuyOU QOF5fJztZgefb90lu9SrkP8Jnvk 2020-04-19 22:04:48 205.185.126.56 9001 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4500 +p accept 20-23,43,53,79-81,88,443,464-465,543-544,563,587,706,749,873,902-904,981,989-992,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5190,5222-5223,5900,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r googlerelay ptSwK2dlKPxrv7hE5hdp3T/3xC4 /QA0lwJtVU1QzDTm95NoQP6+oE0 2020-04-19 21:57:51 34.66.251.97 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6180 +p reject 1-65535 +r HRMB puD5UMrHSvhnyiGXYGlSnW1NPjA AiWDbzk9irG7lSPCJ4xzVJqZmJM 2020-04-20 09:05:49 144.76.78.60 9001 9030 +a [2a01:4f8:192:14::60]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44200 +p reject 1-65535 +r AutonomousAction pvWAENWp/TI6sJKEYsavb8T/hyQ ibcIVL8thmJK1rZPClJVQt2yWTw 2020-04-20 01:22:01 172.104.227.182 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=95 +p reject 1-65535 +r Torroo pwbefb/RALv43jhyjLwqVSotH2A dsmOGbeMaLUw4rIBtF/CUSmByRM 2020-04-19 22:06:30 54.153.249.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r rortor4 pxQ808VI62PZhkfVkqeuPqArFCs kFYZA4y8KbibZNgeGPuo69IJ2sk 2020-04-20 12:31:57 172.104.157.65 9001 9030 +a [2a01:7e01::f03c:91ff:fea3:cb26]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5350 +p reject 1-65535 +r SEXYonion pzBjNBOvRFhfAj4sIUHDqrS0wh0 zrFui26T4Wke1cOwgF6FvL9TNa0 2020-04-20 04:21:24 51.89.149.202 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r hviv125 pzeKIVSDxq2ZaK1QXaFFT34pR5c +23e0JK89Et0Jbiz4lvhVmST6SM 2020-04-20 09:40:36 192.42.116.25 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26200 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Unnamed pz5LahUaX2IoE/pyd2PzRqPtwXM PeeaPcQu23JVpRiiIQsPR660X64 2020-04-20 01:47:45 60.62.21.29 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r TorOrDie4privacyNET p1HYvuIiVkt7plf3S2ZYg2/xruo YbCS6d6Zvh3lOwmtBGxhnF71saA 2020-04-20 00:44:50 93.186.202.32 9001 9030 +a [2001:4ba0:ffff:11a::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33100 +p reject 1-65535 +r advisory p1RT6OXRDQTL3MJnz2NzdvXWoPs R7iGSDI7H85/CI/gClfOxfpfx1I 2020-04-20 00:34:12 52.59.187.180 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=741 +p reject 1-65535 +r Rishi p2ruLDpyTMHNBeGwbJSKwlEvTzM SN1WmvdiiJCuU4r0gBM8xBZ+wQ8 2020-04-20 00:51:31 185.13.37.252 9001 9030 +a [2a03:75c0:20:8f6f::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7560 +p reject 1-65535 +r 75df766f460b p3Ko2ReM6SQsX92tERfeBLDRbYU +NV/AN8Psx525E8kfTtwi3Dl8AI 2020-04-20 08:13:25 51.81.253.216 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nodvrelay19 p333KaUaUdOQyexou1+GB99Sx90 sgJDYNjGLT2MGh0Qgfc/rHt2Hl8 2020-04-20 01:16:06 45.62.246.174 9001 9000 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3100 +p reject 1-65535 +r doboz p38WprMTHq211R3i+NCRT3Aq01c TE0pJWCDDzlfyoi/o0rQSUbeoWs 2020-04-19 22:02:25 92.35.162.160 46111 46220 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p reject 1-65535 +r justanexit p4sKWuLMdqGsFBQUo+PZnvyOKqQ 1mK9U1TpfMHXEzGf4Jdho7kTYnM 2020-04-19 23:31:53 149.56.3.232 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Beppo p5n99f8T0fZV0VOmuoaezUP11ws UGPOFGxLeOn1zkMW9CfJJLzYF78 2020-04-20 08:54:28 93.202.92.52 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=300 +p reject 1-65535 +r snap277 p5vlR2TgtEs2JTHAjxbJ9Ftwkhc 1a4MCH+3GEf9QQno1kIgsHD1f4E 2020-04-20 04:42:43 93.16.51.43 38381 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r tor1worrus p5+UEX1z1K+kvONAo8tuNFyBdZQ JVdwcrvTWnWq9UlY8xd2BQEY1yA 2020-04-20 05:27:29 81.169.232.121 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11800 +p reject 1-65535 +r Odin p6vSFHkG0WIqVtrZqMwqfoTe+Ok EYcXv1mk4ql0rtAZekj0ehENeDE 2020-04-19 23:35:22 217.248.74.202 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3050 +p reject 1-65535 +r SuspectMain p7IEZF2sev21BG7wATxb3CzwlFY Qcsb2vh8rzP/n3X35aGfq2TBcWI 2020-04-20 00:37:19 86.15.164.215 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1640 +p reject 1-65535 +r rofltor05 p8W0DsD7UXXohAdd3IdTHTU/Z5w pA8QJeWtuX/5UeSLtZCjq3wnCec 2020-04-20 10:00:03 178.63.19.126 9001 9030 +a [2a00:1908:ffff:fffe:4c60:4fff:fef5:5cec]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26200 +p reject 1-65535 +r CalyxInstitute13 p8frKg37Lj//wSt3VnB0M91VD54 lFbKbbndZbCdHK0fNRKO8TL4bOg 2020-04-20 00:37:14 162.247.74.200 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Ted p9F1l6Z/CtZO4fOkFKCtygCAF0c hhskigse1MFdDRl5OLVHInNggnE 2020-04-19 21:58:39 185.217.0.85 80 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6160 +p reject 1-65535 +r ObliqueAsymptote p9NOHkpJhRY2DwmBhO7fgTLGkNU 1r1wJ1gXN9xnZYNtSTm6arvF3sI 2020-04-19 22:25:47 96.70.31.157 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=430 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tomforbessrelay p+ZkD+yFybBPt3ilHLmZ41opUx4 e63j+ohCxcuRnLdeIhQ/lHZIpv8 2020-04-20 02:32:21 195.201.21.75 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14500 +p reject 1-65535 +r ninostor p/cBRS+hsR46r1RzAHPGF/hIkf0 1ghqFTydyXeSXDGxwbsM2extgA8 2020-04-20 05:00:20 77.140.209.192 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=118 +p reject 1-65535 +r tor4ever14 p/fKhK2DoUf9jklHPFUTBuuhBPI 4IMU9qOJU86q0Umb7Ds10YjtDA8 2020-04-20 10:34:33 45.62.228.30 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1110 +p reject 1-65535 +r WooptThereItIs p/gKt+BMAATo3goAN/jtVCkkWL8 inEH1kiNLX0r5x84EdHEgVJQivM 2020-04-20 03:12:51 149.154.157.80 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=833 +p reject 1-65535 +r AgentSmith qAZmVtFjkQxIqBhOZjwSRBjqp6g JdmFTAm0Ok/9O3vxfbrJveI9wIQ 2020-04-19 22:29:57 139.59.56.19 11443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=188 +p reject 1-65535 +r huebing qBD/Hlx5g9Q7NRdQZHknS12lrHM b/YOp1TJzbEpcZfUuL8DR6cnDOA 2020-04-20 01:12:38 185.227.82.63 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8790 +p reject 1-65535 +r jbrelay0 qCxOejPcQT7GMKsGqubz3NqX8UA WbqL+fSG5GXtUZ0/4WzaF62GHVI 2020-04-20 10:26:01 84.135.107.141 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r jdcdp qDW+aq/1px2GmXN1iFMP3hQbIJ4 ejUaOr1OSbh69DYY2F843EyprUk 2020-04-19 22:16:39 185.140.64.214 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7330 +p reject 1-65535 +r snap277 qDfX4oSBOWiIGvGwI3fUDEkYHV4 N4k4VE7frZA9cuOArFD3Dq5mQPk 2020-04-20 04:53:53 24.138.15.61 43175 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=573 +p reject 1-65535 +r TorStar qDgpa58BqeJIe8OiXV5fL7ipefo YoHjZ61VDDWwKAjTST9U9wlRRDI 2020-04-19 23:52:04 151.66.105.112 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=348 +p reject 1-65535 +r extracremig qDlz8SKUOgnmq9gLUyqeRDlaVq8 IAiWwPsxSIg1Jqe3ftWX/gyUstI 2020-04-19 23:52:11 87.154.212.232 25678 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=972 +p reject 1-65535 +r MEGAlv02 qEm3+Q2WZ1XPHnofmWSbsH054f0 u9+BxeM71Q5Y3QwJ1tOOjZWaZhU 2020-04-20 09:14:14 195.123.208.174 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3520 +p accept 80,110,143 +r glacial qFfajzco3kR1v82G2RNR9eMCs98 WjQ5scMTu5vHlg0ejun7SsyH+XA 2020-04-19 23:40:49 62.112.10.154 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19400 +p reject 1-65535 +r Faraday qGEO3HSaOBij1TJUGbNUg7Tev0U axfvTQiSSmOdvhRcZlUQFKmUq50 2020-04-20 12:08:19 200.56.44.184 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r angeltest19 qG7CT1uLlk9nrHwnzpKEICWYMnQ 1Ha6k5IsEjzPIW6eorgoQOvj7kc 2020-04-20 04:34:38 185.246.152.22 443 9030 +a [2a06:f901:1:100::241]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9600 +p reject 1-65535 +r sparta qH0Z3RqJMnuNuHjcJ5NCZ1J5m1w d9UQjPg08bLcbPxpN5AHgXCg7P8 2020-04-20 05:51:19 185.100.87.251 9000 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18400 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r thisismyrelay9139 qICNGuu31hg8QlN809mnQ52IPhY h8hMFRMhN9sKOKxD5fkwhWJhHbQ 2020-04-19 23:38:44 97.70.176.61 9002 9032 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1480 +p reject 1-65535 +r iridium qKRuX/e5KDA7zxWBEs9+jtuyeME 46K59mkm84fSY/DH2bJFmfgkuNY 2020-04-20 12:31:13 51.15.247.113 9001 0 +a [2001:bc8:47c0:1628::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r 78bd4d165160 qLK8MMcqmM8Sh7OjqIMCsfZon5o zXKEAqwHFV98TWqFqRv4A3Kuvfw 2020-04-20 08:10:39 51.81.254.12 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r HappyJap qL/h5lxtw8elD436C/V/ChGBRKU uD8IzT17IBNIk28vHYRHGMeEpmI 2020-04-20 02:33:53 76.21.156.2 9001 9030 +a [2601:14d:4103:1370:ba27:ebff:fef0:838f]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r ds238928942 qMBzseNRSoDHYV/on/tWXyg+Bt8 LNE7C6Ye2Dvb3YrY9lYfupghero 2020-04-20 10:57:46 185.165.171.14 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1 +p reject 1-65535 +r Death qMGu1DQ8LKUUycoSVIj9J2Q1Pxs zIqHFqGdTLzjAfWf3wDjX0e/TgE 2020-04-20 11:21:48 82.158.100.67 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9140 +p reject 1-65535 +r Zimmer12020 qMKYgaOW3QsA/Ex5TA72hVT4ymg RTC4EZycXmn5lsLxz3wnfnmsB2g 2020-04-20 10:28:11 92.63.104.84 9001 80 +a [2a01:230:2::dfb]:9001 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1560 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r 0x616e6f6e qNRLgy8yZ6v8c/VAxsTPAin9frM cuMgUxIrTADYlHvMBKfJsBl1dYI 2020-04-20 11:50:26 104.244.72.164 4443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20900 +p reject 1-65535 +r ULayerRadack qNaO1hZzsxTMjNMcInWr8eBzh8w LrICn89efVe+A8ftLhvuIvrsTN4 2020-04-20 07:13:42 107.152.35.64 443 80 +a [2607:9000:0:28::e7f6:c57e]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7480 +p reject 1-65535 +r zlangtor1 qNvY+GOs6BbBzOsR8fhxBW0v0LM D3KDKvDlouRAPdNqXjsx2GCeXqs 2020-04-19 19:49:55 51.15.56.122 443 80 +a [2001:bc8:4700:2500::1587]:443 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r whitepearl qOouuymwukRy8moEo0KWf/BswQQ 5d5vq/3L4E7ZDEpArsMsOG4ZiKU 2020-04-19 19:28:27 87.118.83.3 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r nonanet06 qPzbjBLNukl4hkYTpws5bcrUztU qkLu1CmY/3QAspXoYhbXTwQAbrw 2020-04-19 21:50:33 198.251.89.157 443 80 +a [2605:6400:30:f717::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7850 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ExcellentRelay qP7HXHXCSZdGexVgPb3kPRCN7nU 3eX5SIdwKsfgUczazGG/vRaXVEg 2020-04-20 02:51:07 62.171.135.12 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r air123 qQ0JAEh10daOplRoLF19uvp7lm8 1q1Rg25b5DMce7s4ay0sMEJPnFQ 2020-04-20 12:12:38 84.156.168.187 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1040 +p reject 1-65535 +r ShirinEbadi qSaXD+Gu+cbY1L9X7WuI8/jGZBU /vgSWICwF9zJwV7sVHHZT9Xs7iM 2020-04-19 23:17:02 51.89.23.74 444 81 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15100 +p accept 20-21,23,43,53,80-81,88,220,389,443 +r UenoStation55 qTL1b2nSSpagy8TzKSKmLe/SjHc aMpCzsuN543lSjzdTXYa+HTVrFg 2020-04-20 05:58:59 51.89.143.155 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p reject 1-65535 +r niij03 qUBqAG1ue12jDyxtTkKjOLXjQLI kzSj3KPdUybtPH7a35Krd8+BUds 2020-04-19 21:10:43 163.172.149.122 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9770 +p reject 1-65535 +r 3735928559 qW2mPkQV53b7/M89pxVMgEU0tuc fxvxDQe7EV/zKuLLl2aBntgMG/E 2020-04-19 21:17:43 38.39.192.78 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14500 +p reject 1-65535 +r NerdyBloke qW8Qgo9dO6QqyJJ/A23r2ZTvBL8 YNzUXfHgcTyLQUPB20fz8NW2wLY 2020-04-19 21:43:45 212.159.177.198 9001 9030 +a [2001:470:1f08:d10::2]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80 +p reject 1-65535 +r malt qYYMQu9TI3noRgh4AmRrXUvLF74 ljXGu2JqEVYHnncs+evX3yVv7Xk 2020-04-20 02:19:53 185.12.45.118 9090 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r 2Contribute qYrdlyBF08yu5lx4jD8XW66j4yQ CYKeaKaMkpeyHr5dQalMuPX14uw 2020-04-20 09:07:06 80.127.137.14 443 80 +a [2001:980:ea82:1:20c:29ff:fec0:4764]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15400 +p reject 1-65535 +r bolar qY9JL2UxrjoGjdNTlcqfW+jwNVw AmurQ8T46PdzHci6TB7hN8n77dI 2020-04-20 10:02:01 84.213.16.48 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1590 +p reject 1-65535 +r 5fd833a9 qZTvK7JpvrWPE3uPD+4lZ0Wu/1E GmvCNXj9znBk2GFCX4o3297Vjgg 2020-04-20 10:10:41 95.216.51.169 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p reject 1-65535 +r FlashBear qZpQrP9rzuArR+P67fiVNYeoXv4 ypxheu/jv+OEqhxLpvzO4QboLoU 2020-04-19 20:14:32 185.22.174.119 9001 9030 +a [2a00:1838:36:115::8a3d]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3940 +p reject 1-65535 +r buttercup qZsNnl/VvDyPLQBuyR+Mf0DgnLg hbpPziy+B7DR+jJODcIEarCVblA 2020-04-20 05:10:36 46.4.78.148 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=105000 +p reject 1-65535 +r u698id1147 qaQhPqPXB4VzaMaD8iCMg7h1XYo sYGZpB3FYhAkc0PiseSMUvr0/L8 2020-04-19 19:41:26 91.233.116.51 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2250 +p reject 1-65535 +r BWV639 qa4gooeyFe4EnAA3PJUvQ/CAvMk VBVk6CCwVMxURq0ROp4+21gjGfk 2020-04-20 02:00:05 173.230.137.91 9001 0 +a [2600:3c02::f03c:91ff:fedf:a49f]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2050 +p reject 1-65535 +r Assange011ruX qbKOTU+2omtbbT7e0mVdg2u9Tlc 2L7jGwG1lzftWt5lJBKlf//w9oM 2020-04-20 06:34:49 45.140.170.187 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p accept 53,80,443 +r Raineelay999 qbOuxghl2kgNe5gxv628B6LK4Z0 2cvUc071j5uHLWQXcEx8FVFJM9Y 2020-04-20 05:33:19 46.5.113.113 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1310 +p reject 1-65535 +r alxu3 qb6i4GmdH2BSHIoRZzQJRaQZ0QI n9GovtInJxn+kvNJxdfEywh/Z3M 2020-04-20 04:16:00 104.244.72.188 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49400 +p reject 1-65535 +r TaffyNao qdbZio9f9DeSkasULu72NP7BlBY zjKJbqlQKoAmckRWHtvT62tXxos 2020-04-20 05:52:34 140.238.70.193 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1740 +p reject 1-65535 +r theherosanctum qdwEpclu5ZhnU6FeOEu4Z57o8xk mI5y2YugD06QEyGGERt9FaItvqQ 2020-04-19 23:15:11 131.255.4.48 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=340 +p reject 1-65535 +r snap277 qenPp8IKHUxnvEtEPXXjulwMYkk Vc662W0TXxnkQJfeLs4TrwH1dQ8 2020-04-20 07:08:12 91.174.241.162 40445 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3770 +p reject 1-65535 +r herlitzka qfUTWuGMfiXHx5EXzYx2Gb/rhe0 UpluGWKk1Sbsy9reXkf2cFasZi0 2020-04-20 02:39:11 85.159.237.210 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 20-21,23,43,53,79,88,110,143,194,220,389,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,64738 +r foucault qfVFrgO3Ma0y+ak9aY6iDE+m0Nk EZFtupVvUez4gZ3lickIkyZ47lU 2020-04-20 09:26:39 51.15.113.79 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7470 +p reject 1-65535 +r damita qfcYVJnFeE41tcJXRO1Kt1Q3zl0 CS/KJV7oMzR05tnNd+GRWstCLlI 2020-04-20 09:38:16 91.229.76.124 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5900 +p reject 1-65535 +r Unnamed qhK0WOuqwPLrCo0YtT8XX+s70/U 4ns1rcZ75d/rV9zrmnMDHpre6Bc 2020-04-19 21:41:39 136.243.46.31 10519 23551 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1070 +p reject 1-65535 +r Unnamed qhsCbuDIqVjinGfH2Ihf8nVyJp0 6nmUumMCf813fmoajDBUSCJ+8pQ 2020-04-20 07:57:35 212.129.4.84 9999 9998 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=752 +p reject 1-65535 +r AFistfulofOnions qhxym6i4RpMNU1gIIqgfbDhDLAA u07WWeFb/dzoRor0jXOmtj2uymA 2020-04-20 07:04:16 178.128.249.136 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2800 +p reject 1-65535 +r dontstopmenow qia5e2ynV79jMo7pZwUSBgnPSq0 kjaFfpvCtMc9APEGUGA/5MW7WRw 2020-04-20 01:59:33 173.212.200.241 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p reject 1-65535 +r armAtor qjQhlHXkEoIJXdPAiACe5WKvFOU egJWXUSX5/3oBuCpWVKV6BciMII 2020-04-20 00:02:43 51.158.119.98 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r rixlv qjWdLVnEwL/7n+pszeMLnm7rvos tXltvUJDZjRUDoYkH0I8xioctmI 2020-04-20 08:40:45 195.123.212.75 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=458 +p accept 43,53,79-81,443,531,873,981,8008,8080-8082,8888 +r roTor qmFjFbqXcp6kfa2HGPpZJpxyKec RaC0Y0Yv2CXCIoRRYgHGpZ485yo 2020-04-20 01:54:24 77.109.112.149 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r king qmgMc8tYn4tKkp/2+ZzUnoJ04fc 6AfVp3POkcse+MqImZTpFg0PoVU 2020-04-20 04:45:34 51.68.201.123 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nonanet04 qnU/sageGuSD8Z9EZJDAAJQ2eLs jD3NRY89c+gNiJUVkh9tkQleCao 2020-04-19 23:41:54 198.251.80.214 443 80 +a [2605:6400:20:13ef::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Bertie qna8KaA3zs6ArOZEXlF5MEmaCfI kEGaz7VuQv7BOS2bJvNB83JWx2k 2020-04-20 08:41:28 193.148.68.142 5688 2035 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r randoantchain10 qnuVMUlLLTq5V1DTLRr6i3Hzgtk zyQ9ReheoDGiE5ibR9p9XAIJshg 2020-04-19 23:32:05 68.183.88.223 9001 9030 +a [2400:6180:100:d0::8e6:f001]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=710 +p reject 1-65535 +r JustSomeRelay qn1WnFL6RNeSG7gRS1AEToDRefg kmxD+3kq80jHPOmBMvqhUoOwXCM 2020-04-19 19:54:44 73.90.20.99 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 1-65535 +r snap277 qn7R2bSt/kpGtL964hP8gWI7d6o 1DPnGBpiuJm6IfW/lQbAkse2d2A 2020-04-20 05:13:41 94.68.19.180 40165 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r NameInTheConfig qn8nyoljFB5XkxeW3C2/o6r9UMY gzLJliHSNNa0FRJ9Ymswy7p1ECQ 2020-04-20 00:47:29 110.141.238.136 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62 +p reject 1-65535 +r 148a25f0fe29 qotyN7TSx27UrySztHs3WBKqzIM SnfkU6p66wyJ2iWBfShFVGpo3Ds 2020-04-20 03:48:25 51.15.219.225 80 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33700 +p reject 1-65535 +r MyCoolNick qpiuS9tuA7qkgBHK6Cjs7FCwKcg dKnxhNXmY04b/8pIBwMoylHGxRE 2020-04-20 06:00:27 149.56.98.216 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5080 +p reject 1-65535 +r bebop qqAwRLQq031cVZLWYEptG3L0s74 8GOTT7h+Akvvy3Sfhy1k0kxfaRo 2020-04-19 21:30:14 91.204.45.142 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p reject 1-65535 +r Nozel qqH71qJ5Tj5BFtVYpdNM5g0tmME xAO/ZXqP33FDDzLIYdJSK8Cr/lk 2020-04-19 23:53:11 163.172.49.92 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=15100 +p reject 1-65535 +r BlackHall qsauSo7RZMNlfWTj75gO67S7yKE dBlvYsd+cnglpTs7MHLNF96N818 2020-04-20 09:25:37 185.103.110.144 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17200 +p reject 1-65535 +r Ubuntu64tor qvAK4XCnvBhLpwoQzzWXAIFuU9A Y5sSXrCFzmSYA6v3QWushCtawZg 2020-04-20 04:00:39 87.101.55.54 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1850 +p reject 1-65535 +r PorchPirate2 qvl7N6toXSkkGHPaf9ZiDNThAd0 GAYkLwicmXp1uge+TFSC9csIFhY 2020-04-20 12:30:28 178.175.138.59 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31000 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r jceaonline qv9KmXVD2w2IH08RY4SFt9Rx/s4 HcfPbaJltCMmLLW6VQ9YSrIyIuM 2020-04-20 10:42:15 51.159.34.131 47168 0 +a [2001:bc8:2ecd:caed:746f:7200:746f:7200]:47168 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21700 +p reject 1-65535 +r onemoretorserver1 qv+mirYSOPkES27Lpi4lJkET64g bmQvkuhCbNW5OgTh6TBTzbgGS7Q 2020-04-20 07:09:29 164.68.106.94 9050 81 +a [2a02:c207:3005:1808::1]:9050 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3670 +p reject 1-65535 +r yaudepoele qwzBlRdHbmELhv95a3A2Q7/iHok zbuiVciTnx6/M8RQv9Els5dPDpU 2020-04-20 08:47:32 5.51.106.108 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1800 +p reject 1-65535 +r Unnamed qxoNzFvfKw28zu9KgyXX6W43+Hg wxBu1n2Ibe28AI8ucpaDreh3my8 2020-04-20 11:12:48 51.89.180.225 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21200 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed qyVHiwKOkQDH2LkovnkJgQj6Czs WutLwLuKnGgqrv9roa7L6GA1W5c 2020-04-20 11:42:28 52.175.243.180 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2100 +p reject 1-65535 +r luxurywood qzIn20cLF4g9JNgw6oTr+9x9WBU uWS6cLOTYVTAnpo7mLMx5cXqct4 2020-04-19 22:56:26 206.192.252.123 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=4600 +p reject 1-65535 +r hviv118 q0dh4jr1EegwbpXnj36C93suSH8 /LhthUklWYh1PC1au1maaFjh8IY 2020-04-20 11:41:18 192.42.116.18 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r Yintor q0nziep8KgVOkjvKLm6Yw17c1tU YTRLGRTqNQLOf4Qc+k2sB03JIl4 2020-04-20 12:03:46 62.195.44.72 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68 +p reject 1-65535 +r neuronMail q2aQqvRfU/fzvIQuI3efJMk0bfk RfF9wTmK/56SaACvc3DAdu57XQY 2020-04-19 22:01:29 45.79.76.174 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=55 +p reject 1-65535 +r UseMoaBandwidth2 q2h5iPJg3p7cOzbGYofeJmDtHOA WoGtZC/3DrE3SBZ44Yc5IPR39fQ 2020-04-20 09:51:51 163.172.60.25 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27300 +p reject 1-65535 +r VccineEffort2 q3LBc4b0fLrYe/3BZUQuPK0+WbA d539BpmVUBTUyy4lBSYo0Gg2GQo 2020-04-20 09:56:06 47.56.192.35 9101 9130 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-4 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=250 +p reject 1-65535 +r Unnamed q3OBbl17xSZky7nQBf9Xm6/q/oc gQvZ93GiAdyTKAkdSuUU4OpqYok 2020-04-20 05:25:13 5.39.80.135 443 80 +a [2001:41d0:8:9287::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4650 +p reject 1-65535 +r mindstab q34mw69TaoflCZM1pMvoMuIZQxE Wo9ReXXSLhdBqUUXE+M6WmED4W0 2020-04-20 07:29:31 95.216.193.39 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2460 +p reject 1-65535 +r Unnamed q4CPXiVOK3Hfup3TGTZu3I9H5TE oNpCNB/x5RdzB7b8Q9a2rCbCah8 2020-04-20 10:30:49 91.219.238.113 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2510 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed q5XJmoDKLvm0st9BHr84Zc9dQNQ l+lv6MrtNbe57P/XjxktTosVgKQ 2020-04-20 08:07:45 78.35.58.178 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4320 +p reject 1-65535 +r nodvrelay26 q6I8QifwBqZs7xqcssWMKt+clwE Yyzsy79BokuI02wIs1AAN3qNxnc 2020-04-20 07:16:44 45.62.229.64 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3330 +p reject 1-65535 +r apunkt q6MXlbrSq4CX860P4akg5RjT0/M if3Plc9cEAQSNZc21+4Xdmi/TZw 2020-04-20 07:22:12 185.194.239.220 1234 1235 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2980 +p reject 1-65535 +r TheDudeAbides q66VXQXZBBIwNB1EJnrrPmxdAPY MqitltoPuk2fEBSz4gzqGdqLt/A 2020-04-19 21:29:54 85.10.202.207 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=90000 +p reject 1-65535 +r KienjochRU q7kEGDdD/MlnI1Wry57aKrsR3tI jVKQ5M1whRYe/7aUNlPl2RHcVOg 2020-04-20 10:29:51 193.38.51.238 443 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1660 +p reject 1-65535 +r ULayerManning q8QmiTtkK9oveNfK6ZslESb4n3Q EQFTxCI15P6M3KZU/J1jCszpW44 2020-04-20 04:17:37 107.189.11.159 443 80 +a [2605:6400:30:f8f0:b055:151e:5dcf:7ae4]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p reject 1-65535 +r Unnamed q9R5CTB3Pp8thVocPV1bS134CkY b4fMbc/H5uhTCnIgHhvkJuJ8T6I 2020-04-20 11:40:59 167.114.92.55 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9790 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r balafon q9tmQcd2Xsgaoa4oF9X/KM6y2ek ogapGuLoSbsmLIEADM6zTDVrvdc 2020-04-20 03:03:30 174.4.18.212 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r ADEL q/VUxEyXgl9Gscne4UouK2ICXX4 EPB+4Qh9R5Ixc/x31cJz2YpV6as 2020-04-20 09:10:35 91.219.239.79 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=279 +p reject 1-65535 +r snap277 q/YaaGGOhQHXNV1hNZaMdbu8o6c 4SjYQISFejWlIYGUe+D9YG1usGw 2020-04-20 04:44:58 5.3.222.54 40461 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4100 +p reject 1-65535 +r OdyX q/lAVhqOUoVZdH0iN4R+G9gjzbg SgPm5KOO49QSQaUamEmj6CMNs8w 2020-04-20 01:16:45 178.83.171.83 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r DanaScully rACuuhriqAz0GExDYhV7+RSHuQI U4+y4zGt3odmz2kohobrmB2FST4 2020-04-20 06:10:32 109.238.11.6 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p reject 1-65535 +r snap277 rBQ/V+yjUysJAtWkepTMQ91nV2o 56G9MmzTv1W+5hTPIJo1oiTpKPY 2020-04-20 11:29:09 147.32.119.125 40835 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4150 +p reject 1-65535 +r notsorelay rCJ1gxYHqVzYuTnDuNxGbM9I4rk aRug/m4WdGTFn4m212ah/lhgHKw 2020-04-19 20:59:04 51.15.141.193 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28600 +p reject 1-65535 +r TheEmperorsLight rCSS3V6xhQYw3Re4GDTqWxunRnA E7VTOOPhCekP0R77YjH7zDD34RU 2020-04-20 09:00:23 84.248.192.178 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=51 +p reject 1-65535 +r torcz rCceczBaCdcrkCWii/eO3DM9yFI ziQP0c8YtyKcwd7dh0nkevExI4Y 2020-04-20 08:33:13 213.211.43.139 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29 +p reject 1-65535 +r lattera rCjVc8Fr0MfUKqcJdr82mEoeTeA oZlI40PJzw8eqFvlA6yoZhIWv4Q 2020-04-19 23:02:08 23.129.64.193 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p accept 1-65535 +r schokomilch rCvt0LrHKDjqfm8RP4VsToAYrNs LoCwlhCrioX/5+ZXTSqp2FGQJWY 2020-04-20 00:52:04 176.10.107.180 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23100 +p accept 53,80,443 +r doloop rERxNfBFHlhu02ILMDwDRjeIt50 8xxbeKQj2sRmEJBgTO6a7AdMuRw 2020-04-20 00:04:11 85.17.27.187 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12900 +p reject 1-65535 +r daporkchop rFzs72r2SfKn8EfRAv6bRh2pI04 IhK+cfAS5/sRjXwAQPxdpxhRWCI 2020-04-20 03:51:09 46.234.39.170 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32600 +p reject 1-65535 +r systemli rGAdvbf71TRUBF7cCNrjw4HIz4g PjOaeCd3B1qa3YrpgvEUhBDVKwU 2020-04-19 22:07:20 192.68.11.219 443 80 +a [2001:678:a40:7001::cccc]:9050 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r JustANode rGF4PrNnxVkfz1KrdtGRQVn4fQg s409Seb1msVzIz1AA9lkeTcpip0 2020-04-20 05:25:50 188.213.170.104 995 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1190 +p reject 1-65535 +r Unnamed rGY0frAuTGepvkbZAXbXugKdbhs BOH/3nnkd8IhpQKLBlU7ogmiDR0 2020-04-20 06:37:18 51.79.86.174 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 25 +r torpidsFRonline3 rGb/pKs1pZ679b9McACL8k2Kelw Me/nuiwGlv79l+FH+QmUYpgyPQ4 2020-04-20 08:06:04 195.154.164.243 443 80 +a [2001:bc8:399f:f000::1]:993 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31400 +p reject 1-65535 +r TWCUGRelayNode rGp4uue7yseYx60XRgFHIU+eoM0 qgjS2bCzz9nkepGa3u0ETdBhvLk 2020-04-20 07:59:27 192.99.220.114 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12300 +p reject 1-65535 +r ttnode rGxrzH+XCHf0At7ZoMq+Ui3fgfc KhZqXPRLuhFfVf/ABw7oeHZmCZE 2020-04-19 19:24:03 95.90.116.78 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=250 +p reject 1-65535 +r Unnamed rG6zMpVorLyb0crOhmhBavqm6MM mxYoohDVM6TLGiRoqPIRZmg4www 2020-04-20 04:23:53 37.113.137.158 9001 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r servicenode01 rHF6AbjjwA52F+9lEXpOmcAtx6A 0+6WyUNpQXMN2CbP80B4EQ9DzVQ 2020-04-19 23:54:31 84.209.141.235 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1730 +p accept 1-1024,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,3724,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9339,9418,9999-10000,11000-12000,15000-16000,19294,19638,29000-30000,34000-35000,45000-46000,53000-54000,59000-61000,62000-63000 +r aqualol rHW7DMPlyspaYZcuwpS59can7mE iCi44C0KZynxWKEMc3h6cbCiV2Y 2020-04-19 21:49:53 37.187.21.20 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r mitorip rHz4d7KBv+80cz4ULCpvZHrFfYI T7tguQS04fk7s6r4l/s2PlGiSGM 2020-04-19 22:37:12 83.33.172.92 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3640 +p reject 1-65535 +r privacy rKX6ujEfiy3JekYAla9Pmp6m1wA FDlNgd8hbrIz/Q+++db5RcMfI/8 2020-04-20 10:08:16 81.99.110.156 9001 0 +s Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 +p reject 1-65535 +r toris rK4qcACyvrCHBKqgot3K3WjlimM CMsSSmMDSTgTr/DqXk9nVLhiEqQ 2020-04-20 10:52:08 195.154.241.125 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r Planetclaire62 rLu0Js4dBkGlkL8fwc8FQW/A/28 eUUzuN4+rRlXSviaYHUU+uJsmUc 2020-04-20 06:53:31 91.143.88.4 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r rosalito rLyAkIwWdPX01vjNHqeiRYUeSSI 91tFxXasDDYRRGz0zjCunjZ2968 2020-04-20 08:56:44 109.236.86.82 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=700 +p reject 1-65535 +r snap277 rMSF+uXZ3gpMRbvDh3vyoHvvH7Y 4iuhetN8iLTJ2s2Xvbczdfd5VPw 2020-04-20 12:00:18 70.51.112.116 46808 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=564 +p reject 1-65535 +r smell rMSO/g38RvbUkw7FpxE4iPLqcHo ReyOCZCyfZkww66C1qrxJNaoLSo 2020-04-20 02:03:13 54.38.213.67 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2930 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r kulcosictor rMh0rW1NOsMIy2wERiChWaESMZY dLrw+x9gVM6jSEk4qIaWepwzohw 2020-04-20 01:20:52 193.190.168.53 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1230 +p reject 1-65535 +r citizen17 rMu7xXVDTzpxbvZIgiYYBW8VFGg PXiUOnQXx+H/tAZuCzr8hFEcq9w 2020-04-20 10:38:55 83.97.20.248 9001 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=744 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed rM4zyJUjBNEqEToWHe58jo0zBEA La1bd6KVlZSIJ/7KwfzTgS3AndU 2020-04-20 02:36:34 142.44.245.165 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=558 +p reject 1-65535 +r somerandomname rNm1obYaVnaZlYLKuan8ulTULkE 0tsi8x+u8H50xobvmG3Jj9/xlSk 2020-04-19 22:15:25 145.239.76.207 9001 9030 +a [2001:41d0:302:2200::396a]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5770 +p reject 1-65535 +r kramse rN2ehaBbEnugEEZsE8jEchLoo48 e/bXDAWlsePiXaITnkBcCsfLiyg 2020-04-20 07:47:01 185.129.62.62 9001 9030 +a [2a06:d380:0:3700::62]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11600 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r GibberfishInc rN3DNCgIDZBshjV2UdEtxJxGD0s PBzccoL2hs+qM9gE9B7aNdIPiM8 2020-04-20 11:50:18 51.15.49.134 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24100 +p accept 80,443,5222 +r StoneCat rOKex3AL0RLetCuTTl5ENHbNV3w ooOuPeSz+f5h8DOQBCR+ebOOd0s 2020-04-20 08:54:15 195.201.26.175 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49500 +p reject 1-65535 +r Unnamed rO4NADv9pYwcqcgEvLZcseLiL2Y F76CaHGj7McwBbxrNlk7Z3w3q2Y 2020-04-19 18:56:13 52.177.13.101 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4290 +p reject 1-65535 +r SwedishNSA rPFldUYBBZ7S5HL4k60PpMrxFC0 uZx9SJFSufzU3xhcjJcJNJh45pg 2020-04-20 11:35:22 78.69.250.241 9001 9030 +a [2001:2002:4e45:faf1::11]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19100 +p reject 1-65535 +r LasVegasNV1 rPONKnmkrkemzNgBHrtym/Zkgqs Q2EmIEQ8dekxdLpW/TCYUHDMRwA 2020-04-19 22:58:20 104.244.77.199 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p accept 23,43,53,79-81,88,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r toolazyforaname rPcUIq9BdLjxJ1G832sTvSLY4B8 AQnSJqNumElzlJ1LEmi3dbtsaho 2020-04-20 02:10:40 89.247.1.21 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7070 +p reject 1-65535 +r laukur3000 rPf9W3NoG8AbvoF2xj5GdbJ0ER0 8GwBFwHzl8CEUHhkWVx6KbK3JvA 2020-04-20 09:10:13 139.162.63.125 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=422 +p reject 1-65535 +r TorDiversity rPj8bBQDKgRbRPa5hSXuXARy3VA x0hBm/NLApaM2wo1/EwSHrVUtaE 2020-04-19 19:28:51 91.208.184.123 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1990 +p reject 1-65535 +r torbogen rQ/P2D6kiZ2zRzXlmXAVkt6hNpA CyUVw6q6zPLom6GWC0IdrJFQyAs 2020-04-20 03:15:09 37.138.225.163 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17100 +p reject 1-65535 +r niftyguard46 rRNZuddNUm/vP1ivQRBcYjo6jBg eJ713eaPB8eBGfis7cNr7GL9f6k 2020-04-19 22:15:54 185.220.101.165 1165 2165 +a [2a0b:f4c2:1::164]:1165 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53500 +p reject 25 +r idideditheconfig rRR5htAz351GmEYmISqyUQ2WNNE mad5BrasXnH4hmninO5bc/c8ikc 2020-04-20 08:37:06 67.198.37.16 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=180 +p reject 1-65535 +r Unnamed rRfDc4vEpvLpIbjrrmYyPUnfn9g Dzc9R0qTVjX+Gp1/A526me9/xK4 2020-04-20 11:34:56 167.114.92.51 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16800 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r HomersRelay rRh8GdwVVSoQm90zQ7EkJmHfVwI MnurZPaZXiVSMiANTy6Uiexpa3g 2020-04-20 11:39:06 193.179.39.227 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5790 +p reject 1-65535 +r sputnik rRlJDH27JtOmjvyCT2fmmwqW5gE ol7O5N+TY3/HJ7O4GFGZuuFR1Zc 2020-04-20 01:13:37 188.40.128.246 9001 9030 +a [2a01:4f8:221:1ac1:dead:beef:7005:9001]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6340 +p reject 1-65535 +r waltw rR33P1UB9R++T5GuHajmrA+blvc 4SDX8vEUeof0eHoInzRr3nCyjAo 2020-04-19 22:52:19 71.126.173.14 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r nicknametor rR/Erod7L/6zyE8aa3bpsFeq704 Zb8wXGlabFo2vYIQy3VKlc35tzE 2020-04-19 23:10:17 88.198.112.25 9001 9030 +a [2a01:4f8:c0c:53fc::1]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r Schlangenbad rSnD2xZqXLHj+c6dq8yk3MCffNY Gcy3oeZTgX6FG5kk9QfGOGnyPTc 2020-04-20 00:14:08 91.55.5.76 80 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3790 +p reject 1-65535 +r snap277 rTIqOe/Ljp6aHeKcxaFoYQGE0dQ VP9/zlrEuA1CB4t9ol1OsAeGwYk 2020-04-20 10:35:27 63.131.177.85 37847 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=384 +p reject 1-65535 +r king rUF217LnigFFRGEXyCxxdaG9pEA ph1C7Z9zH46+Auh7zFjPjJojrJ4 2020-04-20 04:41:16 51.68.201.122 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r mothballs229 rVX32bEF57kh+xL/EGL+rTdtnsA t++4wpE9Js1zHe9T58FmI4jZ1d8 2020-04-19 23:16:21 67.163.129.15 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98 +p accept 43,80,443,636,706,989-990,993,995,1043,2083,3690,5228,9001,9030,9418,10000,11371,19294,64738 +r Unnamed rWREwCgP+8UeCIsqfGi2P5EXytI kwuf2OyH3VMu2uT8ZH/V+zdCXoc 2020-04-20 02:09:29 134.19.89.160 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=118 +p reject 1-65535 +r isupporttorAy3RDw rXqhrVh7OK5lSME7jfYKyo3JTJw FrkH9tdRThxNEI73jU1PcT2wGBo 2020-04-20 12:15:02 195.154.118.198 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18600 +p reject 1-65535 +r iDiedEditingConfig rXwBHOAoAkn6BQU8GsjncOJCrfg EOGvFLjcBnMe+lqURn5EdRrHSMA 2020-04-20 00:34:11 45.20.67.1 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=818 +p reject 1-65535 +r AITUK rYZz1HA+Addo6ROC236ceVxoPCY wOgXpO3Kohowcy5MS5KQkkdxnL8 2020-04-20 12:23:11 92.111.4.177 9090 9040 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r DigiGesTor1e2 rYbNGklXPVKntvSjV1DxYarYnIg GsCFSgR6TLX7avaLnE8AIYesRoo 2020-04-20 00:17:35 176.10.104.240 8443 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34900 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r humboldt rZcOlSHmQ5Iq84EdqROBg3ld128 vXCyXVgkiPE6FHjtk45F1wHe6so 2020-04-19 20:02:55 185.132.133.32 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 1-65535 +r Novok9 rahDAT7MMol5d4YJ6XJt5SbdtKQ ID1NkeneqfWTQPtEz54ogtUcBko 2020-04-20 03:49:12 89.249.133.165 418 64090 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=440 +p reject 1-65535 +r Digitalcourage3ip2 rbLCZilkPbufj+AJbn0W+UFLT40 HQHSOSixi9jfPgEDeh+/smnRLy4 2020-04-20 13:09:58 31.185.104.20 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r OoliidaiNgah rbOYt/WsLZNqgIB1hgf1zLS3jz4 zXKlF95fylJIerVxdVKQVIVat/E 2020-04-20 04:43:02 163.172.69.166 59001 59030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=860 +p reject 1-65535 +r Assange008fr rbmLJ9ej+1cyBo/SNgKhvLO+nzg 39Y0V/22cW6mikNR3i1IQtZDCJ4 2020-04-19 19:36:59 62.210.105.46 9001 9011 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r fiedlerRelay16 rb2kEtMzganyM2jJEJdVDiRSouw 2B1CHpvlKh+DAWVUdFgHSoYzdOI 2020-04-20 10:09:33 185.233.107.101 9030 0 +a [2a03:4000:24:82a::3]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r Unnamed rcToMtyKPZJC/6ZCSpm9VeuhQDs R6wzBcnHeQMxeaosdec1gLtZr1Y 2020-04-20 04:18:58 188.155.139.163 443 8080 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1970 +p reject 1-65535 +r eL5gMmiPbfmp rceT1TSuDjlHCWixAbMd54BPs8U Wpt2YxEBHmTjAg7aW1k35roP6v4 2020-04-19 18:58:14 147.175.187.143 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2950 +p reject 1-65535 +r fordmaddoxbrown rc3WgMDXJuYpEkTZ8hCDrvJ2P30 HX9urKGLfRy2N2YcxvASw1W/FZg 2020-04-19 23:56:05 54.37.17.8 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r BellecroixTooM rdNaIr931Wr8GM9Y5djiYEuJhc8 7D4bOprRy9gmZODv8GCc7djA6Zg 2020-04-19 19:22:09 82.64.126.152 9001 0 +a [2a01:e0a:1aa:7c20:e269:95ff:fed9:f969]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p reject 1-65535 +r angeltest20 rearK/vXpXgLMh3DO7rM0Nd3yU0 Zx3koZRyDigqdVnCdsc4exLfkIU 2020-04-19 19:56:02 178.17.170.103 443 9030 +a [2a00:1dc0:caff:f1::2ae9]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r snap277 rgOkS+F0Of/dWjUYLOV6ryTGcmw 3DM8dpwmxmNI4rHtNvfcqs5JSw4 2020-04-20 08:56:22 90.107.246.76 36587 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r Geoff rgjRWTUiN4RMYOAVOshXgyCSL7g mWSwDBNQ07MXSUTQr/7QRB3HB94 2020-04-20 08:15:46 178.254.35.99 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8700 +p reject 1-65535 +r amisraelchai rgmueX62WOOrOExrYEbrXi+w8VQ REcO+m3GixeK15BSWuM5KwvI8fs 2020-04-19 21:53:58 92.219.47.98 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r qjwniwqedqjd rhCvFr/NArPMaLCrpB+t3BxyhmE WbwdHM9ONtvpbRhJ+2VVzXBdXBU 2020-04-19 23:46:01 51.158.160.121 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19500 +p reject 1-65535 +r Unnamed rhDVgei+gnX+F/zutRe3HFUwhx4 gv61E++yNnormbnenYb/3YGGj5Q 2020-04-19 19:17:17 192.241.180.163 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=41 +p reject 1-65535 +r Belgarath4TOR2 rhM3BpwWvYQ7Z2cyiRnDNJdwRZ0 qNpP/U9t4fSAbMGOmj5cDerbIcE 2020-04-19 19:54:17 83.253.14.119 9002 55555 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6630 +p reject 1-65535 +r Cheese1 rhf6r48wKlBq8hZ2ZuxiiCgEQD8 11VtmaSm3IpRKT2f/EIBtE19gro 2020-04-20 04:11:15 185.21.216.198 36711 45791 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63000 +p reject 1-65535 +r bigdaddyny3 riNlaO0BUnhQ+g1b77v2xr2kevA /gbmE2VlWV5CwpshrwYZsy8vvo4 2020-04-20 07:01:40 74.111.25.177 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p reject 1-65535 +r SIGINT rirJvO9XOjGyBVVgvZK75O+SI+M zdUyamUpO1Ra2rHb6gkUF5Jchs0 2020-04-20 12:32:26 104.149.128.94 9001 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=870 +p reject 1-65535 +r UWashingtonCSE rjHg+/DT4bOfHdj1W8Bw0Rr1JLA +vOqLGPskl0Eb8gt2qRu3cGS4U4 2020-04-20 05:43:14 128.208.2.233 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9630 +p reject 1-65535 +r Assange005nl rjw7cWW5EuGqXsTxd8qOTafI7Bg WQngktmNLio2Lp02LSDsCXoAEjo 2020-04-19 20:37:38 51.15.0.170 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r 0xdeadbad rk+uLrXcXQeEWPD8vys39dc/CGg 0FgwH3M4NIDoPAKFN8eGK/MysE4 2020-04-19 21:03:49 95.216.198.252 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7070 +p reject 1-65535 +r Doedel21 rmqMGOdJm1hs02JGrEvK/7v5OrI L90ImDTONACOCd4kQnQSR19SQsg 2020-04-20 05:03:11 91.143.88.62 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13600 +p reject 1-65535 +r glxbltrelay rn72uulqgt8uPG4GjZppfYeBTGc FunWRnEE9oMG8ZJZs/mwSBlpvWo 2020-04-19 19:08:17 45.15.16.134 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53 +p reject 1-65535 +r ElectricWizzard roTSmTWhnkngJwIk4hDk8EE0p+g PKmvrnWa5m7PVM/fwRlRcDXCGDo 2020-04-19 22:01:13 188.68.38.54 9001 9030 +a [2a03:4000:13:228::f00]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5690 +p reject 1-65535 +r BorichL rpN3x1zoIug58V90yfNG5o19tIg pBPABW53yojEX447m8nJG9kqZDU 2020-04-20 05:25:39 5.19.184.37 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r Unnamed rpSZwIAoqn3ingthkwSIrEUIgqE w9uOQUs0AJswDf/aP695VUHxVIQ 2020-04-20 00:11:04 40.86.166.197 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1680 +p reject 1-65535 +r Unnamed rpW9o3pbtGhf67fwZknWzpSbUxY sBeCAeyEJPnHC7ap0jynu6cXlPw 2020-04-20 05:16:59 176.31.229.76 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=93800 +p reject 1-65535 +r useallmybantha rptPOxM89Px1vQaF8EfqQlPEmwk +wI1hLpNmUhFwym54990TMe8r50 2020-04-20 08:05:02 108.56.137.15 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21800 +p reject 1-65535 +r Nepal3 rp1zWafDsyxB3r0jyO5G+3Q9RoE m2nC+QfDzLdDoNGNQ7m7yxSum78 2020-04-20 03:16:28 209.141.62.163 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3970 +p accept 20-22,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r troisi rqjDNm4Pot5WDmbDt6RsUJz/mJA 2zDVQPbhlzf9Jga5XSk8fQWF4Eo 2020-04-20 12:22:49 46.21.147.19 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5400 +p reject 1-65535 +r Unnamed rrHApnEgKB6QtPLBPHLYtwPXfao HLoFp8OGRkou3OFgjxevj2MiMEI 2020-04-19 20:11:47 158.69.92.127 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=10300 +p reject 1-65535 +r 72b6c10e00202aa28 rrHnGXqBBObf7p2p05frrUHSN9k 15QLkqpXD9caW1yc6SqW7KGVXx8 2020-04-20 02:52:26 136.144.215.180 443 0 +a [2a01:7c8:d002:267::1]:443 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p reject 1-65535 +r ACAbeehive rsikLej5yxFeJHnXiuHKS8z1T0o ZvRsWz/zjiyKEoMLIIIKXQKUr44 2020-04-20 06:42:55 94.156.77.24 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2710 +p reject 1-65535 +r scaledtornode rs8eeMsRatcQXIix8I2/14PlhLI FNmSgcTkqy/aVGc9uQAKsUB2WXk 2020-04-19 21:06:55 163.172.129.204 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=32200 +p reject 1-65535 +r HyunJin rs8jQT4Sc4OAx7YeCvUSbUffMOM elwhB2R2+6Tvd507T65mZMbBPp4 2020-04-20 12:42:19 223.25.69.206 9002 9031 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=814 +p reject 1-65535 +r TotorBE3 rtBMZdLQ1w2yky19WgulgWkWjME Z1dEtdbOPs7CL6PIu6Zib76l5u8 2020-04-20 09:15:43 137.74.32.27 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r 1torexit rtSmmDZjCjN1hFAGtarQO/o/ltw y/wtegN3NZR9e1CsxFb1FdoQDiQ 2020-04-20 11:22:50 31.131.4.171 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5300 +p reject 1-65535 +r maggo rtaE4UFi/VDZ1Rg9Bix6iVE5H2M eHrwUOKt8Ec9puEdYw2VRu0yqUc 2020-04-19 21:38:11 78.46.253.198 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=759 +p reject 1-65535 +r linss rtrHCBrhS40kHs8P8XooWKtDg9A os0YQjnfHK7oUSMXLMdg/gsLbiA 2020-04-19 21:23:41 45.79.108.130 9001 9030 +a [2600:3c01:e000:131::8000:0]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1000 +p reject 1-65535 +r VSIFsalyut4 rt5AO9C3zhFPWzv10zsVxrkAG8I 3SimGZcEwG5q5MbGLj+rvtXjhL0 2020-04-20 06:01:48 104.218.63.74 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5700 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r phillwtorrelay rvbB+6D8FvSTFji/BlCFuXTT6Q8 4YAVqIFfupZPZ1rQAO6cEpXf28c 2020-04-20 02:12:17 51.77.251.192 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p reject 1-65535 +r niftyguard60 rwIvNRpLbyUUoJ+SRfn/WspylzU Hlbjk5XMGYkvO55spJ1i/BISx4s 2020-04-19 22:16:40 185.220.101.179 1179 2179 +a [2a0b:f4c2:1::179]:1179 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28400 +p reject 25 +r 43d3f507fd4f rxAeGpLGABZvECpcmczO9h0GVkM GszpUqHxG6Eop91BGjcbhZV0Wz4 2020-04-20 08:24:14 51.81.253.198 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r mox134tor rxArKQI1ySdM8ogHhSoZkKg4oYg GOGDA9ga7BNypTrd83Xv14tgdT0 2020-04-20 09:39:55 86.56.188.66 9013 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1120 +p reject 1-65535 +r ballers2 rxwC1r+YJ7uVbwnEVMKLQxse/+c l2v+qOmrzY1FTcMEcGP2fSjafaQ 2020-04-20 07:08:20 104.57.231.26 80 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r duchin rx8VgZrHZtZQiisF2piematRH58 HvCEyo9rrgyvyDVPRmzmIqzsdKw 2020-04-20 08:37:41 91.203.5.165 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1690 +p accept 43,53,79,81,88,110,143,194,220,464-465,543-544,563,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r 1337EliteH4xx0r rx/HBKUkPMDwijNTQ9GKfZ/Ycd4 9VoRCNnCZ9H64HE0PvIO+sUqt/o 2020-04-20 11:56:30 144.91.121.230 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21100 +p reject 1-65535 +r ArturoIT ryx6EdPD938sLBU2CO7JOPpDLbo NctfP5RMz+ecDJzjyYhvbOWXP1c 2020-04-20 01:37:49 83.136.106.153 443 80 +a [2a02:29e0:2:6:1:1:1156:b142]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p accept 5222-5223,6660-6669,6679,6697,8082,8332-8333,9999,11371,50002,64738 +r Access ry0hz/LpEPVdK33OE4LB+1si0OU qlS80cI/6LXC8l4Z28yFIiD2wRU 2020-04-19 23:49:56 173.199.70.185 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18700 +p accept 23,43,53,79,88,110,143,194,220,389,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ramstor1 r0dTWVAKEbSOEVYcsoKVXfeqFdA wWlS4g/ZSdS0dbAeA18nqEprVi0 2020-04-20 05:56:41 95.154.25.167 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2090 +p reject 1-65535 +r DuckYou r0mXc44M/AFM0E+wmmcNLF8eeaQ 7vSW6dTGG08BpJIXLV5umRWqJEY 2020-04-19 19:13:25 185.191.204.254 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1430 +p accept 20-21,43,53,79,88,194,389,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r luk4 r1ERa3L/8ngGGEusffYVZKt+XJ8 T4/hMd2JRruOlV9SeWihTsgeuJQ 2020-04-19 23:08:16 2.229.201.197 6080 6443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3360 +p reject 1-65535 +r astrave r2ZfbUwzey485n2aIwtbep52cbw 48xjOLo4goP8LAtPFoD5+9tW+4k 2020-04-19 12:53:36 88.87.93.94 9001 9030 +s Exit Running StaleDesc V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p accept 20-23,43,53,79-81,88,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r artikel5ev10 r3CUtihk3pQdzYii8Nuv7POZfkc Q/KNUy0X82fCoe2cptQxEuV3baU 2020-04-19 20:42:11 185.170.114.25 443 9030 +a [2a03:4000:15:928:dead:beef:ca1f:1337]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p accept 22,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r NeulandSchlandnet1 r3Okj7nwtLq0L9KMvUvEs0jofzw O6ZgYtD6O13gc1R4/h+vSsEqyxE 2020-04-20 11:07:20 93.229.224.131 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=110 +p reject 1-65535 +r ufm r3eqW9kkMZUQ+ZswzQky0ysBtcU PPHlAHXL5mKODwqFzzBJ3N+4dTw 2020-04-19 19:29:52 193.111.115.210 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9600 +p reject 1-65535 +r karen r4CCpYxqaly3cgnATFn6wO9+WYY jSoBpS1hQtAoAfSXn3o0OlcJk/o 2020-04-19 19:53:42 83.226.146.217 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2820 +p reject 1-65535 +r schokokuchen r6DCT2NcPhmKFR0Jp5ZDDwd4umU j/ei8+/C/g7Rv6NyJRnxE4ojr7Q 2020-04-20 02:19:19 94.130.57.50 9001 9030 +a [2a01:4f8:c0c:7401:34ea:ef91:6664:bbe3]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4040 +p reject 1-65535 +r cGbu7BKzxg7hB2m r6nluNd7c2zKd3BLRl+fpLlWaSQ LQDM3IdVf+Bc6OoPZQcklJIpq/M 2020-04-20 09:10:38 51.15.60.93 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6450 +p reject 1-65535 +r snap277 r7jtf0NDG2SxRfEcP/jUeyGLp1U ORIfMuwhFDRYragm6sbAHb72yQM 2020-04-20 07:39:30 2.233.122.59 41678 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2060 +p reject 1-65535 +r orwell2 r8aazUfky9XPjqR/m1YiyRvy2mA raeb9rmwi3Kd5L5j/8awjVIb8Jk 2020-04-20 12:18:50 185.112.146.179 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8220 +p reject 1-65535 +r d9962b697a0e r9ZtV4JR/6Oep9QH2AdyMRIlFrg q/KX7jqJsvJaps0kFJDOMZr9Qq8 2020-04-20 08:07:26 51.81.254.18 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r thicantor1 r9hITw2E+V6qEdYtgidn/mOBqV0 0kcuiwTDmYMwhe7YrrXtRlzDjzs 2020-04-20 03:46:04 188.165.6.66 9001 0 +a [2001:41d0:2:c513:0:dead:beaf:cafe]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1450 +p reject 1-65535 +r ImOldGreg r+13CulR3qDOM8H7FGPcMYjLot0 CB4o21/OoUnBk02sDwBhYcQhzuw 2020-04-20 06:05:12 158.69.0.246 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=193 +p reject 1-65535 +r Wix r/L8XG95O24Ufrk8GJfW3aSeVP0 wm9jOJUfcP+AI6A75+f/i9iwKKA 2020-04-20 02:20:25 95.211.230.211 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130000 +p reject 22,25,109-110,119,143,465,563,587,2710,6881-6889,6969-6970,55000 +r Unnamed r/MgupbkM4thoAjSyiUP/g4jsJw oSmcWkfM0k6Go9377rtYBduryuw 2020-04-20 10:03:45 85.144.240.161 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=81100 +p reject 1-65535 +r freeUA98 r/SZrwcaLeLq3CK2e0isyR7u85Q AUrM+1jAcVgi7MzMDVlRQuKikeo 2020-04-20 08:14:53 46.161.40.101 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p reject 1-65535 +r sulaweyosrelay r/j01Y4qX+rSjR7Uo4+41g5AajM XSbL9YIY+MS34DPhDU7uT23SDE8 2020-04-19 23:10:57 90.146.90.65 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1710 +p reject 1-65535 +r ph3x r/qFgg1nlr7N2B4tqIsNumlieOM 0r+DoPjs1XLY/2nvMwvLrBBKPJ0 2020-04-20 11:18:36 86.59.119.88 443 80 +a [2001:858:2:30:86:59:119:88]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4800 +p reject 1-65535 +r Yahta4ee r/0UfbzAZaXO9yWLwTZ8w1hVpDE 9aKT5eHoG0NY4KF1gcgyBQreLQU 2020-04-20 02:22:29 5.9.156.17 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10900 +p reject 1-65535 +r FlappyBird sAR4xM0vOsx9bwKvgDPSkGZzZR8 wyf42/MCdLww8X5wbqTgWk1oYRM 2020-04-20 04:47:23 176.53.90.26 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9570 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r MyTorNode sAtrqUNgBEfPctWNt6NbFnVOQ8g HDC/VvHc2aEwy4W0Q48rj0gcjsQ 2020-04-20 06:57:51 193.108.117.59 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=45100 +p reject 1-65535 +r EleventhThesis sBs0Ml9T40SsLV0et4qhrHP8hoM J/M0M1aG+h9jf6vHkcyUJdyKIWw 2020-04-20 00:06:44 5.188.108.69 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4290 +p reject 1-65535 +r BaerchenWiese2025 sBvwkkTGtzaHu3gcWpyegSl00IY F3cGFrk5K84fM+i3UO3CLoIbMnw 2020-04-19 22:55:11 79.196.251.70 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1590 +p reject 1-65535 +r QuintexAirVPN9 sChweWnY7YTm3qWXqIT3iq1HGXE IF7mOFid/ya3kZ2Y9k7CdDAbWvM 2020-04-20 04:21:39 199.249.230.123 443 80 +a [2620:7:6001::123]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Unnamed sC038FW8zvqPT6BV0Ns/W4infto iMFtWI4OBY+seffY3fOLj+gsNdY 2020-04-20 09:58:29 163.172.218.70 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=800 +p reject 1-65535 +r Unnamed sEMNIdZglFnRQQeMDXdYtcp1O28 QSRfbE111shb6OyMVeQA4gQTruY 2020-04-20 06:34:10 51.77.135.89 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37900 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r schlenck sE6itADZZ55yKE4S+4Hmh1ZnCjo HGXNy6v3VwTZ+DDywx/upI285Hc 2020-04-20 08:46:59 217.112.131.7 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7680 +p accept 20-23,43,53,79,88,110,143,194,220,389,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed sFTttWaCbf4VKcGNmfP0bhbL6Pc 3kFBXl2r8O/dj5WwJBGfHRc8RZQ 2020-04-19 18:51:54 178.195.94.134 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=529 +p reject 1-65535 +r zwiubel sFUxdarbBQHlph/GHOo5cL4TD/I iYYJinTnhrUi+DWHm1pGFQJwexQ 2020-04-20 04:31:22 159.69.186.168 9001 9030 +a [2a01:4f8:c010:1aa0::1]:9001 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r coen sFtLtk/+U3Pik9LACHmPupyQi7E G0fA4pzbwfNNUl+fRdNw01s4suw 2020-04-19 20:37:43 77.55.220.84 8888 0 +a [2001:470:71:6c::1]:8888 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4080 +p reject 1-65535 +r myrelay sGpLvsJ2xQOP5EpItkqdw7YYqK8 gLz+mjYuvNEfpxw+oaoUZpVhD8I 2020-04-20 04:44:00 34.92.120.119 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=470 +p reject 1-65535 +r TorExitMoldova sG8JOj1N+tPpI/TyinSQG9T3TrE eoZruw4ul4B4GUJS9+6oDtIN8b4 2020-04-20 01:16:11 178.17.174.14 9001 9030 +a [2a00:1dc0:caff:8b::5b9a]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8300 +p reject 22,25,135-139,445,465,563,587,1214,4661-4666,6346-6429,6699,6881-6999 +r m4dn37TorRelay001 sHKU4c6/jwwt4JjtPdghlCnYFL8 fRnQqMIfDHQuKl6wNQFUgLxUhis 2020-04-20 10:45:27 89.152.122.26 4443 4444 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17 +p reject 1-65535 +r ireadconf sH/M+sYTGVP+hSN4e0oZDRbfZoE YhKHhIsqbl1xjzpgs3roxOABou8 2020-04-20 11:27:42 88.198.207.222 9001 9030 +a [2a01:4f8:200:63af::222]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Geoff3 sIHKWOubu+vb9+BLYw9iXSAC9AE jDKSB4UaZn9lEljxhieHJXnlbYE 2020-04-19 20:47:54 178.254.9.25 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7900 +p reject 1-65535 +r ididnteditheconfig sJ4jwllyNPbrSUtu3XM022QiH6E g87az42ARKRWirAqSd3RSPEzBtA 2020-04-20 02:10:45 94.130.187.145 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7300 +p reject 1-65535 +r brotherhood sKY7w/2menrdG+CLqoMJxLIE0ps DPPN6sQsak08sUuHicPHm5U6fKM 2020-04-19 23:33:31 51.68.170.74 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15100 +p reject 1-65535 +r Unnamed sK5h9qQ0fyKKQBLd5qd5M/e1+eI NhCz7z/jedDHDfRqdQtWpyM9PVY 2020-04-19 20:07:44 167.114.89.197 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Intorr sMaN3UJlyFDcCM3gEVQCXp6+wU8 TlUAOMqyTDcdF+yHNJWITY3m5Ug 2020-04-20 09:25:38 79.172.28.205 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2180 +p reject 1-65535 +r QuintexColinNSarah sM2fm1tgZRrcWRnA8eqofbodkkk e/nGhEi/0d3LZHjiAwXK4QDGwPc 2020-04-20 10:35:53 199.249.230.111 443 80 +a [2620:7:6001::111]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r PIAjpnexit sNoHxx2OUGbCw5HqljJgtPWE2Ew Qvs3q5bTzTRX6j9AfgWyTXA8wpo 2020-04-19 22:21:56 103.208.220.226 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r AccessNow005 sN1Se+AYQtRgMCZfvZkoIXpwnyg nKBoejd3EX/YVomC+QuwzuMjbcU 2020-04-20 10:32:15 176.10.99.205 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30300 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r TerminaTOR sOWun9O6NJmPJZVHg0P0Y3R+nwU MGjR5rAn6Zokx1qX6sT4VHCQJUg 2020-04-20 07:01:38 198.27.64.51 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r ididntedittheconfig sPF6VvqGhsyzPT8wL8QPBvRjtK4 NfunK6HzrmYqy8oSlUjh10NT1pw 2020-04-19 22:10:25 142.93.169.197 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p reject 1-65535 +r root1Moh sPR5p3FOQw+v+jAHFiQ11qPB+mg 6OmuufY4BIONGpa3Als/qf1kpgM 2020-04-19 20:27:32 217.85.9.180 9101 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=127 +p reject 1-65535 +r copper sQQUI3ec2+gFysvY5y76N6pHu60 da1lhGJJPAyOPJkZLLzfjsaWgL8 2020-04-20 10:39:13 179.43.167.228 9020 8020 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r broccoli sQReEvpOoNRXp0AThmy0HcDSkL8 KXI8pRc4FgWYkVjZ/NaRNJ6XG34 2020-04-20 07:17:52 109.70.100.16 443 80 +a [2a03:e600:100::10]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=93000 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r courage sQgOphyvV2MTnntZbzf+mDAxHI8 gfhQiZOoKim0f+vzqKrguPx8XWY 2020-04-20 06:19:16 94.16.123.169 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p reject 1-65535 +r Unnamed sQ/S30j1FQUzrW8Ds91YN2U3piY z/jKqZ/vMoY+BVMc5hAYnYvmSZg 2020-04-20 11:59:29 209.141.52.58 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2180 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r laterings sRh1UXSwmibmwb0Z3VkUNSrLRUY klVJae1jDK60NmomS7irp4SbKDU 2020-04-19 21:49:25 167.179.119.159 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=149 +p reject 1-65535 +r smell sRityhPUBa1CkqCbURMZmjOai9w bAY2SeaKz7F915I/w0tCMX2Ng6w 2020-04-20 01:29:06 205.185.114.250 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r sudoscientist sRkrG6060KFa/In+uyOswFkwtOM GXY5JanXI2uf2BfMIn659vrzSbw 2020-04-19 21:20:04 108.21.216.110 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r Unnamed sTCJK5tOIKGGjCfQLxPR/gL8zN0 2SwFXgzFnzp3xFzF5aXOc5BkRs4 2020-04-19 19:55:39 186.120.250.217 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=207 +p reject 1-65535 +r Nika sTXdugwwlkDYMRV1ozQVfqKOP68 Hu7LgYbOWWzm78p0O3KhJr4h0rk 2020-04-20 08:31:44 104.244.78.231 9001 9030 +a [2605:6400:30:f881::1]:9001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21500 +p reject 25,465,587 +r porte sTwsVp8/0MUwt9luX/eTPfeg6DQ +4KUdm2Is8sM0vZtpztczsPgxYU 2020-04-20 08:29:48 85.208.144.164 443 9030 +a [2a09:8740:1:44::164]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33100 +p reject 1-65535 +r wardsback sUPUObctI5pBn43OB7io6xtIb6c o2X6gDw2v3UB07ZJ6PYC4EarNlM 2020-04-19 23:42:58 212.129.62.232 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52000 +p reject 1-65535 +r Unnamed sUedEg0Beuotogk8UlLoITBdQAI koc0nnAzQDENcOa7CfLrSPjEEKg 2020-04-20 10:03:04 78.46.203.18 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=972 +p reject 1-65535 +r t0pch33s3 sUkGRhHcRmQF4YJZVvNrIC3Obko 6cZE45zAXMUXPwsclKGAXdoqoAw 2020-04-20 04:44:35 107.150.36.162 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24800 +p reject 1-65535 +r cytherea sVwAcer1CKruKdudB2B8hKot3rM AAq9RzboWYJTGtTyZpgtS7ui38I 2020-04-20 04:56:11 141.105.67.58 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9410 +p reject 1-65535 +r tosk sYOmlZLS6MjEh8BU0ISePJVh3BE 98u4pQEc8ayp8XFn2HMq80E+AoY 2020-04-20 04:13:41 46.23.83.35 443 0 +a [2a03:6000:1831::35]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1870 +p reject 1-65535 +r Tiger sYXIkSybi52NpprgfR1qLCWmYoA 5J4t0LdGBr078AzhfSdACZ8RJm4 2020-04-20 08:38:11 178.17.171.54 443 80 +a [2a00:1dc0:caff:b9::3be9]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11600 +p accept 20-22,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 sYXMA+Pz372ws3QxmkDwbbyui3k 3XaszRi5eMtCchZsouNCyezNaW8 2020-04-20 08:04:22 181.14.189.236 36809 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r LunaR sYc5nicIFVloqDdbgwQnZ/afIfA SiibeiF4xkQMC0Lic0pbbLpqfqQ 2020-04-20 10:52:15 81.17.16.146 9001 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Bazinga sZjAtLjFUfF0+7hBoXJhbj2zEk0 3FnJOnojBKnjeHBb69pKhzjYpUw 2020-04-19 19:19:51 93.180.157.154 9001 9030 +a [2a00:1158:3::2ae]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16600 +p reject 1-65535 +r SecureHSC saoEsPc6bO3/r4PJwehQ3NEwfnA PTto1P5Yx1sNUtEvs4ghl01f9/A 2020-04-20 02:54:30 74.207.242.7 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=950 +p reject 1-65535 +r doggerel sb5XEmVnHWlLCb5lGsMI6fatMwM /wJDW2DdAkPiz6ZKFlFbyLZuFVM 2020-04-20 07:29:22 95.172.235.74 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=70 +p reject 1-65535 +r BobsHouseRO04 sb8om5ZXYNF7NQjj5I/13IFU+3A X+d6M3UNX5CW2OnnXC/sNvpviEo 2020-04-19 19:10:06 45.14.148.96 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9700 +p reject 22,25,109-110,119,143,465,563,587,2710,6881-6889,6969-6970,55000 +r snap277 sc7kIMDPO05CrqqZIFVwzY97URc ENPGDFpxjjZNQm2Fb1cm1gXjLQ0 2020-04-20 05:09:26 109.115.94.193 39441 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=643 +p reject 1-65535 +r martyr sdZTcvhtwsprXRuNQmeE+hMSG+0 9M1DQjj9MImawFeNdVmwQhGguLQ 2020-04-20 00:28:09 51.158.109.217 443 9030 +a [2001:bc8:4400:2400::1811]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30500 +p reject 1-65535 +r bigbrother23470 seK7LAj879CJVQ9xBOmgwWAyU20 tVUI5Xncj8VrANEpJ2xZ4um/pNw 2020-04-20 07:15:54 75.142.113.210 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=190 +p reject 1-65535 +r layersofprivacy seQ7EalVy6MfUmGiLL/OIEyV1d4 XGWbH9ZYcDrYnk0NjP+/vC2sBTw 2020-04-19 19:24:01 104.244.75.16 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14500 +p reject 1-65535 +r C3WPhantomStreak sfCYEMT3udMPSD3OOJGAM11Alow +koxD8uGqWWan/xj6/djY9Dmldc 2020-04-20 11:28:57 45.84.253.28 993 143 +a [2a00:11c0:66:1:45:84:253:28]:993 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=202 +p reject 1-65535 +r niftyentry107 sgAtXHWg+tjzOWJhRxjzXLZyzFc 184+cd7TK5L42T0BMdN17XuM9xU 2020-04-19 20:25:52 185.220.101.107 10107 20107 +a [2a0b:f4c2::107]:10107 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21900 +p reject 1-65535 +r cry sgTedbNwZO9qTGuvlVxXJFeNCzI EQpJlDh5Kkb8Ktl5yBpg8GqcJO4 2020-04-20 11:48:10 192.42.115.101 9003 8080 +a [2001:610:510:115:192:42:115:101]:9003 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26700 +p reject 1-65535 +r snap277 sgeCX4YGxyOLBABvxCRQPcguLR4 AgwDWY8k1J8a5ZiOdGA1Iy5frt8 2020-04-20 03:04:14 78.194.82.26 41969 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=781 +p reject 1-65535 +r eskel sg8ImpSQLrQ/d2JtT00XrIiLihk Hxt5mnSH4ow1LvTVIxUiBePJHFo 2020-04-20 10:51:06 77.55.210.111 8888 0 +a [2001:470:71:281::feed]:8888 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r sakura sg+mwbKw91SOyENKRvNhFwDAV70 aFrZOOcDBjAmixFmLXCMobCgk9o 2020-04-20 00:47:25 49.212.166.38 9090 0 +s Fast Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=94 +p reject 1-65535 +r digineo3 shIRoaLGjy2eV+PHrq9PBK/BDn8 NzbicuHCRYBPuwq692hsFW3SzGE 2020-04-20 00:19:59 185.117.215.9 443 80 +a [2a06:8781::9]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=25000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed shMKov2EB3elBFoIgwYLU8Hj+cw Jl9+Ws4weA9AtvzGGzODAxWFLgo 2020-04-20 10:59:54 31.18.177.147 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3780 +p reject 1-65535 +r daddycool shTHaMiLsI8Be+MMu2A5OfPdpmE +zTqxfvyKbtKiR+PA/R4SCs6hog 2020-04-20 03:10:57 54.39.148.129 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6800 +p reject 1-65535 +r Quintex41 shl8I6T/XRxJ7kW6doi6i8zYmgs v5KrPmqg6HcZwMB8kGbONyeMM40 2020-04-20 06:45:16 199.249.230.64 443 80 +a [2620:7:6001::ffff:c759:e640]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13500 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r DaphneCaruana siFp3bk25M9LjIHpUUvQVlhGaXQ j91wWaH2+Y+GRvo6sn8Pf7QnOnE 2020-04-19 22:11:57 51.89.23.74 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16900 +p accept 20-21,23,43,53,80-81,88,220,389,443 +r Perceval siIocX4+oPusXeksIF+FqdaOXXA WQ6mfYZvp6FG88h3oCe5JoTMrgE 2020-04-20 02:15:31 139.99.98.191 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1630 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Unnamed sipW2K5JSiDKDrhFfzysVPyZrM4 8Cy0l0+ADZavIXpjpVDSGxYGjfQ 2020-04-20 10:00:01 81.83.37.138 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=671 +p reject 1-65535 +r Unnamed sjB8RNiASSEvOBwYltK55sQJPps nFFRBqhUGP/e4ogteqbTB+BxuKI 2020-04-19 18:53:13 167.114.89.203 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7520 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Labitat sjgHBMU5R7HXLny802HnOQHvdEQ vkYLzpVW3wHOcKg9Lz/C24VgXGQ 2020-04-19 23:11:06 185.38.175.71 443 80 +a [2a01:4262:1ab:20::71]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r DefinitelyNotTheFBI slQnqPSkheA+2jF1erHDPb5YdCg jWv0ZxrXvArUQfg2TEi9GRQ8KyY 2020-04-20 02:03:13 195.154.28.200 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=85100 +p reject 1-65535 +r TheBaconaTOR snEVogsF1AcwpAIBRe+mM4HZ1Rs 9rzNTqFlPawaMykCHJNLDuXCwzk 2020-04-20 05:07:31 38.68.135.5 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r Unnamed snQdNfD9rOAzUNvs2L6KhP77M9w ann+zeNscp+Ey6H0mp2Oef+MbAA 2020-04-20 04:42:44 142.44.139.12 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21300 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r HoneypotGuarantee snVDOMz2/yxhGiy6XAkIY+ZdziU ftu/e5QOkaChEV7640CnL97J1zw 2020-04-20 00:40:52 107.182.233.54 21664 13394 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=75 +p accept 1-65535 +r radieschen snzx3O7NUPeZKwfXINf2vw7fnUA RTTQAeeE8BYNgg+Y5IRo3yZIrbQ 2020-04-20 12:18:26 109.70.100.2 443 80 +a [2a03:e600:100::2]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84500 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r Kashkala soAFT0aBY0MiHiB+1R2KNsUMOko kS8NJQmR+KuqeC9Xb5z5KXCL9RY 2020-04-20 01:32:56 207.148.77.208 443 80 +s Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r IPOVERIP sozLYM3fWqZl1c0MO/S7D8Y+sk4 ENHUn6k8mThaD5Me1QTafGn8cTI 2020-04-19 20:46:49 178.17.170.165 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17400 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TorKIT spHTBRfSMpmtfO4+YN/mDQ46RmQ NRRuWtrCXMaMeTHVZL66RCui6w8 2020-04-20 11:57:53 136.243.214.137 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20200 +p reject 1-65535 +r Unnamed spY2rUyzk7m2sjuCDJmgUBeyqBA 7Tp1DcQWgX4h0pN5C7ymYygf9Hc 2020-04-19 21:14:48 46.4.176.48 44945 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p reject 1-65535 +r king srlXF49taHeWWyDvtLsVEzvZPjw jeeL2Z8OTnwR0dmZgqRZbjjcyc0 2020-04-20 04:48:34 51.68.201.117 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22400 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r noisyfirst srmvurNy0ei9bFchXau/EDAWPGU GeLiGUIwyhYw5XjHP5kqpxc9eeI 2020-04-19 18:54:08 85.146.6.52 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r Unnamed ssueXIA2fJAmqAbsSAHiJCWqfoo w7HSb2g9S+SA/2ymIzZjCz5taAU 2020-04-20 00:25:11 5.39.80.135 9001 9030 +a [2001:41d0:8:9287::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5840 +p reject 1-65535 +r Unnamed stA830XrTXSmX6xPAOunhclmOl8 EvuFQSCAUTe89Rlpn4ZnvObQ3Bk 2020-04-19 21:37:34 85.194.238.131 8000 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4210 +p accept 53,8082,8332-8333,9333,18080,50002 +r nortor4 stB+q7jwcf8plHt4higd8eJVuto hsb96XelwOIq9GJmadZTjli71PQ 2020-04-19 19:28:12 217.170.206.146 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ChrisSellsYourData styMxVeaP4USHBq0psOqOLWw3D4 qj7jgoHMn0TEsFmN4Nk8hz1IGbQ 2020-04-19 22:59:22 23.129.64.196 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9100 +p accept 1-65535 +r BraveCalakmulII suDzOxp+cPIXRMPsN7R1+OwHEuI L5v3JyyxgNAbXEKotAZQ0Dufa0s 2020-04-20 04:34:06 65.49.20.11 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r yesidideditheconfig su3WB+epTl/la7+mwV+etPaGndo 6CAi8mvtoobREdjT56gCTKcSUSM 2020-04-20 06:46:51 203.132.95.170 9722 9723 +s Fast Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=156 +p reject 1-65535 +r OnionOnion123 syuTyQ3K8AEjKKjVXWIdJrGG4Ro +jBF3rMdkM8Ys831Un/27h3T8FE 2020-04-20 08:22:23 185.21.216.196 32123 12321 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44200 +p reject 1-65535 +r Unnamed szAArILnGcu+lwg7iKdVjXQkH6U HgiaxmTXNEgsF1CoU5+ucczO3Ps 2020-04-20 10:48:01 79.76.61.235 9001 0 +s Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3 +p reject 1-65535 +r 08c322675b00 szb2epUEipYlzasBj3XDuLKx1MA ZWgKe4Ec37Exuy+0N48xEw3gafE 2020-04-20 07:35:24 51.81.253.199 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11600 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r victoring szv6mqAAVzDBwOj35vU888Vxa9Y D+i9v2KKbEDYqbXBzLwG01jMYjQ 2020-04-20 06:01:16 2.10.193.16 9101 0 +a [2a01:cb08:865d:900:a0::2]:9101 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1380 +p reject 1-65535 +r fiedlerRelay13 szxbjd0utQ7guZFlR+veK8o7xWc oUZn0FsJqd9clxYvh9mkg9Cov3U 2020-04-20 10:08:21 185.170.113.28 9001 0 +a [2a03:4000:15:8cb::2]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r niftyentry68 s0BzhKhthm1twxo3UzyHA9vWSWU +/R+uNcMkUJGVJLfU6nUcppfpfc 2020-04-20 10:52:06 185.220.101.208 10068 20068 +a [2a0b:f4c2:2::208]:10068 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11900 +p reject 1-65535 +r ephemer4 s0Djulh+NkYtjeRNrg98q2dI8GQ eMQ0ia/PGnn8SeBUUuxOU3NDHpw 2020-04-20 04:12:43 128.232.18.58 9001 9030 +a [2001:630:212:2a8:a6bf:1ff:fe25:b961]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3340 +p reject 1-65535 +r rathergonaked s0g28gJ8FOQEBHh2iYa/6oJ7Rig m9CTDfyx2ViKFPIEEWU9om6I3as 2020-04-19 19:56:11 87.145.164.249 9002 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=670 +p reject 1-65535 +r fb7ok18 s0o04bIG27m2IT/3BkS5MGyeehI 7ZVC2STZ5vOm+QenqHPZgjJw9L0 2020-04-19 20:28:23 81.170.155.6 23456 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4090 +p reject 1-65535 +r CalyxInstitute12 s0zJBWJQhH0ZgPCChbAc8LcYwLY RqXos6atSx6d5vKbCxF6bTjGO8k 2020-04-20 00:47:40 162.247.72.199 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Unnamed s02usHkEkbne59qkwrmurtG7fgQ hWmyIjYtK1NWMlqYYTatbHvkKeE 2020-04-19 19:35:30 167.114.92.53 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r freebi s1kI2rWRzyaKGehbvN4wwEKKTPs fC7nhRME30HQ+MgPlSJx1rPA9IA 2020-04-20 05:27:58 139.162.112.111 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=310 +p reject 1-65535 +r niftywabbit17 s2AG2I4szvLh7wgmx/Gw7cjebAY /PcZaUmi0a0H81W2+U9VVScmVaM 2020-04-20 10:53:17 185.220.101.247 10247 20247 +a [2a0b:f4c2:2::247]:10247 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31000 +p reject 25 +r SixRelay21 s3YPILwF2cMq5MPKXX1XYyU2yRM wsJzOgVsn07ijGjFCfC9PH6eHhA 2020-04-20 06:23:40 5.51.254.248 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5070 +p reject 1-65535 +r RapTORist s41c6wtfly0ieXbwojDY0UHnFxA DCul8Bi54Y5V/z3BUP3v3OW4jPs 2020-04-20 10:34:19 2.249.86.110 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1350 +p reject 1-65535 +r mdarder s7o14qbsq/+AG0vi6GEFPAxNaU8 6mcGIHMmmn2tUhTkzP9nZ3ZeiJs 2020-04-20 04:44:14 51.254.125.86 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r Unnamed s7/pGoYyGSHq6Cct8VpT55DAQT8 XWgeT9zmNDOarQU+x9kmFoJFTQw 2020-04-20 01:16:20 172.105.65.45 45761 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49 +p reject 1-65535 +r theseekingchild s88I6d9w1Gu+tRZaQtCH2zUidd0 CpyDA5Ha2jZZ56gTzw/KSVE3kAE 2020-04-19 22:00:17 180.150.226.99 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r brattastic4 s9VsHgrYS6k69txTOoVpw9DopYs UsnhO7yJo+0fU9OGSN20JxR8UoA 2020-04-19 23:32:51 209.240.109.238 9002 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16300 +p reject 1-65535 +r SuperHoover s9dVXyyAA0/E5N1jn8XpHFtsGJk e8xsrOq6FFqYFyunFTinT5b+mz8 2020-04-20 00:06:18 83.97.20.81 9001 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=357 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Hydra4 s9qdZzMhuSJT3M04qXQPLFYskeo yi/zAoYhc9pV1jVR6DQQhRNngbU 2020-04-20 04:04:13 51.15.124.1 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29000 +p reject 1-65535 +r fiedlerRelay12 tAHjBxDHYj6sPxrzRoQzXpEevSs LPEf0zjJeKIepmt+sq+8EZ/onrk 2020-04-20 11:09:44 188.68.55.50 9030 0 +a [2a03:4000:6:e3e3::3]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3900 +p reject 1-65535 +r Unnamed tAm4h2lqOsxOa56AXJzffpBxD3c jLKo69rdef90bQVSvtM/DzWY2SU 2020-04-20 11:56:46 209.141.50.168 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5390 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r pulsetor tBECfJJqm//PfakePK8YVqMh7/0 okSSUiQcxFgeHZanJNSYsltKWMA 2020-04-20 01:42:14 51.15.76.56 443 9030 +a [2001:bc8:1824:1e42::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22100 +p reject 1-65535 +r diggers tBtnvLxUVWT0OmvxLRZV9tjAOoc G8u2bdtJfOraO1OvF/0m+43CXzY 2020-04-20 07:19:41 185.120.77.117 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1120 +p reject 1-65535 +r traktor tCa7WS4gAIt+2enXrFZR7YsOs54 1s/77cR+GIKk4LMac2tolAIiaSE 2020-04-20 08:14:49 193.224.163.43 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=773 +p reject 1-65535 +r firefly tCx5fMjNY8YPtkPoIKEdET309cg VMyH6Y9BvdBARJABizx5195jUYo 2020-04-20 05:29:59 217.23.8.2 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21800 +p reject 1-65535 +r snap277 tDKNbNJDUWUOAP/tUc0IpZPjUJs Xj6ySjEfAmPE9K5V8qqbJoTI1Wo 2020-04-20 10:49:05 42.147.50.235 35657 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r cnsp2 tDQJxqBH5Q/Ht6IzIRApV7r8PWs nkzG5RoKoQz/ukL/TAIde4DT90U 2020-04-20 02:03:14 54.233.234.207 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=460 +p reject 1-65535 +r wommelator tEQQfx+92wIRt+dkW75tFPmQRxE MyACgJtvcNnjC1xiOStQIudU5ps 2020-04-20 11:30:21 91.64.214.135 443 0 +a [2a02:8109:8000:6d:d8cf:444e:2f2c:532b]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4700 +p reject 1-65535 +r oberon tEhoceoGK68jVPBw/sw0TPPCCIA tbjYWADZuFIoaJbqp08f3ilGf24 2020-04-20 07:31:41 51.255.106.85 443 0 +s Exit Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p accept 20-23,43,53,79-81,110,143,220,389,443 +r PIAjpn2exit tFWXysHe2VgFaiNFirSvuOOKunU tAyR+Zyez/APvJyjK+iCiLkgDUY 2020-04-19 22:17:44 103.208.220.122 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1610 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ZaraLibre tFtiwTz9NyNXkDWbTIGwF6cL4Ro VPm5VN2+5ZYRU81jWko5lTMvKxg 2020-04-20 08:12:24 90.162.56.45 9001 9030 +a [2a01:c50e:9101:fa02::12]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p reject 1-65535 +r Sensenmann tHKLOzpNpHUOV2aqx3ifSjSI9F4 EA6C/kM0gKOLhwOUUukOnECXBxc 2020-04-20 01:15:42 87.188.194.206 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=151 +p reject 1-65535 +r myNiceRelay tH+YeMw3HMTTL1mtvGewc5fQJCA vtW26lKu552EgtJ+YrsCt2u6s/Q 2020-04-20 06:54:27 51.158.115.1 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19900 +p reject 1-65535 +r snap277 tIPF/oooiPjgKIXYSIQE2777zzs lxtqTrZNOXJ9gLKwpPJejXcKfmc 2020-04-19 21:48:30 79.119.136.33 41477 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=694 +p reject 1-65535 +r micole tIrF9UfbuEfvuISAv7htQSEe1hc 8R1+Zyszn1ctCSw5DkufqCwG920 2020-04-20 03:38:00 103.236.201.110 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=620 +p accept 20-23,43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r Unnamed tJaSYPdr4/FF6QrwU7Vp2bRB4oE 8E8E7FS8z/AaI5Yvycu4QGCbZ8o 2020-04-20 01:14:59 193.37.213.5 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=94 +p reject 1-65535 +r ToRRTHoRToR tJyJgz5+2Fs3aGnK+zCZp2bWNoA unIZDtL+xEm4dPwqQ3x9q8ZB6DY 2020-04-20 00:09:06 24.118.12.208 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=124 +p reject 1-65535 +r bagespottedtide tJ6q5GkOXOdi0d+LAP3gWXCIDq0 aeeTEQFZTSHFmWzv2TcOfLEZr98 2020-04-20 02:34:41 103.253.41.98 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8074,8080,8082,8087-8088,8232-8233,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r RumpleTor tKP9gNNtLl/q2RKfTu++FV1RjbY M5BI/+uC53PEm7AjonV54wccaZI 2020-04-20 11:34:07 193.169.87.29 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r RenderLab tLkArVATTpUo1832Zava2r9Tqbc faW0iy+OBUZhBh6Q9qBBYIdH1CU 2020-04-19 19:18:30 68.148.246.91 44444 55555 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1190 +p reject 1-65535 +r netimanmu tMr9nL+zTsXarBRpINx9+v6R6iA JlIpBQA/idmxzDE/GnVxQybCmpc 2020-04-19 19:38:34 212.47.233.86 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p reject 1-65535 +r JabberDEXMPPNode tMtGVXO62yM+lWebDxnEoIC4sBg y+Uh5wL0EraSE1H3Z8ps5uvWHQo 2020-04-20 07:15:38 85.214.146.211 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=98 +p reject 1-65535 +r niftyalloumyraion tN0fRsbltD2WVP9WvTIzPWWG5TY U17qqQa+GnFB5WBtYZtGVfToSo0 2020-04-19 22:15:25 185.220.101.129 1129 2129 +a [2a0b:f4c2:1::129]:1129 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45500 +p reject 22,25 +r Stephen304 tQU6v/hFyWsd2PRdzzLmvh5j8Sc mSFF6K75QeSIU5E8fQw6GpLBTDU 2020-04-20 11:20:24 50.236.201.218 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14200 +p reject 1-65535 +r Unnamed tQqYJnpjcT83MZ2JXqEVHEsnvk0 BLbN/W4FOMladFdunV7rOMWKFe8 2020-04-20 09:06:40 87.92.208.189 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5920 +p reject 1-65535 +r snap277 tRJFu5uepEIoc+UPBdMFwToTo2Y iCn52lrg32Wfue0G61jK8x4WAYg 2020-04-20 10:25:54 37.134.24.191 45541 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5750 +p reject 1-65535 +r Sandcat tRcZhTbVUyk3/YkmQo3nRLrBTBE yKwoe7TvfNhi5t7NJqi67HqFMKw 2020-04-20 01:19:09 217.61.157.75 9006 9007 +s Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17 +p reject 1-65535 +r angeltest18 tRcZi4azhZwweFfFn2ZgooH8i0c zYl8YMSdYeGBFuIGf1rnCnilHGc 2020-04-20 09:23:16 94.140.125.122 443 9030 +a [2a02:7aa0:1619::4b42:ca67]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15500 +p reject 1-65535 +r firstor tSEttoWioPz7rkJXOOR40SNhcQ0 imeQ2N/7Lp3f9a2uKFqbMf5OMgc 2020-04-20 08:59:22 93.115.97.242 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15200 +p reject 1-65535 +r Unnamed tSSCfIjXwrPn5F7XeiGFAXQ9x+0 zLoAj/kUCap687tzS8RMbb1PAXY 2020-04-20 12:19:47 82.27.144.85 9002 9003 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=261 +p reject 1-65535 +r Unnamed tShjbTZHdrLZSx4UBgmjuIUxwLs G9GfNCECp/eRFsk3QHOc56aGArg 2020-04-19 20:28:34 178.175.131.194 443 80 +a [2a00:1dc0:2048::2]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r dreamwriter tTa3Gh9VmcOfyLGRXS6+Og3rFAM ReZG9rph69nFtYLtEhsplPH8r0A 2020-04-19 20:15:02 88.198.107.179 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3590 +p reject 1-65535 +r fiedlerRelay18 tTzKBzYW4wujN27EBXf7u/uBLCw qsTTt/+Ns+BjMGWx+JW+cbp8n1M 2020-04-20 11:07:35 37.221.198.114 9030 0 +a [2a03:4000:9:533::3]:9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3810 +p reject 1-65535 +r vryheid tUNa+oGzNXHW57eKCMiUXfIGcG8 IaRuSizDqym4r3APHzmSsff6aAs 2020-04-20 07:32:51 154.127.60.92 9001 0 +s Exit Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=556 +p accept 53,80,443,6679,6697,8332-8333 +r torvhish tUidbFcZKDOxO5Y0UkVSzuOBJK8 o0YWhuw/Cr4XvQ0Flwn55zRFmNg 2020-04-20 03:58:17 144.217.161.5 28057 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=177 +p reject 1-65535 +r 558aff2634b7 tU00M21TzhMCyTiaPSkIoserxjQ 1P+WBw1j+LlXHp1W0ur1uGJZDNA 2020-04-20 08:10:27 51.81.254.29 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Stempelautomat tU5MpXyK7JwUK1Si32iyxvt+2UA MgyRvBarX/qr/lhtqgpzhYqCBqM 2020-04-20 04:09:59 109.250.101.91 443 80 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=841 +p reject 1-65535 +r tor4kryptonit tVBtjgP3vq+hqVXdPDmzj4MLL04 +bGQU9aHRgjG54C0KNp4V9s12Nw 2020-04-20 07:33:16 188.114.140.245 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53100 +p reject 1-65535 +r j4c4l4 tWgTXF40W6+wgMEf3fNI5UWnIuU WBrz5VJsK2TFdmrtS9Z5gzJ7Qwk 2020-04-20 09:01:22 95.216.160.102 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19100 +p reject 1-65535 +r BadshahKhan tW1aBUPDW0XYHXkqRzVZDjYSqBU GghO4HlQX0QnX7psU+8fjhvCdtU 2020-04-20 00:42:45 144.217.60.239 444 81 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r someNiceRelay tXajlN/BK36QDWQ8kASEdl1Yww8 19WZGvEz/b7CuWKD+UIEsFkrnWk 2020-04-20 08:06:53 144.76.223.174 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18500 +p reject 1-65535 +r MrX tYMYRfYxw+BTsS1HFDMukwIZoBQ WUNStStFxWP74NyhLoTvt4pw4QU 2020-04-20 09:25:49 213.136.69.237 29517 29518 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5300 +p reject 1-65535 +r torelay tbQ6hYCf352V/zYuaUbO8WAcBhI 08gZ3SDu7hPXmi893uXJhTQbw4E 2020-04-20 09:36:05 99.104.206.60 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r TORRelayCAN tbZm9ffpEN/0StWM1ipLP0Fey2A D6tYMQPZaiZypG6YD1uH3vI54bg 2020-04-19 21:56:10 192.222.248.20 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=890 +p reject 1-65535 +r Unnamed tcb3EtZWyTkAVqqbpwIMh+7p+jA k9ymtpln2/gBaAQ6HYYPUjCeOXE 2020-04-20 07:49:14 178.17.174.10 443 80 +a [2a00:1dc0:cafe::d6a2:ae67]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4710 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r DigiGesTor4e1 tc7Wg0vujjjSxi8AzLZxXwRA2iE d0JLrJ2Iw90+7hRPuPasr5bOkWA 2020-04-20 07:38:04 195.176.3.19 443 80 +a [2001:620:20d0::19]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r kr3pper2 tjC+gCqANAP0u+3xxLe+ezGokwU PAkU+L1EsYRo2bVFSlptYXSrAYY 2020-04-20 10:32:20 212.51.159.148 9002 9032 +a [2a02:168:4041:29::120]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39700 +p reject 1-65535 +r QuintexAirVPN10 tjIORKIwMCx7+TGeZ1l6m4eIIkE 8fhS9E1WJ+uqCbva1VSoot7HcVk 2020-04-19 19:23:40 199.249.230.100 443 80 +a [2620:7:6001::e664]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r leuwerik tjQQzUgYXtNOnGrmLQSNimhUpco TKahPwihEAKH+0JyzGUJnoOPcJY 2020-04-20 05:57:28 179.43.146.230 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10900 +p accept 80-81,194,443,464,531,543-544,554,563,706,853,981,989-991,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r skibble tjUtd0qRJ2SwsP5il2Zs8J3+MAc SEuQ/DB35oC8qOTp7qntLrnUXT8 2020-04-19 23:27:40 174.136.98.114 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5000 +p reject 1-65535 +r trumaine tjYmo8pvBSGEeFPd7G1ARMgLkD4 eGaJtRwYo8rc58/GY1R9PR7NChk 2020-04-19 21:07:18 79.124.7.11 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5600 +p reject 1-65535 +r frell2 tjj7wDIXTKqUCbg7XO/7SQbUNDQ kPVy0izxTdo6m/xygXXHH1kslZQ 2020-04-20 11:16:04 85.10.240.250 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5210 +p reject 1-65535 +r snap277 tlAyuCjYP6qIh+SRqYShz2sjkeY kZcnhxGDOPHg2bO7jgK3D1T0PW4 2020-04-20 06:43:19 93.28.76.104 44567 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r bucko tlWiD0LZQNmuryDHycKjNFPyoco yfDHaaVK2bb37OZywjOUDQhqXDI 2020-04-20 01:16:39 45.63.14.225 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=369 +p reject 1-65535 +r Unnamed tmXV+dP0HMWsP5fzBvfVn5CwOqs 1mmKcE55pxKWr5XVUE1HRCdDim8 2020-04-20 07:35:41 83.243.68.194 49002 49003 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3160 +p reject 1-65535 +r nickel tnK3u15bn3eDMHOKRoTflGuTij8 E+KV1Di7x7pZzJo1dNGhu4vnDB0 2020-04-20 10:39:13 179.43.167.230 9020 8020 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r simpletorrelay tnnGuIRv7lNpzcGaDS0Db0EA9fo ZRYPhBWVxTQYVQ/YjTeX/XsrHvI 2020-04-20 00:08:17 78.49.104.67 9001 0 +s Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21 +p reject 1-65535 +r GMoney toouAw4AksTtN9HKYobM3xRYr9E 5ahL1XH8s7S929FUezjLm8z9iUY 2020-04-20 06:00:37 173.70.126.44 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6600 +p reject 1-65535 +r owin tpQsY/GlluZVfRP8Cs+EdaCirT8 pOLmemWWK3TDIRl/dN5DVrHJ23Y 2020-04-20 10:48:49 89.41.173.138 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7090 +p reject 1-65535 +r PorchPirate5 tqfWM4Wsb3P+LBOmx9G9OhXFQ7k eE7n/GaBYe+ZDh/pIgthd+fuZkw 2020-04-20 12:39:47 178.175.138.62 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r PXArelay03 ttSRapjZkCfaJdQtcNaG8LNmPzU GR7bzvICO9v7kvL9jSKHsYJU7/w 2020-04-20 07:38:56 85.191.195.69 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r snap277 ttabEry/eJVz7GyiTcs+Si+f8fQ klwV2wySLZ7NXT5JVJorwaA6r28 2020-04-20 10:57:03 90.114.245.216 41207 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r Unnamed ttj0Tz2MtoNbOSOUkWNl42dRw7w Dw4Q/AZvQTRYTAvzWzJfn+yN/C4 2020-04-20 00:34:13 69.163.35.222 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r corky tuM8OcHJTlgsu4wkzONR8hKYB8Y ZcHmLTcJ60VAmM5ihjNJyod583I 2020-04-20 10:12:22 146.185.253.101 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p reject 1-65535 +r Neyo tuQBZ76ELyebEbKg9ZRxg4eqdeU zD7A7kr0i/JJl6gdOyXOZJmOUu4 2020-04-20 10:09:25 188.213.31.125 9001 9030 +a [2a03:75c0:3c:a257::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Unnamed tuZdw6ERaJiSN/guvYEVoCnbNog 99Yzzdj0bgSqebwB6pyyGP7QyW4 2020-04-19 20:32:11 103.230.142.23 443 0 +s Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=56 +p reject 1-65535 +r RattusNorvegicus tuxxOeH0e7kNPCbsRXHkuwtLaYk 7AZdBWLfh+aa3//Q8DuvDmcexoY 2020-04-20 12:06:12 212.159.79.228 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=78 +p reject 1-65535 +r milhouse tvA8NEgwrVDfKOp4SMIWgBz5rY0 dwPtLwnrE2SfYXVHammPphHgwoE 2020-04-20 08:41:53 179.43.169.21 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7960 +p reject 1-65535 +r alterspalter tvC8K5PLPv//9yTLT14CX7Fe+3A OTPfwSau4aktLrHNtWVY0k+RRxQ 2020-04-20 01:58:22 85.93.16.47 9001 9030 +a [2a00:1910:55ef::124]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3950 +p reject 1-65535 +r snap277 tvKokPZIr1rVmV5lzo6jZ11GTAk YmdJQL1t7rBr9YhTSGTQ3XEkmOg 2020-04-20 04:27:17 78.69.176.146 42523 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r snap277 tvaA5ONN4vocuZ9u/sV5FgLQnYk +8AxLx84dwkq9F2gArQigFNdyCM 2020-04-20 09:20:57 2.86.201.227 43837 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=317 +p reject 1-65535 +r yatotoro2011 tvpWtEKAtyfbrGUSXPc41LIvfQs Rp+g4bnEQ/44hAC/XR8WAjnvjI0 2020-04-19 22:00:00 46.223.196.26 9001 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=580 +p reject 1-65535 +r Quintex11 twR/venFPDkBHKhOXLKo41QwZtA Z9ulsByb59/7wtjempb6q0exjdM 2020-04-20 12:24:37 199.249.230.101 443 80 +a [2620:7:6001::101]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Biverse twYpwpoDKXnlrQDMUdIzCEWq/Wo 6A+IUH1P6U8pm4g+Yavts+o+d4M 2020-04-20 06:36:03 178.63.97.34 9001 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35800 +p accept 43,53,79,563,706,873,1194,1533,2947,3386,3690,4321,5031,5222-5223,8008,8333,8443,9418,9420-9422,11371 +r FalkensteinTor01 twvTNP/uI+ZTt1IZrhLPAja8/Ls R/ZLfdrSaKEnnJyjRRoXtPXeCOc 2020-04-19 19:22:13 195.201.168.111 443 0 +a [2a01:4f8:13a:1082::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=44500 +p reject 1-65535 +r AuroraEmperorTorTwo tw7Euq20Ev2136b9wW0/RuGt92E 2s8/Y0aVfLm2Nm5A1izSTve+8a4 2020-04-19 19:31:55 68.230.106.103 9001 9030 +a [2600:8800:7980:700:ddf5:91aa:7f48:1e3e]:9002 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=557 +p reject 1-65535 +r Alien tx5oqAxRVnRd3ndB9t5eMgKr0JI GKX380W0S5JcypIT092fLhT8NJg 2020-04-20 08:38:59 91.203.145.114 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6740 +p reject 1-65535 +r niftybunny t0C87MSpVpIyzdRcDhMwug0DDTM MGOrGMMS0dzCyG3kpTx43Z5ogm0 2020-04-19 22:15:31 185.220.101.136 3136 4136 +a [2a0b:f4c2:1::136]:2136 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53300 +p reject 22,25 +r sonofgodness t02rviSLk1zcEDjNXJKAh4yMlOc BcAuWaDUZ1g98GNK5ppcoHsilmo 2020-04-20 01:28:38 5.39.72.20 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48600 +p reject 1-65535 +r snap277 t2QFP4dtMBflVcyUenDWuyp2ARs HS0Z8DhTMR3bu2+r5i55Ledv+oU 2020-04-19 19:11:54 81.56.135.149 38505 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r ddgserut t2TI9lnEcUCKQEBnrbVir4yOibg QCqnT5Yw93vRonE1HEw3OgqhHwY 2020-04-20 12:47:28 89.36.218.127 18364 0 +a [2a03:a140:10:e7f::1]:28196 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=341 +p reject 1-65535 +r DuesseldorfTor01 t2oEfCDT5Pm1pkQoKY2lWpDWJHI fr0Sx8JvEV6+Vn1ccdKxATW8uaQ 2020-04-20 01:20:37 78.31.65.92 443 0 +a [2001:4ba0:cafe:c88::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=24100 +p reject 1-65535 +r niftypika t3Gqh3aH+I5vHKU1R1bfbIp7ayQ hQ7dHDgFBXDd45ojQgzx0pq3OM4 2020-04-19 20:26:45 185.220.101.15 10015 20015 +a [2a0b:f4c2::15]:10015 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39800 +p reject 22,25 +r StainBaron t4xgikZUANpea7+RnjQ3Z45kvcc zLYqrSHOcSrwX9PKXj9ckX8SDFg 2020-04-20 05:45:22 139.99.120.130 9001 9030 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1750 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 t45pBprNkX90ZnODFG42v6q+fbo HOUV9Tf4WrqouaYVEKYAdAJwzwc 2020-04-20 10:18:21 78.126.46.102 46703 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r snap277 t5A88HOYb8cu8BswVtRRw5AncUY WQzp04+G7E6bLHna5leYhI0nDcw 2020-04-20 09:03:17 96.37.121.36 35921 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1000 +p reject 1-65535 +r poseidon t5WJNVpBiA3/gvUiXylAQ3zt6SU 1qfxmRyvI9gRQFYcMv51sKgZwpY 2020-04-20 11:14:51 5.45.108.48 9001 0 +a [2a03:4000:6:2042::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2820 +p reject 1-65535 +r scotch t6EVxl7RqjDBXhGhmmjrWq5+0MQ 03zYpdCvwXU/OPmX7GZXKoV/guw 2020-04-20 02:19:16 185.12.45.114 9090 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap278 t6oz5/hI2s4336b1SsiqNITunmg btsxEf2dK5HznEIPrwe3RUxZLLo 2020-04-20 07:51:07 92.148.159.136 45800 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=435 +p reject 1-65535 +r fiedlerRelay02 t8I2E98lipfS8/qgXszmg+8Om40 oW9qHgwMGkxmZMhL2uyVaLPFKv4 2020-04-20 04:10:11 37.120.173.173 9030 0 +a [2a03:4000:6:757e::3]:9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r Unnamed t8xkxWbqZIZTe6QYeHDi90R2PKU PDG7qwn9r0w6fNpBvdwhmRMMp9k 2020-04-20 08:32:43 5.95.152.140 9361 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.4-rc-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=750 +p reject 1-65535 +r snap277 t9QQBUIa46yoXj9feIg7ElcGwmk b3LnRTA11NeEH19dyhbgXi9re5U 2020-04-20 10:07:14 77.152.155.54 38045 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3 +p reject 1-65535 +r peep t9dz4hlttbQSnTwFDAY9sPjfkaU 9dq5tdxgzKJ0SkoxTNvrQ2/AfWs 2020-04-20 09:11:26 195.201.94.113 443 0 +a [2a01:4f8:1c0c:6f8c::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3200 +p reject 1-65535 +r sebarmledrelay t9sGRcSKLwI7NbUG33h92qug/5M 5b8CU+Gk/5NW8YogDsHxgi9Nvqo 2020-04-20 11:02:13 87.254.237.196 9443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r Unnamed t+Lr++RGL8kI5IAHUXxT7Q/3UrI JqCyc2wiKSeq3zd+wS2D3WY8c08 2020-04-20 11:37:43 37.59.37.59 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=923 +p reject 1-65535 +r aumatbi t+yRCBkoHaBDDS7/Ol/9JpezzBY nh8RdK7hEKmQXOkinlOUXRDKuqw 2020-04-20 08:07:17 139.59.36.248 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=432 +p reject 1-65535 +r piersic t+9kfvZZcmxxYkOoKHfSCqeXjrw XRvyx13u2o3JSo8gZaoTE6I4GSA 2020-04-20 08:00:01 185.227.82.7 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9980 +p reject 1-65535 +r UenoStation56 t/YKgXN85jXnUcW8pnv9INryYVw hI80ukYN6z5QLSB5gvvBM/TmNSA 2020-04-20 05:59:41 51.75.162.55 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r hatice t/jOe/9sbPMIyYK+vxRYpm0VDBU uNcAfEDrW02FLrSckx95kYDrdik 2020-04-20 12:12:28 158.255.6.242 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=907 +p reject 1-65535 +r Unnamed uBI1UL5qOf9+wtAVyGdVUXkHVX4 jamLYchBxYxqBC9wAs85KJMMdxg 2020-04-19 23:20:45 85.228.42.16 9002 9032 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=22400 +p reject 1-65535 +r kroeger uBfGKZ5WUXh08wGeUcJ+W+R+coQ JcegibHkdYwT05Zt5XXFgRn90Zg 2020-04-20 10:35:12 176.67.169.254 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=7600 +p reject 1-65535 +r Harlock uBs4kCvwJr8lkcotc7mc7rA/CGk je5tP5JtcbajZnWwOlQopTr9Qfc 2020-04-20 12:48:19 158.69.205.92 9001 9030 +a [2607:5300:201:3000::4dc0]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9340 +p reject 1-65535 +r anonymousByPDH uByVRlJCrTDEJC+CWs+0P+lRDAQ 1hOLbX7F679hEfJgAKQuGSdyg+0 2020-04-20 03:20:17 188.166.255.209 9001 0 +a [2400:6180:0:d0::e05:5001]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=931 +p reject 1-65535 +r Equinox uCEEeWpxP6G8T2E93Qm7tvXTsmM SgI4f039sPUkje7Uf/3l8VzQFAA 2020-04-19 23:25:07 188.213.28.132 9001 9030 +a [2a03:75c0:28:8f70::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9200 +p reject 1-65535 +r respecttoall666 uCQKTHFaJZXOVMgqsXXIAhR2i0o B9Fw7ekjdidNr6n4fKvavaYWZhU 2020-04-19 20:00:38 83.37.195.165 12813 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=198 +p reject 1-65535 +r TheKrustyKrab uCX2FNZAKzbhuOjY9Pfhw60Mu2A IXOSTBGnG555V2NCleF/yFNpFW8 2020-04-19 18:57:07 70.173.251.218 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p reject 1-65535 +r pumpa uC1UuS/I+YW04/gFKI9hYypdr2E UxOv4UR+Vor33KZdtQ6rrjqPt/I 2020-04-20 02:46:37 46.162.90.13 9635 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1640 +p reject 1-65535 +r mdfnet3 uD3BVY8NNDU7uZLvk6/q/bImpz4 6e8PYUtmZT9JCwcRsnBSvMkglFg 2020-04-20 06:27:06 193.11.114.46 9003 9032 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r RightToBearARMs uEDH3llud6Ihh+Y4xRFtxbO73dE 0ARfA9rJ8wjNP95x2042IYgi3Kk 2020-04-20 09:53:27 51.15.72.159 443 80 +a [2001:bc8:4700:2500::1305]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3480 +p reject 1-65535 +r mj2 uEmCT4/NeusTDfNW9ZK6QMaGygg zr9Zg+h9wzu2Ips3Jy29xopsRd8 2020-04-20 12:23:39 93.115.86.6 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23900 +p reject 1-65535 +r snap277 uEv29H4QloW4k42eNjK+AO7nx6g ZnlWVZWgMSB78z2G3I+uuJmG00M 2020-04-20 03:06:47 90.92.207.202 41839 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4420 +p reject 1-65535 +r tollana uE8kgjP+qQytQ58pJVajE59uG4I Wbr06PW9UJ9bEp7NZ8wUEFxtzj8 2020-04-19 20:39:38 85.248.227.164 9002 444 +a [2a00:1298:8011:212::164]:9004 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49900 +p reject 22,25 +r lftor6 uFRy6n+JsFcsDTpNA5v3Smeylj8 mFh/gaYvX2NyoyKCPDc7Je4+rhM 2020-04-19 20:00:56 163.172.137.211 443 80 +a [2001:470:c85d:32:216:3eff:fe43:e670]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p reject 1-65535 +r BeastieJoy60 uGE3rpaBcBkBxnIOVcFoBbRr2OM KARDwE+iYtVXsMKG1BMGOAyiDgI 2020-04-20 00:43:26 81.7.11.186 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p reject 1-65535 +r king uGqra15/4QPNmGgLz1QAZUBbrmU UsQXewd4BmyueuOqqOeAGLJu6pU 2020-04-20 08:38:09 51.75.175.29 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18200 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TorrificPi uGrZv/ZwHabYVGnEt/czgTdPmLA o5dyyeDWfIVPeNp7puwT01mer8A 2020-04-20 03:27:23 108.18.247.109 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1920 +p reject 1-65535 +r sarahmanning uHK6aATIxuFArhiXtEzzK0L9I5c oyyTkkObf55BIBXLPwUnqKWxZLQ 2020-04-20 02:42:24 62.210.83.207 8008 8081 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.1-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68000 +p reject 1-65535 +r d16329134a84 uH2lQILt+8xqXgVPe23IRBjvVhI CePezUy4j02URgU2E5M3AUpjakU 2020-04-20 07:22:03 51.81.254.14 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8510 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r minestrone uIBcvb6RpeaNJo/GLcYXtb18yec t/rbRn2egE+lbEkPsVWbgPTftgk 2020-04-20 10:58:19 188.68.41.119 9001 0 +a [2a03:4000:17:80f:5461:1fff:fe7c:9b93]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23400 +p reject 1-65535 +r niftygrolantor uJHLY3DPfFHG+yTYCUevt+1GPQA HHWHYhHBOaclCy/UD7kzbs14y7I 2020-04-20 08:54:02 185.220.100.247 9100 9101 +a [2a0b:f4c0:16c:12::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38700 +p reject 25 +r ididso uJwXB6vX6gzKc/ofBtzTQwJy0qE wilFu5RBzI5T8D3NXcnzfea8JDk 2020-04-20 04:19:12 92.222.36.196 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=47 +p reject 1-65535 +r guenther uL8pSOeDBYb2Tukszqv7IC4vv4U RkQOCs0VT9vjXt9tYTa56+uiWmo 2020-04-19 20:16:34 94.16.121.111 9001 9091 +a [2a03:4000:21:704::3]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p reject 1-65535 +r antiCapital uMMkjfMhpi+JMW42mKHg4TeQFPQ pegE5yH39nWvs8jQ9/mhxfccItM 2020-04-20 00:49:03 24.250.185.253 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18 +p reject 1-65535 +r Assange009de uMfVa36Hs5vQh4xdHWkTBZbQv60 SE6hlRiEEX9dfJiRgFebKEJxlXs 2020-04-19 21:32:35 173.212.239.78 9001 9011 +a [2a02:c207:2031:2233::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7300 +p reject 1-65535 +r RudiDutschke uNWWBA7f9n16IA+yidwWICder1I F77S6KbJimJ5p2ORtRddNgTo8Xo 2020-04-20 12:04:27 149.202.238.204 9002 9031 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,991-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed uNZCQ4xE1iwg1+wRHgJw34nSrWI JhFzrNMl8mAhBy99x4/Y6pvRLYQ 2020-04-20 04:49:16 185.100.86.60 19897 28589 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1040 +p reject 1-65535 +r soltor1 uNjgdEjgQF9CdeUohO2c72P+5KM EmI7euZz59Upvup/IVG0NbaR1lU 2020-04-19 22:33:02 206.55.74.1 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=500 +p reject 1-65535 +r nameless1 uOUUrdxlPWHeH8tnghuwMDd4eC8 eS+vCSLzRMUMQyNL1At/E70IQlk 2020-04-19 20:44:51 64.137.169.72 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17000 +p reject 1-65535 +r Unnamed uPbmiza+4r9Uh1C9zMPCp9tWpiM FYQS4eyv3r/LgvziAxsxwxihAc0 2020-04-19 23:22:22 51.68.182.30 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23300 +p reject 1-65535 +r scratchingnoises uPexYpYyh9IZnQdburLE+5Qbs5A r2z4Cl5SLJB5+SrtxGWI11rpscY 2020-04-19 19:03:02 83.212.75.10 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7930 +p reject 1-65535 +r bauruine51 uPkXRInLz4tKvKelOGd5VBSMKB0 NNDGeYRcLtUjdvE10bNhwxyxKUw 2020-04-20 12:07:27 185.204.1.239 443 80 +a [2a0c:f040::f87d:2fff:fed6:f80a]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10500 +p reject 1-65535 +r arnspringer uQMJ9vn59GNVJgQJRs2ux9vzojE dCgOifY0O4w+NZVkjTh5kCnPDy4 2020-04-20 00:51:25 103.234.220.197 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=90 +p accept 20-23,43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r TranTor uRjrP6TQOk+fYyqhfyF6bAQETvc 3As5dHDaAhpHOjvziNI6i5hKRyw 2020-04-20 07:09:30 185.117.44.41 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p reject 1-65535 +r Assange008fr2 uRoesw5m1SAm780elr/A6WbIPm0 +Mjgi/VAi50apZbSzboymT+yOC0 2020-04-19 19:37:00 62.210.105.46 9201 9211 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r darmok uSPRXt9OexJhh2hg1R+rkH7Rg0c WrT5EBt2emV21XSvUC8hXYmgCB8 2020-04-19 22:28:21 51.15.9.152 20443 29030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r mccorkle uTJPG+2x32Ku4hmwzEFQfOcQujw 5yMt7qCf+iyKAzbhZtRW/dGcmFs 2020-04-20 11:04:32 37.28.154.68 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3780 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r angeltest30 uTUD1FjZ/pfeXBLSEQgocdCPEoQ LaLhQ9DG/EZnYvjgxgc4vQaJXoo 2020-04-19 21:53:31 185.4.135.157 443 9030 +a [2a02:c500:2:217::e528]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7040 +p reject 1-65535 +r cathode uT4E63vBsFhZOkA0gsHfi+dmccY UXl19+ScCxTZfUIPuX1ffoq5ieE 2020-04-19 20:16:14 162.243.72.198 9030 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=135 +p reject 1-65535 +r podeaTorNode uUCqyULpkp5nPDUz9RDFJhtQeQw FGd1M0eR3OKVfNOjX/zMF3bEsK0 2020-04-19 20:38:26 85.214.253.107 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8960 +p reject 1-65535 +r MightyMasturbator uU45RU2Ot+bcfI45+Mi43MoAM8s qq9xWmE4ycBDgLOOIjXQBIHhYZ0 2020-04-19 22:04:44 109.229.210.6 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=272 +p reject 1-65535 +r vandergriff uWCRB+JbyngD96LSBc6Prj9Qhs4 VTEpHCFRP/8rZValdHacoeyOsFI 2020-04-20 05:54:18 185.100.85.132 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4280 +p accept 53,79,81,88,110,143,194,220,543-544,563,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r 0000001dxx uWCWJOJscFKJ5X+V4w/YjRWb2K0 7Eo+aNSN+0Qly40+twXDQtKu8SA 2020-04-20 01:42:59 78.159.99.85 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=710 +p reject 1-65535 +r Hooyah uWmqFpjztwIK0ulxswBq0xmZbiI xMooLU9LyWqxVB+qnPzjU3is/nE 2020-04-20 01:54:06 72.192.130.40 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=710 +p reject 1-65535 +r brokolimc1 uWot8cI9+RadcK3gmTvQAzEfUdo G/MoOuK8e4jcGypnx9iFUHtVcMA 2020-04-20 01:51:02 87.174.115.80 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=300 +p reject 1-65535 +r torreybus uWtRQQBJlSlf6H3M4aVFGb0LtIo cFyE7MVmxznR7lxe/7XIgaEOS/w 2020-04-19 23:54:07 139.162.195.69 9001 9030 +a [2a01:7e00::f03c:91ff:fe58:9e8d]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=87400 +p reject 1-65535 +r snap277 uW9eZs2vWclGMuAMZB2M7wYlAaY 7uJ5fD1sjCc07JHHutxAVHVv44o 2020-04-20 08:32:58 210.253.32.99 42589 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=183 +p reject 1-65535 +r Zion uXRCGqRqsahFURARMvOZSw5s20M 6Cz8MF77bL4N7iat61xJICiyZTY 2020-04-20 11:54:54 131.255.5.192 9001 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=144 +p reject 1-65535 +r duckgo uYd8ep6tdDnBhra0wohWEro3mHQ wFGUhstUmEJcmfaHfpwJlULsanw 2020-04-19 23:37:28 185.165.169.222 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7700 +p reject 1-65535 +r snap277 uZBiCK6nEXQkA1FP4LJEwRciqYg 6qUaSv+dmRSMNgnVnr8R+XCQLko 2020-04-20 06:08:46 86.214.191.132 41433 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23 +p reject 1-65535 +r mobbingsyndromde uZYsGTrkMT1iXpv7lBXEMGIU0zA u0pGUXiE2/Lr3WPC6ni3K8ZdJ+c 2020-04-20 04:42:07 176.95.148.103 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1860 +p reject 1-65535 +r dlxuk uad+JeRPy/fHKPZ/Y6HuFOqTJnM WSvp9mDCJBb4TqfLYL2nP8HyZr8 2020-04-19 19:23:54 81.17.60.149 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=932 +p reject 1-65535 +r king ubO2ux2D9TOHpySkzjuaz1devqI 7B783c/Nsq81xPzDX53NLQINRTs 2020-04-20 05:59:59 51.89.213.83 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r pangea01 uc8QT+MMyYfQpf9yV3DRNOvbF80 WtIBGN3DeYpVr54ypzxhKaHOVJA 2020-04-20 04:06:32 46.167.244.59 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1610 +p accept 43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,873,902-904,981,991-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,5900,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r Coutee ud5Xdx1yI4oNjI0yaaJVukSEE7A yxNK8F5eytHHbIgUjm7uUTxCRMo 2020-04-19 20:29:26 87.120.37.79 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7510 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 ueZB6hkeD8xn12V8Lzj2dlPcR3c fya4/9LrVgBSd+zR/HqnAjqggOM 2020-04-20 12:22:22 2.85.222.222 33019 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=264 +p reject 1-65535 +r theykilledaaron ueemN7ALu3eFOmOcwzJFov648DM /YO59ENNgraAMEvqsLU9rpzVpVU 2020-04-20 04:17:41 84.227.76.48 943 930 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r asuka ufNiNpAif8/bDX1jqhtuPMSnQzg afjZTyBsffyau/27S107oBra4i4 2020-04-20 12:27:57 46.4.144.81 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=173 +p accept 9001 +r localhost ufQ2fNYbdVJpRneCk0SC7WOQSjE o2CwWICiwWPPu81LyrgryBfVQBY 2020-04-19 22:51:08 85.17.65.39 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=42900 +p reject 1-65535 +r Unnamed ugBxq+SlvqZpqFJMHNim7rnV/Dk ++5NUUc1UulkQ2JyRDU1cfV4N7Y 2020-04-20 12:39:41 188.226.154.180 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=733 +p reject 1-65535 +r ResistAndFightBack uhLO8Bax0eqTq5RMTuytd6s6bd0 vKw+HDnzZHmMSzBa+5dii5y9GUo 2020-04-20 02:30:18 37.223.79.175 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=79 +p reject 1-65535 +r 0x616e6f6e uifUOsAPAUlF3DLQNgVvE/4dUkM pgfV4eEnXYfu6ErdyUAXqa8EfOU 2020-04-20 03:29:14 185.82.126.238 4443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9400 +p reject 1-65535 +r smell ujRdu93KnrfJ7AiwKGy36fUTM3Q glCTsVV3ZgKWkT4dJjl6bOONkcI 2020-04-19 23:41:36 209.141.58.170 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2400 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r UEUEUEU ujSJAbxqD+TahsU0M0FKMSSTT88 AQvJHd4eTACMJXwDKZi5lLjh9gY 2020-04-20 05:22:45 65.50.203.5 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110 +p reject 1-65535 +r snap277 ujf0kSTPCiaIX4gaPpnC1LqpXDc w5Uy3iMndcRkGFWRzxmDtGw8QmI 2020-04-20 11:25:09 70.55.29.240 41429 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r geek ujjFaI4QOuEfUNcYjI5f20sOVVM IAcXKMH01NsBk/JWDO5EJ7R9Fu8 2020-04-20 09:16:02 51.75.85.114 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11600 +p reject 1-65535 +r Serge ukSoieZLk/qisRTgLConmoVVxTM OANMx8Xlg1uBFjrq3sNhhzF6IjQ 2020-04-19 23:47:49 66.111.2.131 9001 9030 +a [2610:1c0:0:5::131]:9001 +s Authority Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r dattor ukgaPIBEfvtngRk43dObH3nhwG4 5JzE38brnBZMOJWUBPVaBXwXf6U 2020-04-20 07:42:13 137.193.65.224 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1710 +p reject 1-65535 +r Unic ukm8sM9gmnrW+atm3Gq+rAsac70 D0lAhlksImct9izq1ygP/jujYQ0 2020-04-20 12:28:00 5.8.16.198 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r snap277 ulbpFZ9D9zhvTz5tF5FnPzRm7dU 6XKMjej0Uz1XxgbKCrLs017RClQ 2020-04-20 05:53:03 116.75.221.83 44289 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23 +p reject 1-65535 +r Unnamed uliBa0/kBSQu8ZnmjXCwDbKuVHI FEeX5e1jiRgcvb1tgsGWyEU92Zo 2020-04-20 11:09:01 95.217.212.154 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8070 +p reject 1-65535 +r KienjochMo2 umGx7UEB80FiJITBepu+DsW3C/U 1OTfUrD9uTgrTrGp+bBwIfVz4vc 2020-04-20 06:24:39 176.123.6.13 443 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2700 +p reject 1-65535 +r Zen0xus umVY6fa5f+vsA3FCMPmqkSjwwZo zxl/RjTG9/ruQlcdmM+TvzMRERc 2020-04-20 10:33:37 92.206.109.77 9002 9031 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r Unnamed umlLi9raClLQDi+uigAs/TlKmgw nPP7YNMI908gBm/Jh/GL64qFuD8 2020-04-20 06:37:42 185.186.78.194 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8750 +p reject 1-65535 +r smell uppgtJhVzXekVSW/IBaV7cgWXbI w9dtthGPRTgwtzIGgvSYegr5wj4 2020-04-20 02:03:46 137.74.153.9 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8190 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r MaxWerner2 urvntnAQJ5SRoaC1zyAbhe2z2No fkbm3koq8dwOSKbZPDEvHCZ7O6o 2020-04-20 10:57:52 185.183.159.86 9001 0 +a [2a03:4000:1d:8db:b89c:50ff:fef0:4ba8]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18200 +p reject 1-65535 +r Unnamed usInPz+blV2rUIK9KIqHutHygGY xyIjyNs+r5dP2nfRZ/REPTOqRhE 2020-04-20 09:30:59 86.106.131.136 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4040 +p reject 1-65535 +r rmblue ustHQGojGrYOwz0e1QgcYDsgllU gPgCYQljnU/0cgdGYnh+zNXRC34 2020-04-20 06:51:59 178.202.156.12 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r DarknSpace usywdwWxur5cGxq0jiPZz5923us lN++j1nmElbp3fRGexZHHmjrPFI 2020-04-20 11:54:52 89.40.13.217 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18 +p reject 1-65535 +r snap277 utBBYAGNYfF4O84gp4YZvKvGQJ4 SqJwPfRnDlnIyomjwCDCK59/EYU 2020-04-20 03:30:10 178.140.23.77 42721 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4360 +p reject 1-65535 +r smell utf4ZLf+3M3bAjGFg8vStggjT8A n8WdSyWRvxcUB7WgnJjyJbqByr8 2020-04-20 01:27:33 205.185.113.30 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Unnamed uucLWmGxKj0x3ulOaXrx/ampuC0 7ZDwodP9zZNXIEaHGmTj2LQnRfs 2020-04-19 20:01:45 71.105.118.143 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3040 +p reject 1-65535 +r darkwizard uvIj6d9i0yYfFnXGz8Tl1Q8V+lc 7Ju2PiU6xmyaNO3Oynl5i0BPERE 2020-04-20 08:27:27 62.171.137.169 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p accept 706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,50002,64738 +r KomaKabana uv82KoMZ4fif5MnzuKFzTi4uMqs C98BbiykFP/EJqKGepQLGUZAdaY 2020-04-20 10:39:35 85.216.10.239 9010 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=133 +p reject 1-65535 +r Unnamed uwBMf0xcn65eABhkU3+JOIRE9XI /uVOzVOtzaWNVV+5lKi23oj6wyk 2020-04-20 07:08:34 37.191.202.95 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13300 +p reject 1-65535 +r lebowsky uwNgYFC1d7UD9Mhds9SCGiQtmo8 a94JmJmzekAfB+4jA846fFOz2CE 2020-04-20 10:22:16 178.17.174.2 80 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3150 +p reject 1-65535 +r tortellini uwdJ1ZRmAoTRQJKhbQ9u7JDUqxM JFFTpyLOVUozAUrNcNLvb2UIPfM 2020-04-20 04:11:13 68.173.30.167 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=888 +p reject 1-65535 +r 0ZQIX7g6 uwxjbeicrGyZXLOAqsjEqqtzG6g 0HEfjt28Pnh1Wxt11EwXyWmLAG0 2020-04-20 01:50:12 77.37.142.179 9749 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3790 +p reject 1-65535 +r BestRelay666 uxDJYWz8inznnMEuMmil5zkMNSE XFtoWuXRnv0xufQOJZNfwEL8OTA 2020-04-19 18:51:59 194.5.250.84 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58 +p reject 1-65535 +r Nonus uxedxcg0NhahYcMV64sZdcPDruA CezNApVAV2bNjjjrCe/q2EIf9Es 2020-04-20 12:14:01 89.115.186.17 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r snap277 ux+aznmIG+H+g07lC8cpVKJxKW8 FvcxcvKJAatqS10aA1bOog48F8g 2020-04-20 12:22:12 84.54.187.139 40001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1700 +p reject 1-65535 +r jmlsteele uyZN0adonu1/iviSung/vMZrNjU EGEQFjX4mYjbeI5o1FLg29OYyOc 2020-04-19 23:55:08 198.199.86.155 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=750 +p reject 1-65535 +r Unnamed u1EpbyWBG/FnwxM9m5xEuYYKOvA LJwsOt0PVq+kF+cGUCJFNtpElC0 2020-04-20 07:13:30 198.27.69.36 62942 55891 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=150 +p reject 1-65535 +r Assange010us u1YwlnYH2Ki2yoVK+VT+g3LRZio 7b38RH/K/wjTiiSZFrzmysC3Ahw 2020-04-20 00:59:23 147.135.114.245 9001 9011 +a [2604:2dc0:101:200::2d6]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7200 +p reject 1-65535 +r verax2 u12yGpCgIkbbQ+pGXT4VhRc/G9E mT+v6Vy6QB41CEnPvNO5RAqdwZc 2020-04-19 23:25:56 146.185.141.163 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=807 +p reject 1-65535 +r Casper04 u2D1uhE6C4tEt7N941Z/5WHpL3g dFJ/NMabCfHgxbnfE2BBQkh3zCI 2020-04-20 11:11:53 51.15.179.153 995 110 +a [2001:bc8:3fec:500:7ea::]:995 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8630 +p reject 1-65535 +r snap277 u3cxdfmLXyYv+wTxPnTmudDPHmU sVj5kgU+c98lDz+Wdq1W/Y10Jz0 2020-04-20 11:36:02 78.192.221.75 35163 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3460 +p reject 1-65535 +r cybercybercyber u3hZ0WkB8qZROuVR6x8SgJAELfo zJ7NXZjnULAJQ8R+4uVlg6Y91CU 2020-04-20 04:09:56 172.107.96.70 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=44000 +p reject 1-65535 +r thorus u3sCw+19V1qe6kShCmW0qiicEEo kGAhl8L4tHplx81lFMWACBJ/o/Y 2020-04-20 09:23:58 217.82.110.196 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r onionmatic u5xdFbw7d8ivXLxzP35UVTobe9U wuOnKY/BZ6hzJHB2XtQxWhVl2/U 2020-04-20 08:14:01 216.17.99.144 443 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r king u6PqrUXOu1L+teNuIfbJ5+3dZWs 4EPrdmjraQVsLFYzsooGF4sfLPc 2020-04-20 05:25:33 51.89.200.105 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16500 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r 0x616e6f6e u60yHWgsatppnNCDJpz7X7cc3uA pk79mfSLBTpH1fuOeYcwQamq2bs 2020-04-20 10:27:40 178.17.170.91 443 80 +a [2a00:1dc0:caff:b5::c623]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5120 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r motor u7u61FMmPXhuw0q2igYhQoiRA0U P0OORHdSjlCpUPDVXHM7juA2YTw 2020-04-20 05:47:01 217.82.116.18 9321 9322 +a [2003:cc:6f06:4703:bbbb:bad4:5326:3d78]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4890 +p reject 1-65535 +r Unnamed u8MqirkXzwHWnmAxKzQVlNS/erc dmLli88dVhuVIjEGVDvWNrC7H24 2020-04-19 19:35:01 167.114.92.48 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Blazkowicz u9GxoiaVOWx13/M4qP96EoBKYHo yFL2iYep5HUd6KTbP2s3kSwEwgo 2020-04-19 19:56:35 178.162.194.210 80 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r snap277 u9LpbLT9yOzrz9hZ/KxYU8ercEs w+0WxIoRTlhDDDNII6uyq9QAyaA 2020-04-20 11:56:30 90.89.111.154 34183 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=827 +p reject 1-65535 +r galqiwiRelay u9bdATrMKserHpi/aAR3lVuHLck Yhpi1TIl1nYVVNGDa8eSHFmmRoE 2020-04-19 23:09:19 185.5.248.186 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8380 +p reject 1-65535 +r sprucegoose u9j034/1xppqmJ24we4sp63+B1U mEVinWksMzKuChMoozQbpeiIRmo 2020-04-19 21:48:48 66.206.4.26 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12200 +p reject 1-65535 +r NovelThunder u9m64RMPnzPy+ESaLtZ/mjaFOGM yTpVwjXWnsjlxzhM45BiFxOfiWk 2020-04-20 11:46:16 77.58.201.132 9002 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=591 +p reject 1-65535 +r hanktor u94SwyD9HD/77BUgL0bVYg/BRE4 NcaFtXwKTIhw8iWn3uPEyXWkhA8 2020-04-20 10:28:43 178.17.174.79 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r partofswarm u/h2PFUfh6HMy2ZSu8CsM2v66i8 yEuetC7CApCOwJh6GQmlMoVRLBY 2020-04-20 00:01:00 82.196.11.10 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=760 +p reject 1-65535 +r MaudSuicide vAS5KXu3YSsCFiQMCQ4Nb1vma2c qrCCauzdQW70nJVTeViDXT/woLc 2020-04-19 21:34:18 139.59.36.56 9100 9101 +a [2400:6180:100:d0::40c:e001]:9100 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=671 +p reject 1-65535 +r franksToeKnife vA3qFrlrsQbUUtpegAHLUZ01ong 9DBE4+YIgbm/PyLtoRK3rHqjpzE 2020-04-19 22:47:06 207.154.217.3 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=287 +p reject 1-65535 +r BlackMesaAG vBI9t/YenbMfI7N79ioW2qEBD8k I/txREM4EB1wqOw7+EvpFXYTTa0 2020-04-20 00:01:10 85.215.88.244 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r partybus vBb4u7/Aj82+qDa8OF7aVn0joX0 5LTghCDz178f1JgAIKdq1aLvQj0 2020-04-20 00:42:34 213.139.206.28 9100 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 22,25,119,135-139,445,465,563,587,1214,4661-4666,6346-6429,6699,6881-6999,10000 +r OrgnicCcount vBcNbHnrCe8XGTRmCX0cd4gDGj0 NIYePCCYIGe9MCT4IcsyVnvuWlE 2020-04-19 20:01:24 47.56.94.159 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r gh0stx74 vB3W5cdT8blGwE3++L08kEIGfs8 ywvfm8XI1tvRsSBUBY1RhXhsBIQ 2020-04-20 12:24:27 178.128.93.82 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=494 +p reject 1-65535 +r h7nOq vCBmZYA9t8cwwloTFoiaTX57/wM 8fzRt6y3J09GdjwKuMcyTsJQRHs 2020-04-20 05:00:54 85.143.214.143 20 21 +a [2a04:ac00:1:8a99:5054:ff:fe01:3103]:20 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3700 +p reject 1-65535 +r node002sln vCONoQ9CfCFoX3ZjF/fglGlUuI8 nkgxk8tNRVqTCM4M0Y8H6dYUG3A 2020-04-20 10:59:00 62.210.72.150 9443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40100 +p reject 1-65535 +r niftyguard59 vDh0T9gmGLN+5qWmG7zOh4jVXj0 IUq2+ecGEE2LBKVnfYuTXQ9frks 2020-04-19 22:16:42 185.220.101.178 1178 2178 +a [2a0b:f4c2:1::178]:1178 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30000 +p reject 25 +r snap277 vDo9Q4sgqBAGYhTKDxUdclaFpg8 qdBFMX88ZTBra0EbOmVihvjpogI 2020-04-20 12:16:15 170.231.132.77 43343 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=95 +p reject 1-65535 +r WindfluechterNet vD/LtNps+54OB+ByknNOJPacNus kEV7ODObQWaMBEdFsMCGowwpYbQ 2020-04-20 12:45:26 31.172.31.207 9050 0 +a [2a01:a700:4629:207::1]:9050 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1380 +p reject 1-65535 +r Unnamed vEi2O2jtwBiHbPjdeQXtPK70nkU wCcxX5NSFC8c+AgX+35L6mkuFPM 2020-04-19 21:51:28 103.205.143.115 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=125 +p reject 1-65535 +r fs0ciety vF8AtXPSd8S/qPD7qkfgdNCZTBw RxgRtTe+9A7cWtszZMAoX9WE/ng 2020-04-20 03:01:15 81.28.206.216 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=912 +p reject 1-65535 +r hviv119 vGRQNmTJC0qdqRNzbDYd6tMTsTA JGKvRGyMMSDk7xlvheGUSgTcX9A 2020-04-20 11:42:23 192.42.116.19 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r A1RUREADY vGyW5HxGyNSWU7LiPZouphfIK20 3HZMLReeg1fcwzq6MPyoDOv1/Pk 2020-04-19 19:55:08 76.204.63.172 9001 9030 +a [2600:1700:840:c382::3020]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r Traumflug vHHdktU4cw6sPryPJ5LIy/Ziavk HmfngaPBIYwfHSF0vHlsUGSfX5I 2020-04-20 06:36:12 109.193.51.152 443 0 +s Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53 +p reject 1-65535 +r smell vHfExvh29uakuuOVSQvfaaHKV7c 2nbje5dRRcVcfUeGJSYIx+knVNI 2020-04-20 01:20:31 205.185.115.162 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r YagaTorRelay vHrPrASFTHcWfH1mt+RxMU7YxBA rSC6NyP5wX3VBFd6NmHBUmAmO9U 2020-04-20 09:27:49 144.76.75.184 9001 0 +a [2a01:4f8:191:93a2::4]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12800 +p reject 1-65535 +r freeAssange vIBpvpsIQ8FxCBihUFXZA2Vs7OU 08QztJyN5reWz/P8d4BwVzJiFbs 2020-04-20 08:43:35 88.217.140.222 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3 +p reject 1-65535 +r deluxconfig vJNaXiL3ZnZhQvf1d0CLrZBwgE8 GZtqn+fxjqzi8sVei3mOnHspPq0 2020-04-20 10:36:10 38.102.20.41 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r oenx vKNfcMsOelg/xuy4P3VbCD6eLfs snxEWcX5WvjeqdmW0Up5LbNGdDM 2020-04-20 09:52:55 149.28.183.149 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=302 +p reject 1-65535 +r REDACTED vK+ZcVybZ/4JiN18SwfiYuiYoKI xJ0nJcOigGZCNRW8Vh4E0rBPWPs 2020-04-19 23:56:43 85.119.83.78 8443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r Marx vLasMDppp+h7stbz8ToMDwpsk44 NwI+U73S8bWawUe0mNk7iP5Xsl4 2020-04-20 09:10:26 217.12.223.227 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p accept 53,80,443 +r SympatheticSuit vM+4TBhhCSIVx4yCK0CUBg9Q6yQ pJoWQp+RjnGHc50fqnLe91aDo4Y 2020-04-20 01:59:53 213.144.156.186 9001 0 +a [2001:1620:bba:0:96a5:35e8:267b:858a]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=629 +p reject 1-65535 +r rillette vNLwOfyLjx0zdC5y4V1xD3d/Zk4 NKzI+Mv3eb9bo4n7B7HGRyrOip4 2020-04-20 03:20:16 51.91.100.49 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p reject 1-65535 +r niftyentry117 vN51cluSdzi2/TTqLXj0+ne5mEg s3QXaJMTxZ7oF+pS1cpOkDUh0tE 2020-04-19 20:26:11 185.220.101.117 10117 20117 +a [2a0b:f4c2::117]:10117 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23200 +p reject 1-65535 +r MyFancyTorRelay vN8Qdc+BtjbKlE0Daau8jvEuI4Q Ks00xqg3KvMJWOBWjEeS9DGWS0A 2020-04-20 00:00:14 192.145.45.56 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10800 +p reject 1-65535 +r Unnamed vOD95oEXN1vzdAjnYcub3iYTgAs CVPn6PBvl76Jf76Rb0iBITxIZ9c 2020-04-20 04:39:44 165.227.161.60 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=944 +p reject 1-65535 +r 0x616e6f6e vOKFESBZXnbjFkVjP1/0dx0gl70 c4L1oju5Kb77KxDmFlE1+oUr5VQ 2020-04-20 00:00:39 178.17.170.88 443 80 +a [2a00:1dc0:caff:ef::96b8]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9890 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r MalfunctioningEddy vOhkFbLsKORJ02D2MmR+ldCPg8k dyYBWajDhGbz9c6427AFl+ViSM8 2020-04-20 00:30:57 98.217.124.239 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=884 +p reject 1-65535 +r gurgle vO32wZOqaHrkcbiiLr9rxXwtKF4 1hZc14THFJqBVCGuULeF3f3Sezk 2020-04-20 10:35:07 198.96.155.3 5001 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r EldritchReaper vO+QgZWAXgPpLM/macSHOOVWucU QglLqhz2VBi73xkS8qXe2Ii9V0U 2020-04-20 07:59:57 128.199.55.207 9001 9030 +a [2a03:b0c0:2:d0::158:3001]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1210 +p reject 1-65535 +r DigiGesTor5e1 vPVfhl7m7xfiXv6vhRvEKfGQuF0 FNdJ8lgGWEOF2bxhkCe6WCGptZU 2020-04-20 06:45:22 195.176.3.23 443 80 +a [2001:620:20d0::23]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r metricspace vP5UjqP/igs2EHecI4NQEkqO1t4 M+DA/+9HJGYWxONarYEw4ndGD3k 2020-04-19 22:34:19 108.31.38.18 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27 +p reject 1-65535 +r pluto vQINjts1XFNxmUIKryZJ+gRTbJo 1xeSSJVnvwDxksJdeUQahnP6+lw 2020-04-20 05:27:27 167.86.127.130 443 80 +a [2a02:c207:3004:406::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18000 +p reject 1-65535 +r snap277 vQLQlsiuHFDH6BQ9WPrk8GbwFEk VBkPVDOG0NjIMLHdqO2RHyOXhvM 2020-04-20 12:17:17 84.253.245.202 40597 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=861 +p reject 1-65535 +r danielsrelay vQLynsjCl0WxDO78OYFbsMjWhaU ZYtQNbeTweHudZtcX7T1SAJ13r8 2020-04-19 22:18:44 62.171.133.250 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16200 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 vQsfx1xxtDyHwKPEFkFFKLbeED4 lPMHOV3jTG6nKpiqtdvAAuxJMtM 2020-04-20 09:24:01 92.88.13.208 37061 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2130 +p reject 1-65535 +r 787atxdotmeonpi4 vRh88bRKhOx90bwqycT33iPRZhk bk3Q1vbQicxPIS1ffX08L1nYFGI 2020-04-20 04:05:29 72.48.99.187 9002 9034 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=410 +p reject 1-65535 +r Megatron007 vSapL8ZotzVtAsaCCx4QzQIJkA4 oQwnQHR9L///XI/M69dDADlMxpc 2020-04-20 08:14:29 24.132.56.47 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=78 +p reject 1-65535 +r TorOrDie4privacyNET vSo0reTmA6Jy+q0jrvOJgBuyI7s 4ZAWVrRNw3VWVUA9jFN7m6OC+ZE 2020-04-20 03:51:45 37.157.255.118 9002 9031 +a [2001:4ba0:ffff:15::3]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34300 +p reject 1-65535 +r EdSnowdenIsAHero vSyq9sqYLYsL9zx+o+JD8wrp8EI s46kkNdb8DeGKPtj4f3h10wmyF0 2020-04-20 04:55:45 51.15.113.200 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r netcp vUASt7BeTglTrkbvTY4mXnmxYn4 JEScavFIJf5Wu8b7T6LjLbSZ8+Q 2020-04-19 20:40:20 5.45.97.225 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=682 +p reject 1-65535 +r donate4Crowdfunding vUFyUzw/cnGrzNnwV+Bv2RVHxCs dsmjEnkZYELVCt0tjMwv1wrNOsk 2020-04-20 11:32:09 193.161.193.99 25565 80 +s Running V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=1 +p reject 1-65535 +r mkg20001 vUOVQMe4Y2e38nnJzdS9YBqFB4c Axyt9MC2DMPIk40W0F0SGOtnL/8 2020-04-20 00:09:32 138.201.254.83 5235 5236 +a [2a01:4f8:173:2552:beee::f]:5235 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=981 +p reject 1-65535 +r regar42 vUxkdQgWL1nLROTfwcKyuKk4fMo YgiD/ylyckjb6eQW4fGLYvEs7f4 2020-04-19 19:52:19 62.210.244.146 9001 9030 +a [2001:bc8:3680:4242::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=73500 +p reject 1-65535 +r LDNtorflashLDN vU1MiHAo9OXbysUYLfilppJP4AE NLr5GrQZh+7e9tt95Qwx8FOMTQo 2020-04-20 08:14:21 92.40.26.191 443 9030 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1 +p accept 53,80,443 +r lab6hourietcom vVIfeUuvbCm4QXoIMoPRIOdYNk4 YxIsufQn6vqfpVuNzRWKAzUnjbY 2020-04-20 05:52:49 165.227.136.69 9001 9030 +a [2a03:b0c0:3:d0::5408:f001]:9001 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r Schakalium vVUsFl4u0oh9PxzOnP8VXdothuY KIIJSmq4tjXh1XNVxKE+pXZWhyE 2020-04-20 06:03:12 213.141.138.174 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3320 +p reject 1-65535 +r HouseDimir vVahw2GW7paLKjRjzNZAGbTlJtg IdTdch+VG70WpVbnnOcIPxbmcFg 2020-04-20 02:20:55 82.181.91.118 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6810 +p reject 1-65535 +r maatuska vWqCklXLCOZvvn03SDY1huRrOBA 9YF2fGdqcJnJLmr4lqxau3/2DxU 2020-04-20 07:16:26 171.25.193.9 80 443 +a [2001:67c:289c::9]:80 +s Authority Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r bonjour2 vW//GtWoio1Dhw1D7ERQCBtLK7o C1ABwRshu4ljr68QDk/FL4NC8Eo 2020-04-20 11:16:34 188.138.33.149 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37000 +p reject 1-65535 +r axiomaticbsd vYFVwI/cRGtnGR24GovUTlNWdlA etLtJyFuvru9JU+EemnvwHNkyKQ 2020-04-20 03:00:50 205.185.125.145 42204 32903 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=314 +p reject 1-65535 +r MegaTOR2 vYOajhjpfghEMNk0K5S1Z2+Bo3M GQU+7uoKca7iZPmQcKxcdIf4cZM 2020-04-20 04:44:15 91.220.145.100 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2120 +p reject 1-65535 +r frigg vYctC5tHrwD+tE3KIShiv4WtZmY jY/XkubNRfCnGDFWdAbGLtoU67o 2020-04-19 23:22:18 185.134.28.79 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=919 +p reject 1-65535 +r miou vZO+6MUcEpI1Ngp512zmJW/5lFM eIS4SeGr6iIZiUL5DDHitqxqfdY 2020-04-19 20:15:39 119.59.110.192 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=280 +p reject 1-65535 +r GaladTor vb2UL+g++BQ/1vvlJLtTa+eYSsM H3befp0JCrIU/mUvttjq+7ZU0Dw 2020-04-20 05:20:42 77.180.67.152 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1070 +p reject 1-65535 +r cragg vcEXTHlLVWxHt8zmH/5l+xZye2w wQGmOVccKkn9qfs8Ze5BPDeWHsw 2020-04-20 09:07:48 190.10.8.50 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=140 +p reject 1-65535 +r GIZeStiC vcUm2igPoARLhMXrLcCmfJvhK6E bbNA7dSy2pe8Yk8ATUpnAb5vJ6c 2020-04-20 09:01:00 198.72.123.109 1220 0 +s Fast Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=249 +p reject 1-65535 +r ibksturm vdlLvH1BRHFEgW4t0xUMO/nW2UE 3Piihi1TZw2u0ICP4U80sPk1kdY 2020-04-20 01:49:05 83.77.85.7 9070 9071 +a [2a02:1205:34d5:5070:b26e:bfff:fe1d:e19b]:9072 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5300 +p reject 1-65535 +r TPRSVM01 vexWW4tePcy1fk58TCRe2nF9IIc NGHO9x8gEBRQ02q5YQ3jO2ZgRfo 2020-04-20 12:16:05 193.36.116.234 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r Endernet vgH8K+hKO7wtOZnL+olnvaQwM0Y Oy3XtBhKHwh0liB0KhFTd4yqQ1o 2020-04-20 06:03:31 109.108.241.143 9001 0 +s Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r spinat vgrDtmkghTCMp2b54Dc20cqu1vM qngmzqcoFza3vuadVDUHjiIUo30 2020-04-20 01:16:27 109.70.100.18 443 80 +a [2a03:e600:100::12]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63600 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r 123456 vhwQalcOxyRAFZ6tYZLXYaLoOow uhDyXvuXll2xfJABlbFHY+dkVGU 2020-04-20 04:18:28 217.246.131.219 9020 9021 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r ZogZog45 vjlOKNznyuGPqfGDIXceIQL59dE meRE+pYUjPX0rj7YNK3+TbI63v0 2020-04-19 19:11:14 90.46.62.49 9003 9032 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r HeeJin vjuQJKDrvnL/ISl5+2lfxhF+HvU lLlWdUDAjTJ+B1xYG6C/riDyZII 2020-04-20 12:41:18 223.25.69.206 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=605 +p reject 1-65535 +r wewillrockthatworld vkN9zejd7bnu9lrO9IrDonYwv7Q rEGUg3iKieHWp+d0RskYQGQM7Lo 2020-04-20 00:43:06 78.46.64.245 9001 0 +s Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r ClubHorizon vk8y761ZGTKWOguocPkTo8v+3T4 dorYD5FV4tkJPBATk2OVVF4kxtE 2020-04-19 20:14:11 103.9.76.92 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r TorqueQC vl0U8Ad+fKM8nI01eoyeXxj7L5A 0/gppzOcV/hum8L0yNbg55HY+MQ 2020-04-20 07:08:42 64.228.189.121 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=504 +p reject 1-65535 +r VTR vmV9XyV7iaFqJzDaY2NEO7IPLSQ QxO9bOF+MFzgHgK3ztUbjaR5ltw 2020-04-20 12:31:47 80.108.230.166 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5510 +p reject 1-65535 +r albin vmzyaBS9HzW3b+V2cC26lifugjc 3WYTcsw6G/vNmCtspS3ovjvcZDU 2020-04-19 22:18:53 141.255.161.166 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12700 +p reject 1-65535 +r king vn27xW19h3JdI4JMOJqoOBaFIlQ WO6hGGE0nIA/J5ewDGcyAGL/OVU 2020-04-20 08:34:10 51.89.200.126 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20900 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MountainMajor voX5Leym7n0GeZdhnQ1/TUH3mdc UvltqZfPXrT+RqpJTrtv3kGZwBw 2020-04-20 06:59:46 216.239.174.171 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9970 +p reject 1-65535 +r Datalove voc3WX8ua0+AWJMgLJNRJYKakC4 cCDN3FqrQynovD3+QvlauXVpAdU 2020-04-20 01:48:21 78.194.59.118 9001 0 +a [2a01:e34:ec23:b760:5604:a6ff:fec4:58bd]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34600 +p reject 1-65535 +r fuckdaP0P0 vpsS+qt0KYQtZD4jCDkOzYlh4KE RpNkNppUJy9eVh2EqaX/pIrfqm0 2020-04-20 05:22:47 136.243.131.46 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=98900 +p reject 1-65535 +r AmansAequi vqfAWOzSe+jnOnbL4TqReoMZJoU 6q6GQhn7aXPej6fPnD2NZLogGyk 2020-04-20 08:34:24 85.145.193.79 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12500 +p reject 1-65535 +r sucuri vqhdEAZY9xlR7DUvrkOLYXkzbE4 fDWArlLBwpVRCZZbriFtx6jL1pQ 2020-04-20 12:36:24 187.181.170.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=195 +p reject 1-65535 +r TOL6 vrpSrIkEXW6taOl33z+YvPgzCq8 xdc8+MCPbwcLySn7yDLplSzLKU0 2020-04-20 09:53:10 95.141.36.127 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p accept 194,389,464,531,873,994,1194,6660-6669,6679,6697,19638,64738 +r Unnamed vshUJL1COXXhHtBb9P6rOnUmUQ8 s5n3YHziNzC5aKPvkLiX/xm8cJ0 2020-04-20 00:45:40 220.233.28.71 41623 0 +a [2406:3400:242:1::f010]:41623 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=173 +p reject 1-65535 +r himawari vtDIv0HBLk1WgfzS/tZZnZ89wSw nZGFFLW9i/+kP/UT+INptxjvxqA 2020-04-20 00:55:39 45.32.61.197 443 0 +a [2001:19f0:7002:22c:9012:56b4:7e17:27a4]:443 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=131 +p reject 1-65535 +r Wardenclyffe vtPHMIdJWororaBMVhYhCOa0oVY 2FsBihlgr755CoakPxcWT0bZSW0 2020-04-20 01:01:15 51.15.111.29 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39000 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r yuicat0 vvZdLKZRteSEuw49ox3RkpNf6x4 g0mELRyfx6hA2eAspO+fJZ5Znz0 2020-04-19 23:45:45 71.19.148.20 22 23 +a [2605:2700:0:2:a800:ff:fe64:64ea]:22 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2980 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r BatmanIsAGirl777 vwE3KgRC7xRTWWektKo5pnHK87k fhDaODSzSBIE+3g5P/1+YvSacAk 2020-04-20 11:24:13 45.140.170.88 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4950 +p reject 1-65535 +r blackpinguinDE vwkGKjxOcocyaMxoWYEy3zQx9D8 SyDk+Phof+oFCxfqvonW80jOIX4 2020-04-20 04:11:59 46.59.138.80 60002 60001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=906 +p reject 1-65535 +r quadhead vw+1guN/c4zTPDZREl8ncnBbuOg 3L3KBJP/fhCf58Gw5MdI0pT3sbw 2020-04-20 06:20:35 148.251.190.229 9010 9030 +a [2a01:4f8:211:c68::2]:9010 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=140000 +p reject 1-65535 +r tachyonbeam vxTsTtRsitVvu/WGlNiPAY8xam8 uOqVMWoYn8P/Er/YPqpICDITSpc 2020-04-20 11:12:08 144.217.166.65 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r erwinsrelay vxp3W3KC7DH8r444/JPR/sRDpWY x3rvuDojHvuTUswB7BvHorv7eDI 2020-04-19 22:24:22 82.77.238.6 443 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p accept 80,119,443,6660-6667 +r DigiGesTor4e2 vxtmLR2k5V9wDBMKxYV0tH+3644 +F797V3kyYDVvXcQdMRVXRlAwRk 2020-04-20 07:35:06 195.176.3.19 8443 8080 +a [2001:620:20d0::19]:8443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29600 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r cel vykHfZDdZdixWy38h20lx25QV/s fp1lXB6+oMmORBC52xtctValBiQ 2020-04-20 11:20:57 62.113.227.124 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p reject 1-65535 +r CocoBridge vyv5AWQ9O4vBvB9icFrGYepeDp4 eIBnGHSiRcdGYk68hf7DMvlO1pQ 2020-04-19 22:49:22 109.15.43.86 20 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1430 +p reject 1-65535 +r tor vy4uwa03EeTgaMnOhVaKlgvcWf8 CyE6zALzr+ygO+pJ0vr4yYpnSm0 2020-04-20 09:35:52 79.137.33.24 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2880 +p reject 1-65535 +r TommysTorServer vy6njk8CzFIeZ4Wo7EFpQELIh8w 5sYo4eOK8AO9oNiC9Ajd8XMC41w 2020-04-20 07:00:31 78.46.63.113 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=3030 +p reject 1-65535 +r snap277 vy/y1WK5+ev+DwluO2uQKAi0Hgo MXyWmNK3C46vZ5TuXkTYejD5VQc 2020-04-20 04:48:20 84.72.101.179 33415 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4900 +p reject 1-65535 +r HarryPottor vzdEXqKp89BPS4ffrGJK7yG1WdU MJ4sX+SbFw+qAJiT+g76QDa9M18 2020-04-20 08:10:33 5.9.116.66 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44900 +p reject 1-65535 +r WodRelay vz6bl9POQJn3OqS9cMoUtjX6POo wKLikJXEzRSjJOwnEfCQjWyn9P0 2020-04-20 09:05:44 70.120.126.172 443 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p reject 1-65535 +r tripoli3 v0EUw8TMHoyInJ0PUiU7JpII/zs Dt0NNMgIVJv2TecpMunZUkj/xiI 2020-04-20 05:56:39 188.150.239.156 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18600 +p reject 1-65535 +r skullcactus v0WRwWf/Abiq4nSc2dBJE71nQ8Q 8Ea3eOw54Epl01QXPRu63pWts1w 2020-04-20 06:39:28 46.39.254.189 59001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=711 +p reject 1-65535 +r LupusreginaBeta v1Dgnu0luChhz5XhqqQtz+9T5dE UG13ufWmG/XayEH6LCGehl5ezDw 2020-04-20 00:11:24 213.112.89.78 6881 6882 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29900 +p reject 1-65535 +r Unnamed v1wMXTocZlT+ul/2awBzTfBz21A zLGjAetwrg32vO7oRdGc/IJbqv8 2020-04-20 11:25:41 142.4.209.31 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14100 +p reject 1-65535 +r CryptoHouse v23cFomZDSr4LnMA18xjKEXW8Uw TXjF4jbyH0peXDhbsZ5ZiXj+qT4 2020-04-20 01:15:50 185.228.138.252 1080 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38600 +p reject 1-65535 +r lenny v2+EFaVyWb+3yHjElWxon7fssko ozyFse/DM0oF2QasNiYVQTjPs0k 2020-04-20 01:50:25 91.67.189.235 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2490 +p reject 1-65535 +r Assange018us v3FoYjrU/1QqnpQMTM9XXZvhYyM iAap4uD2yjoLBZF3WlV5ZZKf/N8 2020-04-20 04:00:05 194.242.3.16 9001 0 +a [2602:fe90:604:1::8ff:ad04]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4500 +p reject 1-65535 +r freeway v3NfZpSB7hzMNI8HMVUckz0eIng SQdTfGC79hgnfw5d2buXpDqVeCs 2020-04-20 11:01:05 212.47.233.250 9001 9030 +a [2001:bc8:4400:2b00::1c:629]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28000 +p reject 1-65535 +r covfefe v3opxnsFAs8wgrEzK7+8q6rFUNU Zt9P8LXHF+PWuMd1Gcjbf1PL8Qg 2020-04-20 04:01:49 77.58.250.110 9001 9030 +a [2001:470:5179:1::233]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3010 +p reject 1-65535 +r snap277 v3tSukloHQy797cG0QgZ7uC1dH4 pvMFOZveTU3fcG+PAMc0kHtI0lQ 2020-04-20 10:23:14 78.127.39.75 34161 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r weepy v3v8swlvyB+9C3raZhZEMex/0Rc IjgigtiMRaxNXUGHDn/1tfjL/T8 2020-04-20 02:39:30 178.132.78.148 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29000 +p reject 1-65535 +r biafra v5TaHT5bYWcQPckmCZKbJvJfZHU fnRJ/mOKBd+e137+uIUq4LqnPeE 2020-04-19 19:12:34 104.131.137.159 443 0 +s Fast Running Stable Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=348 +p reject 1-65535 +r stalag v6kF6hDf1Uo4oMEZ+uABgt5MFzs /JrkdybU0k6vFLM76rth7FKT2Ko 2020-04-19 22:28:26 91.223.82.154 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48000 +p reject 1-65535 +r Yggdrasil v7FLmt8fGeWSWMrn/NuqyZN7exA LU2lAgqLMRO0wk2OdFxPy75kIqg 2020-04-20 09:39:31 51.15.118.10 443 80 +a [2001:bc8:1820:192f::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24400 +p reject 1-65535 +r niftywabbit20 v7SvHneoNDQSgAQem2CMQHT1UTI iwTUOLyDTm8ZT+kakVQciroUEk0 2020-04-19 22:15:48 185.220.101.160 13160 14160 +a [2a0b:f4c2:1::160]:10160 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27400 +p accept 80,443 +r SEBO2000 v7qyLKMfbCNExp4F2uVbF4KtejY VuT6+dFbZFVK9MOlXIIqzCqw1Y0 2020-04-20 06:36:32 84.46.79.141 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r ncbanerelay v8EwXIs35RYcLjcTXfLU5TzDis4 pxTeGJZnXCxjMcmTQPFYoHLVawQ 2020-04-20 10:26:11 188.68.46.164 443 80 +a [2a03:4000:22:62::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=12000 +p reject 1-65535 +r Torrific v8Luv+Map4KUmqfUEARr8o6vicg 4nriD6ENIAe5hQREiGrLTApKuok 2020-04-19 21:04:53 108.18.247.109 443 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5280 +p reject 1-65535 +r tremor v8RzQ0IgnI0XKqzCg3UBFvdDWcY yZMMCaO3HJga0WIyfJHzofaRy/4 2020-04-20 05:51:19 185.100.87.242 9000 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed v83nxE3I8iIhaqz/RtPijXItMtM k9I9naoXtDSPKVx2bNwpLlswDww 2020-04-19 19:58:35 62.80.227.49 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2800 +p reject 1-65535 +r FOO v88Pvfqtg1zhGhIPc0UfJ7cTeq8 pTTSY5hz922TyvSY/zkBb9IbGHA 2020-04-20 10:11:30 178.175.148.37 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=12000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r joaobiscoito v9DdvJKddSt8WCMyXa4eA8rHGuc vlrMngRetSehrtxVg0PiNv9fYmQ 2020-04-20 11:12:17 177.189.180.113 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=687 +p reject 1-65535 +r ILoveYou v9J27Ek/PK3JA4klV60KqVYKzeY rdIYldVVlyyKxv1z2g8gaDHd0b8 2020-04-20 04:23:03 205.185.123.63 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2010 +p reject 21-25,119,135-139,445,465,563,4661-4666,6346-6429,6660-6667,6697,6699,6881-6999 +r Zwiebelring1 v+yf3NFc3FT777S8GLalfNGGs84 C7Hs3eOctLmkII0qNjg91wT48h8 2020-04-20 03:47:30 85.214.112.12 9001 9030 +a [2a01:238:423b:b200:e32c:fcf4:8678:d791]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r snap278 v/GKK+CBQEC4MF3Q40D54KiWQDU Usq69cUdQNMu45sW/6Z9A7dody0 2020-04-20 12:43:20 78.113.211.208 41655 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r IRON wADUcYatxcK52Qov+sdVHFpfjQo WtVqaTJpSvGe+RKtq+7Xhc5AdiU 2020-04-20 10:39:16 179.43.167.226 9020 8020 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed wAXwyzDNVMtF/wjtFRURooaxt84 B9qUfSQUDuBgeAOmTZBIsWSO1D8 2020-04-20 10:54:31 185.86.148.79 46140 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p reject 1-65535 +r Unnamed wAfB+HHtEDmc3gAX28ukvT++wvc 2NB4ZxkcI58V3Qvm9V4+/WwaP5Y 2020-04-20 11:11:49 51.254.87.76 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r gsrv wAmE6IyD+dIX6HvdZ8XqseM9b0U I/p/oDPMU2n6vJUmSqbvpnd32bQ 2020-04-20 12:01:03 84.98.214.122 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r nodemaxxxline wAprdUGpSRYpzurfEh3Ka+vR/EU g2lD6gmKrA7nqcSARAw5Lq2Q9j8 2020-04-19 19:42:44 5.253.60.240 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=950 +p reject 1-65535 +r niftybankvole wAwowrGn2AOFF2Js7Km8sjsKMdI 4ZsgPlOSHfgzkklSxt6/EmgfEYI 2020-04-20 00:13:37 185.220.101.130 1130 2130 +a [2a0b:f4c2:1::130]:1130 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33500 +p reject 22,25 +r Hydra7 wBP2p6Ipf6TNANBe9KHFIiuESyU oCqeVF4z9LJQwJ17nxeOAcNDyQs 2020-04-20 04:02:54 51.158.171.35 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36700 +p reject 1-65535 +r manipogo wBkv9D53clAIQXX05ZrBuiKQzjg Welu121JYhmw0BUdZNgO14aCUIE 2020-04-20 01:28:37 192.160.102.169 9001 80 +a [2620:132:300c:c01d::9]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15600 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Alexandra wCXYULNwhn3XBwREllSeEhjUWrw jhNoidO8Gn7Kb6+CtphtxtsC89c 2020-04-20 10:15:53 187.178.75.109 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TransRights wCa4/KphW58MKI4ADKMh1LDyLvw vl2TOcvtRKPUkwML0nzT3KjUrFc 2020-04-20 02:42:02 95.217.142.228 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22800 +p reject 1-65535 +r nobodysawmedoit wDOWg6qLzRGySY0Zf8frnQd1if4 h26uXNTCgBZ8Dmqr1C3fPMGIylY 2020-04-19 19:10:39 82.196.8.13 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=93 +p reject 1-65535 +r C3WLittleGem wEhQZz9lWpH1rTwG4eW5BWxfouA b5w59A84cvbPK7TGZsh/0SHVpiY 2020-04-20 11:29:04 45.84.253.28 443 80 +a [2a00:11c0:66:1:45:84:253:28]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=799 +p reject 1-65535 +r endthefed wFbZiHyZno2dtDzzAOH3On4NHXQ tFmDMwOHx64UiehcTMvF04PKRPU 2020-04-20 10:49:45 46.165.253.199 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2020 +p reject 1-65535 +r uranium wFf7XgHUpZpKU3pkgO282WSiiXQ bXoLk/b6z09uQycUg0CZd26Ih5g 2020-04-20 09:15:04 178.17.170.242 443 80 +a [2a00:1dc0:caff:161::c496]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p accept 20-23,43,53,80-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r cdustueckscheisse wIBJE7tDHWTgYh5bzl2pfWJMrNE uzgtfL2Koi9j4VOGC0xl+q0e3xk 2020-04-20 02:38:29 45.83.40.96 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3200 +p reject 1-65535 +r schmaggofatz wIDRIAwdnT5Tjvd3pNwFx9p3v8Q y8LBxvTn602LgoYbYl3s64f2oVs 2020-04-20 06:07:35 178.82.241.4 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2040 +p reject 1-65535 +r PhantomFreak wIM9OV6B8Z7F87vGDYlHC+LxUZk tdiZ6QwSQAys5uvbLu3Pk9Hc4iY 2020-04-19 22:58:01 23.129.64.207 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8680 +p accept 1-65535 +r niftyvolcanorabbit wI3klljls8/G8qlStFPEtgjJoWo 1sWIaUu32cGMQLlZi5HO0oLwNRQ 2020-04-19 20:27:21 185.220.101.29 10029 20029 +a [2a0b:f4c2::29]:10029 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32100 +p reject 22,25 +r imANiceRelay wKD+tkc/PzGCK7jwCASXGMoBdic zHnWiHDKXKYYvnZn6vcDAGmc73A 2020-04-20 11:26:08 37.139.22.180 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=449 +p reject 1-65535 +r 0702c2a95433 wKzj1kXjYZ08WYdfowcOqshimhs FgCFvTpamgZ8aLYzENU8Eb1xn8k 2020-04-20 08:14:48 51.81.253.211 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r F3Netze wK6robVVGf5ThKpE0DEr6YIW2nE DLsfaQO8eTMZ4Y89w84k40wNeRQ 2020-04-20 07:04:01 185.220.100.242 9000 9001 +a [2a0b:f4c0:16c:15::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=81800 +p reject 25 +r snap278 wK+LZVTLpKpCwPy3QHzJjTDECCc YzQeK8rIRBxChtNsndjvyeTxJG4 2020-04-20 05:23:43 188.63.114.134 42699 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2090 +p reject 1-65535 +r twofish wLq5LdGP+D4xXMEUI49xz254LWY 0IrtCE1NvQppjz62orNur1UOh6U 2020-04-20 08:30:33 164.160.129.5 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=170 +p reject 1-65535 +r Dystopia2 wL5FViYIRuS612COHlrf+AiSwow 1CiTPW83+j6qAbDQ3sUXqES3zNM 2020-04-19 23:43:36 45.77.226.49 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=383 +p reject 1-65535 +r SlurmExit wL/AoDQb0Ck/CT3saWa5kDijG3k O6RNI40MHbul3U56GCMpI3aqI+k 2020-04-20 02:41:18 178.17.171.39 443 0 +a [2a00:1dc0:caff:9e::8e67]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p accept 53,80,443 +r toritounam2 wMTzOQRuuCSZn3EdF4Ry/fU75/U bPlI3ZJYEbWutPmfiYZzLh+CgdU 2020-04-20 11:51:17 132.248.241.5 9101 9130 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5000 +p reject 1-65535 +r RattyRelay wMu9F/hIyPmkkQSpbbSYATsw8U8 8LQPO92hp5Wo7OMmyzfjIj1s4nQ 2020-04-20 11:42:57 85.164.38.214 9001 9030 +a [2001:4643:975a::7]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25500 +p reject 1-65535 +r RichBoy03 wM7/17vBAwSQluqJUGvqtCvJxco f6SaOE84apEeZWWN2cJjt5PPgeQ 2020-04-20 02:55:15 109.136.79.244 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=780 +p reject 1-65535 +r snap278 wNlEdH0KTysmy8vLjV3PrBJWIys hKAtqLY9bJNIVWumNALPge5CK4o 2020-04-20 06:55:00 86.189.130.239 38279 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2800 +p reject 1-65535 +r mitsuha wNqq5e5GG74TlF/ktS8yq9xrw3Y dhynTlNKX6wv2qK04NJu2W2Yk8E 2020-04-20 01:52:15 51.15.246.170 443 80 +a [2001:bc8:47b0:1756::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p reject 1-65535 +r thauriiya wORGO1PzPT8m0RJ8iG7o/l41/Ds s16L/pyRM1KgrOdRqAhpcYUgRaM 2020-04-20 01:40:51 71.127.182.175 9011 7013 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11 +p reject 1-65535 +r FreedomForParrots2 wOamZwZDhbnLWmhc6wa4Xt2mqgA XhZ4MvuS96b6M04dvtqxuLpPHyA 2020-04-20 07:00:39 77.123.155.45 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14700 +p reject 1-65535 +r niftybephomet wOczShgRhKvQdpjQStwZ4V4+4YQ eWwbgsUVZAjyHd4KYmYmOfeIDRQ 2020-04-20 08:52:46 185.220.100.244 9000 9001 +a [2a0b:f4c0:16c:9::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40900 +p reject 25 +r TorThdNinja wOlAUxl/cewoMrquFXkaGvoJly4 QKspoFwjfcXdrjqjRNQ50wqyqvg 2020-04-20 11:42:43 51.255.45.144 443 80 +a [2001:41d0:302:2200::4673]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r rittervg wO2wjXVA0d08ppgJ7RfZefUbZuM DXBQh3tAfw+5xP6Y+i+Mgxihsuo 2020-04-20 06:39:32 97.107.139.108 9001 0 +a [2600:3c03::f03c:91ff:fe96:d927]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3010 +p reject 1-65535 +r noname wPPA74HYQYI3mqTKWtWlKJ0BEUU eGGIfMCr/CInjcLcawQYAIY3IlU 2020-04-19 21:03:15 195.67.191.210 9000 9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9580 +p reject 1-65535 +r flies wPUIraFK5+qfj2ZQrxSbjfw1tZg hOUHPSenytx1vo/zTxFPgNNMr1k 2020-04-20 03:57:29 89.187.143.81 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17100 +p accept 23,43,79,81,88,110,543-544,563,587,706,749,873,902-904,8443,8888,9418,9999-10000,19638 +r BobsHouseLU03 wPt8fthHiueIRrXFWF3WLhYiIuE WiZLUtzVNNL8+z9rezg+9zVv6qU 2020-04-20 07:01:18 104.244.76.149 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25000 +p reject 1-65535 +r Mognet wQLlNKHSbtKESs5q/URKC9SAAWs wqVM7fEZ0JWK1mXgvAlRk8tfk34 2020-04-19 20:27:12 97.93.100.43 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=498 +p reject 1-65535 +r niftyentry84 wQ2qjIowJf6S4cM34DCVBTbejeY HGqZJIgObCyZniQ/1FOncbftSkg 2020-04-20 10:51:34 185.220.101.224 10084 20084 +a [2a0b:f4c2:2::224]:10084 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16100 +p reject 1-65535 +r Unnamed wRrUKgTsqqOYgqYxQiSvXjhHqjE LEMFpeZSWaGbcEZCG/bAslLstco 2020-04-20 01:05:17 185.128.41.82 17497 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32 +p reject 1-65535 +r SuperFox wSiFWtVaGyMlivzV1p4PtrWKop4 1gdrJabN7/fy/xcMDXRMDwrKtvk 2020-04-20 11:56:41 51.154.53.96 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7890 +p reject 1-65535 +r taine wTDdkUqNDkhOaNzGgbQ0oLoETZ0 ESWqw6ybqItptMis1mlaZV/I3H0 2020-04-20 07:58:42 130.193.15.186 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p reject 1-65535 +r Avvariik wTpNgJCGsr6tfe/hCPfty9JLpvg EbV6Y2kv+cnpUMkcK5bJ06Rl8Wo 2020-04-20 06:00:00 216.154.42.49 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=262 +p reject 1-65535 +r snap278 wT3fNTprJBDdNWCsreJZdMTocng v87E+WbHvbIgxJc8gTTik9qOEXA 2020-04-20 10:21:09 190.155.227.207 43275 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=170 +p reject 1-65535 +r myNewRelay wUABbUnMtnOm5P4ZMpOxoK5EayM UyPgpyC3XLYlc9DPqQLKlMQZrAw 2020-04-20 01:25:42 134.255.247.113 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=290 +p reject 1-65535 +r YankleRotaryEngine wUzmwhRWiLZA62RX85wcbh3GhNQ pTLSpuqNK30dOiKNH1jlPu1kQbc 2020-04-20 02:22:42 130.63.78.95 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=664 +p reject 1-65535 +r Britannia wXqtYuHc1g8ZmjL6yui4TPh2018 DRGZ5yBwJ5Yb6dzjIYdQ7iZQUzw 2020-04-20 03:56:16 51.89.150.163 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2650 +p reject 1-65535 +r soginet wYbkzXMwLCGOEuwiq2Q2cRSNlgk wbRzuWS82dNsd8treMctXKN72/Y 2020-04-20 01:40:06 62.113.206.33 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=432 +p reject 1-65535 +r Unnamed wYjNZJKc2Hxqlv6dBYqatK7SGsw GQXmyWT/AaoAI2XgSvU8FWE3vsM 2020-04-20 10:19:54 75.127.15.73 47001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=660 +p reject 1-65535 +r angeltest10 wZOdNmSd6YogJCljHY78cBKNX18 6Xyi4vBX8+DsaGyaYi0SA80UBiY 2020-04-20 09:03:09 178.254.20.159 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20400 +p reject 1-65535 +r PiratenparteiNRW wZszdYs6UUSJQjPsTJXXmFuf0QE 2nUYpE0rddsHhZQL6HlKPXWUB+s 2020-04-20 11:58:08 5.199.130.188 443 80 +a [2001:4ba0:fff9:160:dead:beef:ca1f:1337]:443 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30300 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r WAVY wZ9RSVoUk50qlC9LlbLAp2lvtWY dTs1jPUwICww3iHmYkExXjlkfaI 2020-04-20 05:00:54 83.97.20.84 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=610 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r fiedlerRelay03 wbUTu14VoYh7atyowBBjBzL8OJo 1RpIFo4AfababCX0W99RiCx2pww 2020-04-20 12:08:49 37.120.190.160 9001 0 +a [2a03:4000:6:b39a::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4600 +p reject 1-65535 +r fuckcensorchip wbecTNm3E7u2sFIhVbRqe/47+q4 T4X3vFiPeVMVzhOKacChQgPIo54 2020-04-20 11:26:39 89.163.216.11 443 9030 +a [2001:4ba0:cafe:df9::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68000 +p reject 1-65535 +r MapleCrew wbjGiHhnztJWRFQFj5CCMR+vGsc mKkfoPOvQCECwyBm6uP0MW1+DC8 2020-04-19 23:32:40 192.99.35.91 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r pros2 wbtn0/vtaNS61ADRpJxbeezjll4 rWUUWQ/keHWjA2D3b0MfzJFgG7k 2020-04-20 00:45:29 145.239.84.172 80 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9700 +p reject 1-65535 +r RELAY6969420 wb6WedoeIG5NEbd4wCBMiY1i2VY a2LC8c1+hZbXxtJEY8JHezqQN0g 2020-04-20 11:29:44 104.185.133.203 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r Unnamed wdjaLwdvrbljydpbXJ3oNSjU4xU GwUOKO+kguHa6ncIUc0itdYyJ1E 2020-04-20 07:02:46 195.123.226.53 80 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r satfreaked wdzEcMgPbXAsXtEVFZNkRL06AlU 9WSpdl9Vt/PTqb09orIVDVanV3I 2020-04-20 10:03:14 86.86.173.62 15025 0 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r snap277 weuB9GctF1udGRFG5awtj4Byfto ghCRbHqBWFQSd5OQkgu/9wvZq1s 2020-04-20 07:02:38 96.241.56.195 35182 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r smell wf7WpdA4Jq6cmjF6rjcLZXhmLeQ Ayxwobwc2TtSMytv1CzT5NMrZYg 2020-04-19 23:26:51 205.185.123.166 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5190 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r ylxdzsw wf/yejjfjcizENB4wT4j8ICvKVc z91Y0qwVNHAtEfHgwQX4zG7vYs8 2020-04-20 12:37:05 207.180.198.205 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25 +p accept 6660-6667 +r snap277 whNEZ6nzXV05Xgohin7b9oBbT6o Svw82hm/VZCDqtkxGls6UCOppxU 2020-04-20 10:05:58 90.32.176.82 37601 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21 +p reject 1-65535 +r snap277 wikzbxoRdd7BjxxZmXdct/+TPzQ Wse9ZK6PWO46W0AjeOHhz/RO/7g 2020-04-20 03:32:52 2.30.251.196 41119 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p reject 1-65535 +r rickvanderzwet wiup7W3uBx0rN7lxjcz7alPq1eY 44DBla9cJFO4li9cMJANqGhPJGU 2020-04-20 02:09:19 80.127.152.30 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r FroggiePeppie wjmVLQyOTqvD5rCo4LYjaJF048Y WcsCraRKkkLjtGax3sRnqSMHDBY 2020-04-20 08:02:38 94.23.195.99 9090 4443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47000 +p reject 1-65535 +r AntifascistTorRelay wl5cYol7rLowlXHCVICEtFBQ/t8 eAjoiNG/1eh9cPsmmshqPy+3L6I 2020-04-19 19:01:31 185.217.93.92 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17200 +p reject 1-65535 +r erbse woIkhZfRyFIqKnUl5hyLd7vDdhQ oSWQMecnJme2ge4kiNyRuSFNOH8 2020-04-20 02:16:31 109.70.100.3 443 80 +a [2a03:e600:100::3]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=63800 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r EXBRIT wpERRkDqMzpqxYAbXg7JXAEt/ms BxiMqchKwnfPJUgKlvV6B5svCgc 2020-04-20 01:59:21 23.129.64.214 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4800 +p reject 1-65535 +r rochusberg wpOMo4DhLTxx84FDlvEtSVqXxdg UuitUnIGbniaYdvAObqwDR0IYec 2020-04-20 01:02:15 79.251.204.64 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23 +p reject 1-65535 +r torberrypenguin wqP0MV3sf04x0YgY4QArDGouVTU wpv7d+TshDN52jo0LgAnOcVKYAk 2020-04-20 02:42:31 87.72.73.231 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=594 +p reject 1-65535 +r Digitalcourage3ip3 wqqwiFVYUPxDTmiUP1UQcgQrhfE /DkriuQwy6V+CkAvYdiZHliBDgA 2020-04-20 13:09:07 31.185.104.21 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r bgsv2 wrG/dmuVz3uLOBNX9sN2RhtY3rg I3B7s9vdwLcjfvPVICyAB/gRPhs 2020-04-19 23:10:36 93.104.213.2 9001 9030 +a [2a02:c205:3004:1323::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3840 +p reject 1-65535 +r Unnamed wrIWxlPNIhGg6fR1jwPard0iplo ppbKXndKb9dNOYBevVCdwCvilME 2020-04-20 07:33:29 40.113.232.85 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5620 +p reject 1-65535 +r dvorakftw wrJVllkeBOdHol0UXmDs2kOSxk0 ylImIhbwZVgiWFgTTg6bsAUaI80 2020-04-19 23:57:00 185.103.243.74 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=194 +p reject 1-65535 +r t4cc0reTor2 wrRRmfxvmOIb+v4IMzSPKI+jN+M EGEbOMkH6gLwhsd1YvGaTqk8TQQ 2020-04-20 04:30:21 51.15.39.65 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26400 +p reject 1-65535 +r behrmann wsK4OfTP+l97ekDLC+hPfZSMtRA hZ75g4DaobdMseqs4/mXE4pnhE4 2020-04-20 07:21:58 46.28.207.107 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r nodvrelay15 wsiZ6R96VQNRQ3d2kAiDvJeb7s0 Zyrc34F70sBnu2HmmcQA0vVo9SI 2020-04-19 19:14:01 45.62.227.240 9001 9000 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3800 +p reject 1-65535 +r AugusteFriedOnion wthbxUk2Fxf9766JYH9KnfLUwOQ M7o5PrDYoozhhsw9hF3Vh72sbrc 2020-04-20 04:26:08 5.135.152.66 4443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9090 +p reject 1-65535 +r RunningOnFumes3 wtpaBMvipklhyN6NA+WNnPSKc6Y deuDju6ci8uV3GIAWeFgY7NqXwc 2020-04-19 20:21:08 185.175.208.180 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-79,81-442,445,563,1214,4661-4666,6346-6429,6699,6881-6999,9001 +r Bastard wu5A7oRR8nwjV+ix6h6Ob2Qic+s TC4hwcfLKUvj4/Zn2fCaSd3gYbA 2020-04-19 20:58:04 217.197.86.173 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=769 +p reject 1-65535 +r Knowhere wvZTpc7jDI1XE/pK5/demSpHkZY YFeOUCACtRxojuTaMvTnYl+jMeU 2020-04-19 21:40:43 51.254.114.134 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16500 +p reject 1-65535 +r RocklinTorRelay wvs0bs6kj8mArUQrrbfNEOFOU6Y y3ARkeKrFjVL4YbP8PLKry9ORtY 2020-04-20 01:41:51 76.14.151.174 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Fission12 wwMDj9zHKAWhYP9k6ZQzOkns2nE xuK1+7thQdLL14c/BJ+51Z/DqlQ 2020-04-20 02:25:05 54.38.219.251 443 80 +a [2001:470:73f7::7]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19300 +p reject 1-65535 +r 0x766c6164 wxQTwyPbK9VbQ3Gl1GiA2evS+oA 7PnoaaegfNwC0BLGtSH8DGsgMJg 2020-04-19 19:30:07 5.14.156.124 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1850 +p reject 1-65535 +r t4cc0reTor6 wyY/S06SEnt80V6Pl0a0OCIzQko wHQJW4L9DQ2i8XTSUI6fQzJHiv8 2020-04-20 00:36:25 51.15.91.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37000 +p reject 1-65535 +r mistersixt wzJQ09E96rsD/tzu71HPCXfy0Eg MbnqW+/4vKgNA/OO/qGOsipW8Vo 2020-04-20 10:01:30 94.16.114.254 9001 0 +a [2a03:4000:28:365::1]:9001 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=56 +p reject 1-65535 +r UDwdoN9 wzPFbqrUBKzd4vs6Z1xfXaRqgeI WAlM2VeMkRVa9SQEZhMZ4Twf5Iw 2020-04-19 21:09:38 185.22.173.122 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18300 +p reject 1-65535 +r Cir0X wzs229V21N4UFEPSgSJXXaFZ0bM XSrdPa+eBEnvTNLEY7h1DwKQLP0 2020-04-20 01:24:35 37.120.178.124 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=563 +p reject 1-65535 +r smell w1HCyzdXU3k7QnUzffZUhY1OoCs G3KOkMoYdWWol5ocmkQGlGpsLM4 2020-04-20 02:03:30 137.74.153.6 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6530 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r jmarshall2 w2NuyktAkABWWQqn2/xu0JN5hS8 bFS+gxrBQLSPFmX/1hNFfa4uQrY 2020-04-20 09:52:57 93.92.205.248 9121 9140 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7340 +p reject 1-65535 +r theia9 w2pDTbVMZuGpelZThYzjYCQ1LE0 REiog9DJ46UlKGMGiX6pxTwJN74 2020-04-19 22:57:55 50.7.74.170 9001 9030 +a [2001:49f0:d002:2::59]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8400 +p reject 1-65535 +r unnamed w3mQVLx/DSAft8D53jG/Hz2Gijc J2yQxTdCTRvOf0G/GtDjQNB4QJo 2020-04-19 20:19:57 54.37.200.155 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18600 +p reject 1-65535 +r pataky w3+HwBJeJuas9UNm+iGYIJ6Far4 tcQp24mSeL6GFS1KDD5v+lCyadQ 2020-04-19 21:42:28 185.80.222.164 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r Solarhost w4RgsLWuRDlAgn/zCGAuX0oStcQ e7l4rrFR9Vvh2HXZLW4fyS3u4dk 2020-04-20 08:22:16 94.249.192.203 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p reject 1-65535 +r fckafd w6DkL9VWO5S+7gwW5IoRMoHrLMU MxaFsMLbAxlnUO2q7AANDwGC9MQ 2020-04-19 20:05:22 138.201.158.239 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2220 +p reject 1-65535 +r ALF2 w7XJOR42Yxq+qJoZwkdQ29/3zsg DowwL6QzJYiVzJNzw6fzvAtwgBY 2020-04-20 09:46:23 212.199.61.5 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r strugees w8/Mm1mTpvDRNJhYxZjEp4r+Ufk 50eMzJ9qcCx65SfQJEpGozTVtjM 2020-04-20 12:01:00 165.227.47.169 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4310 +p reject 1-65535 +r Logforme2 w+Dp6h/z/Pwn6Fa/5hUzAg3X8JA lhKC+jyppy5byVGPHJEG8fA+w78 2020-04-19 22:23:39 85.228.136.92 444 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45400 +p reject 1-65535 +r jaquerespeisNode w+/a5FlpLMItcYH+8PCleRVvQ8E 86nzHb6f/YJCeR8VQDYmgCflcfQ 2020-04-20 06:52:14 201.196.17.150 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=283 +p reject 1-65535 +r diezwiebel w/L1KrquvSRFQQvZwfzqSdMT00A +9VqAgOavvpraYmZl7OEqeoLzoc 2020-04-20 07:25:08 83.135.205.48 9001 9030 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=346 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Digitalist w/P6QnPiUxLdITFRGTfU5rv+aKA 6UvzsFSkddxyWFvSOeTAOlQTeqY 2020-04-20 06:36:02 81.10.144.74 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=508 +p reject 1-65535 +r Magica xABc/D4sec9QcnfhoX/yo87jRcg 3gPVgn3g9xetsZ3eUTOFAqkIOdQ 2020-04-20 07:34:31 45.119.203.171 9001 9030 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=121 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tor4ever4 xBEHrwvWQT4NphS8UfNJoyD5MwE xhlbuPvRPSfumgutll5qpVKDSuI 2020-04-20 04:07:27 45.62.230.216 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r zebra620 xBTyj9K+wVUwJCmbMdTnJr6454g I7FMv3h7R5AjXd6h1GYFmvqOogg 2020-04-20 02:24:18 188.138.112.60 1521 1433 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13800 +p reject 1-65535 +r Seccom02 xBreIpWYIB+RNCbpxrlkcJiu4o0 /aNVwPL2Ll/amfcLdZfWXX+QwgQ 2020-04-19 22:51:26 51.83.254.153 443 80 +a [2001:41d0:601:2000::16e5]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14200 +p reject 1-65535 +r avanixRelay1 xCL4hpnBik8pnYNDkbFfB9vmBiU ddgfdg83/9oqIFsu8KWglyAVx84 2020-04-20 05:41:55 51.68.137.123 9333 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2120 +p reject 1-65535 +r MEGAusa4 xCvVGk7Yr1VPeBWRVSp6cgJpRA8 eD9IrQUfo4XuBoyd5XEAFe1sLZA 2020-04-20 06:07:35 195.123.233.5 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7750 +p accept 80,110,143 +r Raptor xC9WYuFUdskpUrooHvF1hYaMOM0 Qe1YKWliFaRGQtxeEOldkWXUWTU 2020-04-19 20:01:32 187.178.25.42 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=744 +p reject 1-65535 +r Unnamed xDANPAO7QfX2K66Pxix4rA6Y0bw YoDWul4gYh8LhCiXC2NPa2k8byA 2020-04-20 09:27:28 78.94.141.202 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27 +p reject 1-65535 +r PAPRIKA xDC+7nAkj+CA6P3oVkN5F7MUzTg rsGTr3vo4EtpUMFfBYFtX5HIWyo 2020-04-20 03:09:42 91.219.236.223 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=749 +p reject 1-65535 +r OpiumFlvour xDNtdcEh0wbdT6++M/gmrVP61Q8 1MTTfd3jAk8nxKxHpg76l+eJy3o 2020-04-20 02:49:21 149.28.174.234 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=89 +p reject 1-65535 +r snap277 xDSJybwTSQ6CrDxj1JUJphad0r0 qVHRTZiAxOyeeOIiplBfdSHjSQM 2020-04-20 10:58:31 176.109.171.140 45825 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2760 +p reject 1-65535 +r jerailNode xEIxgYiHPZQbGcJibsbmUZErRts uVJ8qYUzds4hVE5hY2YlMBgx9L8 2020-04-20 00:25:09 76.68.55.240 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5400 +p reject 1-65535 +r Unnamed xEzGS+2ScDGls7Cnzfap4o8Fiz8 cUke9+3blqeOuoVnmzpBV954dbE 2020-04-19 21:46:41 172.86.148.10 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1710 +p reject 1-65535 +r Unnamed xGMnY9vQPNFfEUZcWkc8VL/w7Gs B/DO4ch0XETQUGLSKMIJmnfpHRc 2020-04-20 11:13:47 167.114.89.206 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r whvger xGSutAig4x8HOFqwe2mzqNdckLE E+OgdEHlJ8L1qPOz4b+ygcD53BI 2020-04-20 04:07:57 46.142.239.159 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=530 +p reject 1-65535 +r wecoev xG4dLk9Od5EQNVdiWn34b2V/Cvg h7mYtfRHUrsmODMGt3yYAfaGNWk 2020-04-20 10:32:12 95.222.96.172 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=113 +p reject 1-65535 +r KaaTorRelay xG5nKZS1MZJzcUwrrgdBHLTvWh8 gRkpSWdsNsZ1dbAXJrZW9AR5qHQ 2020-04-20 08:03:37 82.64.197.25 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r PercontorQuick xHKxv2ynhPGos6VqB+lRkmETzN0 bnRwHmqffOQpy8DL3GPgQYFZbRI 2020-04-19 21:34:16 80.85.84.72 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4520 +p reject 1-65535 +r uname xHWEd2TmHsHXGlUisJpwzGy7LcQ 3uCTj2yCQa8StE2/6UEjgbWAbG0 2020-04-20 10:35:49 86.57.149.13 1443 9130 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=4210 +p reject 1-65535 +r niftywabbit3 xH6PAlZFxiG+i/i19shWSkEln3s N+6pdkKzgGhDSxp7ODVSWVUyYME 2020-04-20 02:40:46 185.220.101.195 1195 2195 +a [2a0b:f4c2:2::195]:1195 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61800 +p reject 25 +r snap277 xILUgpzi3GICQ54w47JHdeqX+z0 /G+A/5LIO4uNRQv8G+XktmySgUk 2020-04-20 01:41:26 5.159.107.232 43585 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1410 +p reject 1-65535 +r Unnamed xJoXdRDKplPaZye/Dgf7f1ag8J0 5FoOC7+zl6pUEu06b4drnDS4K34 2020-04-20 11:41:45 136.243.70.198 9001 9030 +a [2a01:4f8:212:24c4::12]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47500 +p reject 1-65535 +r Assange028us xJ4+NFkRcqU0Ch035bTj0LkeDxU KzkcSfKBf4EbcEpFdwufJjUrawE 2020-04-20 00:39:49 194.242.2.25 9001 9011 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3000 +p reject 1-65535 +r mistersixt4 xLDbaQ4zYz9qBc9oWNGD9/b5P6k E6NI5gUpA/9W7JIZDTvljv/wbLo 2020-04-20 09:15:48 37.120.184.82 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=732 +p reject 1-65535 +r DjMiddle xLIaZrJ+gv72rJfOrv5C3/XHURw PxiFKfcowfFkMM2IUbjWpfIZbIQ 2020-04-19 21:24:24 173.249.57.253 433 80 +a [2a02:c207:3002:8283::1]:433 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed xLQm/ek+BJJXrq4FpY6ZEixvbpA RCNCxGxJ4RmB/mCTtfPxvP9DtVQ 2020-04-19 23:34:39 5.9.157.117 30334 65079 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=347 +p reject 1-65535 +r torrible xLzwDFGPEgaL7j/A7uXrnGAx7UI lJYRmi4jnZFtkHv10f1L6qhd44o 2020-04-20 00:18:00 100.37.9.108 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1270 +p reject 1-65535 +r alpha1 xMG1sK9sfLtOen99P/FWPJo5sQE 8IjN/fVw+wyfmAmltB3YLPDOK64 2020-04-20 09:17:11 94.158.244.60 443 80 +a [2a0a:c802:0:1::43]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4320 +p accept 20-23,43,53,80-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9999-10000,11371,19294,19638,50002,64738 +r 00was00 xMcRiplGndq4tci7Wlf41s7wdl4 hu0KxR1craZuApcQEq0l0i8KMTM 2020-04-19 18:52:04 45.95.235.55 9100 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6620 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r 4dfd6315e32b xMv+mvn9AM9cZJqsbhnUIR4KnJQ HXc4HRedZGERYTJtX1dbUG9+qc8 2020-04-20 08:23:28 51.81.253.197 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r grace xM/x3eWkN0mpCvKDR2C+VKsIuQo tUBoT+O146+4Dcocvh/VYAeMU5w 2020-04-20 06:39:45 167.71.153.179 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=784 +p reject 1-65535 +r Uwantsmooke xNQ+wYF597LoGH1+KE1tVHIXs54 eVKfROMpSNjAZqSiI/uXjpqPAmk 2020-04-20 12:07:52 192.254.79.138 31337 29031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3060 +p reject 1-65535 +r artservice xO9t+4o8RCsab5o8vmPZcOdxv7I /9HUPVM4Rn4EoUCtx4aVR54XDtg 2020-04-20 00:47:21 91.221.57.179 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4690 +p reject 25,119 +r EhRelay xP0kA8ySkpe1WaSeWCUWlE91xqk fFnX2Oi1JOj60d1+jOgOtlq+BGE 2020-04-19 19:52:28 165.22.236.251 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=250 +p reject 1-65535 +r Unnamed xQz4XL4KMn4y7noAEWHEe7s4znY PLvdINJTM310fH75Zh1UJ3WKM04 2020-04-20 03:25:03 87.123.76.245 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2750 +p reject 1-65535 +r pasiphae xRFRed66+AoPtZ69pyoqRMxM7cY bmivmYe3XdrfBGbEP9r+1ExdJuE 2020-04-19 23:39:20 195.189.96.152 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=66000 +p reject 1-65535 +r ThereIsNoCloud xRcBkQ3qmY9PUSh6cbfpREmj6bw a7jk9eqW5VMo21lbiBBAfD5Zu20 2020-04-20 07:46:16 5.42.141.211 993 8080 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=994 +p reject 1-65535 +r TORTestRelay90 xR5sZ/lsdUzzPE9YymwSO59IqCw wjg5xJNMkBud5aEfLzPYtUEgdPw 2020-04-20 10:53:34 188.193.97.115 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r Unnamed xS96AmSufGUJdhZuoTmCUB7IEM4 lodBpB6oOtfJ7vPftivV9a83+W4 2020-04-20 01:59:43 188.165.213.156 52743 52345 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=9100 +p reject 1-65535 +r chieBiT0 xS+QxDZnb+Rz86ZoPvAHXoiI6SI QDrATjye3RPAjjpnophRyUCbQ/M 2020-04-19 20:36:24 176.32.33.221 9443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r meatloaf229 xULUUtQtvQGgcdLaHObuFa9A9cI YzIfgbGBfSB3db5IgEnbSDLi0mw 2020-04-20 00:45:56 67.163.131.76 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=97 +p accept 43,80,443,636,706,993,995,1043,2083,3690,5228,9001,9030,9418,10000,11371,19294,64738 +r Echalote xUXtO+ApsibXSz95gjWVHS/u4+E k61pIBVSqdC2kzcEFIfTmZvPXLI 2020-04-20 07:19:59 212.47.229.4 443 80 +a [2001:bc8:47a4:1c28::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=48800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 xUkSGZA5TAGzGdnTe/8rERzWrw0 4IhAgC3cWFsLOjJiAgmGjzv60Uc 2020-04-20 05:56:36 88.151.72.60 44145 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=34 +p reject 1-65535 +r DefCon xU6B6wR9fsHgWwrG5yO+G/XK9SA SWbzcDl2HPuqHpBZ7xEO0Wh/Qo0 2020-04-20 01:32:20 94.220.77.213 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r zzz xVlN8y/uxuxDgWImW74Mnj9ZL2E kKNuOhcXGnbp6IRqjz/JdesM6N4 2020-04-20 08:31:04 93.174.93.216 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42800 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r tropby xVrEI4xmzo0Ag4Vy1WOihNvvAig gYJKNlH5Ob/btLNlvJOK1CZj/OU 2020-04-20 02:11:06 46.232.248.80 9001 9030 +a [2a03:4000:2b:4e::dead:beef]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r pochath xWS2W8iX/ArM6MKdNSC64TxaIQ4 Y7JevPTWaydRmRTG+TWhdPTAjeQ 2020-04-20 01:22:11 37.120.146.42 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11900 +p reject 1-65535 +r balsak xWwez/DFkFg8GycvrzFtRAz8BZc toUbXxOh16yW8gyH/1lG4Y3RD4Y 2020-04-20 12:16:39 96.35.46.11 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1050 +p reject 1-65535 +r torrelay xXfFbq1lTIKdH/L4YTP4mhpZqok ycaC9q8V/ypukMdXfXgxqt8FRu8 2020-04-19 18:56:24 185.163.45.253 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r ihuhubhd1wya xZbYWrJkG+yWEGrmLl9yx1G3viI ZCRj5rykmjfufuSdkXN3C6Em7/Y 2020-04-20 10:13:58 52.119.113.195 443 0 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39 +p reject 1-65535 +r ibibUNC1 xZ4HlDc0DjrRTmeFwKkaW28yhWY nWTWq74tX6PiHQphz+Xnb4u8Tdg 2020-04-20 09:21:41 204.85.191.9 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Quintex17 xaU7zBdO+P0NyyI+Sqkp+lV97bI o1jn4B5WhbWFly/SkZZ+YDQC/+8 2020-04-20 10:52:40 199.249.230.107 443 80 +a [2620:7:6001::107]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r jivin xab+5bw74Z9bnrCGypXa05PYpPY AEKiU2caO5/Kk+3hvxobH2T47wo 2020-04-19 22:57:23 103.28.52.93 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=95 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,10000,11371,19294,19638,50002,64738 +r pablobm007 xa8RtZW+IR5C0aEhq+yJUV07DLw KB/B88KVzXAAr7+clxClwma1Z+Y 2020-04-20 00:44:39 159.65.10.189 9001 9030 +a [2400:6180:0:d1::509:3001]:9050 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=600 +p reject 1-65535 +r thecodename7 xb0Lecw/oIV39Cf8SDSzZbe5Lio OCeOV4WRWoRh8dHH2qbiNQ7c070 2020-04-19 20:42:31 171.244.33.189 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1 +p accept 20-23,43,53,79-81,88,194,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r stoychev xb8nVg5LAHNl+6ltMvnnRhQhjI4 Ixrp1y7+3rBYRp9AOzAb5mL5024 2020-04-20 09:37:36 104.238.167.111 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43000 +p reject 1-65535 +r ohsally xdVdEfJsUqa/7o3SPCUFSKpn6aw rj1ca4CpO568/rHDwmxPMAQBjtY 2020-04-20 11:00:50 93.95.100.166 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4080 +p reject 1-65535 +r Aggie xdXmNdEVySHAYJKf2+oI8hQokZg on4D2+CwYRXOSYYACsAUE8ecdQQ 2020-04-19 22:06:16 107.170.219.188 9001 9030 +a [2604:a880:1:20::24a0:1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1830 +p reject 1-65535 +r gnosis xdkbddm5kftTxBq2lNl8lh03tas BVAUqYUBM74URzjq5OCXs75H9yg 2020-04-20 05:08:52 213.251.237.184 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r HSB xfdqe0WaaO3SVWgDJfY3C2DgvDw 2IGq4P56vERzEn554V1cV8PKJm0 2020-04-19 21:31:55 5.9.82.76 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3060 +p reject 1-65535 +r SubspaceRelayAlpha xiKvKh4Pc/hgQ3XtE9UesG7UlIw igsD48gWlAOX9G/mNTMpw047vJg 2020-04-19 23:18:09 70.113.147.62 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1470 +p reject 1-65535 +r Unnamed xjEQvdhzbSwqcz/5YvWNWP3mOi0 OoSj13UstiO5DMPIVsCLYWPzH9I 2020-04-19 21:00:25 148.251.192.160 80 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=84000 +p reject 1-65535 +r tORu xj9Ox0Nxk71gcNXL0Oq7thDdAqo 2KTkju45RHJdRg2ZnZ/KNZ+j/wU 2020-04-19 22:18:00 54.37.138.104 443 80 +a [2001:41d0:601:1100::218b]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4060 +p reject 1-65535 +r marcuse2 xla0Gu+0ChQZZ+v0nW5pYDybShE ZNZC+06leVwMqkPARAQ/ml1CI08 2020-04-19 22:47:49 178.20.55.18 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r TorExitVIF xl0+G6J/DznC+EzjHSBVm/Kjak8 HZ9LLYgkvnHcsV51DfRnpZaBa3o 2020-04-20 02:12:46 216.239.90.19 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8280 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r theseekingchild xl3kpzgLrKyUeFYZWdxZ3R/14bk w7af8ZdohACKZWLpcLz3CN/wyQ8 2020-04-20 01:49:28 103.102.46.57 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=304 +p reject 1-65535 +r JohnSmithSrv xl3txh9oaU819ipYbAn8QR5NPDg xKjiEUa2lvSVF3pqJ/c1fTVqdi4 2020-04-20 02:06:04 104.244.79.68 9001 0 +a [2605:6400:30:fa31:9050::]:9001 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17 +p reject 1-65535 +r TrickDepression xmBNRXrDGeU9wxS4Hw750Wy5N6A fgoWvgT+vdPUsqrKgLv4dX5DtBU 2020-04-19 23:26:16 8.209.79.125 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r 1505192200300605 xnwzx2zcM91y+qd1NbSNfpbABtI tu81XmWd3Pxy8wVT7WRAhWX1mPk 2020-04-20 04:15:53 5.2.72.101 9001 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p accept 80,443,8080,8443 +r badgercomb xoBxim9RqPfF1OaCae1bLAf+Uxs h14jO5CJSPNmI0lVMRg7PMQ1xz0 2020-04-20 02:33:13 66.228.33.44 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6590 +p reject 1-65535 +r bartle xpn0CzNE0008WWeRp+vGfkHGKgs y9rEQ2964YndXBmCVdhvAyVyyBo 2020-04-20 01:58:13 50.7.179.251 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6600 +p reject 1-65535 +r Geheimschreiber xp0k+TU+FthegrSp5Fcd+vbc9TE Di33lpyDPgtJC9xfBr2C0H/VDg4 2020-04-19 22:04:45 86.186.247.236 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3630 +p reject 1-65535 +r RunningOnFumes1 xrHeDg/cAAgKurTweA81aIXJu4I QedC5MRJ/HP52uGQuzzLTF5jThg 2020-04-19 22:10:01 185.175.208.179 443 0 +s Exit Fast Running Stable Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=990 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r JAJTorBits xrZWumvBbjERWhstVjlqUxZfNAg /r537X9j8TnEBVkSNlJEOcalklI 2020-04-19 19:22:52 71.60.192.20 543 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=320 +p reject 1-65535 +r Unnamed xros2kArZo+xRve668CdBuvvuHM FlZOgN7tnEJKkdTfcES7nLhpXLg 2020-04-20 06:36:07 51.79.86.181 9001 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 25,119,135-139,445,1214,4661-4666,6346-6429,6699,6881-6999 +r pdxcomcast xuFFO4yveW5M9l22qBKDvd1yL4g jrMh+Bt2BOsTUV+rCwPs7aUcMyE 2020-04-19 21:05:11 65.100.46.164 9001 9030 +a [2602:41:642e:a630:2a05:d264:4e14:cf93]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1020 +p reject 1-65535 +r niftyentry85 xuGEwJg8aLfov8YhXnKJ4J6Xqg4 23t2zEJcm2j6vlu3UkMtanz/91s 2020-04-20 10:52:37 185.220.101.225 10085 20085 +a [2a0b:f4c2:2::225]:10085 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r Assange023gr xuORDLrcptLX6TKrMaA47dam+3k 9RuFI5AQH+GhTUTnjUe9kDc9PJg 2020-04-20 03:01:28 185.4.134.104 9001 9011 +a [2a02:c500:2:110::2d49]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r lxoliva xubyWD9KJRL3Na0Zq8xUEtEHM0I nSXgFXpVHHXrFdaBCpZA7iFwYNo 2020-04-20 06:46:05 177.99.135.87 9001 9030 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r niftygrankhul xu19N6o8yqWGsi4KMLOVpeWCRAo zILCUchVbSzHWga2EKjXOtC6AYg 2020-04-20 08:53:11 185.220.100.244 9100 9101 +a [2a0b:f4c0:16c:9::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45200 +p reject 25 +r LSRodentNinjaRelay xu8RXZlzF6MseErA+ZRK4Fgco34 KCOWYu8v1npZEO9XLdGjhQYpssw 2020-04-20 08:03:40 52.47.91.150 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3430 +p reject 1-65535 +r LilypadRelay xwXEXPJKMMXZe2HrNdbX5CRtVqA Vpyt4BpAq74yMrdSeAHaqtuVpoo 2020-04-20 02:17:48 68.115.26.245 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=230 +p reject 1-65535 +r Unnamed xwo8s5K4BU6KRB8HQFMMwXa7Ck8 iHWE3z9MdpmdVcN+fb63vDvYB5g 2020-04-20 03:24:35 185.246.128.30 26778 3432 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=939 +p reject 1-65535 +r TorOrDie4privacyNET xxBvDGp88PWSy6/3x5vYEVOxtfU wcO/WGnk5ZxpWPfxtJSsQpM3nHw 2020-04-20 01:16:18 37.157.254.113 9002 9031 +a [2001:4ba0:ffff:58::3]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36500 +p reject 1-65535 +r HomeRelay xynXaF6NNzR5GiGctE8dEmXHeCU KwJaUwgwlELLEsbEe+wsI8NWAO0 2020-04-20 07:04:57 136.49.179.248 9010 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=310 +p reject 1-65535 +r Hydra15 xy5zVmyzN3quWEn1kmrWYOSvgqI P6bxITiyyRcadc480E5WVcUWLho 2020-04-20 02:41:53 89.34.27.37 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p accept 53,80,443,1194 +r nunyabidnezz xzJuHmZcLnc2U8AdSbJXpWpIccs aXTiAveiCGb6gnI/B40dJoDbeBk 2020-04-20 10:03:44 98.201.42.132 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120 +p reject 1-65535 +r niftywabbit19 x0Rp7AR4fMRY+x3N9FbFCSzwixk CmcJ9MNRbpvzv6QtV3rn0plknl0 2020-04-19 22:15:39 185.220.101.159 13159 14159 +a [2a0b:f4c2:1::159]:10159 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22200 +p accept 80,443 +r cosmotor x0ZTr7hDSlWlAlZ6cFIBTGz4RQ0 eX31MynbPQc005CvukeV3akWOOg 2020-04-20 08:36:59 78.47.98.200 443 80 +a [2a01:4f8:c17:251d::2]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1490 +p reject 1-65535 +r nodetechnoweenie x0tgJPLgdufJ2+wk6eNz/lVpLA0 mfUFUprnusnVO7W+UedTQkJtBvo 2020-04-20 11:47:13 34.221.76.150 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r freakonion x04sf7URhhpInGD3UDpv10wScj4 45iD5IFj2AYxpe+1zneq14OkNek 2020-04-20 00:35:48 5.103.132.68 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r americium1997 x1zdgYMWq7yDn58N2uyHP89gw3A clMvXf1cRpnt/qrBFt8UwSIvNaA 2020-04-20 12:15:51 51.77.136.241 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20400 +p reject 1-65535 +r snap277 x1+880LA1h3wr4GFq3nMPm54Ftw jk263agpayq8QWYIyulzsG2KZi4 2020-04-19 20:46:37 2.123.60.221 43115 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r ashe x2ET1as/xzHWeKQI63W8BvRGX04 UwbFdKeuyqHj4W6wxI9gcTLGm3E 2020-04-19 20:22:05 198.16.92.157 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4160 +p reject 1-65535 +r snap277 x2ypbmVmMIcV42C28p+g10dMJfg z5RAOVhcULWJyNH5e/XNwtf0/+g 2020-04-20 10:52:10 37.115.200.247 33219 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1360 +p reject 1-65535 +r tormb4 x248R32MI+CvgrSi9mQerAuLYQg lJr/8VFxJwYk0fhG1+bbVI66VYo 2020-04-19 23:03:54 13.229.73.242 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=260 +p reject 1-65535 +r MINJUS x3jZJ2ahu04gand7FN3XJZ+x1zk eqWz0wqbL14Oe2b1KyP/wgSZ92o 2020-04-20 08:32:05 95.211.118.194 7002 7003 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p accept 80,443,1194,6667,6697,8080 +r Unnamed x4DZGMg6Y8iuXTeOMslL/ODelVA ZI5d9LItWGBoNt0lLq0Vj6Ill88 2020-04-20 06:37:45 51.79.53.139 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 25 +r MyNickForTorNode x4QQNpp6sR4GzvqjJCzNElmkGMo mQK5Ov2X3SOg9Cg5l8XjDeL97yU 2020-04-20 05:28:09 79.165.92.148 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r FsocietyLTD x4g+GU20XFUneLLu7ka/wJKqqaQ gtHP4LLKnw+x/4bJDbcru6fgqxk 2020-04-20 10:28:01 51.15.1.221 9001 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=108 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r Quintex46 x4r/7uMg6g+GCWF2PmE/0vrIVfU nawXMMzDYE+dr0MGJ4obN4OHAfI 2020-04-20 06:50:53 199.249.230.69 443 80 +a [2620:7:6001::ffff:c759:e645]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Unnamed x5OjPyiCbR8YRQQxLGaOqBV67yg wLgwhYgfmr4J0Q9LE1Lz6wlHfqc 2020-04-19 23:30:01 217.182.95.221 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=704 +p reject 1-65535 +r ori x5OriFZd3TyeTG8VzLnYx++WTOk UohqWpEql02J0kRpXcjNaSu7Nro 2020-04-19 20:39:33 85.248.227.163 9001 443 +a [2a00:1298:8011:212::163]:9003 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48700 +p reject 22,25 +r t0adwarri0r x5RtmhkrvkTByKkmqLE1rEldZjY uGl88Okm9BpRl6XI167e3u6WS7s 2020-04-20 07:04:49 198.50.238.128 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4830 +p reject 1-65535 +r Zeilentrafo x5gg8rNIWyWdQIUWRitwDpkASHI nBLikUaGqmW1kDJL87iD77N4VLw 2020-04-20 07:48:02 94.199.214.229 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1800 +p reject 1-65535 +r snap277 x5iSbS8Ppq42VMbMyB3MaiQOoR8 GZdQQUc6L3zNYvlGEhLJq8AQJ5M 2020-04-20 11:21:25 197.2.132.14 35889 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r TorOrDie4privacyNET x6AW4fhc991zkUrkD1W3GD0RuP0 GLYGrwGgd0h1ehBAQP4IADFFGuM 2020-04-20 01:16:08 217.79.181.90 9001 9030 +a [2001:4ba0:ffff:58::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38700 +p reject 1-65535 +r cryptonanus x7Xj1Q2R7w97bGWiJwoisqfdrHE 1z6x0gUHL4+pL+qsdImocW3EcYs 2020-04-20 11:24:12 80.211.192.151 9001 9030 +a [2001:15e8:110:3f97::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8260 +p reject 1-65535 +r flaus x7aht2tkdts9qMlg4mLMdCW1xfg LRyeeQuSEznbR+51oixskPR0FSE 2020-04-20 02:44:53 62.109.4.115 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8940 +p reject 1-65535 +r Unnamed x9SozQvojWjDg1/LDAXKdoai5tA M8cV6y+1vF7Xb/ndE0VHzfnfkTw 2020-04-20 05:46:45 92.100.37.98 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=52 +p reject 1-65535 +r okamoto x9Z8lFrhin9TKZ4wooTg47yeQwk q4UKaVue7pNwketFWhuYpGCXbUI 2020-04-19 21:12:44 216.24.242.34 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6300 +p reject 1-65535 +r pizzarelay x+UNe3aw52Ft/gfrg03rAgSmQyI HoKNJZtx3NCX9V34AsKcfqnmwms 2020-04-20 12:31:51 90.224.11.107 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=25200 +p reject 1-65535 +r Unnamed x+fYxIUNak76hI98OSL0yjRC5ME IEihCk01HV6ZhAGNYBL8thnmoJk 2020-04-20 12:04:15 54.36.103.231 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=742 +p reject 1-65535 +r MCdrKNe2 x/9gbVnH9r7KijQdPPEbQj84LV0 ygGZo6DyWwF6/mCwUanZXHEOoXQ 2020-04-20 12:08:37 94.16.121.20 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r nazara yACAILVQFZSSVLdJoqp4CqIrGKE 9ek3a6w1PbOW5Wf5mmhX2uvAPNE 2020-04-19 20:45:43 167.172.202.31 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=2000 +p reject 1-65535 +r Unnamed yAS+j7HHxC1DxKXiA553qg/zqLQ Og1G8cluItH299D8xrM+3226vs0 2020-04-20 12:41:00 192.42.116.161 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=819 +p reject 1-65535 +r Unnamed yBEZfTrk7rKCIkCLMJRuLH3W7jw rG3nsc1+QNWhGCbAOs9mHqN/on0 2020-04-20 12:01:18 205.185.113.57 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=883 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed yCojOoncPZTPMh4WItmlOOEmwhY soVJ7HmorqRVNT2D194gMHMxc4k 2020-04-20 07:51:59 212.47.237.191 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3460 +p reject 1-65535 +r ethentry2020 yC867g33hdnH9AeCyb1ePd/uOqU 6JgFnDGomaU2UXeu6sF926FZh+E 2020-04-20 12:28:53 91.54.218.198 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=753 +p reject 1-65535 +r ToTorOrNotToTor yDu4rj9xLay9aCkFCQSqW7QN+Vg 3ZPIK6CRUL+jYdiE4q4FQ77agjc 2020-04-20 01:15:43 77.224.5.241 443 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r FOO yGuYTmzaHWgv/DgVZriluqv7QAc zt3Ytp9pjJQtPjL/9xLXweLe/C0 2020-04-20 11:08:32 178.17.174.224 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=12000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r charon yGxTjvCiTgEDQvMNvKzCp+t8qDM 3G49/m3aIWuuBWuL3SZr92vCBlw 2020-04-19 21:38:29 173.249.8.113 443 80 +a [2a02:c207:3004:1074::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21600 +p reject 1-65535 +r newton yHHJFImIbV4ulME+oaX9xLbcUgQ 81y24MocQYU8U39+N/2KklwL4yU 2020-04-20 07:41:47 76.95.175.223 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=879 +p reject 1-65535 +r theia4 yHpNi1NPeP3w9GObVfEhQB/vJZw EkC/C+NW2KhJBU9V8TYSbEGz4Uk 2020-04-19 22:57:54 50.7.74.173 443 80 +a [2001:49f0:d002:2::54]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6700 +p reject 1-65535 +r snap277 yH65OrN5Ic25GBrZ5QhcdpTgs4w GBmqf3hptvUuJyeHC/W0wPgHF3c 2020-04-19 23:19:24 179.93.39.123 35117 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=363 +p reject 1-65535 +r laxus yJHgb3RADZKpSWxq018ZszeTOrY M8rfOT3RWYMEaLL7Ectx2RzFziA 2020-04-19 20:13:36 107.181.161.182 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=458 +p accept 43,53,79-81,443,531,873,981,8008,8080-8082,8888 +r freki yKsbKvDLquNhGoFLTH043ODL/rQ MoI10ahhNgs5a/K4klH+zFuo++c 2020-04-20 00:49:12 185.100.87.207 9001 443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50200 +p reject 25,465,587,4899 +r rucola yK4m1IGVBNAVetTF3n1aCn4ZDRA 1fWwiQou1VDAxiqaCpox9E08kf8 2020-04-20 02:18:23 109.70.100.9 443 80 +a [2a03:e600:100::9]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82800 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r mayforth yLDHcBh08LWvzasLriMf4wPIIo0 iOKDaznAJyWWv6hDerN4zW9DmyQ 2020-04-19 21:13:26 43.252.37.14 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=433 +p reject 1-65535 +r dustsandstorm yLNPwxnjMBhZ/bvCOTNwgTAviY4 1ZD+wOyCaXKM5ePDwatOm2ccHgM 2020-04-20 11:18:51 202.157.177.224 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=403 +p reject 1-65535 +r welladjusted yLaW1dW5K70O0kPgSgzzHpP8U30 VxUnKAG9WOsc9jyB3OMq+G511y0 2020-04-20 01:32:50 176.9.180.47 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=72 +p reject 1-65535 +r cressington yMO5oRgwMUwVOM8Zq8OrJljtaz0 39E/JOT66fkgHQxlMK+4hPhs4EU 2020-04-19 22:36:38 190.10.8.68 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=933 +p reject 1-65535 +r Broomer6801 yNxrKOQ5ePu+IXMjyQGiw1Yy0uc 7g0Y3d1gH+bp89Wd/LwAyNTxVr8 2020-04-20 01:36:38 80.101.143.242 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=601 +p reject 1-65535 +r pros1 yN4m0tEZvn9Qnmcu4aPV+yXcupc cBM7kLeaXAfs7DH6gr8qqUADuv0 2020-04-20 09:32:21 145.239.84.172 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10100 +p reject 1-65535 +r snap277 yODXQWbrB51SXStbdDwB3g3bc2Q 9rpsP8ztn49aNg4yUKheueH6/vo 2020-04-20 11:42:05 99.250.141.16 43715 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1350 +p reject 1-65535 +r relayzy1 yOIuJxj6kWY3j4cnBUsE4Quuj7w P2369jmgFKH+qjqx61IsKFdeoL0 2020-04-20 01:28:36 108.26.186.82 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r Unnamed yO2Gu/Fl6NvM7cwUQ+GutYyx7QA dScrJ7fdwPDw6d3/CbSAHcYmG8U 2020-04-20 03:57:45 97.86.53.120 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=920 +p reject 1-65535 +r miko yPOIyOh6DMxmlTpgtqSUIyUFXEw Tybwh9cZ02lFspBq8AgSsac+4HM 2020-04-20 08:54:35 140.186.10.163 443 0 +s Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1390 +p reject 1-65535 +r Assange003ru yPQC/fieW1HYYq1o2MF9+lo3G6A mgjvZdxfT/7NTsf0Jx2QwCn1xms 2020-04-20 02:49:32 185.22.172.106 9001 9011 +a [2a00:1838:36:29::9001]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r niftyguard07 yPb2wYNEVPHpJ6SgXo5U62I9S3M xFTZ18RrkxDwcz29iUaGpjWK4LY 2020-04-20 12:45:38 185.220.101.216 1216 2216 +a [2a0b:f4c2:2::216]:1216 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p reject 25 +r tuasorella yPt4twSmLwHNvJAAR4PTwieHQCg 7Gu8f7n9dpWYaWovgKVqmmCrXow 2020-04-19 21:05:05 69.195.146.158 8080 10001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1050 +p reject 1-65535 +r cowcat yQyjt/4BoUa4Jo1Wl33EosAkueo Jg2qmQVwxV4DZTDLDq0juEmrG/0 2020-04-20 07:28:38 192.160.102.165 9001 80 +a [2620:132:300c:c01d::5]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14400 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r torpidsFRonline1 yRECEx5rnOz8VsSimtpOY414cvc DpbE8319l8vMOEGBh98OAgEk4e8 2020-04-20 10:58:40 212.47.254.236 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5320 +p reject 1-65535 +r nobody yRzc4FpKMycjuyGJjhvFX77eWRo UY0BxDK1iY69HUNIX004pnOKQ+c 2020-04-20 03:15:24 89.14.119.60 39617 32825 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p reject 1-65535 +r eddie4nl yR3/auRc+qch4SE0IZHCaHcR8S8 dG9r0a78dfxDQM/+xO0JobN7ClU 2020-04-19 23:10:37 37.187.96.78 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5600 +p reject 1-65535 +r netzhub yS9p7ldWIA8WDM+v6cPJhNPm1WE FfjGnHsg+oct4Tybd22e/ysogxs 2020-04-19 20:03:13 195.201.20.82 21 22 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=30900 +p reject 1-65535 +r punasipuli yTAAp1TxknrNO2BzS9jUF4aL8EM 7Eti8tILKNYFLqAiR211Ox1k8T4 2020-04-20 04:05:19 94.140.116.25 9001 9030 +a [2a02:7aa0:1201::6eb7:1743]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r Unnamed yTZGygIX9zRS/BcHKX6tTFcxv6A KAl/csSjcND9Js47n+DUT8is17c 2020-04-20 11:37:52 167.114.92.49 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r lewshlyhatupaladeb yT+eCmw18JZaX39uKGIo7opC/yY pGvc4DCeEJ+OGI69+xz4I0RimAw 2020-04-19 20:09:40 195.123.247.40 9001 0 +s Exit Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r Unnamed yU0T9uTWPHvKJwEeJ99wTRnMnFg 73Jw6bliAoTuubNSjno+DNIZ9uA 2020-04-20 08:34:29 103.101.129.72 40806 38425 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r talyn yYV98mwnRz9zONYTgyycKZq/d74 NbWuzefCGCkPI5t/Ivn8a9Osidg 2020-04-19 20:32:51 79.137.79.167 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed yZAWWXPjofJ+drGkKd4V4A9TgSw fCoD3ZPaxGtIZ/1nJw7Zxea1xGA 2020-04-20 06:17:45 185.246.128.157 40628 43290 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=140 +p reject 1-65535 +r ProstoVPN yaghx2ygctfU02jgTN3aGVsfXE8 CHbxqiK/4IQ5JRP1hMMsTHrN4Lc 2020-04-19 20:07:08 51.15.54.182 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r CedarHill ybFrXTf1McjGwCgeTsTwVuhFQdA WwV7/r93cQFU1FjW+b1r3bw/MkI 2020-04-20 08:58:22 45.33.27.210 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=623 +p reject 1-65535 +r Charles ybNKvyww2la9AGt7QmEAmAcr70w 35h2naKcQ4PvHtBf7sx7e3uDTJ8 2020-04-19 23:48:10 54.93.77.70 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62100 +p reject 1-65535 +r sybaze ybaMgCyiDD5PpG13FT1u3IDxPPU 5wmTSEdBedOjzSYOFTUGApTYVLI 2020-04-20 09:43:30 92.243.0.179 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.1-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=381 +p reject 1-65535 +r angeltest25 ybyEHhgLNfIp/UdmT4TPiorbP2g PjH4Bgwn5c9/o2VLf5oyKj3J0wA 2020-04-19 23:45:10 185.118.164.41 443 9030 +a [2a03:a0e0:bad:bad::61]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=360 +p reject 1-65535 +r DaVinciCode yb2Y31K/j3bB/KQBBGV/K8mWrio 5K6l/ooKz48kfHL+La3PLSZnhGU 2020-04-20 12:15:49 81.67.187.21 14586 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7040 +p reject 1-65535 +r bonvoyage ycXBhLLoegUxnfE6yGQjefFh/ww EdHpzVJV6zc1kPrIgGPITZ2ORLs 2020-04-20 12:19:31 220.245.147.170 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=72 +p reject 1-65535 +r cycasctornodensu ycbwRGzxDbba5YjpGGpuedwUank hH4LNsrrwOX2/lG1nJvSNpujfJw 2020-04-19 21:47:58 46.5.93.128 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=740 +p reject 1-65535 +r 8af34cb1 ydArFkS9R8E243n9+vSXPRoc4Hw An2R2REHKD8U2KI6dexay1fUqNY 2020-04-19 22:36:37 193.111.26.37 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23400 +p reject 1-65535 +r TorForEveryone yduMfvkBPVpVEjlBSsxAsGDhFNY ckjEvdKMpUrLRq7XSqv/wtlQheo 2020-04-20 10:50:20 86.81.82.159 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2790 +p reject 1-65535 +r DefconFurs yd85qr9ONDCeBOHlbbn6bPN64UA /j75TZFsaDLBDNWhkwB48ARwn6M 2020-04-19 23:00:54 23.129.64.190 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4540 +p accept 1-65535 +r VolkerKeyWebExit yd9kr5JuLlhONF0TvOSpfCMaNr4 2WbEAu81Cpab1P+Fbt46qpuVZFs 2020-04-19 23:28:25 87.118.96.154 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r wommelator yesjrRyH4tg4pxJK2zqoIgQcpIs Th+0xEFpPLe4oGmh/3xkM+nI1Ow 2020-04-19 19:43:53 89.244.76.1 443 0 +a [2001:16b8:5a00:5f4d:e86c:661b:a9e4:82c]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r be0d2ef2155c yfrhHCgBpCazkwi07MxCYtVz/9E hghRjnprrhX+vPsFkWObD3zVtxg 2020-04-20 08:09:09 51.81.254.11 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14800 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r alkalal yg5ys42X18xof4ja4TamBQnPtt4 g7NMUa2ctMbBuU3Jg/plIIFFO1Y 2020-04-20 02:48:35 195.254.135.76 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r pbx yg9ZFvIUd+rTblP9ej0O6l/aL6Y gxzdLyWbp0FDJs6PKqcCKDQJJ5k 2020-04-20 00:03:34 94.140.116.167 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4920 +p reject 1-65535 +r snap277 yhppu2zS6TNek6j9PwZbXu85ZEg 5Q6vhJPpFAWFf6ym7fdCp2YkoIA 2020-04-19 23:59:28 78.221.28.59 41043 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r OnionWindows yilgP+IUPJvwav52q115QBlCccE GtfnjP6cOeq19iefaV5EuHEopgo 2020-04-20 02:46:52 80.211.150.177 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4320 +p reject 1-65535 +r niftyjackrabbit yjfNRnmUSdg7a5i4wixkmQYweIg 9ccB5XJp0c3V6k7J+WqsAuBHo8w 2020-04-19 20:26:23 185.220.101.4 10004 20004 +a [2a0b:f4c2::4]:10004 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49900 +p reject 22,25 +r PaRaD0XTor yj7gQE7t8IFyPSoPcxPaUMyrI6Q VrHaH34Ygw1J41/tWM+VRtUoYXk 2020-04-19 19:21:17 84.141.36.228 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=85 +p reject 1-65535 +r privacy4every1 ykLZWUf/5f29pRE5+vgJtDUu/+w hcyBRIIbkrZSmkMYXd3t2FmOcRI 2020-04-20 03:08:49 66.228.51.207 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=2740 +p reject 1-65535 +r 1blupowered2 yk6d/ofeh+UC87UD0H7I78ruJUk bSzVFxyRvqpvCC3CQNCOJkwtPeY 2020-04-20 08:19:18 178.254.23.142 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=70600 +p reject 1-65535 +r FOO ylW41x/SUbCWBIoiU3TE/W/k1gU Wrhp7GF0q8h/paf77/2NDGPNgYE 2020-04-19 21:19:14 178.175.148.35 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=14100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r phasenraum ylsRJUIzN4ME5YPyjcW6OL8Ev3s yuoJ8wB84wv1OaeT29gkqDtjtD8 2020-04-20 01:20:09 79.254.1.69 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p reject 1-65535 +r bentleywashere3 ymGLj7j98cZwunE5sePvziV3FVE PkoxLrO+1s+uZfrs9J10M6/GFXg 2020-04-20 04:12:12 198.199.90.205 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6170 +p reject 1-65535 +r renewablefreedom ypRwQhcmDnSD2ohxnKzXqUxWTVw Rboqu/x8b7NdxGLNRvc3umezYx8 2020-04-20 06:35:24 185.220.102.8 443 0 +a [2a0b:f4c1::8]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r x55378008 ypWzWExE3tgQevWz2MJcVizGTdQ ibQ0A7IVT9yKiOseYO3KD25fQ1w 2020-04-19 22:18:41 46.4.49.62 9002 4443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=83000 +p reject 1-65535 +r androidd38589bfe28f ypnmi32Qp+mB1gNQA358mZHIntI JlZn85dUb2x0L0SPN7keGUD6UHo 2020-04-20 03:01:16 87.74.191.26 8080 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62 +p reject 1-65535 +r Heimdall ysHusyT4ztrpxDLpnOj0Ld9MtJA TkgrcWrD5BIYoOn0zAgdjhcaYps 2020-04-20 09:51:57 51.89.23.157 9001 9050 +a [2001:41d0:701:1100::2896]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19600 +p reject 1-65535 +r beroal ysWQO6dL61hd2UfrZXsZWOJfbMM usN7a4NDw37S5sC+JSg0RN+rCEs 2020-04-20 12:27:15 192.162.141.53 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1250 +p reject 1-65535 +r faficzu ysmYUg1LgyYopgeoO+OoecGoLiM P9XlymP4lBpp8kJMsOVM4hBcqtg 2020-04-20 09:26:39 155.133.16.199 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=171 +p reject 1-65535 +r Unnamed ys2dY7dZs1VV2Mllo+AQcenftEw mGzFmqZoVxszNarIDSXTfJAd2uA 2020-04-20 12:34:57 188.165.255.84 4443 4080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42000 +p reject 1-65535 +r niftyentry94 ytFHbSPNOA9vDpgPvl9e9KH96RU XnwLKazI+NzgG4xmYlf36v7WQj0 2020-04-20 10:51:53 185.220.101.234 10094 20094 +a [2a0b:f4c2:2::234]:10094 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11900 +p reject 1-65535 +r Ironforge yuHqMyM9ztaedrQZMG7Qo6YZ6EI rjqfJD7kVwL/vNB0MqkbUlx3eds 2020-04-20 01:25:59 87.143.147.201 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=700 +p reject 1-65535 +r thematrixisreal yvV+sw/Rc4mVTJ8rQwJnNPgOOcA vUP+IVq26CoRlXpYcC1WUNLf6UE 2020-04-19 22:53:19 83.212.100.100 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6960 +p reject 1-65535 +r torrelay0001 ywQIRsZH8zjuGVDGzAMmcQIIjFA zp0DSczj6PgOpX4xWvIyvn0Yvd4 2020-04-20 07:12:33 153.126.128.94 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=501 +p reject 1-65535 +r OrionX ywylNx/OAJ1RwqXQmPm/gikPkGw 55hF5bZSBy8EORc6V7pNqwrRI8M 2020-04-20 10:25:57 82.140.239.164 9001 9030 +s Exit Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7200 +p accept 80,110,143,443,993,995 +r pkswitchcph yxmsb/rBO0waFDtCOITt6kOB7S8 w42tPKeJaENxg/wS46MHIVvSXvY 2020-04-20 10:47:06 212.237.100.250 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8340 +p reject 1-65535 +r Unnamed yx7EA6czH+JvIY0XjfiQgBTMT2U bEeeOlyWLtyHZkaILb5Db5E0t6Q 2020-04-19 21:08:58 95.141.83.146 443 80 +a [2a02:f58:4:300:216:3eff:fec2:a0f9]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21700 +p reject 1-65535 +r Unnamed yyF1bSE8CYEu0rA9wRHN6Tc4f50 36fTDz5vItIclMDrofM43xoSMYo 2020-04-20 00:58:59 192.52.167.71 443 0 +a [2602:ff75:7:5de9::]:443 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7400 +p reject 1-65535 +r Hydra9 yyiSXaYQaaQ1hAMNJhBHHx/9QQA SZCnQIwQ8/PoOqysOKqI8iQ3DVc 2020-04-20 08:23:55 178.17.171.197 9001 9030 +a [2a00:1dc0:caff:129::4938]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p accept 53,80,443,1194 +r apunkt yy29stlCLVethRSO+VEa9M5NYFI tMwTVbZX+PKuKS411VdJvqTYVRo 2020-04-19 19:20:41 185.242.113.242 1234 1235 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r Unnamed yzie+Pom9AwJJaNIc9jx7IJVKXk CIz0WW6Fh3dqzc6x9PB0sj/8pVM 2020-04-20 11:43:57 102.37.10.202 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=350 +p reject 1-65535 +r smell y0OLQwGLlmlQu4C7Pw9Vpo9KWps rCUBk7WBLr1Cz57ppyFLNJu0wJs 2020-04-19 22:22:43 45.9.148.218 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r doutreval y06+nEdaYKXyzaksg84JO9lF2UA gb8RiShpR4cyyqwKfGHFutgqT5E 2020-04-20 10:33:23 141.255.166.150 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r Tohru y1bLqC+t4t58DL0Z7Pd2x/8Fhr4 zRf2l0s7i0Zlq+H6D+3MZCTDvzc 2020-04-20 02:22:01 144.217.240.161 9001 9030 +a [2607:5300:201:3100::753b]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10900 +p reject 1-65535 +r 3a07dbc8ceae47a08b y22bax7T4BhuMBnvqKo05+V5E8A B1F3OHS4OCHPY0AFdYwxsLsYXM0 2020-04-20 09:13:29 51.38.125.129 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r callisto y3KnToGX3zsz7moIleW7hx0Qz5I zEpwv01Jhdmf4HV8d5S/Y/WQIT0 2020-04-20 07:27:35 54.37.234.66 9001 9030 +a [2001:41d0:601:1100::9eb]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p reject 1-65535 +r bem007 y3kF3+xxymWiry8/Ro0GEvJQ/X8 glOqxjtj0GPuO9o5vs9yycjtJ04 2020-04-20 12:10:13 178.4.239.238 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=960 +p reject 1-65535 +r QuintexAirVPN25 y3wNhB/jdu9D94Rf8gGwKQwKI54 2wplQaG1tgVwXJdOCwtsyuredxk 2020-04-20 07:34:40 199.249.230.78 443 80 +a [2620:7:6001::ffff:c759:e64e]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r ByteIndian y322gVdty0N+I7RYmyFvE6tqVQM Ty7EM9R8p42eVbX7MybVlWwa+Ms 2020-04-20 06:40:01 163.172.151.47 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8350 +p accept 53,80,443 +r ididnteditheconfig y4PDZhvNGpKYOteJHUkBY9AaU0I Y1DlsQIts3c80USGJddwP2gafqk 2020-04-20 01:09:01 77.6.180.228 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2170 +p reject 1-65535 +r alienstargate y51ftt/w1ePig0RsS/wxuIogpK4 5Nopx3oviSXEHFUJ/GJCCjo1q0E 2020-04-20 07:08:07 217.100.113.174 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2350 +p accept 80,443 +r tor4ever7 y6UOslZ1OqpEujQG+2xFzrFYPKU cX5VEpsc0q65cZF+YGpSaSLJ3uo 2020-04-20 03:26:20 45.62.230.60 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2320 +p reject 1-65535 +r dthpulse y7WuN+KSepFdcPpxVy0uogPwPoM f1TMSL9hT0jaKCQ+gN7xTe0CW50 2020-04-19 21:20:41 81.0.226.3 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21000 +p reject 1-65535 +r GrmmlNott y7pA99nyhPR6JD7iwIHpZoJ0HSI UQFf2D3C3UEUOhOYkekeeWmCCvg 2020-04-20 03:18:40 176.9.39.196 9001 9030 +a [2a01:4f8:161:36c1:a62c:457:6b0c:a1f9]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57000 +p reject 1-65535 +r niftywabbit18 y8BbDEt4ntFi90czwP/C62q01JQ GrY1WSGSrH8v7WbwGo8JCq/5MUI 2020-04-19 22:15:36 185.220.101.158 13158 14158 +a [2a0b:f4c2:1::151]:10158 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p accept 80,443 +r PacketPusher y9AJWKO4l3dOMz11wk5qdfUiDcw TkKEUPu1UZEk+s/tQHRbghhayxI 2020-04-19 21:10:14 185.165.240.126 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=46200 +p reject 1-65535 +r UV74S7mjxRcYVrGsAMw y9DRvREOxSljCC2DmsaonQriQ+c Dddx/YbnWkrKHaWD3rRTfAPgfeA 2020-04-19 19:56:42 176.31.103.150 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7840 +p reject 1-65535 +r sheikah y9hdSfnIvC/KsSVcfRllJP6SZlk 1k/bJjMkLJyOLiWhKLUxvb21iOY 2020-04-20 02:20:18 198.50.196.138 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10600 +p reject 1-65535 +r bananator y9xW01RSnRzZaIJ1DQsqNEitBBo /szCcr7PA9hOTThslAOFUJw/I10 2020-04-20 11:02:30 84.172.212.108 9005 9035 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=533 +p reject 1-65535 +r niftylaogzed y/DM2dgNei+C5Pthw2+2iYpOulA 7skLOi9ZeNwyk2obBS559ASyjlw 2020-04-20 08:53:19 185.220.100.250 9100 9101 +a [2a0b:f4c0:16c:7::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59000 +p reject 25 +r Unnamed y/x601UrZrq7bp/+AyLY0/kpEK8 F6ji13vKO1t9Y97YdZgV0uwtILs 2020-04-20 02:31:49 141.98.215.123 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=190 +p reject 1-65535 +r KagamineLenAkari zAnfsBYIGtUGhtrJZEC7LW80MlE aALJWhdhqdSi7+5EdtcihgYE0WE 2020-04-20 00:32:35 51.158.148.128 993 0 +a [2001:bc8:2dd2:1000::1]:993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22000 +p reject 1-65535 +r Unnamed zBANwBeiXiRMNclku1GOQwhBWsw SCII/PPAHQntB3G5zgMpcIrh8AA 2020-04-20 07:18:56 37.191.205.53 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17700 +p reject 1-65535 +r Quintex38 zBTJfx0j7pd2aCj8jthYLiHhFmU X/MANUD3jal++urYwTVsJuHn/xA 2020-04-19 22:41:00 199.249.230.87 443 80 +a [2620:7:6001::ffff:c759:e657]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14800 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r silentscorch zBTVc1mFUpC9gDao93NG3LhfWFE czxVfWo7yI9OirQIE21XvYfI1ps 2020-04-20 00:07:52 172.105.120.162 443 0 +a [2400:8901::f03c:92ff:fe60:8e8]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=739 +p reject 1-65535 +r tornickname zBvec9SN7zICxoihWNBxjIhTYNQ GlVQoIfRzOu94S7BNLF0leAgCoQ 2020-04-20 05:32:29 51.75.200.9 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8170 +p reject 1-65535 +r Assange019de zCF5qX1OxVv6VrJ/IwDFMWLOu24 iF4+j77GXDSmswb23BT4KCXV5Uk 2020-04-20 03:03:50 51.89.126.22 9001 9011 +a [2001:41d0:700:364f:7::b9ae]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28000 +p reject 1-65535 +r giano zCLCYNGonUtbOoTNyftMs8ckI1M Yjo4lEGwHs54Zq8uVXK/LDfZ6Rc 2020-04-20 10:03:56 151.76.163.50 443 8080 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=991 +p reject 1-65535 +r Orr zCpXPpBJ/vDTmCYnwouHzYdspig nr7UmhC6usoLdf1UyeVFwEb+Fa8 2020-04-20 10:46:16 139.59.16.5 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=570 +p reject 1-65535 +r memoryalpha zC2MPCpOXsqvAn0MkCLGa57VgzA r/SNjBNtmjRiyPXqb80JzbQ+qmo 2020-04-20 03:17:19 188.192.197.141 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r Panier1 zC42hL5dIEGn+BzoynvvvG4GdG8 VsgxCXoPy13EoUV7E8MnhYfJXLw 2020-04-20 03:53:27 35.177.60.68 443 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 +p reject 1-65535 +r kokopon zDKiB5zuP/3p+OKcqzaawgwrXwo nL9FZy7IFBYxrnmGMhKv3ULeVVg 2020-04-19 22:51:07 91.222.247.27 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=821 +p reject 1-65535 +r QuintexAirVPN4 zEo66WDjYX9Jv5iHt5GGwUy6aBM NSYI+T01AWi8OjJBIk+alX1b/XE 2020-04-20 11:14:20 199.249.230.115 443 80 +a [2620:7:6001::115]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r shelob zEwstYUn6hxkITMO8+/jNE4NSp4 5MnCJSKtOmRPZ83cV1Rmmstl0d8 2020-04-19 19:37:39 38.109.217.107 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1470 +p reject 1-65535 +r snap278 zFFtR+z3w771XG+ZVr6l1r9CwLU sf4O4OOQ0Hu2UyxsH3pDoxnPE5U 2020-04-20 12:18:04 151.84.113.157 38495 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r PwniesRUs zFkRrKkGsqKgDbw4rlp/j3uCof4 psFfmg60G0NjgI3WuiCqpZvB9iw 2020-04-19 21:41:11 51.79.85.48 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Th3S0und zGUadiCoEpIJv4ZcpuzB8JAj3Sg dMLUpAXhvNvlH20phBCC4lL3kjA 2020-04-19 19:14:06 84.39.180.193 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3010 +p reject 1-65535 +r Piratenpartei6 zGkQzyHRfBvWj+IkznaFvrQlWKg 3kbLgm9sAcV+h8kj+aTqFWVqV+M 2020-04-19 19:55:48 188.68.39.83 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=25900 +p reject 1-65535 +r idolprocess zJHd4YwWDsE34E7B50UIGHuudwc 8eB8MlMdDdXxqqVJPpvBAd5Jlx0 2020-04-20 09:19:58 76.244.38.127 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3800 +p reject 1-65535 +r fumed zJQ5npDpZbp4vrIv1OeDZXjLPNs 5c6O2RMJiIgXQkJZHBN5ZOFB3H8 2020-04-20 11:07:06 124.109.1.207 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=95 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,443,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r KarlRanseieristTot zJd8rHkawDunQtYbmkB04aB1Caw 1hELydGbBSqUN2AeIfGwMRc3h7g 2020-04-20 02:43:37 87.140.73.81 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=117 +p reject 1-65535 +r mikrogravtor zJ0QGsa5Od3kM6maRCtfYiMv9uk GIOvOSOfRV5D44wozuuzcaQYz1k 2020-04-19 21:50:14 45.14.233.11 443 80 +a [2a0e:1580:1000::11]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29700 +p reject 1-65535 +r Unnamed zJ/jUIpBlKhZ4/wD4Lm3kzApWiA WUoxHHb+YS8oEurp2rana+ToST0 2020-04-20 11:07:29 131.255.4.214 32671 37564 +s Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=71 +p reject 1-65535 +r fr3anonAF zKVUcqIiK6yxuJEDUljCF5DMpAs +SFaCCeJrBSR0bMoAsBU9+NJZAg 2020-04-20 08:17:09 95.130.9.90 8443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=28000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r guthard zKpiDVyrNM6V/jyGPZ5lIMB0Udg +I99zvQfdgen1XD4zGuKGHqsPjE 2020-04-19 19:32:44 82.118.242.147 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22600 +p reject 1-65535 +r KevKosay zLIy5aoQzcvVTpGarqLQKIMiOrU Ky8A2EH3yTxukgFlCKIDah2/RUA 2020-04-20 08:38:05 3.106.77.224 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=96 +p reject 1-65535 +r snap277 zLkSK0J0MCaOqX8B3ovz1DH6tEU wjfm1nm5q6+sJg+tN6N6KPKDhhM 2020-04-20 06:05:23 90.157.173.234 40871 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r phillymesh zL3rci9uf4fHKg/m+8ukpQU4BAs WnEVH2MXTdMLS8U9eYKWnKqIf8A 2020-04-20 11:56:40 146.185.176.36 9001 9030 +a [2a03:b0c0:0:1010::1a7:c001]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34 +p reject 1-65535 +r schattenbahnhof2 zMsBlBAToF0qmjpZJskBG0J6GJY r02mTHpMtqZn1gQgqqQjFl0KqEw 2020-04-20 07:20:26 188.68.53.92 993 9001 +a [2a03:4000:6:e34b:7cf3:194b:368:22d]:993 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r trustn00ne2 zNZbhGudXLJ1vRjWf0fH9iwRb3k ovOEkTTNFt6NuM5Ex3jhZKiBkUM 2020-04-20 12:02:15 87.248.7.41 9002 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5560 +p reject 1-65535 +r orwell38 zNh57l+8X+dYyOwJjUA3LHyCxcA PoX9feSzivUSyAivX5GNkaEO4Zw 2020-04-19 19:18:14 188.68.37.135 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18100 +p reject 1-65535 +r b0f44cbab55f zO2liUrtaL2Og9sgy219UK1YGW4 yu+0hGmWzetlai+efBYY0Yayl1c 2020-04-20 08:14:19 51.81.253.213 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8260 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r scator zPKLyPsmyMFy3udBcCBWkU0oSb0 SD+mlwYKk7Fca7UJtVISV6APDIc 2020-04-20 03:24:26 163.172.141.10 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15400 +p reject 1-65535 +r YTrelay1 zPL9AEj8yahCvogUcs7BSLtO9Fg /uSxDexHLHroZg/HHkWp7CtEbws 2020-04-20 00:10:46 212.114.110.143 443 0 +a [2001:7b8:60c:1:4:47:59:1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5680 +p reject 1-65535 +r Neo2SHYAlien zPUg4oKycYDvBWoPOJ0IRvu0XXw r/YKsNts+g/dDt0Cgj9bi7d1ZUI 2020-04-20 01:03:47 89.25.33.13 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r oj287 zQUt4oxceQ0EPJZXGl5ms8Ks2+8 GFHq2nr8AO3dv9UMZOcZ1WUveCM 2020-04-20 10:23:42 5.228.129.223 9443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5200 +p reject 1-65535 +r alemator zQcUU2r/HFHEk1nWol+fsnC1Ebs FoaZn0Em5bwFKE9JK5nwMZW8FcQ 2020-04-20 03:06:21 80.219.124.59 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=760 +p reject 1-65535 +r niftyeltab zQnNfH+IFbNyEMfRpihZnHjSLW0 /mU5OAzD9B9ry6IyutSMvLsAogg 2020-04-20 08:52:46 185.220.100.249 9000 9001 +a [2a0b:f4c0:16c:6::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44600 +p reject 25 +r wishosting zQ7uEuYOaG4F3DtzC/pTtKItvM8 P0qQtew4X/I25MSwdxdiWou6Mdc 2020-04-20 07:12:29 46.105.55.153 53601 53602 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16500 +p reject 1-65535 +r jaures4 zQ+aoaUGRDCx3o5kXLp6UCsn7V8 cpuTHBT+USClW7ZPYAubU9SRR1w 2020-04-20 01:15:08 193.234.15.62 443 80 +a [2a00:1c20:4089:1234:a6a4:2926:d0af:dfee]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=580 +p reject 1-65535 +r geheimkaisx zRC1KsyKCtfRtMQLhJdxvR0N/0U t1z+wjI+bzlJkFpvN1QOJQL01b8 2020-04-20 02:05:15 5.181.51.51 8080 8090 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p reject 1-65535 +r chewbacka zR/k+CVpszWEqFf2nNxKnpd32o8 bPTeB0gDI7wv5miIQuyAzcyQzgE 2020-04-19 21:52:08 178.174.172.173 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r Hydra10 zSG5l689MK1xnAZsOMf6jI/oPHA +N/yBdmGYKqFdizy01Jdi0UAUqA 2020-04-20 03:30:06 178.17.174.68 9001 9030 +a [2a00:1dc0:caff:54::a46d]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4630 +p accept 53,80,443,1194 +r order66 zSScwTtq3TQm1gO57VtR/HG41yg yMJyWkBSOebUAQyDYtB383Kd4h8 2020-04-19 22:27:29 185.86.148.90 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p accept 9030,9418,9898,9999-10000,19638 +r vr241tor zSTncTaCREMeHaMGA/8RoxfbIV8 XxsYblEM7uLytyu76pKPu1Fh+IU 2020-04-19 21:35:14 89.144.12.17 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58500 +p accept 80,110,143,443,993,995 +r snap277 zTAhzH2ns9HDym7eiMCsr1e4zI8 Ic4/NN59KBguIX1KqQpq6qd8ggM 2020-04-20 01:53:06 76.26.67.12 35949 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=410 +p reject 1-65535 +r Unnamed zTlZ6e06Z57uKIP65UCg6l4/plE yPblmYgmLG+vcvP3vdZ/MSz6Kv0 2020-04-20 12:07:44 167.114.89.199 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9790 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r normaray zTnCWCZbJeqkq6T9yy35gQTKo2I uEczAVBQha6whIEtTBr+hFQ6SJw 2020-04-20 00:45:59 94.130.200.167 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=130000 +p reject 1-65535 +r Somone zUBqPLzzE7CwaGkMxwbBQkhM4pw TFW0uzQcoou8rICXUB3Xq1wWinI 2020-04-19 23:21:52 46.246.43.138 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=1060 +p reject 1-65535 +r neurans zUbN1GQ/owrBDRejhytWC04X8Eg zK+2qagIyE6Q776lOSzBarL/zic 2020-04-20 07:19:01 45.76.25.11 443 0 +a [2001:19f0:5c01:152c:5400:2ff:fe70:da49]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=436 +p reject 1-65535 +r uname zUlCYE/V6jem7BiCtNjVTkup69U /JqrxamMUecr6PPI4Z6RqB5TwII 2020-04-20 09:21:35 86.57.149.3 1443 9130 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=3240 +p reject 1-65535 +r FOO zU0u0LElA0SWPwGtR4vkgqZr5HE XM9PgsMZxEafCJkzRPPrBcf2wFw 2020-04-19 19:50:26 178.17.171.115 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=9440 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Assange003ru2 zVMWp1VUwtrbh+82JOldhIwwnOg SXDJHsPSzIrIr2qpGPDdY1z0ITU 2020-04-19 20:49:41 185.22.172.106 9201 9211 +a [2a00:1838:36:29::9201]:9201 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8800 +p reject 1-65535 +r AllieRoscoe zVzxJf7Uvl2l8ln3WvPU3RgsVNA CbbyjZogwin0DKTrQ2PTHG3mm9U 2020-04-19 20:45:13 217.12.203.242 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r lairofthesnark zV+F2znFSWVYBgMFrgtxW+VLeUs m9k+h4U1WK6pwwU1KmLSfQyqz5Q 2020-04-20 03:14:25 50.193.143.42 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r TRFIAntti zW6MVIcE9M5UTNcTZdRvEQUY++0 WItRrSoUW0qybGmArjbvM85COPw 2020-04-20 10:28:04 95.216.140.159 443 0 +a [2a01:4f9:c010:49b::159]:443 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18700 +p reject 1-65535 +r justsomerandom zXpRjEeKWGr8jmPjLKAVX/BeQ5w ulB2aeF2Lta8zFqx3JKwGUTyxW8 2020-04-20 10:16:44 51.75.18.244 9001 9030 +a [2001:41d0:305:2100::714]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1160 +p reject 1-65535 +r CheenaTorExit4 zYccraFb1UYKtlutHDBqyHCmpCc MZpxHd7CXNICv7a6CkOWPHIbeUU 2020-04-20 08:22:08 185.222.202.133 9001 9030 +a [2a0c:b807:8000:c93a:ff51:90ac:0:1b88]:9001 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2990 +p accept 1-65535 +r EgitmenTorFreeExit zZI5l00EBf5BtNLEBvrjQ3l61Oo CAecVCRE4b5nLo0CkwhR44/URHo 2020-04-20 07:23:01 185.86.5.223 9001 9030 +s Exit Fast Running V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3590 +p accept 1-65535 +r titanium zZVJ7VplW6R0J6d4NcVf8A7B2iM EXW6nmn9k6ZVOhZNNB/tkfM9HAI 2020-04-20 10:39:12 179.43.167.227 9020 8020 +s Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftychionomy zZfdCEKnkYSn0FfsrO90CMI5xxA adU+MLCdvq+4qY9jqHIHGad0HOk 2020-04-20 09:14:02 185.220.101.135 6135 7135 +a [2a0b:f4c2:1::135]:8135 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44800 +p reject 22,25 +r agate zZikufUNGJF31PiDn/pym1Jd8SE 1nON8TPhKPQfnVgKGzVXNiuxnTw 2020-04-19 19:07:54 94.142.241.138 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=297 +p reject 1-65535 +r mcKitty zZv+MJAQd41k7V5V1e6qkrICDeg B/w2H4nz2iFm8VTWQZ37dF3fuas 2020-04-20 10:55:34 173.249.48.86 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r 2fjsaf2ja4da zaLDNq2H4i3wKYOIej90shBw0C0 lBpyL/vWE8//FadTNZwQ2yTGIsI 2020-04-20 11:46:36 192.145.46.247 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35600 +p reject 1-65535 +r niftygerbil zaLqMm4icsV6yyZ3PXJSwhF5W3g mZC9whV+8Y9QNh2KqbldBTK16iE 2020-04-20 00:14:19 185.220.101.143 1143 2143 +a [2a0b:f4c2:1::143]:1143 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=55600 +p reject 22,25 +r jonasBebe za66RY9hKXdmQ3UZNAdqUdhRw0g ybcRcqe1yeaU7OwvDypmfq8PUog 2020-04-20 07:22:23 95.216.53.157 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33200 +p reject 1-65535 +r Hairytrotter za8LdMRf1bGVUZio2SyKUYpT0Hs mWfpn8AGUtnCDYZ0anzcFTqBDyQ 2020-04-20 07:51:43 136.243.8.18 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=96700 +p reject 1-65535 +r Unnamed zbBc0OcIilqbaJqEQlK0xoG3TzA cjVSEP0UVOQi7xy2E7FBaFcP5LA 2020-04-20 11:04:56 95.84.140.36 9090 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1920 +p reject 1-65535 +r 2mpdhack zbJgXSvSjaMcyRlW6LrRR7ffivk d1yaQkKU4GVwdnbR7aMJPr9STXM 2020-04-20 07:08:11 24.147.232.251 9001 9030 +a [2601:19c:4500:1012:ae1f:6bff:fe02:95f0]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=518 +p reject 1-65535 +r YellowHouse zbmOJyLHfw7Ap/UWepLacENuaHE CH/nIzzeovMLagq0L7XzsFOGTiU 2020-04-20 00:31:00 84.118.98.18 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=190 +p reject 1-65535 +r PUUK4W8SKJNW843 zcTiZmh2hu7GUxPUsKXT+hZTAV0 N9r7XR8aBmU7nWnJ8stjNPmKfZA 2020-04-20 11:49:36 158.69.153.242 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r 48f16fea51aa zdWewpwirG8lZAPwSd/PT0TUrTo AuNFTH6Nkz3nEbVDNB/0+Fu8B+0 2020-04-20 08:10:24 51.81.254.10 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8980 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r rotorstator zd7DzEsP1QVMmbLShD3otgmkyro To67L5PuFn+BZkfXe1EOtvSMXuQ 2020-04-19 22:11:56 74.91.21.2 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3700 +p reject 1-65535 +r noisyyanky zeQUnw3GWnvhrkQDQL4cehgTXik zSKw9EY0+aTT/Rr7xaAqPBPKO9Q 2020-04-20 02:41:32 192.250.236.130 80 443 +a [2607:8b00:0:96::2b87:498c]:80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4730 +p reject 1-65535 +r silversurfer zeTF3J1jnpFbmbRh7iQwRPyiZLY sCWhtqoJb9STrcZ24z2+zcBh9eA 2020-04-19 22:21:10 178.17.174.211 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p accept 43,53,79-81,88,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9999-10000,11371,19294,19638,50002,64738 +r DuskyHusky zelVA67Efx8/fqou/UJsL/+zwqI nx1rxFYDU80Vrs6AedEHIt6YMWs 2020-04-20 02:22:30 73.225.111.191 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=564 +p reject 1-65535 +r TheBlackH0l3 ze1hWtHMz3DBGIe9ipGNPQs5KQw rCVRKhSHK0RKxQ2ElUmntO50jQ4 2020-04-20 08:05:35 95.208.52.79 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=132 +p reject 1-65535 +r torrresdemorte zfNksXW89jqQM1Tl9XdktMNB4jI CF1iTy4YOYHv2Z+/fD96tZwtn4A 2020-04-20 00:19:13 77.1.94.65 8080 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=131 +p reject 1-65535 +r BananaBoat45 zf0/2kKZXXnu9C9YBn3/hifnwXk EYvnd/cAZO7f2lCdG1eQ1wvNoNI 2020-04-20 08:01:04 75.110.46.136 9002 9031 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19 +p reject 1-65535 +r Unnamed zf5Hj4w6Jrzq7CqWkLzv3qiSxuE cFOGMzCGndL1BlWLLTfnebKxz0s 2020-04-20 04:38:14 172.97.214.219 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=111 +p reject 1-65535 +r snap277 zgJPa+ZFwkWvMviJ24ve6IrjzFc UhN1fYuyiz+qvWfKBV0S6eg+H2o 2020-04-20 08:13:24 88.89.236.250 40347 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18 +p reject 1-65535 +r Miniworld zgNceUbO5oQlzSNY5iDkCKnII/0 y4YChmn6b4EnAMeP+1qWyVj02NU 2020-04-20 12:27:45 193.106.31.2 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9200 +p accept 554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r NeelTorRelayB zga6HqRf0yp56vf+ajsZGef+WFs VGhZP1oiylxXI+ogcpt04oU9uv4 2020-04-20 11:03:24 174.127.242.253 70 23 +a [2001:470:b:1e8:af1:eaff:fe86:ad09]:70 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5010 +p reject 1-65535 +r TorFakedOrg zhU+PIExhaUWw0HPjCvmvvun064 b6OZkVIc9XMDcLkqZ9FsN2UYlVw 2020-04-20 04:28:25 87.128.111.190 9001 9030 +a [2003:a:37f:ef4f:dead:babe:b00b:beef]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48 +p reject 1-65535 +r EuropenSheil zhb8xoqO+w0dPg8+e6Kk4ZUCZuk Xfd2ei6qh4zHLxTyZG450ADYLkY 2020-04-19 20:24:56 47.244.148.197 9001 9030 +s Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r dobbo zh/XZZ8t/pK4gwg8DGyXRhbRfz0 Hh8llQF9XGptFbrJf+nRTcP+fdg 2020-04-19 21:32:06 185.15.72.62 9001 9030 +a [2a05:f6c7:62:1::5]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r swgpitor ziQ3Sw1TuFRPwg3+poETyAtoFV4 xF0R3flIXze3hqKFh0YCe8z/Hbo 2020-04-20 06:02:49 62.178.138.46 9001 0 +s Exit Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18 +p accept 80,110,443,6660-6667,6697 +r qki ziVI+93l4wHDCawHWjGYwHVRIoI ldJgnbbcp3KY4D9FYkjVaQOQS0k 2020-04-20 00:21:51 172.104.126.109 9061 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=686 +p reject 1-65535 +r freezone zjTy2lt7QZ2dEmUw3OhuqH1tE+4 ELe1diX8EJL64FFWM2ccJS3lC78 2020-04-19 23:44:30 37.252.188.16 9443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24000 +p reject 1-65535 +r dpvvdt zkLRNOIjyCCQUq/fxTRAiKy6ko4 TvupX+Mqo4vV0G+qTAM8ggzTjq8 2020-04-19 21:17:38 77.37.160.18 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r BeastieJoy61 zkfwNW2GzwoaIAjZdiMhbVYPsKg 7erjZ2/mXLzfd+JHJ31u9jPeuRk 2020-04-20 09:28:33 85.25.213.211 80 465 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 1-65535 +r rymndbjcyirjoytu zkn5MpvxGKHB1CAVN1qtKYRPkwc nVaWeiahOGuyUwcLOX1V/FDzpqE 2020-04-20 11:22:34 45.78.205.127 80 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60 +p reject 1-65535 +r WindowToTheWorld zlVHVOJF9z0HdbTHkilt2uFuIoY OylIjQ6vfmWqtSmb2vJ14FFdbyA 2020-04-20 04:09:38 45.67.219.13 9500 9501 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=70 +p reject 1-65535 +r tor4ever9 zlZPQ1KbvFp42ARJa2Vul7+r5mw 3qoTrfSKWqJgoGwJh8wVG1aAQm0 2020-04-19 20:29:21 45.62.229.190 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r guidelli zljPZm8gmFdQL86vHLUvY4r/vWM wnCWXOg6u4eM6xzMFhnn4/7EwG4 2020-04-20 07:01:09 194.187.249.116 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8730 +p reject 1-65535 +r armik zl7TRTmMwC1XM0fC8jj4CxjmgO4 72MzZ/TLDjv6NL4AlrKxgukX/PA 2020-04-19 18:12:32 178.140.193.198 443 80 +a [2a03:e2c0:bc7::2]:443 +s Fast Running StaleDesc V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10500 +p reject 1-65535 +r itsyndikat zmgT/qJW7mO80qF45FMgK/qmT6c jY4tkMj5q4N1z0loXRk9/KxLoZI 2020-04-20 11:11:42 85.10.196.35 9001 9030 +a [2a01:4f8:a0:6171:0:ff:fe00:12]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10400 +p reject 1-65535 +r UenoStation53 zmlLqNAZ7mDY54OMwXfmic6oJeo WhjLgCzmcoMHTTVUOgVkyU4Dymk 2020-04-20 05:57:59 51.89.143.153 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13500 +p reject 1-65535 +r updawg zmmRYqd0leh6ivNztnTaNsHqc5c CghuSpDRXPMM21Vj8MsRmM/IF8o 2020-04-20 11:56:07 45.77.151.38 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=664 +p reject 1-65535 +r snap277 zm8IWxUuohXPASiBRS2o4mExSHw oulrc6C2sgBgrph4Z8kgG/tMAh8 2020-04-20 00:08:15 73.139.34.219 40007 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=180 +p reject 1-65535 +r murphtor znf2pTf9HszN/w/o5ftEakOON1Q 1Lxuj3hqo5yxDQ8sZ9PXsQ68GZM 2020-04-20 09:26:24 185.251.165.74 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1610 +p reject 1-65535 +r tor4ever2 znxcAGfw6lPFLEXGlq+8PESNEFQ enoAugqwDCIJwZRLu2H8YwseVEQ 2020-04-19 23:43:12 64.137.178.40 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6900 +p reject 1-65535 +r mj4 zoY8Iq1au+r2Bq41oieBxAnYleU MYJOxw9Zd+04mpB7kdYZPGiQSeo 2020-04-19 21:15:37 93.115.86.4 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21800 +p reject 1-65535 +r Unnamed zopj5wSUNXDIjZUQUcH9VCA4DmE HNLMvPVlyUcqJ4ydEu8N0T2BE7Q 2020-04-19 20:13:10 5.252.152.207 47018 31843 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=103 +p reject 1-65535 +r tor4thepeople3 zqyjSHTq0QPSfKanZQsWES8Ssgk tlrgWARJxI+j9TLZm5NlozNjEFc 2020-04-20 10:57:29 51.15.43.205 9101 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62800 +p accept 53,79-81,194,220,389,443,531,873,989-995,1723,2086-2087,4321,5222-5223,5228,6660-6669,6679,6697,8008,8332-8333,8443,8888,11371 +r snap277 zsDuoJsRSrEuYUlmFsKdToBxc+Y 0gc+b28PRxB4Wn8/R/3LFtIMGbs 2020-04-20 12:48:23 93.126.114.216 43949 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=100 +p reject 1-65535 +r boardwalk zskvO+ii86RtPAQnIda9vy9A9MU iqLslQ4b3USMaP84HiqavGgkcpM 2020-04-20 08:29:14 82.192.94.125 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18400 +p reject 1-65535 +r ndsrf ztUtqvENne2uA2Jy1dAFDxIfPt8 ENJ6/d8wpn3MVoS2dqXolwIPsHc 2020-04-20 05:52:09 78.30.49.180 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1630 +p reject 1-65535 +r FSF zugE+gOoemXKpryzolC17ZI8CL0 zQKFCxcOjRQXkZHGOF68WwRakr4 2020-04-20 05:18:30 209.51.188.48 443 80 +a [2001:470:142:5::48]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3820 +p reject 1-65535 +r vautier zuz7uC/EhAUeiXGcSdyAP2WqvHI zfPCnfpijy/5tcZpVNTrzV64/rc 2020-04-20 08:43:00 5.135.65.145 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7990 +p accept 20-21,23,43,53,79,81,88,110,143,194,220,464-465,543-544,563,587,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8080,8087-8088,8443,8888,9418,9999-10000,19638 +r Arav zvL9Dhlz6gTRRE3a7/GwvDwMObE X7IvTU4MQE5wSJjwWYiL7iEOAqo 2020-04-20 01:02:10 80.92.223.69 8443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=577 +p reject 1-65535 +r apunkt zvvLX85fs3eErUibzexG8dWcBss G2pRjCs/f3LzhmfM1mA/6A8gttI 2020-04-20 03:08:34 24.134.229.209 1234 1235 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=650 +p reject 1-65535 +r Assange033sg zwUdRmy+sxkl9IqTLiqg1/IDEgs HgijS4U4IG+4vAgBYRfGyKAEikk 2020-04-20 00:25:53 51.79.158.69 9001 9011 +a [2402:1f00:8000:800::1225]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=861 +p reject 1-65535 +r Garlic zwkWqCS8aGWdox5AFrX8DKap4pg +aCIecxxFVPQ8gJ5XJYsCjp8JWI 2020-04-20 07:34:01 46.19.141.86 8100 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r uoaerg zwzGneHn51otmV/Y2fp9IJg1Mdo FUQWLj7jvOChBhRyw2yGnp5m8ww 2020-04-19 23:55:21 137.50.19.11 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4840 +p reject 1-65535 +r 26resistance zxFY/n3xnfyL+EXhotMf6Gw0T+I 7b6FWCXmjaTd7k2mkNvcN/OKkX8 2020-04-19 20:25:59 80.211.89.207 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5130 +p reject 1-65535 +r Unnamed zx506e7qpDArVcyiJ3cVgt+TtC0 nF4CcEr5fUSeApQTXEH3oQX6uvk 2020-04-20 11:25:14 104.215.50.137 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=74 +p reject 1-65535 +r bmTorRelay zyXGk9nabwBcq6nDal7RyJyBjpQ Ude0K7y+5jwX7wgrwgsUWjtHYQI 2020-04-20 08:11:59 45.33.77.218 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31 +p reject 1-65535 +r SEBO3000 zyhTznTKhdtDPAU6b0U0kgpRT90 2eF9Or76V8SFtFnnwqtIMR08TmA 2020-04-20 01:46:16 5.9.173.33 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=44000 +p reject 1-65535 +r Unnamed zzuMpjsilBvVZUyIwzOB1xEpbk4 pt9nYmnPmXC25CWhjRQNKbQQtOA 2020-04-20 10:15:40 2.60.3.68 33333 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2760 +p reject 1-65535 +r DOORtoTOR z0NYCHKXVNdqmHpV4UODylovjE8 SAIxlLIn6hoTImQuiIWJ1X4wZvI 2020-04-20 04:37:22 34.91.138.230 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11900 +p reject 1-65535 +r fleischkaesesemmel z1VmU+cE97YZ4bvAroao4uGFoX8 NXdlzdQGaTHtjFzSTr84tiwuP0Q 2020-04-20 12:34:29 217.254.44.68 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=481 +p reject 1-65535 +r beepbeep z2mWxoud9ubnvsCRNyDabsuAEdM fG56WyT7RvFnyf1uBTBGKHZHfGc 2020-04-20 03:01:59 174.138.18.84 9001 80 +a [2400:6180:0:d0::2b9:1]:9050 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=485 +p reject 1-65535 +r cryzrelay01 z2pggAkbshCqOJL+/i9qOW2gjfM hbMxeGMm/SiFlP88t8hH7gJ0UXc 2020-04-20 03:30:46 82.149.227.126 8080 8443 +a [2a01:440:108:11:82:149:227:126]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4840 +p reject 1-65535 +r Assange018us2 z2ubadrB+FHYBzsuG7P9elDbUH0 0WHL1FBFrdF/9IDgdI9CnpyJJzA 2020-04-20 01:07:59 194.242.3.16 9201 0 +a [2602:fe90:604:1::8ff:ad04]:9201 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r Faravahar z20Kr7OFvnG44RH8XP9LR5I3M7w MiKaq2aqkuOBCcKNT0sm/vGE/aQ 2020-04-20 07:51:15 154.35.175.225 443 80 +a [2607:8500:154::3]:443 +s Authority Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r lader z3c94LT1N7uA2jVkMplAO3vxGvo NMotKAlpmUPawUNs/qF4cc5JwL0 2020-04-19 22:34:33 125.212.220.60 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50 +p reject 1-65535 +r BuglabsRelayFR z30rS+zRfgT6DWBCKYiPkdFmXAE 1oD5ex/SbbmAiRk6t132uo5J284 2020-04-20 04:43:08 92.222.92.10 443 9030 +a [2001:41d0:401:3100::2229]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1530 +p reject 1-65535 +r snap277 z38TeIEbVS1Iyaux/g9O4rHPpXY 9AhHWaMvV7B+HXaZt0oHdQcflNo 2020-04-20 11:00:59 181.29.103.47 39385 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=217 +p reject 1-65535 +r Assange034us2 z4zEdjKY93/2Ta80DSbRu/M2LFs bwT0IB8nypwqtQkxIW2zD2jaSMM 2020-04-20 00:56:28 162.212.158.82 9201 9211 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12200 +p reject 1-65535 +r giant z4/Ud57tdaD7nbjzOifVEGSOCyc z9QDwT32cxsn/3/9gDeWnh7m7x0 2020-04-19 20:03:11 185.132.133.30 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r MollyLee z5exIeURuAEl7Y3/J8pAOkgMsgo gYHpaAjnZDQJkIZARymzGI7Nmxg 2020-04-19 20:19:31 43.251.159.144 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=930 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r PeeVieh z6RaRzn75HfYxlAINLWfQadJopQ 75NP5RRI911HAuEiDcukjE1Glcg 2020-04-20 09:37:38 103.119.112.78 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r serv z6dEfGanCZMvA4/uawKLhKbmdug wwdFK0u3NByONXTDDNe3zEyhfzI 2020-04-20 08:07:11 134.119.32.208 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r snap277 z7BhYtQPnUaJmb1I+wG3luDhsZg 4QbdA2Gw136w3QHX+B1bHJOeWtM 2020-04-20 11:45:59 90.252.155.234 33033 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=667 +p reject 1-65535 +r apertureRelay z7FsWCssxAhPA2Sbknn0euH5bJA 0WvH3Qqfs+sZjaLFLrtCiITB/H8 2020-04-19 23:33:13 178.39.127.53 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4260 +p reject 1-65535 +r Unnamed z7GCuAzuZrxwHKEgduNyH6hAuag 7lWNFFob6dJwwGYRevvxe9mRwSs 2020-04-19 20:09:29 213.243.172.46 9001 9030 +a [2001:14ba:1f00:0:1117:e76e:843d:f803]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50 +p reject 1-65535 +r omue z7vUV/pqolBWSogt3BGBDdMmkWQ 3BVnrAZ97ge64QTeUgpkIgmL2qU 2020-04-20 02:18:07 92.116.198.74 9002 9032 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3820 +p reject 1-65535 +r cl30p4tr4pi z8FeQLOfzLnFtc7T0vGErfuizJg cYitjcNKeOgw9F3Lg/0PJlWbCrE 2020-04-20 02:18:32 87.15.198.59 443 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1840 +p reject 1-65535 +r BraveLuxor z9NLHhxP4TY8ORadZTic84VoELE kyKwRpVGp8DE6Bm8QC0vwbVE3vc 2020-04-20 04:32:14 65.49.20.10 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9600 +p reject 1-65535 +r UlhasTor z9+Z7hkj2HAyn42uVDmP1FQJ8B8 nv63oPo1+gEPgZtGL17KlBho2mI 2020-04-20 07:38:07 212.32.240.165 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=990 +p reject 1-65535 +r nikomo 0ALAYfVstv5v96J3R+wqc2mrupo vel3pUnMIPlDYflP040hHbl8RWw 2020-04-20 02:38:30 91.121.76.207 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r TORmany 0AfFs/wBWtT3CMotu0Q/n7WRWYc iDBtNAJdVXilj4OZZQfhNQuP6U4 2020-04-19 23:34:59 89.163.225.145 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22800 +p reject 1-65535 +r BFRelay 0ArHzZGy8TRerbATLYI5Z+Jkbd8 McrHux/XlMmwVVCQRm2TRDJ6EVw 2020-04-20 06:02:17 212.47.235.180 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3660 +p reject 1-65535 +r snap277 0A0qKdBEmNZvCfnl4tihTu16rRw uK6+9eqjo9rniqNQEhIZ35lf8u8 2020-04-20 10:21:40 82.235.204.11 43197 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r k21hermes 0BlWtVW6WdQi2ZTUGsljQYOXRZc 5zq6FAq4HIAXXrlYdAu/nxfaFpE 2020-04-20 05:52:55 95.183.51.126 5831 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=171 +p reject 1-65535 +r Kimchi 0Cc8hWbMmuzkx2I3bJsGb+Dx2t0 prq3nLxLQhIjLOjD9gCgBpa0T+k 2020-04-20 02:19:42 54.36.120.156 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68300 +p reject 1-65535 +r T0rly 0CyyxAt4bvqBGwX463+8zt6wWjI EkdYK1pIHAMSaAScH+rM6kkFMqs 2020-04-20 04:14:33 81.36.82.56 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=512 +p reject 1-65535 +r carrefour 0DVOLCHZx9KIImL/La81YY7Vjbs jEMAwB+QjVMYvZJD/HwoyIZD19I 2020-04-20 02:00:06 81.17.30.44 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3700 +p reject 1-65535 +r itvara 0D7MknhrQgBfVwFPPJRDlgf7yGs 7qEVwygBMz7z5h6q597OFVDwooA 2020-04-19 19:57:14 119.17.131.40 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16 +p reject 1-65535 +r snap277 0EI6ZTDdIshSqU/cUThxO56hoPo pWO0Guy/67epOsq0M/G+oum5w0E 2020-04-20 01:51:40 73.197.100.48 38781 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r ajourmag 0F9By3igAxHY7Eq7TpUVgugpjQw RCib18j2FAEnJwau6fF5Iidd5nA 2020-04-20 12:01:47 94.130.181.104 9001 0 +s Fast Running Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=22000 +p reject 1-65535 +r ULayerDrake 0GgdqqvDIDELhhaVHWwZ9p93im8 h/8eEmTqh36oubn8r23ZVsMoXQo 2020-04-20 04:21:33 152.89.244.251 443 80 +a [2a01:367:c1f2::694]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10900 +p reject 1-65535 +r snap277 0G78z/y1o84Fj3BJD8gnoUtJRjo LeDQ9UFCtp6wZXEEBwKBy1s7Y1M 2020-04-20 04:23:22 80.234.118.215 42937 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=47 +p reject 1-65535 +r Skyhold 0HZWF2n1yT1ih3fj4F1GM9eD644 Oaa7FyHjE6Grf0ey/YhwwfcUu5c 2020-04-20 02:02:02 93.41.149.117 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r beerbox 0HnWgYkmaExZecGBcfsYhipKV5I QQJAsN4T4pE3X3Aw4W8RR09iNRk 2020-04-19 19:36:13 5.79.79.133 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=67700 +p reject 1-65535 +r Unnamed 0HpkH5andn1rNFexVZEezg3nFOc hFD8lqwYGWijql1GlxebRVZOiVw 2020-04-20 10:41:52 91.219.236.127 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4980 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SNTor 0IZgttcLYkmlfYm7eo8uoslSvTU iB9XYpDR5lHHs5yOEyuPNi9v070 2020-04-19 21:47:41 130.89.149.57 9001 9030 +a [2001:67c:2564:a120::57]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53900 +p reject 1-65535 +r TheBeSharps 0JWwwntX4+/ujNuNRxtWAwops5A TWWeEHYQ6kBh4mYCJgcwnpvciMs 2020-04-20 08:06:46 51.77.50.168 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3800 +p accept 53,80,443 +r wingNutM8 0JlHXM3XKguhyP0TnYfy0qkx08A 9yNc9PO4iYl281Fw7AR6k0lN6NE 2020-04-20 06:00:57 51.255.173.98 9901 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15200 +p reject 1-65535 +r TierraNorbu 0JqYK75loWK+eW1XDyV46oJES1Q eLanGshYf89bqNuatjkBDKdX1aA 2020-04-20 11:46:12 81.19.7.75 10009 10008 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=100 +p reject 1-65535 +r UenoStation58 0L9qZAAIHaYDFTbs6tWfeb2r62U +kGK12f56s8I1dNQXogc525yYGM 2020-04-20 05:58:57 51.89.143.158 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11600 +p reject 1-65535 +r Unnamed 0M3JPJfI1MJ1EX9tRLlfiQmgHpY GOF0ewzqDwihKyXNvSozrXRMdD0 2020-04-20 07:56:05 144.76.165.136 42570 50178 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=120 +p reject 1-65535 +r toritico02 0M6JixUwwU+fzifhRJlBV5YH8dY dZIkS+BsbPX72uTjESm5Kts23HY 2020-04-19 21:09:34 143.202.161.75 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=927 +p accept 53,79-81,443 +r OROGOM 0Nk9XotGvXK2hhe0AuLbwW+KoEA Q8xA2a66G0MU13qzBYF+DBpO/lU 2020-04-19 20:30:16 50.7.8.29 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6060 +p reject 1-65535 +r moses 0OGWKyRgulTYHhQmMA0Jcg5tQ+s 4l2/pxIUsPDPweP5XaZxomALZvA 2020-04-20 01:36:49 69.164.211.18 9090 0 +a [2600:3c03:e000:34:ffff:ffff:ffff:ffff]:9090 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r fulcrum01 0Ofz0fWtxi5zUTfUtqpdGSSPeE0 1j7KvNYi6a5C7ZUQXheX2Fe+kCU 2020-04-19 23:04:34 92.3.146.135 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=43 +p reject 1-65535 +r misi 0OnKAVbiXhThjLFWemB/GR6Rm7E prLz5C/FE0SS3CksmFGMCZniYCw 2020-04-20 03:22:53 50.7.178.146 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5010 +p reject 1-65535 +r CHIPrelay 0O3Fig59f+KKGl42YmCoCu+b1Eg 00ACQ3ja4XXdZJDutAcboaGBEhg 2020-04-20 07:34:32 107.5.24.181 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=113 +p reject 1-65535 +r snap277 0O5IEFe3U7slwxCAZChCdX7Vtic lkNyzmhQmIg3aDVGX4Fu13S5feM 2020-04-20 05:37:33 188.255.65.216 40373 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=586 +p reject 1-65535 +r PeaPossum554 0PCfpD9o4TS55WdDeX0ED2RxdNE F+qCVIFel0ip9fcPuC5EwHZ0TEk 2020-04-20 11:12:17 193.22.133.92 9092 9093 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5600 +p reject 1-65535 +r CoolcomputersTOR 0PKILYRFD0fD/JItX2omKrE5XW0 oh5PcOfnfiJc9Zs/JsBWne6MZXQ 2020-04-20 00:24:10 45.20.152.171 443 80 +a [2001:470:1f06:488::2]:443 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=460 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r beauvoir 0QuREuWd6qTG+lB1IeYeuG0sKn4 sgHiiffgJH2FCE9x4Ftl7+ZQfXQ 2020-04-20 12:40:26 91.77.162.130 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7890 +p reject 1-65535 +r Unnamed 0Q+hDBrhMz8qxpU8hjGQyBYonG8 7TbD1t6HEuve5V3/nVFjkV+CgMo 2020-04-20 06:21:17 90.110.121.217 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=47 +p reject 1-65535 +r ca0akatala 0RHKkoCEqQfYvps/Hh0FInpfu+A q7zO4h51/auJhC2KPIZBVUYttko 2020-04-20 01:03:41 167.114.144.152 9002 9030 +a [2607:5300:201:3100::397a]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r Assange025au 0SAy9FMowG8FOSFHnPdwogg3i58 D0OnQOxbAH7baNSfhDGGTtfbCTo 2020-04-20 00:30:33 139.99.134.27 9001 9011 +a [2402:1f00:8100:400::6c9]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=358 +p reject 1-65535 +r bmwanon3 0SPA+PVigEaTxH1oxheGAjspXpg SdfuCp0dqFLJJ5/et4uNn6VbYs8 2020-04-20 02:15:16 176.9.1.211 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r zahnpastaschaf1 0ShWykpCoWIBMMvTqD+aY7j05Gk C0riKG8XjEl/KFs5gYq6aO2IluA 2020-04-20 01:11:57 2.243.81.224 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=130 +p reject 1-65535 +r dliwdiffipca 0Tj7Afi9qhzduLpKTxk0IEoRExs W1ZaeguRZLDH7rfCi9AwaDPoH4Y 2020-04-20 08:45:44 207.224.178.213 500 4500 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4 +p reject 1-65535 +r ThoridalTheThird 0Tn4/s3RGEsYChmvmORCFYbmz2w IZaZmkVWghWw2tmv9E8CLlzMWLI 2020-04-20 01:39:53 188.32.247.50 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3460 +p reject 1-65535 +r snap278 0UW7XpdNAHxZLaUermoD57R+0Io bEbt/ISqZJMl7P3ruT/nKvnhPAY 2020-04-20 12:28:47 94.158.124.173 37637 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r snap277 0Ubc89QEtjQRgGmtaE87sC+JD1s F/D2g9LpROA0R5+Zf8QpfmHqapk 2020-04-20 12:47:33 46.159.58.223 44403 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26 +p reject 1-65535 +r nxaat 0WFiMRgiURRk6cbOL8YuSKBUiyY 7bNO4nyV8Sx9CLszb8Y5kDYduE0 2020-04-20 01:25:03 138.201.92.183 110 0 +a [2a01:4f8:c17:3e7e::70a]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=895 +p reject 1-65535 +r itandme6762349 0WLhGzPvTRuNDP+x0tKs+pTYZKU /EgxGePiAtsAJ15L9DCRDhHzOto 2020-04-19 19:05:57 178.128.9.8 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r notanotherrelay 0WhAT77soq6XUXLvcXLV+1LIZjM F5DvfZwY9uk1gKWAtjfRqIJu9Tk 2020-04-20 05:01:53 46.101.107.139 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=157 +p reject 1-65535 +r rem0231 0XRGskmIRDaChKDDDfrFFd3rq4w l0LIq49bBuemLA65nNnHyO0KKxY 2020-04-19 23:42:11 144.91.77.179 9001 0 +a [2a02:c207:2030:4712::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=261 +p reject 1-65535 +r caae76d10377 0YLshpbztybSeiY+aYk+qn2V68Y wH3eL6B4ODTziP5Zojq8nac4jv0 2020-04-20 08:19:05 51.81.253.204 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13800 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r OhNoAnotherTorRelay 0ZXlzorne6yRZz5s+3vQr1coFkY esu+/2fuK3+wzUlzx9BLFOAwL50 2020-04-20 10:00:10 76.91.204.161 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1400 +p reject 1-65535 +r fastoberargrelay 0a5+g432NesTZ/ICuElG1zFCza0 ioXNoDlj4pdUbAPAPGx3z/SjNjQ 2020-04-20 10:43:08 80.208.185.34 40001 40002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8100 +p reject 1-65535 +r theia2 0a+/MRezCLbRp6p2KxMV/YamuK8 NTRE2RH8D9u3m3SFvtzw44B9AVk 2020-04-19 22:57:54 50.7.74.172 443 80 +a [2001:49f0:d002:2::52]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7800 +p reject 1-65535 +r Icicle 0bGlUP7joF5xypCA0UzKO3RsDBc jzToJM30haMGgVkhr5UGazq65yY 2020-04-20 05:37:46 51.77.52.216 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15600 +p accept 20-21,43,79,143,194,220,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r endif 0bSGI9+CncAPuA0etT2pM3xdaOk /ODxW56AlNVOpWAoEUuK2r7iAkY 2020-04-20 08:02:37 95.179.214.37 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=78 +p reject 1-65535 +r Unnamed 0bYIiDROLv9jF6JyBh5CbR+1S6c 3Iw5titj+N5PMBWY0/Ge089PKHE 2020-04-20 11:58:45 216.244.74.42 443 80 +a [2607:f8f8:630:b34::2a]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7700 +p reject 1-65535 +r 0xdeadbeef 0bhT7Sfk39yjpU0/LiacTZRnf2Y outXB4JdwoCb9ZLjrBzq24t+LvM 2020-04-20 02:20:13 37.187.96.183 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5470 +p reject 1-65535 +r Piratenpartei1 0cX1+Pr6L5ioR1NBa/g7g/EoITc G95+YCdRwTJGVrHeY9YL26kHazw 2020-04-19 21:37:55 81.7.9.33 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15800 +p reject 1-65535 +r juggernautrelay 0cYPm88tugendZePZsmSfTqUkLs AfodZqwHvCO0L6VtMsW00EdCNSY 2020-04-20 11:47:45 46.232.250.51 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21600 +p reject 1-65535 +r Magratea 0dS6IeorGVgmZW4jf97Gacq6TVw zlR7l6YXmYkd5/y1ws9KuYlBK5Y 2020-04-20 07:21:48 185.66.250.40 9001 9030 +a [2a00:f10:121:a00:1c00:62ff:fe00:17a5]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5390 +p reject 1-65535 +r bunchacunce 0dhEAJ0B7f3KOZ7H2ubAhy8vegk FbhyDGupPWlG2h9wjKPFB5ui5Ng 2020-04-19 22:11:07 77.68.42.132 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=9050 +p reject 1-65535 +r bradpit 0ecGuQIaC/jpZj2yB9nZ7AOnDaw L8P3QEjtqTjwdeLbGyJcZkm2N+U 2020-04-20 11:12:53 217.160.141.52 8443 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.1-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41600 +p reject 1-65535 +r snap277 0fEdLE0/LeP7gsrmAaLbQh4hmV0 d2hFvfYyKkvBfgQl221BGCPGXNA 2020-04-20 08:12:12 83.97.250.144 39413 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1060 +p reject 1-65535 +r kriefukegtai 0fH1qlvPXatExETe+CghuL7GYUg Pt2HfR8/VJyODTqMiALnWir+hgM 2020-04-20 04:59:08 181.119.30.26 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r t4cc0reTor5 0fLFyCCz+WvmFEy/uE/d+dDsCBA +uZ2zanubBkTqAOJHGdC7QrSkIc 2020-04-20 00:25:33 51.15.81.148 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35200 +p reject 1-65535 +r Unnamed 0fZ7f2okEy4o2ybl5tHmwyDt4P8 jwtQMN3Q/qTESeM9HuzNpNmrJH4 2020-04-19 19:01:47 95.211.153.12 58154 47694 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=78 +p reject 1-65535 +r Unnamed 0fmmKIfNB9XPBYCnYc6TcAqWMMQ DxzAy3vI7A1PFMECXaQqdGHlkvU 2020-04-20 12:03:27 91.66.103.94 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=856 +p reject 1-65535 +r curvedpin 0gDhbCeuXD9cL4hs7BhZDcbCUYU pqVTurKH+LUe1mGuM88Grt4Fce4 2020-04-20 00:49:56 217.69.5.20 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=3560 +p reject 1-65535 +r Unnamed 0gpeqmc40z/xN/b31GtDB+vDXb4 cZ1XkHv6CqhXkTVf/rOck3k4LPE 2020-04-19 22:31:21 73.133.91.197 9011 9010 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=76 +p reject 1-65535 +r StopFossilFuels 0hC/CRYgYsBekx9xuuzZPdkQLxw Tso3AWyUAdHGAlUR6McZSvfjlHI 2020-04-19 20:24:33 192.99.69.17 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7200 +p reject 1-65535 +r king 0hU1liVL17JYnBMrw5U1/RhkF7I gRzneNJnxEh45vvxpiz/674ZEEA 2020-04-20 05:09:26 51.89.147.74 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9700 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r CIOforTor 0hiitguvK5Ep2dCbjPtELFrV2nE wGvPlco6GIIy8W3jrXauLbco1Ew 2020-04-20 10:16:18 149.28.68.142 22 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=775 +p reject 1-65535 +r lpf1 0iiuJlyWbKTpqMS3RqMKlzcGCjI iVQ4+R5vrQ+1Syn6kXgfKZtLnS4 2020-04-20 09:14:22 78.129.186.28 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=75200 +p reject 1-65535 +r UntilNoEnd 0i4TKIbRey3eby70SWh7Q9qBcng cySc2FzkhpI4+oNjXJ3Gp32MVjo 2020-04-20 06:27:48 104.144.123.149 443 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=980 +p reject 1-65535 +r mesrouilles 0jI3YZuAZCv2U6dNCRKmHPiqTW8 0t8CdpFcKYk2X5+GSjdBRjl4fRY 2020-04-19 22:18:54 109.24.157.46 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2400 +p reject 1-65535 +r natividad 0jZB/RTqqsL+N5W6vnFO5lzPLcs moC5wxiSzCW8SJ9xcB0SFZRsSMU 2020-04-19 23:07:34 113.20.31.45 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80 +p reject 1-65535 +r squigglysquirrel 0jfi8f5kykf0BUTLU0A6v49Rw9g Ytv3whuUnRnQo2Ze9RKjU2TaqhA 2020-04-19 19:40:27 46.38.251.7 443 0 +a [2a03:4000:b:24f::1]:443 +s Fast Running Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23800 +p reject 1-65535 +r tantricsnake 0j9Is3Um+QTuyzyO0HR+8lTBG7Q CS4m9qTGK+e5DXy9hYs2mOF0rg0 2020-04-20 03:16:32 31.165.50.156 19927 19928 +a [2001:470:26:819:222:15ff:fe47:96b5]:19927 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=826 +p reject 1-65535 +r 5da24675192c 0kKVgY41w9ZT+S/8FSacfODiVXo mFjm4QcpVUC8h5r9fe3apSFUpp4 2020-04-20 08:12:00 51.81.254.0 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11900 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ULayerWong 0kXD6CRFaUXGdZWZy4oFRxNaBm0 gITjXxC9Bk+Xn8Oo9lhUnoOqdiM 2020-04-19 23:14:46 107.152.35.69 443 80 +a [2607:9000:0:28::847c:1d8a]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r kukuruz 0k0MKKtIdoz4t53XYtYdtP0BVnc 2MYPB/aWR6XUSzB9zW0BhOfeFvM 2020-04-20 11:17:40 109.70.100.14 443 80 +a [2a03:e600:100::e]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=93900 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r FreedomPanda 0k+3FDRdS5Bhzqiay600MIHxSSg V+TbRFEBgHuYjrqIW3bF6vn7D/o 2020-04-20 05:23:29 93.190.141.26 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r QuintexPhoulRules 0lIQzgfEnypPK8elBusPXqf14sI SkwbvM+1HP4Kl02U5siBrJBTSp8 2020-04-20 10:36:23 199.249.230.112 443 80 +a [2620:7:6001::112]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13200 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r amaterasu 0lQXwEAHThok+/N7gjNkNzHw26U c8BPh+C5/g9i/polhlqCbEb12YI 2020-04-20 01:17:07 84.198.103.245 9001 0 +s Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28 +p reject 1-65535 +r AccessNow004 0lUmi6y7RWJVTPIBR3Mb2g2MRSs qytZcHafWvayiPt3B1he/eEkAdg 2020-04-20 10:33:14 176.10.99.204 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28400 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r ymybe 0l1BnBZ/PMjU0FzSp+KUW7KHk0w FeNcoIr4Q5y1HnTufPzadZ90MiA 2020-04-19 23:12:58 46.80.137.189 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=790 +p reject 1-65535 +r bogustorus 0l7pIRbRY1pBpvfkeNk/bQjAN7Q AmVeTNbriPsC6wcLCq+CSGi1Ghw 2020-04-19 19:33:59 162.253.55.248 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=589 +p reject 1-65535 +r bf6 0mDy6hfTdYFNe15miQTFLyGXAVY bgFq43bsnY1+q5Y24r8dAfUBO60 2020-04-19 19:53:10 185.11.146.95 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=165 +p reject 1-65535 +r HazelFox001 0meqoANNFKlh+j27k734xW7Snmg 7jDKhYNtcdQTJ9DBrfocnQUwuAc 2020-04-20 11:59:27 83.15.29.198 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=211 +p reject 1-65535 +r niftytelicomys 0nIIiBu9tepW79HReZGHUZWR4yU nTO8OqddcfK2EoVV4tJIWlL015g 2020-04-20 11:47:41 185.220.101.137 20345 21987 +a [2a0b:f4c2:1::137]:27666 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24600 +p reject 1-65535 +r zlasvegas 0n1IQcE7h6FA8JJG1TIemcaCS7I aNoi75gohW/cyS8q0RG+3utn1Us 2020-04-20 04:22:12 209.141.41.103 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9500 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r roubaix 0n126CfpKZesa8s+h/9uYewHCZQ JUmXtGAP/pt/DSbLkaPrOxwCRNk 2020-04-20 03:05:35 5.196.73.184 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=297 +p reject 1-65535 +r niftyentry64 0obtM/yyg4W62do9axKmBMCDQxM OgvSrNMaShP6h38cIRanfv06Z5k 2020-04-20 10:51:55 185.220.101.204 10064 20064 +a [2a0b:f4c2:2::204]:10064 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r niftywabbit11 0opfG7uCzVmAf6+aEmBCIJJ3XaI H36uoftwjR3AGNGV00pgDVmZhoo 2020-04-20 10:52:12 185.220.101.241 10241 20241 +a [2a0b:f4c2:2::241]:10241 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38000 +p reject 25 +r BourbonKid 0otQb5a53bte4dOAWgBjAHY7ZwI 1Ak1ly+ZZR4C0R/eNW3QDLeaCWA 2020-04-20 12:05:11 217.160.29.199 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=653 +p reject 1-65535 +r Assange020ca2 0psx/bXt0tG5TNMcLxO1z0EbEmg zQ5OX4lpNPVfjiuf+o+eJ84DLYI 2020-04-20 12:40:45 162.250.191.15 9201 9211 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6490 +p reject 1-65535 +r Unnamed 0p1riFKvopTA5ALfeHB8wXXs32k ZBBVPS6LAtpIboGR0qybETiGZE8 2020-04-19 20:25:05 70.44.88.31 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=107 +p reject 1-65535 +r hubulubulubuhu 0qMm2ALhYmHyqHos5E92ZObvMG8 m4LD2nB8smpb5fAcoIN7LvTQ12o 2020-04-20 02:28:52 84.157.51.118 143 0 +s Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=70 +p reject 1-65535 +r BiochemistryClothi 0qYJV4u+aaTNfB3sEEs81wQCNTQ K++HhfSE+Khbn/BYDmN+3qe9cR8 2020-04-20 09:01:09 8.209.93.160 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5440 +p reject 1-65535 +r JollyJumper 0q1nVEi/oHS6jwE3URqzBqMnH6Y Rm+pXCvVTZD5XlhyocbRQ3lqdtg 2020-04-20 03:18:11 162.243.194.203 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=79 +p reject 1-65535 +r k0nslNET1683 0rGZVXu64qfe6A/LBO9ceRp42xo uDRtbTd47f5xMZl2We3/K4VeLro 2020-04-19 19:33:23 198.12.66.114 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23500 +p accept 20-21,43,53,79-81,83,85-86,88,90,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1043,1103,1113,1194,1220,1293,1500,1533,1677,1723,1755,1863,1883,2082-2083,2086-2087,2095-2096,2102-2104,3690,4070,4321,4643,5004,5050,5190,5222-5223,5228,5287,5675,6880,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8502,8601-8602,8888,9418,11371,19294,19638,50002,64738 +r FreeHrvsk 0sB2qJgzeqL9O4qwChkDEvNAXxw P52tOTb3pG9i6ZZN3x4d7TfrEzM 2020-04-20 06:29:40 45.95.168.146 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5360 +p reject 1-65535 +r snap277 0sND4VY9QOOH3S83mWz3VqrB9EU PX+a4/nB0hAcZ3zl6VfnozWhGMw 2020-04-20 05:57:07 109.20.87.190 40085 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=954 +p reject 1-65535 +r Unnamed 0syo+ite55U6d4WEsPlUi981B3A IA28FOyans9a7MY6aTx74ldPzuE 2020-04-19 23:47:15 139.59.67.16 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=270 +p reject 1-65535 +r torthegrid 0sy68GZO9cA8j+l3ZuEj+ctbNkU R0dUiZ8aVSI7IS1ACus2BlmXX9U 2020-04-20 01:44:21 5.9.140.188 9001 9030 +a [2a01:4f8:190:14af::b00]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=96 +p reject 1-65535 +r snap278 0s4GIuWm7y9Qs8NEwDWxwt9HmIY 9zoqzqXWhWGt36aLiaTnQ1gfPdE 2020-04-20 12:21:03 41.142.109.112 46237 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r DeathArmyRelay 0vFZHga32ze3gBqe6IRj1rYBhKM eLxKBcAkCftQoFTAVWP4ZrltMWU 2020-04-20 00:26:12 176.152.45.213 9002 9031 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p accept 1-65535 +r cairnes 0vTaxZGLsIKlz6xSdbKfrJs5mys JnYIwzETvyjVx7O1vSxIhUzpvuQ 2020-04-20 12:31:22 95.211.210.72 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p reject 1-65535 +r Zion 0voCi/dqq691DSZIEwim+6BVFDM EXUm7VDa3IrrjDxVMqXu/Pdm058 2020-04-20 01:12:00 92.196.159.81 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1020 +p reject 1-65535 +r Dibbelabbes2020V3 0v0BkxqdjbGJ7tYcddJ7fXESBFg oWNVocafxwkIqVEYJtXTcHzf6ok 2020-04-20 00:40:59 95.88.24.67 9040 9035 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=44 +p reject 1-65535 +r 327c865b2922 0wvOwO4TWfVX4ae1dAZQuZK5fgQ nYA91wO/6TDjUGmaxnI9SrOUiGM 2020-04-20 08:14:46 51.81.254.19 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9980 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r mine 0w6dTWOQaGEdbZaGHJXCCZFAuAU XzAbsqGIeqAyniEWVNThEfOqtmU 2020-04-19 22:26:10 46.38.237.221 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8890 +p reject 1-65535 +r ISNJRelay 0xFcIJ4yDz93yDU4aDxHQQoQ0ic CTXJV+qoefs2lB4uMeSDOJ96GZc 2020-04-19 23:32:42 173.214.162.70 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p reject 1-65535 +r NYCBUG0 0xfHiJFi6exKHaGhCVwqDzd1Ntk r9fw0jf2Z9oAXTnsDo3GhM3aEDQ 2020-04-20 00:50:35 66.111.2.20 9001 9030 +a [2610:1c0:0:5::20]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Eliise01 0zGMfH7IRHPmlHvELSvKeOAL3jw vy9G3n4ouRu1WqCBRIS1BIjfT/8 2020-04-19 20:38:29 185.195.237.24 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8170 +p accept 20-21,43,79,88,110,143,194,220,749,853,873,902-904,981,989-991,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,8074,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r QuintexAirVPN2 0zKS/t4k3UDyOFKD5VyH+FwJQ7Y taLEKXKvv5+ajXKwBeyrDa9vr0M 2020-04-20 00:53:39 199.249.230.121 443 80 +a [2620:7:6001::121]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15600 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r mytorboxrelay 0z5UcuZxDwRvRQC282eiZiOB1P8 jrkcXat2tcVRb/68Ds9IS9Jx84w 2020-04-20 08:57:12 78.210.254.127 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=769 +p reject 1-65535 +r BraveKhafre 01aCq24p2RqgMOA6m+tCcA2Woe8 hM8m6z9OUr7OXv8YSa1rsK/6FIw 2020-04-20 04:27:24 65.49.20.10 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r rot1 03a4R8DB/VV3vnz4Kuc1wolQnjc BmUK1iTXRPQdsBX2de6j4njIR90 2020-04-20 12:38:37 195.62.52.239 443 80 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r jello 03uPw6kPphURmj3W7f91RPYyuAA KcHG2jqU/0//htIgMvHQGaX+Kuk 2020-04-19 23:04:10 79.140.41.13 12345 0 +s Fast Running Stable Valid +v Tor 0.2.9.9 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2920 +p reject 1-65535 +r zinthrop 04DFet6P8ZifZ9IgVc6q1/FomtU R5UIBBNScNqs7p5TC90ebvN5mdc 2020-04-20 04:06:16 31.184.198.183 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r Unnamed 04qlYmK8d2UOFtrlvYESz+Q2c8k Vs4MoSvDia/kZ1Sqzr8xfebFVvU 2020-04-20 09:05:42 52.155.110.95 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=870 +p reject 1-65535 +r 558aff2634b7 045qAmBYIqxwCtCPBVEJOr7VC2g 0LZMQB4+jIROLqEJzpC7rof502c 2020-04-20 08:09:27 51.81.254.26 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13800 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r jersey 05Mo0urjgW+cXV0bsZ0cFOLnlII qlmPjsp6M75a+Tj/nmRAAB7r97k 2020-04-20 03:44:25 145.239.0.204 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18800 +p reject 1-65535 +r Unnamed 052aO0Hp2hKMVVlkYeaAAvAy6NQ nhfwfmYn0WDav4BhIP4b0d8qdLA 2020-04-19 23:00:57 52.246.254.204 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3530 +p reject 1-65535 +r FuckGoogle 058s2Qojb5SmG3Zha0hzMp2neIg nv7gXiG0Xvt+vT6lzj8UErajr6I 2020-04-20 06:24:20 87.118.112.136 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7740 +p reject 1-65535 +r 3zpzl3mnsqzy 059m3kkQ064cNBXkUBIZ07meGE4 Q7E3HaqxGeKaRBHLsQZXPxwWIhQ 2020-04-20 01:41:33 45.56.90.176 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=520 +p reject 1-65535 +r 5fd833ae 06j+uIFpw7WFnZvDjiykZSBkdcc hGX3IaFpJjg7OpIyEdIi2mbjzC0 2020-04-20 10:10:41 95.216.51.174 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13300 +p reject 1-65535 +r blockchainsociety 07cq2i8+7aK6mPZF1iDKHEBgqvQ XfcgrGZL1erM0o+oNGO2zt6/340 2020-04-19 21:31:03 51.38.185.201 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r piriti 074MT+w6xZVZktM257+Z3B8mAgw +/e6Rsu4AbHmRxXddJWwHYoDDVE 2020-04-20 04:09:37 204.13.164.107 9001 9030 +a [2620:13:4000:6000::1000:107]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5890 +p reject 1-65535 +r gGDHjdcC6zAlM8k08lY 1AX8zwat7fiY3y8pyTSNy2IwMbo WBeh8/5fqNXmxRn1Bb90xqm8PI4 2020-04-19 22:35:58 5.45.111.149 443 80 +a [2a03:4000:6:2388:df98:15f9:b34d:443]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r quetzalcoatl 1BBTdpo4v63m0G9LurmIxrNN/Fg zRa8ExcU7YU/4eGNNGs2jeZYnZg 2020-04-19 21:22:33 213.152.161.35 15804 15803 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=430 +p reject 1-65535 +r gare2lest 1BMAKVK23gcDu43GbSI4yMSxGxQ zKbGRU+DKWE8KBqS3jo855YKESw 2020-04-20 03:37:46 86.243.64.232 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=455 +p reject 1-65535 +r Unnamed 1B8JJDa1yKoQvXGEr2TC+Yt7Avg ZwhlPi8RYaaKwGmzZyhtY6SgSLk 2020-04-20 03:22:22 92.116.150.250 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=270 +p reject 1-65535 +r BigMacTorJuan 1Caz9/8USq4krs1y7ZaCDdszgFU /j5uvWkxPICkhpQCmuOoUlGa7Ew 2020-04-19 23:32:55 173.240.255.4 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r Akira0x00 1CyFFKHdeuGRJmqBF7++iTPsWHM LqYLXIWX4Y7mPg0GYP+f23Xneuk 2020-04-19 23:04:21 80.211.133.241 1984 0 +a [2a00:6d40:72:2ef1::1984]:1984 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=908 +p reject 1-65535 +r Eliise02 1C7odL0F6vHt/EgF4PkLJNdMa4A hwkclOkNhTkyixTXnukR0VDkgso 2020-04-20 00:31:58 185.195.237.118 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 1DJlwOHhY62fSCbkE6iBdTU0/v0 Auvjtb0Efv18XP3lSHBF/RUxjHQ 2020-04-20 01:55:25 72.133.210.70 36187 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=720 +p reject 1-65535 +r Osterei 1Dn8O18KgXlvRiIyAZepADLK5Ns RrubuDEXhgHaW7KrP2wIZIFUrl8 2020-04-19 22:32:00 109.106.57.91 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1000 +p reject 1-65535 +r ZeroCool 1D7zF5n9zlojXR529DJMAPaASwU 0EPXn9GOW2kn7bQDHpu1Rj7h9ik 2020-04-20 01:59:14 23.129.64.217 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6200 +p accept 1-65535 +r korff 1G82j9z7k2Oiqbgnn/wjMbVAvQ4 iXaRhSPi+ncRfrjVdptMA1ZlKQE 2020-04-20 12:42:08 188.214.104.146 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r bridgyvps2 1HL72cizuZroopKY7BZbl0xcPRU SS4y8sjUzdRz4lrXg3kBKoxstQo 2020-04-20 09:44:49 136.244.81.197 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=942 +p reject 1-65535 +r Unnamed 1I3CKoEL9H5mxnimOqVHFd0+mHk YFBsDTEONXDaxamLD3LLGR/MebA 2020-04-20 02:55:06 51.158.111.157 9001 9030 +a [2001:bc8:47b0:20a::1]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r cepa1 1Jkb8Uv31LtoTlarAqRKbKY5FgY u+GJauIpq+2R/BmU+tB87B9Ooxk 2020-04-20 03:28:05 185.100.87.41 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9990 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r AllCreaturesWelcome 1Jt2WLgm5QfME4ru/NYTWzIcCW0 VSQVQxHOLG4a3fIKnn9ARBMeHfk 2020-04-20 06:07:40 173.212.221.10 8443 0 +a [2a02:c207:3003:1795::1]:8443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r Layer13 1Ju3UUx49oMD2HmvfD1dZxSPWZs 8vSA/VluNmDnASMnOaMeXymAtgU 2020-04-20 03:52:25 51.15.232.19 21 0 +a [2001:bc8:600:2340::1]:21 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2560 +p reject 1-65535 +r Unnamed 1J0AcdkjbvxqxScpKJSlohQ/gV0 NUEFjAA2ap3TPS7XUUiYApvWemY 2020-04-20 02:49:07 185.244.128.21 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r Lubuntor 1KR2eOWObjj8kPHYD9Gf3+bFjZA qyMNFsi46Dc1Luqry7eUmULzSPw 2020-04-20 08:13:56 2.233.91.176 19001 19030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2830 +p reject 1-65535 +r pot8torelay 1KguIfbCf+CL0hrmZJH0Ly1TRvE bPqzUI+ilO4hsraOiL9z7xu8/iM 2020-04-20 04:30:39 129.213.118.101 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8480 +p reject 1-65535 +r MokshaMedicine 1Ku6qZpEYKUfS44xO/3ukRkTrFM HE/ETtGo8nY470957eG6c/soChc 2020-04-19 22:58:53 223.165.66.57 9001 0 +s Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19 +p reject 1-65535 +r Unnamed 1MFnMudl61LrC3Sds13BTI4N+ZY N3bwdSymkIQAtQfc8clsdUJk6Gc 2020-04-19 23:18:01 144.76.168.36 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4710 +p reject 1-65535 +r snap277 1MZnNicgnx2erQ9LJ5582P/AUPs GXBzNDfDVwjEOcVpEZnHXrJmXqk 2020-04-20 08:18:58 87.222.10.14 43789 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=149 +p reject 1-65535 +r Unnamed 1NEHaAsIl9/+5QDmJamKqoBgx/E paW9aHRPZC6pA3yNTua30DSvKaM 2020-04-20 07:36:09 168.235.67.30 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=97 +p reject 1-65535 +r micheletor 1NoO2P+xd74EPwliiq7dz5PIYJo 78CyHq+ri3QQbJsBshlxepXfeXE 2020-04-19 19:45:50 91.68.43.163 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29 +p reject 1-65535 +r NotNSA 1O6AFsIEMq5H+14MK2D+YLC/IPM ko+/Zt2BeNrqst3rlubVJ0OeSnA 2020-04-20 08:04:20 172.93.48.197 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1470 +p reject 1-65535 +r ratatosk9 1PYTSNyS4isDEMHWAoOXlRZmXNs Px0DlNOLVK6IZW+VlUhHnCx7nrk 2020-04-20 00:20:34 193.150.221.63 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=460 +p reject 1-65535 +r theia6 1QEBoqvQncJF9+lsCBjQA83WI1E xZ1FS2gK4EAarZS5klFAF3Q5Q0U 2020-04-19 22:57:55 50.7.74.174 443 80 +a [2001:49f0:d002:2::56]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9000 +p reject 1-65535 +r Janky328891 1QOeHr/ZbZo/mEa/meyfde3ekCo yo0GAWTfFwc97GumKkicvBtLDDE 2020-04-20 01:24:57 37.187.115.157 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4000 +p reject 1-65535 +r morha 1QP7sZvmn2PXrKqbZ8qirHtEixE wz4vi8ZRs+QRAwsha4NoYyp4/BA 2020-04-20 02:06:52 188.120.234.26 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r insula 1Q33aYLw0r/bKKdTB5zdY6GSwy8 5JpaB/fqMGOHWb7SxlEd8gGeWQg 2020-04-20 02:13:50 178.79.134.196 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=542 +p reject 1-65535 +r comeandgo 1RsoFNaygpX+pIc0OzdnrooHVCE 1CZe8Z5PS8fETXf7FUYFL6fRb5o 2020-04-20 09:49:27 204.12.225.70 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26 +p reject 1-65535 +r SmokeAspectRangers 1SKPpaqf2zgl5vGZr6n55vlSahc oob6oQF67BiSbqw1NmVP1UPnkJA 2020-04-19 19:40:09 82.221.128.191 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9460 +p accept 20-23,43,53,79-81,88,194,220,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Waldmeister1 1SoWAwPGONn7A0Y/imt5NNV4f0w hU430ITPfEkTh3bU4iKOTjZLkN4 2020-04-19 23:50:00 145.239.7.168 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57000 +p reject 1-65535 +r niftyguard08 1Sugd8rKkBl5Ncm//DE4hgYT7M4 C3SxfS/DXBKgwnF6v8hqQl8/deA 2020-04-20 12:44:40 185.220.101.217 1217 2217 +a [2a0b:f4c2:2::217]:1217 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 80,443 +r GottaGoF4st 1TfoL7mBC1+d9XVm4/dp8SzlUhc MdjkX+UoPJesPNMXiJWiFVGjVj0 2020-04-20 06:28:12 24.208.7.160 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=281 +p reject 1-65535 +r node01 1TrhcL9mUKLGZASE/htd0cCriVs gdBgWCx95GWR9cwjCw/JNgT9Y7E 2020-04-20 11:44:56 84.245.10.24 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r ididedittheconfig 1Ts5uZ7bXqJhzbSQzfMOn4NaUUM LKB7FoA+jlR1X1o84Jh32ZPIc5Q 2020-04-20 02:32:52 193.148.70.201 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7040 +p reject 1-65535 +r Unnamed 1UlQtL/q8zhzgpND0jYKUbSPQ7Q JD6yuQ07L2ZXkC/dplIf6awo2XY 2020-04-20 07:46:05 52.231.51.79 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=320 +p reject 1-65535 +r MyTor4U 1WB63R/dtldILiPwmrFzMQyAJZA CkaVkakAJ7AXFQQG/Jv0BOIyQHw 2020-04-20 01:28:01 5.189.142.118 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p reject 1-65535 +r nicotrack 1WjqoqcBevzT+61kERySy4/TpBg vzFaAK4Csut8ewJRFW+HnnqmsXY 2020-04-19 23:52:31 212.74.233.18 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1640 +p reject 1-65535 +r snap277 1WlABqIaXCfAzTWGVP53vbeXnz0 UbdFKXOA4FtKo5Bzohlv1ADtUk0 2020-04-20 12:44:31 72.191.35.77 41803 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=639 +p reject 1-65535 +r sTORch 1WqY04/Dx14DR+7z3ZwSdJr3x8U YSn5++9JbD8uKjYoZNYXVvjGCqo 2020-04-19 23:19:09 217.182.196.70 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110000 +p reject 1-65535 +r 3D2XP5F7V7GXBQ9 1Wt8wJ6VWY5k7Nr0PJ+eOBC0rDs yvCtuoIl87DcZ00PXMe8TSXayQo 2020-04-19 19:30:35 51.75.222.161 443 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10500 +p accept 80,443 +r TOR2503 1XtX8DgXCNdFfYIWAsxGo9BWaTM ADGri3PC+FMuchGHAl1fmdI+tIY 2020-04-19 20:19:16 185.38.151.56 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=380 +p reject 1-65535 +r angeltest16 1YErq1KCCk1Ejl8W7jY6D0zu9pE LYqlHK7pLoTGPFFpH7wNi39nhUo 2020-04-20 07:43:32 195.123.238.164 443 9030 +a [2a05:9401:0:acdc::191]:443 +s Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=44 +p reject 1-65535 +r bauruine31 1Y2jKpeP6twSYbWodjEm8+krCEk DP0MehY5VLI+nOfjd/q9s/eMSyo 2020-04-19 20:18:45 88.198.17.248 8443 8080 +a [2a01:4f8:222:30ca::1337]:8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=123000 +p reject 1-65535 +r CTFlyra 1Y6ll95tc+70KuhB5kUFTgCRrPM TAS0is/0HqvIw0QLGEnWPXrfvBU 2020-04-19 23:39:03 188.40.63.57 443 80 +a [2a01:4f8:221:485:188:40:63:57]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2450 +p reject 1-65535 +r Enflurane 1ZjihlFkr22ZWPyaN9glwoOoDDs I8QTZ5jyVfOWKhmIaCvRdlj1KZM 2020-04-20 07:17:25 2.80.76.66 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4480 +p reject 1-65535 +r komeru2 1aKzrh6ARwF6C7xyCf1iTbhNR84 DMsP9uawN+IZnTsjz+nNloHex4s 2020-04-19 19:52:31 104.244.76.184 443 80 +a [2605:6400:30:f99f::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r Unnamed 1aiYsLn7bES0jYDBo0Mo9a+RlfU 9g41uTF/T1WZlcl+r0vL7srTx70 2020-04-20 05:02:36 51.81.253.219 443 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5930 +p accept 1-65535 +r revopaste 1bGXTpAZfNDbOmY/gDDiACE1SJs /btCY6rfdWRBYhrf0NkfneubBGA 2020-04-20 09:07:09 45.142.214.107 9001 0 +s Exit Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r Unnamed 1bYs2xyFcpI7WgP/COM+hbmKi1c 48SWQQrPN981ZFMmuMONTuT5NpE 2020-04-20 04:11:02 82.64.154.215 9001 9030 +a [2a01:e0a:1f1:f6e0:a01f:2cff:fe07:60d9]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r afdstueckscheisse 1bbAUbi8UGfXWSiQht7CBeqfYxk z88WYLrKilbYrjCd57tyhGqzLFw 2020-04-20 06:06:40 209.58.160.36 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=570 +p reject 1-65535 +r FastNode 1bga7zh/P643oIhHWpd3Gn8kb9A z9987EM8g7RBDQkffqlSQ3w+MRw 2020-04-20 04:45:23 5.252.224.98 9001 9030 +a [2a03:4000:40:41f:3873:21ff:fec6:753a]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=60900 +p reject 1-65535 +r nx1tor 1cM/PiA3KO34Nh6oaLKTnMxD+vs CP2zdRePiW8r5ngMj5Kfq8z0P14 2020-04-20 06:42:12 12.235.151.200 9029 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6600 +p reject 1-65535 +r skosh 1cb2Kl0bPHEcpeb503cqQy6W9sI gLQsheQ5H8+P1rrqNDw3qDy4eMQ 2020-04-20 03:49:34 94.130.40.100 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=73400 +p reject 1-65535 +r Graph 1dSVdheISA0JkGVPTEtuW9ESang QGniRl8yA5kfPZ3h87LHhzZG5a4 2020-04-19 21:58:37 5.13.219.75 9001 0 +s Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=31 +p reject 1-65535 +r CheenaTorRelay3 1djDHh+EW0ZWSxEiM+7PtTkGCRU 9PjHH9V30MfpuoUe/CjztvdjFMk 2020-04-19 22:21:44 5.135.158.162 9001 9030 +a [2001:41d0:8:d8a2::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12900 +p reject 1-65535 +r che 1fLGX0ExoUaNW2eog4qbftjASeI EhB4Fh5F5YuuMwvJPo3EWsWv7oo 2020-04-20 10:53:07 158.174.122.199 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49500 +p accept 20-21,23,43,70,79-81,88,110,117,143,194,220,389,443,464-465,531,540,543-544,554,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5269,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19350,19638,23456,33033,33445,50002,64738 +r CloudSigma 1fVQLBdioLc3qBpr23jdv378dyU 8GH9AwZjq4Pp2lWJrRjhvbseBwI 2020-04-19 23:33:19 185.12.6.234 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7800 +p reject 1-65535 +r llama 1fqsQTgnK+4p6kuj8ZgbJctrb18 NXn87FvyOSxEizPEjIZwLHlXoxs 2020-04-20 08:46:22 66.42.63.19 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=163 +p reject 1-65535 +r 0xFE31x00 1gwtherZPSPxwAh00zS7+Kls1Sk kQ8CI2UUznr/dQjpsf0f14mFw7A 2020-04-19 20:38:52 51.68.186.59 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p reject 1-65535 +r MrExit 1ij2uyMws/eNu0vtRmsKWG10eC4 vtap5GbFWqToc5iCxxnMiG23MJg 2020-04-20 08:16:30 144.217.7.33 443 80 +a [2607:5300:201:3100::c20]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r tordebain2 1jdUF5VAx7RzZKBwh5GEzP3JQ9s V6DWyTt9z/9oABMsaETqoYZi3xs 2020-04-19 23:43:13 95.216.222.158 443 80 +a [2a01:4f9:c010:4bc6::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2880 +p reject 1-65535 +r ByteIndian1 1kyWzQd7tB+uhHuP5B/xll08hys +TSXRMgdm24BB/dmAgxFNZ3c8aE 2020-04-20 05:25:04 163.172.151.47 9002 9031 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7920 +p accept 53,80,443 +r nickesrelay3 1l24S/HrTdIluaHNnO/Ye1laMPU S/f3e0MTQLsaHe5LqgnxzREwTsk 2020-04-20 05:16:19 193.11.114.69 9001 9031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20300 +p reject 1-65535 +r drogo 1mcPtUshgYznwTUkqgAyWLjjXTg B1nY8x4fRhGVxMImtst/8P1athc 2020-04-20 12:41:53 94.100.6.27 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6800 +p reject 1-65535 +r Unnamed 1nEEAR2KOftAQyc8NBvVgyhiGbA 2BCTmponM5QD1pTbqrBulyVFdNY 2020-04-19 19:04:50 144.217.64.46 20580 18607 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=490 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r ZwiebelSaft 1npcLaBydrbm0MQCiSSCzqNXClc FpqwKOOrY+hcuCbmU//PKeErbEg 2020-04-19 21:11:49 198.71.61.123 9001 9030 +a [2607:f1c0:1800:b3::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6160 +p reject 1-65535 +r mmarb 1n3wwsUEvC+e92bzBuKpZ9gf/Fo BKhArZtC0amE4/PxmkZUduWHvTA 2020-04-19 23:00:38 51.89.85.242 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r smell 1qdAXoF6re/Kyk3pBtvwgGqx4Ew ZuRmhYX0sanFANpHQaqMfj/jyQY 2020-04-20 01:22:44 209.141.48.144 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5050 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r pipit 1qnjIHF7wcjDaSkvxecpKz6ZTtY MWnZMDnLy/L06FNLz4IHUYhef/k 2020-04-20 02:31:05 199.254.238.44 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r Unnamed 1qyLhRM3L2R0NEyTuKWorj48liw 6fsuL67jz8OFdlAzB5T/7dIOu+I 2020-04-20 06:10:46 51.178.52.245 443 80 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SlowBison 1sFJ3Zx+Zl6S51Ks55bD/P5K2n0 EquMgdD5SkLd6usD729FUqUA9No 2020-04-20 12:27:36 198.71.81.66 9001 0 +a [2605:f700:c0:1::de9:142a]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=330 +p accept 443 +r noxdafox 1sl33wlohIh4rALiH3ile4S+SbM 9KPhW9n6q+NnT3z73akqvoJfdyM 2020-04-19 20:51:51 89.27.53.224 110 143 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=759 +p reject 1-65535 +r wrongopinion 1snn5DpE6/4OhJhK91jR9c8xMHk tY6FlmX+nZpiYiTaY3EV3wrpsz0 2020-04-19 22:22:54 216.250.97.250 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=507 +p reject 1-65535 +r king 1tO96meTsbheThDVQObHziTCyfk QRYFF/fZBxcGzA6nJ2gZG4ZMs2k 2020-04-20 04:38:35 51.89.147.70 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r hsalc 1tVb5O+E8M16DhECL1HxQ42bGGE qdPcIft3m1Nakk9Xl0wGs7M4Urk 2020-04-20 06:42:31 185.56.219.31 443 80 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r AnosognosiaRedux 1ta2YUye8trROsDJRIetjtO2h38 ZWVIZw/biKjZeAgSzFluE7PYZhI 2020-04-19 21:19:47 185.220.102.8 80 0 +a [2a0b:f4c1::8]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=68900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Goetze2 1tj3YCr8ZEEn6KUjysTQQtoc8sU 54ZgGXoIqpJ3P/3ZrySnXzI6Qfc 2020-04-20 07:16:43 136.243.247.89 443 80 +a [2a01:4f8:211:115a::189:2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34900 +p reject 1-65535 +r BienwaldKA04 1tlnMQLfFDXBpm9MmOaLVvGSFvc EIBL96apyMcx70xy/1ApZdGl6xo 2020-04-20 01:04:45 88.66.141.186 9004 9033 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r Bundeszensuramt 1uYNYHgzSGrBVTQx/6VOzIeMmv4 WiTdTy4RivFsEwPZgUZLF15u48E 2020-04-19 21:32:24 185.115.177.149 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=256 +p reject 1-65535 +r snap277 1u4L7/o1OLtTlX1EdhcMI4bHITQ PgRu/U2sMFcosvc/DRRygAq3fgk 2020-04-20 11:22:45 176.223.74.85 34455 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=27 +p reject 1-65535 +r puia 1vA+++URQX133PwaPx611L9Qn4E ZlZJYYQQWgUO+NiK/K2MBP3O0Ko 2020-04-20 00:53:25 213.136.78.104 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r snap277 1vpNDC/gjOl6mnZZRMU609mV7kY T17ci3XhZOWG1R1Yyj4Zd0oD/PI 2020-04-20 09:33:13 90.169.225.151 33505 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3030 +p reject 1-65535 +r QuintexAirVPN28 1v8ml86lwMfahHl8LnEWOBT8JGY +NMw1Q8mwaihCaPiMTupsP+EG8k 2020-04-20 05:33:17 199.249.230.81 443 80 +a [2620:7:6001::ffff:c759:e651]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22600 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r UnivUtah1 1wGsr4ZBPpJSnqjjIIjH/EXqb2k /opFZMEp9bNqLbyeeNKjh7pamiI 2020-04-20 05:31:33 155.98.5.5 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p reject 1-65535 +r shhop 1wgtuX5/BIHL9LiMpfVoM5nhlqM 2M5wpaowo3LFCt4uWWqQVcXVt6k 2020-04-20 07:12:30 212.83.166.62 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 25,465,587 +r NaiveFrenchPoodle 1xC4RJyOxOPtVbjHSDtkRe2aDbs lw4lQ01jZETuwFXyI1+LNn5Wkw4 2020-04-19 20:12:43 51.77.149.34 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12900 +p reject 1-65535 +r lqdn 1xscocncfoymQVjhBq13CiEWD+4 M45sE/h2hSgbdk46ikS0/27k7FA 2020-04-19 20:41:17 185.34.33.2 31415 9265 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6880-6999 +r snap277 1xup7mBwKwFAAq5ZVGbFVYnkFUw gZeaPvBrKoX7+yBMWfyKYWxL15s 2020-04-20 11:03:58 187.18.199.36 43745 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r FalkensteinTor01 1yMPTxMySijDCK+U4jhdCn8bBfk l97ZWLagqJ2/mpeUl1jw9nyVRHI 2020-04-19 19:28:24 195.201.168.84 9001 0 +a [2a01:4f8:13a:1082::2]:9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=59000 +p reject 1-65535 +r weizenbaum3 1ynGiDgswqV2CJcWvhBJDS1m/OQ BV/wRniYmhGdKOJTaQqNdh74YY8 2020-04-20 05:16:59 62.102.148.69 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54500 +p reject 25 +r NuclearShack 1zFr9/1jPddHSxjDPh1f3rBNJqc ROVZYTNQSWbLDjrUDhiUBondMhs 2020-04-20 05:55:08 158.69.205.247 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r emmentaler 1zThN91TYtUGiuPgIR6yl7dsFhU OtiVpGHDPdeq83I1FXNAsHgG2Ww 2020-04-20 05:44:27 179.43.169.14 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r ThreatLevelMidnight 1zixYeDCF9oVxslMGD14q2WO/Io SPbuFhEJUhOBwKiGX9CbtkZnuE4 2020-04-20 12:08:32 185.10.16.41 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3980 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 10CWUs4zaJi49939Ie3Jpt/p9Ks dIgUq155ZjdiN3o9+nSVimgkzLk 2020-04-20 03:05:55 75.132.49.53 33727 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=68 +p reject 1-65535 +r imascriptkiddiehelp 10SjgPT8NPnREgii+ejGndVWw3Y 2/QrgBgRO1YcrFAYbFHbRiI0mr4 2020-04-20 05:01:01 87.64.232.119 9443 8282 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2450 +p reject 1-65535 +r CodainGate 109hnHTC5gGjnr5YyONN/rO63pk 0u49zJtWm9ykKdUIr7u5qfb8Lh0 2020-04-19 22:05:22 173.212.217.247 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3690 +p reject 1-65535 +r rofltor03 12EQ53D7X20Jy4AdY3nDOhpsDMM qxFa2Vuc5CVbhE2ULsWpnX5QkT8 2020-04-20 07:36:05 192.99.152.50 9001 9030 +a [2607:5300:201:3100::348e]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p reject 1-65535 +r rye 12LXB/xW7RaddMeERRa0YhPhneI 9vqNlgFyo80Mx61BfnUmaRpke+Y 2020-04-20 02:18:54 185.12.45.117 9090 8080 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23400 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r rainb0wsss 12wy3h1oRbnZcfMA7+dEkjjErAg c8au9GZ3zdQfSFOV9/qwf+i8HMc 2020-04-20 08:05:07 108.62.123.92 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=208 +p reject 1-65535 +r 2propstor 124f3Ho9iZKCu4gvdBEbNqbRS2Q 5NBfEOCDnWGrRBH1VFWcCPV+FL8 2020-04-20 09:29:42 69.62.162.178 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r zmoe 125Pug3G8nhJGJwfnd1hrjQMG2E 9QP1xDqmpDc/GHqReOOXI03q9Kc 2020-04-20 00:50:19 158.69.63.200 9004 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r Ruminant 13OpirWVIosuDCYm7b9zLi9TlCA jd73jocLdO8wO0d5dY9/nJFtUkk 2020-04-20 03:22:14 95.115.84.118 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=830 +p reject 1-65535 +r slashcrypto 13fTH5UIHQ9yI6rV+KdJd9UkFF0 zjEwUAKSI3uD7/vW0bxTJsxQI+s 2020-04-20 01:51:57 85.235.66.146 993 587 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=37000 +p reject 1-65535 +r niceRelay 14KaIXJiIK93QBvlsrEyljoL6Cs GEGQWp5LD2nHGwpsPMSOHBWNZTo 2020-04-20 05:50:17 94.254.74.134 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r grapeATfou 14wZgxEKyxzUmZPFJSwALJot9B4 6QkyfKc79w6JX6BEt7PrPRr02sE 2020-04-20 10:43:58 89.245.196.14 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4050 +p reject 1-65535 +r snap278 15ALURbvNih1rcJqwHVBBnpseY4 Bm4idHjnS90O2EYkhAgmLXnDbik 2020-04-20 12:43:04 94.244.35.222 34764 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2720 +p reject 1-65535 +r pmfncone 159T/4RJOk6ga6YssABnwCYBix4 LlgulwtnrkCSe3s/B0ijjEDq5j0 2020-04-20 04:29:34 104.171.113.18 20710 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53 +p reject 1-65535 +r goodvikings 16gOlYkqr1H/JM98LOSTEZMbVfc 7CS3MQho5+MnlQ85Ck1g53iORfk 2020-04-19 23:49:22 198.50.128.237 9001 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=62 +p accept 53,80-81,443,3128,8008,8080 +r snap277 16+4u8c79dxMI+NoPPzs8oAZM5o 2fSIdvC2/a+LkYz3lu4OxpBP/4I 2020-04-20 07:20:55 84.119.220.148 39501 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=240 +p reject 1-65535 +r ph3x 17Rlyxttvig1FH78xBvhb7wD5XY 3ZVeQyzP19L8P9QxV8xRzw17q9s 2020-04-20 11:18:03 188.118.198.244 443 80 +a [2001:858:2:30:188:118:198:244]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5000 +p reject 1-65535 +r darmok 19EnN348bJe8CbdyCamgxOMMrW4 AObvayc7/uStZVsy80hlpyYkgGg 2020-04-20 00:09:42 91.121.154.109 20443 29030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=302 +p reject 1-65535 +r z81zq1rzvi23 19Qlfr3KumIx9NV6ttNQGx7NqrI 1VTX+XfcUSCL8yWco4rPwLmj6+E 2020-04-20 12:00:41 62.171.169.177 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p reject 1-65535 +r bauruine55 19kFGEUEc5qnkP/zLfiCzV00z2k 1PsmkOmwPBpoJRUfm6ePs2zxR6A 2020-04-19 20:14:31 158.58.170.183 443 80 +a [2a02:29e0:2:5::7]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r SECxFreeBSD64 19uOgmBPgGdm/D+AITz3GaBIHQs 9IEpmdxEAJnAvkpxW1misyMUlu0 2020-04-19 21:16:29 195.169.125.226 9001 9030 +a [2001:610:510:184:195:169:125:226]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16600 +p reject 1-65535 +r Unnamed 19xLrIgWn51VEiHiLDR2E6NpL8A kr+CE2phaEVp/DTU1FaD1U9d2tQ 2020-04-20 07:53:38 84.139.25.9 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49 +p reject 1-65535 +r ThorChangedMyName 1+G09QT8IgJ/oGul8fD1nCT6KRI PFauEX2agTrP2Fu8YKAi6Mud8es 2020-04-20 11:58:58 66.55.67.28 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=90 +p reject 1-65535 +r smell 1+uPAnW+7B5o4XWzF3WlnryhbDA kBSQ5HOBgPvapzEH7RErfOY451g 2020-04-19 23:53:39 209.141.60.236 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4500 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r arbitraryKenzie1 2AVsrUo9bufYJ0gCdHS/XFPladk ufEXGbubE9+EIEoUC6uqFP5I7AU 2020-04-20 03:24:19 95.216.14.222 21 0 +a [2a01:4f9:2a:f21::2]:21 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19400 +p reject 1-65535 +r csgeorgetown1 2ApQ75v9d8/OpTJvOJ4k+TLW+do I4GiRdG5Wjumy5/Kr4FhzvLqDIA 2020-04-20 00:05:41 209.148.46.83 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2530 +p reject 1-65535 +r bonjour1 2A6iFia/roBE5AN/52UlLhV+NYY fqKr+BQkGNQU1BimBiD+ayEGM8g 2020-04-20 09:20:39 188.138.33.233 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=76000 +p reject 1-65535 +r hviv120 2ClDQ0skIE+/G0uBjP6mTyBd6sM jTmmVyYt14177IEnjmFJ2sv4jnA 2020-04-20 11:41:28 192.42.116.20 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r xak317ne 2DNpeLgIdYspTtIvekBSFAnEQR4 s5diwzl8mww6cJPbfJmhhqdL/qE 2020-04-20 10:31:59 88.99.170.178 9001 0 +s Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16 +p reject 1-65535 +r Unnamed 2DOnOc/iZQ0NN4JxKjrMYdci2Og mLlOGnfdvYfYiWwHEsnBwLHfmeg 2020-04-20 10:24:49 78.108.216.127 29166 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31 +p reject 1-65535 +r Precious2 2DgOCN7fbJCgnsN40fbBiB73lHY nnADnzB71yOf8btd/FCWok4Vm1M 2020-04-20 00:10:36 95.215.45.138 443 80 +a [2a02:7aa0:1619::394d:31f1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19200 +p reject 1-65535 +r MassRelay 2Dl4BrPyOJ7Gt6r1vJz9uQPq/eI 8ygxWXG17lsg33E7oSB4SSSjccs 2020-04-20 08:41:07 157.131.113.196 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5900 +p reject 1-65535 +r Superfly 2GHrz9XG0sRn6ecduJWesKNsj9M En35zvZGdVdkmIJppuoEW/piDLI 2020-04-20 00:45:12 133.242.146.78 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=390 +p reject 1-65535 +r ULayerEdmonds 2GutXtVOugVeeWyHvpm7xLWofhQ PJYO+ixlf/Wzp8OabBDmMQLGtHs 2020-04-20 07:52:39 23.160.192.167 443 80 +a [2602:fea7:10:0:8000::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r saberrider2008 2HMwSPyOyRAkZq2PMJhiK/G/cf0 G+eTOPlImi4ixbhuibkvDyw+z90 2020-04-20 06:18:10 95.91.105.14 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=980 +p reject 1-65535 +r TonTliquid 2HqUeiQFxBIIxX0y7R0MouvpOvY MX+w0UMkOjI3gPEHeWYCsUJ7Afw 2020-04-20 10:00:18 209.59.173.26 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r Garados 2INxJfmVWbU4W0oJ3XAHlR3Re5I uAEdnzZCJbzNh7oQ9SVyEpSO9ZE 2020-04-20 01:13:53 80.253.92.71 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=21800 +p reject 1-65535 +r Friedrich 2JJn+xC/Yl0x/3aHr30SsDu/dXw AIfixk5mgn9x+hR49qRCuLc1gRY 2020-04-20 11:27:00 35.182.71.209 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21800 +p reject 1-65535 +r Unnamed 2JKvo8lqdmjA67eTwY4Ro1wXGwg K6kMaJIpXqSX/V6q3bv+M66GfEE 2020-04-19 23:15:09 12.28.90.125 54329 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=55 +p reject 1-65535 +r rippedlion 2Jcphr4Z4Ch3cN9RxHxjClPcbpc W8OuPPvqlxr9XVqFtZE2o1BDU0U 2020-04-20 06:15:01 45.76.179.27 9002 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=631 +p accept 53,110,143,220,443,993,995,5222-5223,7000,9418 +r privexse1exit 2KH1qOoa9T40FLnEj+axDDGsybI EztQJvRJ5pxlgDxc6jA3+9Ky9JE 2020-04-19 19:35:05 185.130.44.108 443 80 +a [2a07:e01:2:13::2]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6490 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r porthill 2KLQCAsMc+HcDsnzO0l/ZOX7P1I 3Eh7SkecphDkc8mxmf6/2JuTmQM 2020-04-19 20:36:57 136.243.176.148 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=90000 +p reject 1-65535 +r snap277 2K2jt4rFeGjkcn2hna+1T7uwQwo 16t6eBpiSrqLDK6eptIOlTsKk7M 2020-04-20 10:56:10 83.199.121.146 46785 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=145 +p reject 1-65535 +r AaronKSQC1 2LFvuc3/IowDsaYos7RWIPk+Mgo G5BuCcQW9BZSAiN4FqD32tgPsQU 2020-04-20 04:41:17 198.100.145.207 9001 9030 +a [2607:5300:60:8cf::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=3280 +p reject 1-65535 +r aberto 2LTDHk2vnLyJ7BPj9dlorWzci/0 jKSpKQ/R1oLAHKuR2XUGsjtss18 2020-04-20 07:11:59 91.203.5.146 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2660 +p accept 43,53,79,88,194,220,543-544,563,706,749,873,902-904,981,1194,1220,1293,1500,1723,1863,2082-2083,2086-2087,2095-2096,3128,3389,3690,4321,4643,5050,5060-5061,5070,5190,5222-5223,5900,6666-6667,6679,6697,8000,8008,8087-8088,8443,8888,9418,9999,19638 +r sci 2Lh9MrfLsh2MVAcPntiaDouPzgE J+BX2mKE7GsbJMXL4Doym6qyFOA 2020-04-20 02:05:09 149.28.63.128 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=3810 +p reject 1-65535 +r CheenaTorExit7 2LmadVazpUaRD1BfN09V0kF+7hI H6eUpX3aXqAtjMbrR+RrRszBJ6s 2020-04-20 12:09:13 176.123.5.250 9001 9030 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8080 +p reject 22,25,119,135-139,445,465,563,587,1214,4661-4666,6346-6429,6699,6881-6999 +r cepa2 2LmuLM+vMKeXSq65s/6vA1sHDYE FSZgKhk1Q7N1OVSfR951HjIQpKo 2020-04-20 03:28:04 185.100.87.41 444 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r dfiusec 2L1DezFlID6JDQ21ffKsEoyVs7Q HbOEGm5tjEkGSr4temUs5dvP5cc 2020-04-20 01:28:15 104.244.74.47 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,83,85-86,88,90,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1043,1103,1113,1194,1220,1293,1500,1533,1677,1723,1755,1863,1883,2082-2083,2086-2087,2095-2096,2102-2104,3690,4070,4321,4643,5004,5050,5190,5222-5223,5228,5287,5675,6880,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8502,8601-8602,8888,9418,11371,19294,19638,50002,64738 +r iiiq 2MgKX0PGUMmGQKXC4VkJScyWpHs owTD9fsuoybCwdFKNWSOBcDPgPw 2020-04-20 02:50:54 89.247.195.231 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2750 +p reject 1-65535 +r bchgang 2NR/nrbTeWvSCqwxUwuNHdkgNMI v06EdEuFVPZUnp4NaAtGyVtRKPc 2020-04-20 03:46:41 185.247.119.31 3389 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=330 +p reject 1-65535 +r skwidchipv3 2NkRQk5bmBAIrvn6ysVxhSM1uQg KU2ABcyGKfbxxlW87HsG4u5oDaA 2020-04-19 20:11:33 91.186.8.150 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2600 +p reject 1-65535 +r Unnamed 2N+WYCYbFYqd9sPX1j3ZKw/Vufc ILPnWcaKpQwE5U0CMaYYKFG9wwo 2020-04-20 04:04:17 185.61.148.225 443 80 +a [2a02:7aa0:43::e636:5252]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29700 +p reject 1-65535 +r AMBROOS 2OS7f+100meCnPO9RfgsgJpdN5I MaNcU1FwfkNi2iv3a6OhBOHgPOo 2020-04-19 20:46:26 185.62.57.162 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7080 +p reject 1-65535 +r nononicetry 2Ogy3TM0dpQN0IPoAjDhe8LBb18 43zst7LJpmrezHfxvDxfpkFl0zE 2020-04-19 22:24:41 159.69.152.208 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p reject 1-65535 +r tryler 2OoQXnmAP7AECowqZ22T2uos//A pmJMW/VIp/E9U6+aBkvTOVOwlbk 2020-04-20 06:48:51 185.117.82.71 9001 9030 +a [2001:67c:21bc:1e::1:1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28900 +p reject 1-65535 +r Chandra 2OyYMTCG48hbV45z5WD0CcyVnsQ jxtBqKc58sM0HtlwJACL+JXA/6E 2020-04-19 23:01:44 45.77.13.56 9150 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=323 +p reject 1-65535 +r Unnamed 2P3HISo/QFcd+xL0F34Ad4oFvGE V3/nFN8wFMxrfBqZB7iNSopDSx0 2020-04-20 12:20:58 198.98.51.242 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7280 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Piratenpartei3 2Qe80LlRDEYu6waI/VQhzS4XK3c dn7BhJTqeqcq1CBhsQOvl5FCwYk 2020-04-20 02:10:29 185.243.8.74 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19000 +p reject 1-65535 +r balthazar 2RY4KewuejQumJMlYsfr7zqVPww xf0uY5pwDYFS+yppYxyYZNVWy+g 2020-04-20 06:18:47 37.48.84.193 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1490 +p reject 1-65535 +r snap277 2ReiRxmEv5s5257fUzNEmLtpWRU Bo0WqQehFcqaVON8wjYyaCLd7QU 2020-04-20 11:40:37 90.77.20.45 38213 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4420 +p reject 1-65535 +r Unnamed 2R6XP592H8l4SWFvO1ewCDrG2iM ASYl9ppAuFSqw0X1evkgPB94nFk 2020-04-20 00:15:08 82.36.64.183 61666 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=456 +p reject 1-65535 +r Pinto 2UAAIi/GOIJztcl6+w6A1/NjBg0 gjju7a//L9YFFCJ+/BPbqsxhfwE 2020-04-20 07:23:46 37.44.215.83 443 3306 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p reject 1-65535 +r Tardis 2UHTgOUijntNNyr01IRimpbcSLk 4Yj+UMKMGsiDv9jYELh+ZCbrvPo 2020-04-20 03:22:53 158.255.212.178 8443 8080 +a [2a03:f80:ed15:158:255:212:178:2]:8443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=272 +p reject 1-65535 +r franovgnet 2UdiOzDJ1uFC59kPxzaLGipPUEU M0b0jGt3lOKSpicx2BPVQBjTxRY 2020-04-20 06:08:32 51.75.64.23 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4260 +p accept 53,80,143,443,993,995 +r Splinter 2VmAwV954JSuJVuo8bV/1sgfK1Q IJXHF/PRoorg3A2+P8cG+D22gNo 2020-04-20 04:24:01 200.122.181.78 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=369 +p reject 1-65535 +r lolZiggs 2Vu34l7E9k5JkIjeW/2bbmHsbtE CEhnXGzjY/Ef6Xt1qmDawnvVcPM 2020-04-19 22:48:41 154.59.112.72 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=21000 +p reject 1-65535 +r tor01 2WWFX3eln7vF0SJN+5wSqZI1UHk 3ZW6hjAVJ5qvTOCeahJsW2yfSH4 2020-04-19 21:09:33 51.158.173.137 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 1-65535 +r AnonVerona 2WXG4giePmH128atB4xJSAzwcOk vj59yjSHzNHsbWhPbMFeBY86fR4 2020-04-20 07:35:22 37.116.74.90 465 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=330 +p reject 1-65535 +r nickesrelay4 2XGk4YEWK9mf7kwq1gXWBKT9XUs 0WS99Hi5pG/zbvs94kRDQdXCb9M 2020-04-20 05:16:58 193.11.114.69 9002 9032 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22000 +p reject 1-65535 +r NoPermanentRecord 2YPslyZMD7HJechKzZHHAnPEEnI e5Fa8RI52iWPcAiPz08ges5cjKI 2020-04-20 05:12:45 62.75.142.215 9090 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=214 +p reject 1-65535 +r my1stBsdTorRelay 2Yrhkfq3tQ6FHzRLeSk5S/uvt2o PkrxRAA4L4cB2lYo3TSmMSF2zG0 2020-04-20 08:36:23 146.0.34.111 9001 0 +a [2a00:6020:11d1:4a00:20c:29ff:fe47:8aed]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r NeelTorExitA 2ZCxrAwYcJvDsqKN/xxMZBJFWbw WHtP71lm2fK0LaV9d4nm1Mwe8/g 2020-04-20 05:36:45 71.19.146.41 143 110 +a [2605:2700:0:3:a800:ff:fe87:5681]:143 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2870 +p accept 53,80,443,8080 +r Unnamed 2Zwyhx+lP7MZa21QPKLPRPyQgmE 6aIx6qU6JPIcN6eyt9vaTIJO6CQ 2020-04-20 12:00:28 209.141.33.133 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6120 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Warticuno 2cnswTCM37s+oH56wrBhfdWD+Rs hATaBND7sMp/1sutagL9FKTh6EQ 2020-04-20 02:34:57 104.238.138.241 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=2440 +p reject 1-65535 +r KYOTOKYO 2dE5hJMlSRHm8BezrvhA2BMcQ3c p3/Wp7inXKpgJD3grafDZdx4/lo 2020-04-20 00:38:50 13.230.39.30 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=579 +p reject 1-65535 +r slowplace 2dLwfIXQOfnhs5fSf94aUsdGBRs TEN5GHjwLrdGJaV078JJAaDq/l0 2020-04-19 18:57:06 178.128.86.51 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=222 +p reject 1-65535 +r traktorzetor 2dbDXpMv73EAoAyZwZk1boLat+Y qY/kUDXdEaODAO1dzjBooPJ2ln8 2020-04-19 23:07:53 185.8.236.131 443 80 +a [2a02:2b88:2:1::2f0f:f001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1060 +p reject 1-65535 +r tzkuatnode 2eGkPwEEjS3nUCgvmEv+7MmJHX0 x8hslrck4ZQa9y1mXq1BT7cbj50 2020-04-19 23:41:54 137.74.117.63 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8930 +p accept 1-65535 +r squish 2euZtY67MWgTJN+9FboMjHI4tSY l6jfPbPi326CXxXWz4jDHYCITUA 2020-04-20 11:03:22 75.34.64.170 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r atlasfragdev 2gTJwIJpOdXUYKB0MVSBDNHRMd8 GSx1Cai0rcfPP+ddt8nx2ZMhrU4 2020-04-19 18:57:58 45.79.181.153 9001 0 +a [2600:3c03::f03c:91ff:fec8:1e73]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=583 +p reject 1-65535 +r interstellar 2hPDzX6yPN/XOcMYVWWLxbY4Qe4 c2DJiRRWJMCJmVqXXdc0Z42ZACc 2020-04-19 23:34:57 104.196.43.128 443 0 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=490 +p accept 23,53,80-81,110,137-139,143,179,443,445,5985,8080,8888 +r snap277 2hq1MfPUMz1fJ0WLXSSJ9KGZhCk lia3gqVM74xglkhgmOhgmy7zUL4 2020-04-20 07:12:31 92.137.154.128 43269 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2100 +p reject 1-65535 +r Mjolnir 2huLjWF5CZAlcnkM6LuZ2lAsZIU ijHFDJ58scOsWtrycq4LJdY1UKY 2020-04-20 10:24:28 205.185.117.149 443 80 +a [2605:6400:20:3ea:c2a3:1162:7224:e5df]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 25,465,587 +r bassblitzed 2j8xca+BqugPMgofYiNtyZhSGKk fZJ1ERH1+3pFzdjXzgqs7fMt+5U 2020-04-19 21:58:42 45.128.133.142 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r barron 2lOYTbooQgFp809PRMsk46CUZ0c 9muB0JkBp0a+GyvmrrrIpq5FS9A 2020-04-19 22:28:23 81.22.255.146 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r anon 2mDIXVJjdMHcioeW6T8S98owGfI h/DMSFkV4dQ4NB/8tzNovL6fK+E 2020-04-20 05:26:23 51.175.245.162 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p reject 1-65535 +r blackstar 2nESbh0LEWBVM7etOZ3Vp+yOLw4 Cax7uds40pKCvtxqXYL+ssBo3SY 2020-04-19 20:16:22 80.127.107.154 9001 9030 +a [2001:982:cb89:1::5]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=789 +p reject 1-65535 +r Publica 2nomc08wRpPc+FiU7U+xDcQj+Zk Gl/tJX/iTVGVLnwIYF0uATUegeI 2020-04-19 21:26:21 51.15.58.175 10238 45030 +a [2001:bc8:4730:5a04::1]:18293 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20500 +p reject 1-65535 +r kyra 2n0OJ7CPAyx2Y7WMMgheJSnLzaI 5zlRMdIr65LCIDpvI3KC5E2zPKA 2020-04-20 00:17:03 91.216.111.52 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=90 +p reject 1-65535 +r PCGG 2n0ssh1z0ZRppu2jqTXbanYpsxc gKslkvSoMwjBLMWBQ+q6UVJNPm0 2020-04-20 05:47:25 110.141.223.194 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110 +p reject 1-65535 +r rddtor 2ocKL4lOkz7DkcKbTp+qkHDvr7I rHJvHC414vokte3f6y6cyyQ5WwE 2020-04-20 12:42:02 85.229.202.131 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=560 +p reject 1-65535 +r z0rb4l2 2o129fWBlpO1yW9Jm6GfdAQBR2k 8PcbAlZCog0XUHod8pkjTIEx3rM 2020-04-20 12:28:27 148.251.11.21 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=135000 +p reject 1-65535 +r tapatapatapa 2pHCYNanj3SL3xcTGh8dGEQ74es xbaGFsxRlsuA+jVLm/mx4GECCAc 2020-04-20 10:01:18 50.45.171.217 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5000 +p reject 1-65535 +r svnW4qmO 2pnx/atgum4kwOdlhe3VBrXToyw URnkjvqyqUlqUBhjSLUDbF5JaH0 2020-04-20 07:05:19 188.127.189.155 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.3.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1320 +p reject 1-65535 +r bigmekk01 2p4Cu4CA5HMVcFL3BDm3iGqoVp0 POLbH/xaeHgftYPgiXZiAWEWZWw 2020-04-20 05:04:58 93.177.67.43 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r netShelter02 2p8pb7cyxgVBd3/sxSoX29VNAvo FtUX3Zgs1ARQUEpNwxjtCRB2YBY 2020-04-19 19:20:06 185.121.69.16 9001 80 +a [2001:678:a00::15]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=41100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,25565-25580,27000-27040,50002,64738 +r ResisTor 2qIdJgbNsiziGHJtb0bTikJSSwM Ok/lKZ3InfqLrVNUzpDDrFs0nEQ 2020-04-20 00:42:19 77.189.3.253 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3660 +p reject 1-65535 +r Arne 2qOfwAsZazU8KicUWcMFxCmvCeQ XyXfHkNnnPqBFpxipzUwQ4VAn8c 2020-04-19 22:02:05 193.35.52.53 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r angeltestexit2 2qgG6VKdd++UaF/A5RM4bvZbg/g Wyy6KrAwkgPCccrg+IP/ijxLkt0 2020-04-20 12:26:09 62.171.159.164 443 80 +a [2a02:c207:3005:149::]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r PacsoT 2q+zbPRuH2p9E11bhr0zNOQgp8s Kml+KS8+2oGDiY30XKsb0xu1NWs 2020-04-20 09:38:57 78.131.72.89 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2180 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r malene 2sglu/BdZ4q96hwwhujZnPC78RI BY/qsIOPB+6X7G1T0M0gberGWbA 2020-04-20 11:28:17 185.73.220.8 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20300 +p reject 1-65535 +r UbuntuRelay 2tHsASecPkRraovhguAKTu2tqqs rjWg2kY2XlJnhmSDDVmBhACzYtY 2020-04-20 09:05:05 178.75.144.242 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=947 +p reject 1-65535 +r scatterhead 2txzMI1TC3Vglpy5VM3b13wBD8E V5YWxAlTcPsvHiyGZ45AkFWtofQ 2020-04-20 08:30:27 88.207.122.220 19001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=730 +p reject 1-65535 +r NowDNSa 2tytN95eIufh8yOScmAVXqs2icI CnaehXFIhZATz7KUSYqWODznswM 2020-04-19 22:52:16 158.69.201.47 8443 9030 +a [2607:5300:201:3000::1413]:8443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10200 +p accept 43,53,80,443 +r lysithe 2uldZowJ3oID79FjlPTbjUQZVZ0 miEZXjX3K1aXb3bbUBrNeqaqeN8 2020-04-19 19:30:28 68.183.53.124 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=2800 +p reject 1-65535 +r default 2u7AzdIU7assHSGGsgLceezLFlU lrDApJtYvcQCHeK6Esc6mjVunqs 2020-04-20 11:11:50 94.19.87.218 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3680 +p reject 1-65535 +r WolfsDen 2u+Li3mccRqGNQ/cQzeys6dbl8k fhRqjbcKba+PChu6N7aDgpM3RTA 2020-04-20 11:16:23 51.255.150.177 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r tor4ever8 2v/AlD7PtXH8mqgpfHjOdt/jwJ8 hoT7Imte5UHAgu/FbCx5g37Eo5E 2020-04-20 05:23:39 45.62.230.25 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3430 +p reject 1-65535 +r WaddennnuunTOR1 2wp0GbX3wuj/OFPlgivVUuhlIe8 maYNnR1XPg1kSDPuNpW2TRtKKWY 2020-04-20 11:20:13 84.178.228.67 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=360 +p reject 1-65535 +r GermanCraft2 2yaCFTrAzK7NK9Hp6+mcaBWAeh4 iJWg87sa3TGCstg9PrGMXjkKXCg 2020-04-20 12:03:10 54.36.237.163 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27000 +p reject 1-65535 +r fiedlerRelay11 20dyCnV2TNEAIBLmJfbOF3QaGjo 2SbtvE+H8BcTsIFUinE0DYEeBH8 2020-04-20 10:12:18 188.68.55.50 9001 0 +a [2a03:4000:6:e3e3::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r jinx 21OXXQKVcJnoTzGRlLj1x8bRVxI si57dCKpLP3WvAAmLLTf+J8TMnU 2020-04-20 05:46:21 62.210.9.178 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1750 +p reject 1-65535 +r 72ab8f63bbd93503 21jtUOkgxR9cGgROagS6ZpsUz9I P2TQf6W8998WkRzOOApyhaY/26A 2020-04-19 20:47:13 139.99.139.143 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=180 +p reject 1-65535 +r Schmutzig 21oQAVL7eTfwLwC13f/9ASeJwkI /Trc8d7tlt0h8wQs858jBrLDvVU 2020-04-20 02:31:35 145.220.0.15 9001 9030 +a [2001:67c:6ec:201:145:220:0:15]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36700 +p reject 1-65535 +r Songino1 21/26IBqZnTie/adHh6/MI2ah6k 7U5L8w/hGKR8E5da9w3pqsTInK8 2020-04-20 06:13:08 180.149.125.138 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=106 +p reject 25 +r RRDOTR3 22DZ8eiiqfXx+YR+Bbxihmbtyfw lPZR9MdHd8+LnJR01fjRNBQmxuw 2020-04-20 08:39:51 178.128.247.50 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=294 +p reject 1-65535 +r Artikel10Exit01 22ragVPfaxSLGohDtIbiA1RJllA EhyJj/O863mPif5lEy+n7Yy631c 2020-04-19 23:33:22 89.163.239.216 443 80 +a [2001:4ba0:ffea:2ae::a10]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=61500 +p accept 80,443 +r tor4ever10 23msdjCleoORbf8XsHII4Jv0yfo 1IecKWo4X7fkKHRn2DgOH6PsQjY 2020-04-19 19:43:20 45.62.229.8 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2370 +p reject 1-65535 +r yuggeit4 23zM9Mj8rURTeVI8jT1PUPT85Xs ih88Q07rLR7TD5uNe8L3aM4qCGk 2020-04-19 20:45:59 172.105.35.249 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=191 +p accept 20-21,23,43,53,79-81,443,1194,3600,5190,5222-5223,6660-6667,6679,6697,8008,8080,8332-8333,9418,11371 +r topinambour2 24KDpOFSAQqcr9pjzA9WrKFVZ2k 7Xw/WooWP0OkV71akmPQAQhznb4 2020-04-20 06:58:41 92.89.144.177 8080 13033 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23600 +p reject 1-65535 +r ripde 240UVM4HiETdpEfIrL7kQLJnJY0 py1v7aFwRgW3PzHIjRuuuIkmmzc 2020-04-20 09:42:06 85.93.17.143 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=520 +p reject 1-65535 +r anonymousByPDH 25eXxvBuz2rZCRfJ95ODpd+wXbk 5QZMZ//2aeSEfSPAA1gLaUPCBcE 2020-04-20 08:06:35 104.167.107.106 443 21 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2420 +p accept 43,53,853,993,995,5050,5222-5223,5228,9418,19294 +r John0072381236Smith 26LbuFLga1i6rwm9G+kfowoSQ8g 4YNjqCM/y5v+GMjRDySiUB9bKt4 2020-04-20 11:49:35 92.249.143.119 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r nocabal 29Z3Z2QBl/+W7GqHaERk/Ej2EbY F7rm8UqfPARzWjlhf+8K/t1i8q4 2020-04-20 10:58:53 78.46.53.11 9001 9030 +a [2a01:4f8:110:12c8::2:9001]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2190 +p reject 1-65535 +r Unnamed 29kV+W5GfBv7wX5rA2iIl/ol5Ek 7Jeu8bI0JcFB8TPR/Yrp4yt1yu8 2020-04-20 00:38:24 136.55.42.240 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r MurrayRothbard 2+K0s67kZGf3TFxQgikgys89VkQ pDAvsSxqcHqij91qNmu2dRm149A 2020-04-19 21:42:38 176.119.28.25 443 0 +s Exit Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,18080-18081,18089,19294,19638,28080-28081,28089,50002,64738 +r spechttor1 2+gvojuf48skYqb89Sid7Ty/Su4 cP7ec+tE5N87tmeQ7Lava+/cweM 2020-04-20 01:05:32 138.201.169.12 443 80 +a [2a01:4f8:171:35b0::4:1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=137000 +p reject 1-65535 +r ikhebeenbootrelay 2+0PdBjP5fIOnsxKRUDTFdAjrXs BfNx8lzlPMC5pYDCt+LgqoIvCQY 2020-04-20 00:55:37 82.217.245.7 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=697 +p reject 1-65535 +r snap277 2/UW32p7+DNfckbZkuhdl+FKyq4 29+k43b2oBSzz3hvHcqNQJd4r0U 2020-04-20 12:18:39 83.24.120.235 46195 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1940 +p reject 1-65535 +r casadum 2/hu8evghLM2DTW7l5A493ospRc yVmoyX7tlYRwxUoH0k8svLm4vCI 2020-04-19 22:16:12 93.188.166.145 1012 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7970 +p reject 1-65535 +r 5fd811a4 2/0ikD0O7Sm8LR6lV9k+be2j3K4 mTEsRNoeg+9XhbkL9cFHfhty71c 2020-04-20 10:10:41 95.216.17.164 443 0 +a [2a01:4f9:2a:11db::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p reject 1-65535 +r underworld 3BY93vS28Ma8Im+fZlalowxcVoY m+GVb8Zwh31jQ5Sqhs/TJmDNiAQ 2020-04-20 03:15:10 176.158.236.102 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5080 +p reject 1-65535 +r artikel5ev2 3CGRZj3UuuyzT5ScysP9oATOW84 SZaBXrBQ0CHFSq6QcWmTZyTYEQI 2020-04-19 20:12:42 87.118.122.30 443 9030 +a [2001:1b60:3:239:1003:103:0:1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r eclipse05 3CZ5CzA6/xIlavfQFrqnDIqINFA m2HFmEP/VumM7m3ITzX96cBN1EA 2020-04-19 21:01:24 46.167.244.57 9009 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r dowtf 3D5+1BtBhSQo+1BF4z4lWdSeODA 7T6QZKVaNr9QzhVJ231fNbG2Nyg 2020-04-20 04:00:51 206.189.20.183 9001 0 +s Fast Running Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6600 +p reject 1-65535 +r Ripley 3EZFwiiOWHmfS49qwEtY9H24pD0 qGHMzZ5j/swCcco6aW21WPqx7+c 2020-04-19 19:47:07 8.15.179.182 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3900 +p reject 1-65535 +r SicceggeOrion 3GpmsUGDzDduiSefukD96CScRAs fE8utMKKok9SBP8XgvBP78xMZXI 2020-04-20 03:54:45 195.154.133.113 9001 0 +a [2001:bc8:2aa0:100::1]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=180 +p reject 1-65535 +r ntppwguy 3HXsGZDgGLY6TcooY91/vYxZ8/w ptGio57Ajs3iV/514+icVyQGvno 2020-04-19 21:47:08 198.50.135.213 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=2900 +p reject 1-65535 +r 5efd8dd 3HnJ11z9epH5Iyki4F0iXL3LdwM 6GtSqY4PGY5sxXVdCPLKoGDEkNc 2020-04-20 10:41:46 213.239.216.221 443 0 +a [2a01:4f8:a0:83e2::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=125000 +p reject 1-65535 +r luftballons 3Hur/zxeScki0jneGlxSUvUdL4E v0z51P+huPxHtCfUOJxC6m0pkt0 2020-04-19 22:53:37 87.92.54.132 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6260 +p reject 1-65535 +r angelwindowsexit1 3IGqOx1RVm2/J7+lYuQEeuscUto +LT9Q1JTpDAI6kTGDBviCSVBDrw 2020-04-20 12:22:14 91.132.147.168 443 0 +a [2a03:4000:37:645::]:443 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8900 +p reject 1-65535 +r N1nj4 3JVkrovHv19yLjZ3yJftG1eMjYE 6uSOA197FLpVf4fas1Rif9lF7+Y 2020-04-20 05:29:58 176.9.98.228 8080 9090 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=85000 +p reject 1-65535 +r Unnamed 3Jdx+aQDQPXP2sOFC87ZI8Nr8/w DRzWp/V0/i6muYAFsmqJLq/vUqM 2020-04-20 07:57:28 131.255.7.73 55777 47737 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=51 +p reject 1-65535 +r m00t0r 3J48ZXbMmgSq4cRlIQqXKnIlcaA MzjtGUO4G0weHxZXVNuTBNMLcTk 2020-04-20 12:43:59 83.162.230.105 8080 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18900 +p reject 1-65535 +r romeojuliet6389 3J9QNm2GwOrC09PjGUDEtyzt4aQ Y2kvLRymaFUzM2TMMVNjF+ckPTU 2020-04-19 23:28:44 64.120.110.26 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=903 +p accept 20-23,53,79-81,88,110,143,194,220,389,443,531,554,587,636,749,873,902-904,981,989-990,992-995,1194,1220,1293,2082-2083,2086-2087,2102-2104,3128,3690,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8888,9418,11371,19294,50002,64738 +r SweRaspiTor3 3KoXb3WwQocTHG14t8/drG8mkdk sq/cMc6OHqoDk1gnnNjnw0lYMoM 2020-04-19 19:23:34 92.34.132.198 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p reject 1-65535 +r HexFromHEMEuropa 3Koc7XGDtWHRjPWAvpkzvZFo0QE /UPmUSrRUI0Mk8OwOSVgDWHZCEM 2020-04-20 03:15:14 188.226.148.15 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1150 +p reject 1-65535 +r rollingrecent 3LWmv37C2Cd0WeKIEVcGKGxLnIY cD00xeBlVBjkSdyB6SLFRIMZx/o 2020-04-19 20:18:39 46.64.251.128 8986 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=121 +p reject 1-65535 +r bh1c44n 3LW4YSGeAQg0PaLy448XoHIOses dyg5cVHjZus5yrLlumRjEnInsMk 2020-04-20 12:41:42 172.104.131.118 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2730 +p reject 1-65535 +r eludemailrelay 3MbHDo9DQMvWM/UGvJ59mYGGAdk hZ7cuOB8X7t6cfO7x8DtdCdegZA 2020-04-20 05:25:46 93.190.142.146 110 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17700 +p reject 1-65535 +r InfiniteMercury 3OWqWyKHZjvn2+nIdjX6hGE42aY 5ZF7FWttCE6Z6u/YqIzCWcaqqew 2020-04-20 08:06:28 185.17.184.101 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r MaxWerner 3Ojb+UV2JyrRDZlsmqB5SkVn8wQ +yWSmUVYiiHVJL+daf8SZ588CMg 2020-04-20 07:57:45 37.120.190.193 9001 0 +a [2a03:4000:6:b330:a440:54ff:fe8c:574c]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r sabaroff 3OoqbYA04WSk/92K/5l+L2+y7Pg 2862UrGt68u40VXlGMShL2wYAoY 2020-04-20 09:22:27 50.7.179.202 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8550 +p reject 1-65535 +r vincennesfailsafe 3O+tJitmXcjjGEl2Q2YhS8pp3Dc GK7qKSg+VbXzVTtlm78tAifG2CA 2020-04-20 12:06:36 99.104.206.58 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p reject 1-65535 +r toolazytofillthisin 3QQNQnXov3yc/POR/EQIw9G/DG8 lUR6jTAgRtga/OV/XhMTth6HPBc 2020-04-19 22:26:33 51.38.69.161 9001 9030 +a [2001:41d0:801:2000::c0a]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5390 +p reject 1-65535 +r redsphinx 3Qj084WpdQHuUy9R2BJuO/Tcw4I np43SYBUECkyE2ifasleX7c1Jj8 2020-04-19 22:02:56 178.27.123.39 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p reject 1-65535 +r flowjob04 3Qqmbdnk5x/6+rZY34MA8c7qA2Q OQ/UljHZzL+orrZGgdXWSBXue3M 2020-04-20 02:05:41 152.89.104.206 9001 9030 +a [2a03:4000:39:45c:241f:53ff:fe4e:45e9]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34400 +p reject 1-65535 +r chaosDelroth 3QyO7FykAqn6RHjxDDGkQPcfaIU wItBAUL6B6iwBfD+JFqLMQtypbI 2020-04-19 20:24:43 195.201.9.37 143 0 +a [2a01:4f8:13b:f15::1]:143 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=94900 +p reject 1-65535 +r idideditheconfig 3RG3UZkvLqWRY6u8YI0IXeLOI1I PJzffDFJjjpiwqPIKZcRMreaV64 2020-04-19 21:33:04 93.8.239.208 5761 5760 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=280 +p reject 1-65535 +r hands 3SznnGH4OV6pOjGU/oc5SsQEU/E Ybu4r7UbN0v9vwc9TNgdtd1OAJY 2020-04-20 09:25:40 109.169.33.163 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=170 +p reject 25,119,135-139,445,1214,4661-4666,6346-6429,6699,6881-6999 +r free2play 3TLD7MNSHVjX6dfg40O3APsk5ac v8HGZBAF9zs29kDxJx2Mywtx8Tk 2020-04-20 09:12:45 66.228.58.95 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=2880 +p reject 1-65535 +r snap277 3VCPlrxMtOmoAWFeSwPEl+D/8A0 Qhxlrg5K/ZlADwFeDYXjZCtngFY 2020-04-20 11:04:14 78.227.101.134 37313 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21 +p reject 1-65535 +r Toyota 3VOooeMcOVmvivtaBvk8fDY1DCk m2h3TW0AkNV6+fcEKaGRzY8R8gY 2020-04-20 05:48:58 31.220.2.100 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed 3V2iHMUDZTOuIBDeLH5yvizfnF4 w1yhnDQntGvn5h1Gx1oRmSzDVtk 2020-04-20 11:20:29 195.154.250.239 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12200 +p reject 1-65535 +r Assange014nl 3XvT5b0LpIqMcLDN8Bf6WYi4fic LAjXyNCjuSk28rSz+MbldI5ojBs 2020-04-19 23:05:13 5.182.211.119 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r reactortornode 3YCOzk8uJPN3y+EeM17NoZb+O3g sE9xbiT2rYuRTUfr37KioX+3c6M 2020-04-20 10:12:37 185.207.139.2 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35800 +p reject 25,119,135-139,445,563 +r grenouille 3YI6+0FTgKgC3K65RhrmN2BBB/s RMfuS35dw47XMOvUpH40FifwV/k 2020-04-20 04:51:22 178.33.183.251 443 80 +a [2001:41d0:2:a683::251]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18200 +p reject 1-65535 +r DFRI0 3YvXMHAXQH/MNvjQSmiPdKB3TAI 4C3CHh2H6jvWeOMw1qDDeDPAETY 2020-04-19 23:36:49 171.25.193.20 443 80 +a [2001:67c:289c::20]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18900 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r telebube 3Y9adN03Xx1qeYoatQEWM5/r7QE VHmeHHozxu8PjIrt9zkpxRZx3mg 2020-04-20 12:24:13 87.147.199.72 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=262 +p reject 1-65535 +r eclipse 3ZLBIc2Qfse+LwQNQ4HbZ0jO3Hs +aqDkhmTb13kymSsqoVzBWBcysM 2020-04-20 00:33:52 180.150.227.75 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=88 +p reject 1-65535 +r snap277 3azaIlKCU3XQ7a0LUkJ7fCr/1YU 0VksB9fqlZ6vCQz47ACoAwhc+e4 2020-04-20 01:58:06 110.151.64.66 37189 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=85 +p reject 1-65535 +r tor4ever5 3bIi00CnN2iHtNVzS4yS9ApJQcA Y5FHMCqjWix2oDOe0Rpo1gFUu+4 2020-04-20 04:26:28 45.62.230.111 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2100 +p reject 1-65535 +r NickTorNode 3bbxt6gn/90IZr/5vaiNV6+zOjI c9JfBdi/3MdnwkLNgOPiIV92sKU 2020-04-20 02:42:22 73.235.200.159 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2720 +p reject 1-65535 +r zouzounella 3bsqOCUq3aU+RJLd+YLKbMbhDsA Ng5bNpYVqruReHOiTMUEIkvkklo 2020-04-19 22:13:14 83.212.99.68 443 80 +a [2001:648:2ffc:1225:a800:bff:fe3d:67b5]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4870 +p reject 1-65535 +r HonifTular 3hsHsOinSMHIojxLvYnsA7mJzTA o3FsQdDGyZH8SUYMhRTHGeLQNjI 2020-04-19 19:36:31 213.176.246.53 48343 49331 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2450 +p reject 1-65535 +r OLOLOL 3h9hOu+HXl/NHkcYZqjeS+wvEWA 3MsLSGTempcJFKjakXzIBYXXwWI 2020-04-20 11:32:49 80.89.228.15 993 994 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1150 +p reject 1-65535 +r 18cd7354bd014e9e96 3i4G/mfqyd13LsuFofw+A38dqhE SSzxWNte05h+/BvIrxVy3Vz3mUc 2020-04-20 03:10:45 99.85.80.169 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r YelloSunflowers 3jYNwZFSky5gdnQezmCpbcYNSEc AD2MuyhyDdBV5bBFJfEt+tnWLG4 2020-04-20 00:55:19 69.250.241.88 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=124 +p reject 1-65535 +r smell 3kWctH2rNq+8mlTvGev42Y7Wr34 uin5+tZGgwAj8LqsrXo17PxET5U 2020-04-19 22:22:56 45.9.148.25 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6300 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r PIAslcexit 3kakJCMwT8N5PHNklTndowkSKmU aiiYUyxnYNPy+0gJZO24FLAMm2I 2020-04-20 08:24:36 173.244.209.5 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9800 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r 0x616e6f6e 3lFOQlKNT7i3mAS1YQCLSCuR1AI nhuRFvgN6Ja4R9TLdEIlGr0S6Xk 2020-04-20 00:46:04 178.17.170.112 443 80 +a [2a00:1dc0:caff:15c::5627]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3870 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r torrremio 3mWQ5yTC24E05nSx1h4OfA25isw /FpafGRRlGnrGr6cR9JuWE49Cmg 2020-04-20 02:09:02 91.61.236.99 8080 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=129 +p reject 1-65535 +r Someone 3mqleFkHA1agvmv1lYuAJud9Ffs F/3h3KGV/Z32pHl9aVZzHtjM5aE 2020-04-20 09:43:53 77.201.41.49 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=264 +p reject 1-65535 +r Surtsey 3nL+tHToo8xQLPxDYhGA6p1GL+A cCLyZIat2STbMsjBNmK4H1afspM 2020-04-20 00:33:52 165.169.205.127 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=121 +p reject 1-65535 +r gergernet1 3nToxPPPD7vLfnYbswcgUNHU3Yg TfonvMLaAmB86ijFg2MenW1Uq8w 2020-04-20 09:36:46 217.199.207.250 9001 9030 +a [2a00:4d80::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p reject 1-65535 +r Unnamed 3nZPtOq73o68GTbANi4G65Ius7o 9FGDbk4vSKj6dUHyeStBn+2fPzY 2020-04-19 19:11:48 142.44.133.94 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9110 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r CheezsystemsTord 3oLu+iRBDaF8s8o+48lVI0m9Xx0 uLO2FZJqHUnmJ9kfyLHJK+2DHQk 2020-04-20 00:14:55 173.212.222.109 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=463 +p reject 1-65535 +r kohlrabi 3oR9lOeLLlYKuH0nLckBktMUTxc R880+iFp0Rd9er1irkuQFUE4/+E 2020-04-20 02:18:40 109.70.100.15 443 80 +a [2a03:e600:100::f]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82400 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r thesanctuary 3os9CUarsYDZmPAPgQBG6enFRoQ quOTbi7Ozzj3pKcMhzj+IA1ppGA 2020-04-20 05:25:06 45.79.67.237 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r LibertarianNode 3puXt+BW/h37JBPJ5WqyXnLFws0 674eEymsTZjvTtw9j2e7vvNpjck 2020-04-20 03:27:14 83.212.104.45 9001 9030 +a [2001:648:2ffc:1225:a800:4ff:fe0c:28b]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4500 +p reject 1-65535 +r CloudLink01 3qhPCEMoADRrrbNfHqwbKk1bFl0 n3pTM+ldbx1zqYsTg4ZUFzUV31c 2020-04-20 08:04:33 173.50.86.103 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16900 +p reject 1-65535 +r sparadra911 3qmLf5uot/igmNOTmm/kRghLSOc QvQ4KTrxCdNvDbaeRkYV0UFMz/U 2020-04-20 10:07:22 94.140.120.19 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p reject 1-65535 +r snap277 3reEK9JszRKZpx2fhOHTIjy0CsQ VXD5TOA19zXl858TnbHQC9d7Yls 2020-04-20 03:05:37 85.15.92.219 33927 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1 +p reject 1-65535 +r Unnamed 3rkucDWDvr7UXlFIlYCX8fuCcv0 SIaXPXJ+BRfwzn19aqvVl8fHlxE 2020-04-19 22:08:31 52.141.36.108 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=835 +p reject 1-65535 +r ThorExit 3taJL/idvXN7polpihcbI5LrPoI 9tk2EZryT8AWzFsv3kQ/kq2D4IE 2020-04-19 20:39:17 92.222.38.67 443 80 +a [2001:41d0:52:100::112a]:443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3510 +p accept 43,53,80-81,88,110,143,220,389,443,464-465,543-544,554,563,587,636,706,749,853,991,993,995,1194,1293,1723,1755,1863,2083,2086-2087,3128,3690,4321,5222-5223,5228,5900,8008,8080,8082,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,50002,64738 +r hejehuja 3tjmwxJ9F+V8uAfAZAvahVFHct0 c2rjEwObMntC/Mhu5+ygHByaK40 2020-04-20 07:05:23 86.101.214.77 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1290 +p reject 1-65535 +r ariolcnode 3uEyRvkhCmhXA4k4n6CMwVWQizQ RpiYFKRA4HxPcxTvdTR71/9blt4 2020-04-20 08:19:19 79.200.219.134 9001 0 +s Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=12 +p reject 1-65535 +r PepeCollusion 3vHpIHJ56Hkq4RTVT6wRDP5eIKM Da7XBh4vLxg+h8J2dCLVeizwmTE 2020-04-20 04:56:50 107.172.227.24 8080 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p reject 1-65535 +r Joker 3vM2XxwBL4DlaHe17wXOcr3rDMw /G1uxihaM351esTOKZJFeI+w0Ok 2020-04-20 06:57:49 139.162.210.252 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4750 +p reject 1-65535 +r FalkensteinTor01 3vjHYKef7yNY4DrloZUAhqvrlT4 y6DizHeGPpbWOX2mSifEOrD056w 2020-04-19 19:26:27 195.201.168.84 443 0 +a [2a01:4f8:13a:1082::2]:8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=65000 +p reject 1-65535 +r anityatvarelay 3wLjV7Joum6QKfpt+4vCied2P88 rNMrvdQ1qRSBAans6EqdYpU5XQg 2020-04-19 21:13:14 195.154.164.111 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2180 +p reject 1-65535 +r Toooldtocare 3wYFUYVn1jerqEbK4u3lDoor1X0 tJaYb9QS2e5Eafh1909X2SLHJFY 2020-04-19 20:15:52 141.155.5.128 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5900 +p reject 1-65535 +r Quintex19 3yBJfkh6l5mV2FGlvOwxPfflvFE a7bZdoCReukOUlyKgRUyNS5/ZYc 2020-04-20 10:54:29 199.249.230.109 443 80 +a [2620:7:6001::109]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r strokkur 3y5p/TQyQTD7nJk4/ebbqBxMHgA d09+C6RZvTkz8JuoFTv65kIiR7o 2020-04-19 20:22:39 2.110.219.47 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=31 +p reject 1-65535 +r niftygorellik 3zkIYLVhC46ZxaeLQJmjcFzTaxc qOErQPr/wuSdTWS0vAtU/44M7uc 2020-04-20 08:53:19 185.220.100.251 9000 9001 +a [2a0b:f4c0:16c:8::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47900 +p reject 25 +r deepSpace1010 3zsH9/kM+wlq3K9uoATRFD8f/i4 opFJFcW1b82UlMwActgoVayBm64 2020-04-20 11:40:43 51.15.100.60 443 80 +a [2001:bc8:182c:514::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=46700 +p accept 20-21,43,53,80,110,143,220,443,873,989-990,992-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r giesing 30CX2Amvy28upJhxm8LD8Q8ZLzw W/ZnTAXaJvLPfb5aac4D38PP+lU 2020-04-20 09:43:17 82.223.36.196 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=84 +p reject 1-65535 +r giorgetti 30RQBpMqe6lC8+u0RX16vy5ABuA Qlc58NSLOlDu0Iv8XUEFRYvHeQM 2020-04-20 11:38:15 217.23.15.200 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p reject 1-65535 +r dodoo 31V/P1I8y3YqUNSz3zPovq1Pedg h4CsZMoDUwxzSfmPzb2ZRk+7XB8 2020-04-20 04:24:44 137.74.113.129 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r tornado 33qhbhpgN8X8u03tTzps0mLKN5k G3rLVXcwIcwnwQKe0h/msMFH5d0 2020-04-20 06:21:50 195.154.253.226 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7500 +p reject 1-65535 +r Voyager 34HYMdT/aG9SyayqnrVxH5W/TdQ pe19kvh2wMj/DNdeKIxuWgi83U0 2020-04-19 23:27:47 72.5.72.227 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6400 +p reject 1-65535 +r Assange031uk 34YJiWi7zZY+OOA/w/wYN+9mfBM dMjMIViRQa6btoDAetf3tB9hT8M 2020-04-20 02:45:35 51.75.167.144 9001 9011 +a [2001:41d0:800:2885:2b0::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r Unnamed 36QDBr6m6vKM70r+1HOih3qQ+bU 0lfv9UUDsJnyEn6n8GeK3tKMd4E 2020-04-19 20:43:29 194.88.105.13 33914 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=137 +p reject 1-65535 +r snap277 36iqano2/km6LxVA+HJmzxhMMHY 7BGDhjb0BhknofsFAVViT1ULvcM 2020-04-20 07:54:58 31.23.240.103 33079 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1160 +p reject 1-65535 +r niftywabbit5 36qGrUa+qHXVAYzBzs13yfl5+w4 rZbqHehELpOQw600eboWVWdBhds 2020-04-20 00:40:49 185.220.101.197 1197 2197 +a [2a0b:f4c2:2::197]:1197 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59000 +p reject 25 +r synapsethemole 37ilqSnVx5+0d4YCayVoC0iuoqg SMaS4/yrilvzuBCdKptYPJp4wug 2020-04-20 09:21:08 24.14.128.92 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8 +p reject 1-65535 +r snap277 38DZ6uAGIF1erqAKNlcRm8pYPIU Ngd+ULmBStVBx/7PBUK1Z+NPxuQ 2020-04-20 12:23:32 79.166.244.104 45979 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r 9500 3/nnQdAPdJmP6DzWJg7k2eCw2/o IUrN58D8DttfhiwK2r7pidxRtys 2020-04-19 21:03:22 89.164.113.211 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6810 +p reject 1-65535 +r DerrickJensen 4AI6wUGAESov/wCoTGBJhiuz5sM EMMLkfIXJ3m2wzOvpD15DpIbCM4 2020-04-20 10:42:19 147.135.112.139 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6100 +p reject 1-65535 +r DigiGesTor5e3 4AbqBMaWu9bjVAdTgTEwX/PLjBY /dAG600CUFMxV3tfGu58TKURDbg 2020-04-20 06:44:25 195.176.3.24 443 80 +a [2001:620:20d0::24]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r descartes 4Adk7dLV2jOM6i7thpHh/Kr0puk wQpF0WjpIRkjtcuc/CmmrUV2zHY 2020-04-19 21:41:20 46.188.6.64 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7270 +p reject 1-65535 +r rawpower 4ApVtSt8kz5xXjCokuGyfHzIfv8 EVEXV88tUd8EUrUh51OZRDNT1AU 2020-04-20 11:26:06 184.146.234.232 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r Brecht 4AwIfs+yfXv5aZNvH92TVOA8ri8 MBmIX7V+FYY+1husGdlGuwQs4O0 2020-04-20 10:06:15 144.91.106.71 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p accept 53,80,443 +r despacitor 4A39VNwWXVRS+9NTDTAYba0Bagw b3Yjz1yzgbRX/H5z1dxlMBG8J8w 2020-04-20 11:00:44 163.172.53.201 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=74000 +p reject 1-65535 +r niftyblythsvole 4BPMmMzB5q/c/JaBpT3C3v5dTMw 2qAUEsbFRb0PiB6zxM7wJ8ImYKE 2020-04-19 22:14:29 185.220.101.132 1132 2132 +a [2a0b:f4c2:1::132]:1132 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54000 +p reject 22,25 +r Unnamed 4BRL+oJrzMPmSJWzKygngpYyRs0 9TDLzdp/9laFe8KEO//nmfvAl8I 2020-04-20 07:25:56 178.32.223.87 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=37 +p reject 1-65535 +r FrodoBolson 4B+W71yGWi4cXRyQxDpvb9Qy4D4 /ihSEgB1MnGL29SdGCFfvnrsli0 2020-04-19 19:11:54 85.117.234.222 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r yaRelayNickName 4DlvewZH25k9WX/LAykGa0ATvwU m6+xqqRE0fl1oafzDgvm+WlCa7w 2020-04-20 08:19:56 95.118.109.111 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=892 +p reject 1-65535 +r Unnamed 4D5YGqQqIR9p3GNgixmA8QrlLCY E3TK62fvUHKmQ6DZdMrArHRuMDE 2020-04-20 02:25:04 37.191.192.239 38443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17900 +p reject 1-65535 +r albator 4Fyskp45F4cHcGbClGGp0i7PCAk YImi2IhGfEv0SjaprZ3Sp8OY9lA 2020-04-20 10:53:49 83.205.101.220 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5980 +p reject 1-65535 +r licinius 4F6rWIKFwB6IB/AKB827xGYqWNk BXlO8lFRmrnEEPA+WdoEmDFBGL0 2020-04-20 00:52:26 217.112.131.24 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8180 +p reject 1-65535 +r BurninThruBridges 4GIMyPtLDdd7hq5zkgpqWrWInm8 9bGJg+6hOoUU5jmYrvsyPzWx9qM 2020-04-20 11:11:52 74.91.27.30 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37 +p reject 1-65535 +r UnknwnRelay 4Gcf4kS06KSPF5NX9/TV5qCyePc M5nIiJXpSukw8j5iych9L2O9hN4 2020-04-20 06:56:52 139.59.155.174 443 0 +s Fast Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=422 +p reject 1-65535 +r Unnamed 4HnV02UfjdBAjEyiTWTiI5jjD6s qe3S13XAO7FLPrQElZl9fWqbvVE 2020-04-20 08:35:55 51.75.194.222 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3500 +p reject 1-65535 +r bartor 4KSb9lwgJMNm7F4T5jG5fE9IVlY zlgJ2xI6WCGQXs6b+oO6bgWT+/4 2020-04-20 01:09:51 83.77.193.34 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=173 +p reject 1-65535 +r Freebsd2323 4KtKH6lt5f6ySRA/JKjZoxoLJKs K+5DzFtt/NxUdmgu0OKBxCKkPaM 2020-04-20 07:25:43 217.163.29.244 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r nodvrelay30 4K58HOT0St9NkOnK2tCNCly/w9A YC1APULdgSl2kff8x0tjrNLk5mA 2020-04-19 19:04:52 45.62.235.116 9001 9000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r KherNl 4LOxAibwZ6GyFReNGaGe8xHn/cM 2T8n3f2ZBhinGLUL6ZpmW5NIhdk 2020-04-20 03:49:37 51.75.206.12 9000 9001 +a [2001:41d0:305:2100::7cb4]:9000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p reject 1-65535 +r snap277 4MEMzyTygcM7DVZlvBOWKftu2Kk icHTvHAg3/IrbhnG+O9tMyDRwdc 2020-04-20 09:53:10 109.177.81.134 36209 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r snap277 4OAysNVs1fJ3NVB5G/8xHwaW37k 0iOODycPOAZZaD3XOC3bEapmDvA 2020-04-20 07:03:31 82.245.67.10 42837 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=332 +p reject 1-65535 +r nohum1970 4OOy5obs7/bTkeJ3bGRY3dd3lZs Qe7ZPLIM7Lu+srzDpI9qwG71y2k 2020-04-20 09:23:28 193.105.7.201 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1020 +p reject 1-65535 +r harley 4OlaidL8nOkiK9UCeoR7nSC5g4w s9RySAuThFqxQrDytuaTgdDWvsw 2020-04-19 19:23:47 185.113.140.49 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=205 +p reject 1-65535 +r Unnamed 4Oyu8PzdaAXBu6DQhcQV4b3ZorA C3xKln88CW6vtd/zA+Iq2uxfje4 2020-04-20 03:35:14 141.239.236.210 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r Cosworth02 4PY47M6Ri1RVzinSzZ7Mnb2PiyE n+RRnjhEfMrM/3UjRS8k5U9HZ20 2020-04-20 12:27:48 54.38.55.4 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r snap277 4RfkExmZSGd6YH78I/l8kfBMpv4 tV7TwiDZFiNMU+6rzaWH9xh8ei4 2020-04-20 06:19:21 187.190.65.167 43061 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r Memains 4Rhm/W5mlNASkEOx7T4OOKDKTZY gyMUx1kzXR6hy1W6JaaZkXUpzxc 2020-04-20 03:32:44 103.249.28.195 443 80 +s Exit Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r yutu 4TXVOE6kK0p3EmjNoTnXPRwWosQ o/o3gMFFmyYzpYpVJ43Ox0DVBu0 2020-04-20 02:16:27 78.47.147.245 8080 9090 +a [2a01:4f8:c0c:1fe9::1]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23200 +p reject 1-65535 +r DrebtorUSWest21 4TgtKHcF5Rl0YfJQOa0Iqbl9AB8 gznU7zlJKdU7KdEOxTDkKKS+zFw 2020-04-20 00:35:41 138.197.213.154 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3510 +p reject 1-65535 +r ipheiboqu8oorai8Ais 4T9+4VNe2K6rkqXurumgx4LtM+I ERW5NlNwr0JBBUW8vTpMhM2qU20 2020-04-20 02:48:43 84.239.153.105 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18300 +p reject 1-65535 +r VonKuenheimRelay 4UswqD/4DFdrLsDyyKXynUG43I4 /W/vKALUhHQRs+X4iBVIa2XK114 2020-04-19 19:27:58 116.203.64.212 8080 8443 +a [2a01:4f8:c2c:d75::1]:8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r BOOTCHAROO2 4U0QZp3W5HIjX48BYVRLTnt8s8c /Ssx1va95bwlGgULx8vUsOsHFT0 2020-04-19 23:36:52 108.53.168.46 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8200 +p reject 1-65535 +r variable 4U9rOHqDKsD1BWQSix4r1Anx070 xdiXRVai0yL7dmzzHF4Zdjm9uxw 2020-04-20 03:18:19 51.75.144.233 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=58000 +p reject 1-65535 +r Freebian 4V/kRvIwo1ud9LhivoR/J4cxs/w DwYjOvCyN6fkvNonvXefhz7jXvE 2020-04-20 11:22:37 69.221.232.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=720 +p reject 1-65535 +r DannenTor 4WjxXSi14HwWuCVVmz5EPoy8Zx4 OrgMsS4yQckuA4qUG5j3s4ZxiiU 2020-04-19 19:44:02 188.194.90.111 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=59 +p reject 1-65535 +r tor4ever18 4WyAxwYWkv1ohGqpInEGkfGdvqk V/uuimFWYV0roSVnnKPF+o8oxgo 2020-04-19 20:39:55 45.62.226.232 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=714 +p reject 1-65535 +r hypergrass 4XdFxkJV0pINm5/PnvkwxCbuSpE 1AkmKaf5ML/KxqCBVy7dPlQ7nZw 2020-04-20 12:25:53 91.250.98.158 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19300 +p reject 1-65535 +r TESLATORNAZISLAYER 4X8ZyCQKRQhCk9cR/ZDUVlQpVl8 SigyvsrgTjQml91auIAT0NRXhCA 2020-04-20 12:05:30 98.115.98.84 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4770 +p reject 1-65535 +r king 4Z4yc8TOXQWEKNaZZRAe2XaRYD8 WrZlFJbaDOE5sczrzr6pgYrvu9I 2020-04-20 04:59:03 51.89.147.69 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10100 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r debouch 4aJFs6ZNQmhwtlOmK+HYfDmRACI hADiqio0esOZu5oI/qmnjGnu+YI 2020-04-19 20:49:21 172.105.122.161 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=282 +p reject 1-65535 +r Technodrome 4aZJ4ZdOqnjU26URU/Xz7zAmkxg Ro5GnoXV3YRD2w0WMZmWswa2Zq4 2020-04-20 02:01:33 66.42.163.145 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r snap277 4akmxxRZTLX0lHSHaGNUbg4OyRk 1CgXIgnsx9AeTcnawy8PeRRyZ70 2020-04-20 05:52:39 37.143.229.239 35643 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3000 +p reject 1-65535 +r hotbrownie 4ak7X78Wm6kIQ5qxbneG00ebttc hm1puM4TGMnkQljhfZP+j38EtUk 2020-04-20 10:38:40 51.89.6.40 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r SwordHogwrts 4bVJJcWezoEyabmjMJt6XrV+m5g 25hZxt7PpvEtwTskj3LJtUzvJyw 2020-04-19 20:47:50 47.254.146.23 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r grandma 4bq09bDp14kdzZeQyPGG2BcoNI8 dKnqVtX2fbY1m1RgO7xmiqxMpzM 2020-04-20 11:23:42 87.185.37.212 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1690 +p reject 1-65535 +r Unnamed 4b0D8i1hUEwMACNf1wWAKUQg2G0 NhAk3bzqcMS1NGjf9TP+lyGJWYA 2020-04-20 04:31:21 109.189.17.254 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9 +p reject 1-65535 +r Unnamed 4dyt0Yng8dxwOJ9BmGdauHPpDY0 5NtbqpY6SwnghIcvTQ1b2fNtgmw 2020-04-20 08:15:37 111.221.44.109 33446 64436 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=152 +p reject 1-65535 +r M435 4d2afCljz2C5Z9zTRor4za5krhQ tF5gLyUWrZtlztrExBSHQ06HEPw 2020-04-20 10:43:59 83.97.20.183 9001 80 +a [2a04:9dc0:31::c0cc:b7]:9001 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tordotcissincdotca 4d6aFmh3ZnNgvst2gOCXJNjQFf4 iHQzVwtoAOqWo6/n3Cw6q1IAF+Y 2020-04-19 22:58:49 45.73.2.211 443 80 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=17 +p reject 1-65535 +r LxcTorNode 4e6qkWe0CjZ9mrQwM2SIAOmuLnQ jM92KrE0z5xcfRi6ja0Ys4DqFEs 2020-04-19 19:27:21 82.95.107.51 9001 9030 +a [2001:980:8e2f:84::3]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=671 +p reject 1-65535 +r tornekwi01 4gqZ3hfZn3PYiMfTPEaAe3Ghl/s jFkfBhC71mpH/2Zlfa+r4seYNpI 2020-04-20 01:15:22 66.208.64.128 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2500 +p reject 1-65535 +r VimRulzEmacsBlowz 4jWUHIQD+2PskUNvpNz2sCDrUaI DMLIZIMpvwONuMW6QWL6q0lBxKg 2020-04-20 10:09:21 66.228.51.186 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5410 +p reject 1-65535 +r bitcoingang 4mO4YO+hd/Dd4ww4H4k/KAXBQNw nTlaS5m5LOXbDlQODOGCT55Ddjk 2020-04-19 21:41:50 94.21.27.216 8443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6750 +p reject 1-65535 +r sinilaukka 4niE35tJ45CIkJVdVB1GiI0x5Xo X3bV8x12qgG6QZMFb+ppQzhmH7c 2020-04-20 00:35:10 62.78.143.66 3280 3281 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2 +p reject 1-65535 +r ctr0003 4nsR58qur3sr0J3UQN1a3ivkVGE HsqIwi8Kc9fNbx/UipD+eiTVHA0 2020-04-20 02:31:35 84.19.178.79 80 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4720 +p reject 1-65535 +r habana 4pJAaz/IavlN+83CxMxZSuifW7Y jObAKGCtSxYDr0Jmw1DqpRsBx2c 2020-04-20 00:46:00 3.8.235.167 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=660 +p reject 1-65535 +r Unnamed 4pMXvAhobT8NQg//wG5xSJoOVFI tmUisS/5JTosPTtGo3TCjlNCUCY 2020-04-20 03:21:54 88.198.56.215 29644 29189 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p reject 1-65535 +r Unnamed 4q9YefOf9A34mU6bj66rJRiu66Q WCkIegelIMJb4/f0NqciFQB0cwA 2020-04-20 02:51:19 5.9.129.218 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=530 +p reject 1-65535 +r Zimmer22019 4rjeyXBlfuHLhy836B5ZUmKF7z8 yaS05wqiPvtH457m8REYTzXr6xI 2020-04-20 03:25:06 178.175.148.34 9001 80 +a [2a00:1dc0:caff:29::6d8e]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4310 +p reject 22,25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r niftyentry88 4rm6lnI8WeZa4H6Ct0x6Ma+HQiU zxIEhN/Vh01vmRrMlkUW9dfKhKQ 2020-04-20 10:52:43 185.220.101.228 10088 20088 +a [2a0b:f4c2:2::228]:10088 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r hviv113 4rqv7OXD07T/5hc7MJeUjg9zBiM K0E+Wq/YhCwz2Y11cpxVf3oSns4 2020-04-20 11:41:11 192.42.116.13 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r jacket 4sMANimu2lmIPeKRj86D/y7ll1s aBDB18bS5PB/rMDDLMPzy7Q7nhs 2020-04-20 02:37:34 46.22.220.37 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ElToro 4sav46NHsUz2OCpeqMY7UPfEeRo Kk52M3fvlQpPUqFvb7gDP37iWN4 2020-04-20 11:09:25 85.127.39.95 9001 0 +s Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9 +p reject 1-65535 +r bauruine111 4s8J+ZgkjHETmySyySdArtscbSo i+ndP9M2LYUZUUPPwzYUvhjrL4k 2020-04-20 04:52:15 107.180.239.164 443 80 +a [2607:f298:5:101d:f816:3eff:feb8:28ae]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16600 +p reject 1-65535 +r snap277 4to3/l6WqVkFJ/ICy0JdAFg/YCw /1nEUGqOiV8fGfBu6l21xsh8HGA 2020-04-20 10:36:20 5.29.241.124 39087 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r TorbeiderSeebruecke 4t5PpoJXiAagTlqpiSKzKfAgn4E hI1hR4mtkqAt4Z+vW/gaKEj1auE 2020-04-20 04:31:57 79.192.55.96 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=55 +p reject 1-65535 +r LongburnRelay 4wDO4iVaIrPfUueYoyN9U6+uwvM BE6VfeXijkRPdhq1u4tnrmkDEOM 2020-04-20 04:33:15 111.69.49.124 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=130 +p accept 20-21,43,53,79,88,194,464-465,543-544,554,563,706,749,853,873,902-904,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8074,8232-8233,8332-8333,9418,9999-10000,11371,19294,19638,50002,64738 +r TOR2503 4wni48P0RyqD8yJsMVgY2we/d7o zsk2nlIUi4lJpBQZbo8GZ7Iam9s 2020-04-19 21:17:26 194.96.72.43 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r Daenerys 4xKpONcQRb46XB/zq4fPdGQZSGE TUIJwN6NFG/5OajxCtQArr8AmXY 2020-04-20 01:07:49 104.244.77.250 443 80 +a [2605:6400:30:faa9:4abe:8b09:7ef9:18e6]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40200 +p reject 1-65535 +r niftyexit 4yHQEY2tRLvHSlwm/nz9uq89oHc tYDWA0GYTWF6gCCvX1uV0IlFLOs 2020-04-19 20:27:36 185.220.101.41 10041 20041 +a [2a0b:f4c2::41]:10041 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p accept 80,443 +r robotventures 4yZLmHQrgIi96d1gwnoDmCATYzI q8y1WNaopkAblZKMJWJnltcz7zY 2020-04-20 12:45:17 27.122.59.86 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=495 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r UndergroundAirways 4y7TphDPyfZbxy0xHcGz2YlADZc Fi0KSB0/qlvrqlcf6kBIfT+71ZM 2020-04-20 09:21:04 139.180.107.55 9001 0 +s Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43 +p reject 1-65535 +r niftyentry71 4zCoh1SEBilkRSc5T9QwAdW4nHo CYb6y/K8s5V3HdHh3lr1Gk77FWs 2020-04-20 10:51:10 185.220.101.211 10071 20071 +a [2a0b:f4c2:2::211]:10071 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12700 +p reject 1-65535 +r doof 4zI/qT3s+eZ2PKlfDuJOcSkzFto jCuGuqiky0pgFB6H71R0bskXqBI 2020-04-20 00:09:19 205.201.63.19 9001 9030 +a [2620:10:6000:23:b:b:b:b]:9001 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=472 +p reject 1-65535 +r Carnavafoire 40wo1lJSDXyNOG6jlY6pJJEOZHs XfZs5s/BpjJjVhi7z3hOU6Nv5oA 2020-04-19 23:40:43 216.10.247.146 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=800 +p accept 143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,50002,64738 +r guitti 41AOLJ9rhwhQVok8QnmuoLPzd4I BVZLLNea2vzYhD99pvSHLvYjpJc 2020-04-20 06:07:32 178.63.172.13 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p reject 1-65535 +r snap277 412M9kM8vE1Is84ajXizwLMjU3w A6XHsa3UQYr0p8DI82BCJ+MjrUg 2020-04-20 11:47:20 78.218.49.71 45173 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4 +p reject 1-65535 +r naiveTorer 42U2QEIAp0kw2xZYWL1btVTSvqI AQdYYFTQ0RgWhq3lfpoNVxcPqiU 2020-04-20 05:57:49 81.6.40.24 110 143 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p reject 1-65535 +r Z10n 43MidS8TWjRPoz4X9K+nTCemh+Y YYAtIfSk0eBcAPrBIpjj128jLws 2020-04-20 04:56:58 144.217.7.136 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p reject 1-65535 +r hackeriet1 43mmys76/huOpoUDv8/xIVvx7n8 MTee63k5miQhROkHBiqd4YMAQU0 2020-04-20 07:10:27 185.35.202.222 443 80 +a [2a02:ed06::222]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9750 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r Coderx64 434Bmu2HJQmC32cOTY0JcE3bRME RhiZM6rRgeM+Xtv6gy1ljrt8RiU 2020-04-20 00:53:13 5.165.206.150 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2200 +p reject 1-65535 +r PXArelay02 44R0gpP8RCnitCc2DbT51MPWGdE M1HAom89wX8J2S6+OQW5V5fvrNk 2020-04-20 01:37:50 85.191.195.69 9032 9033 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r inquisitively 44zM4nWtxG3zX7dkqijU73Is+lQ +5g1wog2aFmXEQWkEg2dlecpzJA 2020-04-20 05:38:17 81.7.18.97 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3500 +p reject 1-65535 +r baxTianRelay 45p1i9gd0n6KonmYaI6BbQoT3II kM+JdIHG6AktpAgGxzdL49J0Ebg 2020-04-20 09:17:13 92.222.172.56 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p reject 1-65535 +r theqube 47Bznu//DeQgO76FY/KhyJ1BA0c SXeW1nTAp/8p2vZwcmCcjtSdNS4 2020-04-20 03:01:40 45.125.65.112 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4810 +p accept 20-23,43,53,79-81,88,110,143,194,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,11371,19294,19638,50002,64738 +r morgtor 475SNgPpywOKKJ+jgGbgGk/nvZg 6oGNMYAiR6lZFJ1yGKToanxVTnA 2020-04-20 06:13:12 2.205.68.224 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3890 +p reject 1-65535 +r las1 48gLkWIPm0NSxAOy1pLAlAPaJZk f/pntYHkKPjCuDSmhroIpkv1Nc0 2020-04-19 22:12:09 209.141.50.178 9001 9080 +a [2605:6400:20:104e::2]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p accept 43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Clauzel 48u17TQWBEe6PkI7w2w2Tg2b2ws vl/C3zyqNBbcZEs2dqLsG8pbWqQ 2020-04-20 09:31:36 88.99.35.242 9001 9030 +a [2a01:4f8:1c17:4608::42]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=610 +p accept 443,8332-8333 +r jaredfucks 49YbrqC3yxLKztyIIcUgVXvfzqM tTNOqm4uKBPB9Ifj0MUIg5FsTdg 2020-04-19 22:50:18 144.76.107.94 8080 8000 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=100000 +p reject 1-65535 +r OvervagningErFrihed 49cul03kxu+jdlY3e6ekv+nPIrc tpspS4YgKa/0g9JiQc3TR69vO9c 2020-04-20 05:18:15 78.47.20.212 44203 0 +a [2a01:4f8:c2c:a70c::1]:44203 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=56000 +p reject 1-65535 +r taipe 4+dWA5mGYepnxnZ0k/xgaDDdw0U VuV8ePtsLHPpu197xiF/qeI34zA 2020-04-19 20:18:36 185.217.0.96 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8810 +p reject 1-65535 +r cebeta 4+nGwLVfHBlq3/tm3Mm9wxqeTyE VJtXdtP/UEk0dyPFhKlAdOTE4yA 2020-04-20 04:48:24 46.183.119.58 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=560 +p reject 1-65535 +r avalon 4+wR/WWPPrK8IQld6o9JcJYRPHk joUM4GEPSWVDteFYMR9uosPuCbA 2020-04-19 22:18:13 66.183.173.28 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p accept 53,8333,9999 +r TOR2503 4/DAJW7TMPcDR7nnHOHsVBMMjBU sI4VqNKlkWZRapserYGu7vLIKl0 2020-04-19 19:57:04 212.88.4.54 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=309 +p reject 1-65535 +r Finisterre 4/mMhsngETjdjqBrHmYKDNtLJ4I LTATG3L0TCLU4xIhKShZjauKu2U 2020-04-20 10:08:48 95.216.115.85 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30700 +p reject 1-65535 +r ZeroMeaning 5AEtOw37XLdDohwspBIxu6KXhrs xoFKFlZpIuh8ylAul/UcnuORo+E 2020-04-20 03:53:39 66.70.204.175 443 9030 +a [2001:470:b304:2::51:1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5390 +p reject 1-65535 +r zwewwlSE1 5AnzC/81P3iD8H3Elz37YjYa1U8 FX4daPedfquXXooSGgw6K6o0fbY 2020-04-20 08:27:49 94.140.125.70 9001 9030 +a [2a02:7aa0:1619::67b:3de7]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=30200 +p reject 1-65535 +r xmission1 5BsW9931LrsdtCaKsv40CzetiQQ 5PlA6AwXsI9Gio0ab4UujENH954 2020-04-20 08:55:24 166.70.207.2 9101 9130 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4200 +p reject 25 +r snap277 5CD8fgOdBd4p9Nos3+vzzFNAFZo xtWUsV2G7e/ubfNV9CUF9cUWozQ 2020-04-20 03:09:07 188.218.20.88 37933 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=840 +p reject 1-65535 +r theia0 5CQFCO/DCNAWZaB72YuFZHQNM3Y zPuwo4jqgKf/iWLLlLhv0mVULNE 2020-04-19 22:57:54 50.7.74.171 443 80 +a [2001:49f0:d002:2::50]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9100 +p reject 1-65535 +r punki 5DJEaE4Mkk7AgrjsxzX68vjPHEU MlgrL4AyhAaEvZu1Q+xW6eYpAQU 2020-04-19 19:40:23 94.32.66.15 9001 9030 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1030 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r Haggar 5DLGuQJU3QZ1+G0+TV86LKEA3os HGAzKJMUqyGwWq1WyFYZhFJGZJ4 2020-04-20 12:14:40 194.55.15.222 9001 9030 +a [2a03:4000:31:461::bad:c0de]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=33000 +p reject 1-65535 +r HSLtor 5Do0bLgd3zZLb/aCNa+tug6Gkrg wRftIfIFYos6u6ug8ArTPNmoN5w 2020-04-20 07:32:11 185.220.102.7 443 0 +a [2a0b:f4c1::7]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=59700 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r king 5DpplqslxgD5AqmuKEo+BCCjmQ4 TV6TQXChu6v9T13PrtUmnf1grUE 2020-04-20 05:06:44 51.89.147.64 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r witlynx 5D+cM6dcddei2ChmNn3HWF7AEgM ZyUPSvdXZki0TKrMHYpWB0pVPBY 2020-04-20 00:11:41 37.191.253.15 9023 9024 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r snap277 5EZZBUNE9kHQ2GFyxX3R2eOy2B8 h3Z6ldCdg5wZkCXOd82TTsRkxd0 2020-04-20 05:20:24 79.84.43.145 38921 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r AsiaArgento 5FngI3TQOF0uJRXLvnB+ogiWa88 fsOHxMJLZNXgEoIdNvS0c73iHUY 2020-04-20 01:43:44 163.172.94.119 9001 9030 +a [2001:bc8:208a::1]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17600 +p reject 1-65535 +r snap277 5FyC7b7r4iXVBxCXDStQoX0QJgg NlZPJ93s78cAXVrC5Ib8WIAcB6c 2020-04-20 12:15:47 46.43.194.55 36649 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=344 +p reject 1-65535 +r snap277 5F0rql1jAA94qhxaq+rS1w+aWPU wFJYVY/lQ5od3nmLf06RL0XMKsg 2020-04-20 00:28:46 204.197.182.65 35629 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=679 +p reject 1-65535 +r Unnamed 5F7Dgw2K1/I/8b74rB91GVVaNRU mXL0LQVt8AQs11bN36d+QK6oW34 2020-04-19 20:43:05 174.16.189.60 10001 10030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3600 +p reject 1-65535 +r Digitalist2 5Gd3xu+2A2GQ76rZsT7p0OdcVRA egdXywvd86VMrs0VqRoVYo0Uh6g 2020-04-20 08:11:43 37.252.188.101 9001 9030 +a [2a00:63c1:d:101::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r teller 5Gl5owU9Q63xh0Y6bkhWyHW8jIk /+GRDchI0cETfYm0jlEui2x1e7A 2020-04-20 09:29:34 69.164.221.78 443 8080 +a [2600:3c03::f03c:91ff:fe70:357]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1460 +p reject 1-65535 +r snap277 5HYOtNaAvtGqY8fMtVja/qfK7Jo OQ4lsTLppAZfZuEepkHgAMTv4+0 2020-04-19 22:50:56 72.19.136.53 39021 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=261 +p reject 1-65535 +r Quintex34 5IDVd/WOeCpbxPpvSaZlDpOJMC8 wmWKkH3tVR/RxcN9QWdetbPFLr8 2020-04-20 10:38:22 199.249.230.114 443 80 +a [2620:7:6001::114]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r Unnamed 5IrQLFT9P4w6TqN0Us4ygaDSRqQ o55dCeigpuOzJChGvoPQz788gnQ 2020-04-20 08:40:58 79.143.183.69 9200 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=450 +p reject 1-65535 +r bliblibli4 5KI/6s+g1wZMZpS+kb+UgF485Ic CZjwTRhEcxgLdlOxCeTbLRSZHkk 2020-04-20 04:34:58 185.146.228.131 8086 8087 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31400 +p reject 1-65535 +r UseMoaBandwidth 5KfPMtHsgVIeI0yL9GOE51g4qNc vgS65AINj5nq/J8El7HrfnSOOmI 2020-04-20 08:51:04 163.172.60.25 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29100 +p reject 1-65535 +r king 5KzILI/74xI6StaxGAJaU2gLbkY yh9LeofVsZFxRRmke/gDFn3ztKY 2020-04-20 05:15:03 51.89.213.88 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12600 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r niftyhousemouse 5LBMfXNLIpTo7OBXMD6JuR7ohGI vs3Jnmh/bf0pIkhyOz2QtALIRc0 2020-04-19 20:26:21 185.220.101.2 10002 20002 +a [2a0b:f4c2::2]:10002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42100 +p reject 22,25 +r torrelay2 5LTXKDWbJPflv9bGvg0I7TiYEUA mohk7cT7eY4Y1dIYjC1CWi77Fvg 2020-04-20 07:30:50 40.77.63.180 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1470 +p reject 1-65535 +r Sobit 5LbBF3Yd8Fq8CK0KDq6C2XAUxCc VZ64jKII3hGDUGNr2KuOff8NQ1A 2020-04-20 10:52:53 100.8.248.128 8443 8444 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2930 +p reject 1-65535 +r CalyxInstitute01 5NHyXfvkhCCIZrpKGpWLcxJ8sK0 PG7ARhfokQFd7DJszRuJODNbyyk 2020-04-20 04:13:13 162.247.74.7 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r julianSMN 5OJ9gCNrQh+uoleXSVtX42/598I C4EW+i0Zjwn3ixGMKRTTjMvqz4s 2020-04-20 01:53:49 37.187.107.91 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3960 +p reject 1-65535 +r nomelaga 5PeGni6a9Xnsk/XMuCPs/LKX2k4 sCIevrD8dpllWYHgBpE1SdeNse4 2020-04-20 02:47:34 85.227.86.58 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43000 +p reject 1-65535 +r stargazer 5REr1tBoSD9wW1jSUlTKgUMLxEQ lZouSZS49XC/iJuM0TLvwopx4Qs 2020-04-19 22:16:15 45.55.240.225 2916 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p reject 1-65535 +r Unnamed 5RHsjK4m5A1viMmIDUXIYq70rII bXJVJJkSxApqpmQP0D99CuLmZu8 2020-04-19 20:37:11 88.99.84.214 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r NormalCitizen 5RYguQ3LMQE47Ynt7dClw2Gq4k4 x7CSHiFeuA9qIfdMMJ5AwWUbSaA 2020-04-20 00:37:33 185.100.86.182 8080 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19000 +p accept 20-21,53,79-81,110,143,443,554,1194,5222-5223,5900,6660-6669,6697,11371 +r ididedittheconfig 5Rc2WlGJnyKOmaIunk71k0cYD4A P+ZzU7gH7uXzYifL6dwYAI3KHZw 2020-04-19 19:54:01 164.68.107.222 9001 0 +a [2a02:c207:3004:1426::1]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1700 +p reject 1-65535 +r Willy 5SEA6JT+jl+jjrZ3XDVoW5/Rfh8 SR6guSGSV3iHy6sv3Vhyk9nxTF8 2020-04-20 03:33:26 94.113.211.23 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1970 +p reject 1-65535 +r 5b4e9f6b0090 5TWDnOyu2f7SfDei8HpWkhs7obo QSLDr0zNdlFp9Ta/MphrIo6LsTo 2020-04-20 08:21:25 51.81.253.200 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9420 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed 5Tk9JTE87JiWI+mWHfBOeWeSkYk 8mQK/IF3paKhmnGVM5VuLMyTZMQ 2020-04-19 21:13:21 102.37.13.111 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=335 +p reject 1-65535 +r Shrdlu1 5UbJausiWL0HM5SQJ+j5YVb2spA L222HgBmObjzeBjXLm0PLBsyoQY 2020-04-20 08:19:55 82.64.94.30 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15200 +p reject 1-65535 +r torEFF 5UsPp9lXWTNEsMMWyDq8HNLuh+o jGKit20L1eHF+hLk4Mow9Rx0QoA 2020-04-20 06:39:38 173.239.79.203 8080 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=760 +p reject 1-65535 +r snap277 5VZkESKxduY9FD6LqQzHFZ41ihc 9jKVcKILNa7CeO+hvOI/WCd8VD0 2020-04-20 12:14:28 78.222.98.85 43681 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17 +p reject 1-65535 +r Himbeermakrele 5VecTW1ZBNuFUqoUw4+wIAghOFs XxC+M62AfveaEgd63LcxtqA9i6E 2020-04-20 01:20:13 77.191.6.37 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=838 +p reject 1-65535 +r pangea02 5W8HdZ5wTE9TM04WEGbxL69/fJc ldLYdDSaW8z2NC9+ia/OvsoCP7U 2020-04-19 23:22:58 81.16.33.31 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2440 +p accept 43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,873,902-904,981,991-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,5900,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r whoopsie 5XcwQlH0ioXMADm2WWmMdnP3IdM 1kcO6bp+lPgj+JL5dOZruVtf6/I 2020-04-20 01:03:49 75.184.16.251 17612 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=580 +p reject 1-65535 +r epsylonhost 5Ygci0YFLyl1uPwchLfMBgcO/ag 9cBcxYq54JkJNjuXcEtFiEiGXSo 2020-04-20 03:30:07 77.3.128.62 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22 +p reject 1-65535 +r Norman 5YpIpiM2oIzDxrQIApI3VOZaJgk T8h5QFGISyceTDzRsWU0i1qgkNU 2020-04-20 06:33:35 52.52.230.13 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r Tory 5Y6JXn6ziSeUpZkjsHtFuw1HtWQ ROJ8HqfM9x0Et2qnsP/7DHDxlJY 2020-04-20 11:02:12 47.144.67.35 9001 9002 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4400 +p reject 1-65535 +r myelay9139 5ZLrJ+S4OQF2kIYBUyJlFyBuYp8 pwulJ1y7OKH9igz801GM6B6116s 2020-04-19 23:21:53 97.70.176.61 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=715 +p reject 1-65535 +r milliways 5ZzABgB04Uyo6UaZmbhixeHOSek qc0OluDUu4BQi7eEJbTodApWjH8 2020-04-19 20:53:38 83.68.131.2 9042 9030 +a [2a01:190:1501:9050::1]:9042 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=987 +p reject 1-65535 +r WonderWoman42 5aqF+mnNwxkAyG5kJ8fl3hHeni0 HtKtMl1q9iLcpSyqIGDhMIKvgwU 2020-04-20 09:00:24 194.109.193.142 1194 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=49400 +p reject 1-65535 +r TtitudePhysicin 5avZUJcJsATT95czHrIxLqV4KWI S/YaMq0emDRdKPYP07+Wrj8n1w4 2020-04-20 11:27:50 47.56.197.215 9002 9031 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=158 +p reject 1-65535 +r kyouma 5cyRuv58zWgAPoc9MuOAJ2ONSdc JhLMrAwHvrv+P2KvYNOTScLYs20 2020-04-20 00:14:38 148.251.67.170 9001 8080 +a [2a01:4f8:202:31a7::1337]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=42800 +p reject 1-65535 +r somsom 5dE7cmSJ6RomD3C5W3rZlJu2qV8 3kJLAQib0JCHlCTHzs5PgM/1cW8 2020-04-20 04:27:02 188.195.110.54 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3510 +p reject 1-65535 +r askatasuna 5fPt2ScUjF6018tx3LyROC9Xp6c HUreIWPZ5kORjE19NUrHzteC8Zs 2020-04-19 23:30:17 184.153.177.172 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=414 +p reject 1-65535 +r ChDickens2 5gXnDoand3oi3yJZ36nFNgtUNGo rU8rqsbRRKpXr3h7TBGLfTQ/Mkg 2020-04-20 08:39:27 188.61.64.84 5497 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9330 +p reject 1-65535 +r FlyingCarpet 5gyTH/iV9xefCb1cb6wZ8SQP5h4 G5AH2ozqkcIAFh9ceejDPB/kJ/o 2020-04-20 07:41:32 217.248.227.149 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r GuardRelay 5g2bCT45tZbyJah0z6bjQ3gXanU 4cMjXDgirI9OU1soLqzsTLl6PpI 2020-04-20 12:23:35 149.56.115.167 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r fiedlerRelay19 5hXrWxB7BLKoku9jAYhy1qkHwOQ Q2WUfKRutbfj9/G56FKpS2aRElk 2020-04-20 10:07:25 185.183.159.99 9001 0 +a [2a03:4000:1d:8ee::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6500 +p reject 1-65535 +r astarseran 5h1jRCvgbMjMpgyXLeHDrj3Xhx4 Aai8cQrMHyCfiSlysv9WzAeMdrE 2020-04-19 23:18:13 62.197.207.182 9443 9080 +a [2001:470:1f0b:524::443]:9443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1840 +p reject 1-65535 +r sulawan 5iOl4EPtK3TMKAvQBFFP3QhU3Iw ZFcHC440OThi8csoD9/53sRuAqc 2020-04-20 04:54:13 109.68.191.132 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r niftyentry106 5iiDNLwPlTRYF4EYgN3qGE5jrmk e6Ivlvxha1LcMwBtBwDddC/yNoE 2020-04-19 20:25:50 185.220.101.106 10106 20106 +a [2a0b:f4c2::106]:10106 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11000 +p reject 1-65535 +r BlasDeLezo 5jD13BBq4/igIDGWPx4LrT81d5s lRryRN7jFZV0VqZzo4j0i5HxfPQ 2020-04-19 19:17:19 79.159.154.75 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=360 +p reject 1-65535 +r snap277 5jE37KVrgwL2h46ezUNFCexiKFc DPYMzqVVw21CQt2CSDjeCILGtsI 2020-04-20 06:32:48 109.212.94.4 40633 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2 +p reject 1-65535 +r AutonomyCube 5jODeYkH58sicIvIF7bErWuFNCw rNFVnDJdt5F9ZUn71HBPE9Wattg 2020-04-19 22:23:26 90.187.52.233 9002 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1880 +p reject 1-65535 +r Unnamed 5mrvqgiW6MQ1cPZmHNrS1h0k7Jo 8iDTPx6K2D996DUFiCg2LODOuC4 2020-04-20 00:53:26 174.3.207.128 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=350 +p reject 1-65535 +r snap277 5oi1+DMnLH1EMcYPHBtWn02DeJ0 keXLYnIQMeVwU0dm0JpvWwcyCwI 2020-04-20 10:10:29 2.153.35.245 38827 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2630 +p reject 1-65535 +r MonPtitRelay 5onAPAmQ/c5P0lxfHfF9XaeTtiA k5i9JNOi6oY6GiJgMw/TJkWtHf0 2020-04-19 23:03:36 82.64.136.240 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r zwewwlUA2 5ozJwuJi4BxMccj2bwdRewq14kU IFOqRcCbQ+2nihBZKi1Wk+Z0/Sw 2020-04-20 11:56:37 217.12.221.110 9001 9030 +a [2a02:27a8:0:a::12b]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3310 +p reject 1-65535 +r affinezeussv 5pAQPz44ij2cElk28a5cZMGibVE SkpRznSJfhLdyg8m8fSZBtrvrao 2020-04-20 00:43:40 50.65.176.4 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=52 +p reject 1-65535 +r BeverlyHills 5pAi3sAPJZsYsvbqYWevH/S1SPI /okUzFvrdaHMccxpNKum8aAdjfU 2020-04-19 20:44:35 75.87.173.23 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=670 +p reject 1-65535 +r Unnamed 5qirUwvSmRm8J1wq3Xs8uzgcGsQ 3FY5RDOR6hPFrCWnToeURyte5sY 2020-04-20 00:10:58 46.128.207.135 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r TugaOnionMR1 5rb02ak27RSz+Ad5p8NzT2eEtC4 QtGB1fZJcZwihHrgLpJk4cL2SNo 2020-04-20 10:02:30 78.47.222.177 9001 36759 +a [2a01:4f8:c0c:4a57::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=25300 +p reject 1-65535 +r malekalcom 5sBHKOkznfIvMxtwF9Snqj8lLws w3J7TP+kRalmJW9CwOoeTbyaJ+E 2020-04-20 08:51:41 149.202.208.203 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=118000 +p accept 6660-6667 +r YouOhKay 5sUy18dhTxnvgJ9QqnNQVLq0eXk +FOSxGtk14ZgLDihs1yJwftcW2Y 2020-04-20 02:53:15 46.17.63.214 443 8080 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1100 +p reject 1-65535 +r smell 5swptLUM86h9UUOwIRRvy50QAgE LbEfECpqZuMHQbGQ9mDOlXWXQ8c 2020-04-20 00:49:01 205.185.114.238 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r FFFRelay 5szJgVPf40knfoUqt+qtlvDonyA +ifqYnFwEcWA3cJouVwio1kBzX0 2020-04-20 08:29:07 51.91.99.55 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=16900 +p reject 1-65535 +r anymouse 5uUKaJlb4773I/q1vho5gWbMBoA QIg8Xigwp0icg1Cu9NqjQMM1EZ8 2020-04-19 23:38:39 192.150.187.151 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4800 +p reject 1-65535 +r snap277 5uwPKo+TT3a7p0gZV2rSowONyrs sa3J2ETvDqq82P6+9ILiGh1R6pc 2020-04-20 11:56:36 176.206.44.197 46467 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r smell 5vY0PJhGc6K9s4Tlres4m4ViTtA LJiMelXBrfmBnX4OBMS4JUkXU08 2020-04-19 23:49:54 209.141.45.89 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6620 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Unnamed 5vfAZhVxa2gUMBZXUoGhzpXHM/M PlF4X/iOWfGPvVOLDYKB6BgX/kQ 2020-04-20 01:53:44 176.67.170.188 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=847 +p reject 1-65535 +r niftydormouse 5vrJp/M+5m8DxVwRl3Cy1F08V2s 0KtjINLb6LQBjsjNAdoGjsdfV8U 2020-04-19 22:15:47 185.220.101.140 1140 2140 +a [2a0b:f4c2:1::140]:1140 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=30200 +p reject 22,25 +r Rantanplan 5xJWcHv4mMKq5ljCEqL2jnFLarY h3uCMyYD4IGC5M602xyjC0YBmcA 2020-04-20 03:07:29 84.174.204.229 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p reject 1-65535 +r king 50B/n7PoenFUGk8zjZbSXSCzjyA aIZTerWXHsM+RKPCnWA7IM5rlqA 2020-04-20 06:01:45 51.89.200.107 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11700 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r hailden 50d3PGHPZxoiLrkT3hfaMwdKbXY GJDlgE0DXeBNxtReMNWMibEWGDA 2020-04-20 00:07:18 98.225.157.78 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5170 +p reject 1-65535 +r Nepal2 51H5CNVxYg3ca4/UKMh8HtLq7Ic C8fZJDz7V0xDiM8CETKIOIN5lRI 2020-04-20 09:15:53 209.141.45.231 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5340 +p accept 20-22,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r Rumpelstilzchen 51joV+DqEbbZk7dC7X4eHMsBxUU FbpZjp2OB39VYAMlknVa7ov8WlQ 2020-04-20 06:29:09 83.78.52.47 13928 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13 +p reject 1-65535 +r Unnamed 51q/KdS0F9PTVlrtr4nk+dFuc28 Hx/bk009TygTJ21qIBTKhPwLWDQ 2020-04-20 02:59:30 37.191.206.197 38443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10200 +p reject 1-65535 +r FortyTwo 518qyhoYKRr+Uua+C6wfgFq8FDk ceYBuAD/rIObaD7dI8rIqOUlBRA 2020-04-20 11:23:44 184.97.149.222 9010 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=250 +p reject 1-65535 +r phenix 519lGoVk+ixKLDzz4j4sbF9cOVY Vtj34eeP48tfyLhwrSmOYRhUVzs 2020-04-20 05:11:55 51.75.254.63 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=17500 +p reject 1-65535 +r Geoff2 52fDuCla15sC6AohNFyfKzwq19s QcHNyo7Ca4tZNHQu10Cr48T6YUE 2020-04-20 00:49:19 178.254.31.125 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9400 +p reject 1-65535 +r miomio 524rwvySc7+6OJR+tVcgdicNSdU lGcm5rQylEP2mAXHZ2W382h6lJ4 2020-04-20 10:01:07 116.203.47.92 9001 0 +a [2a01:4f8:1c1c:a9e5::1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r Unnamed 53V5V7ssl+FvuBTt76AgGMhK+D4 qcAQs4nFFbMGS7NQBKW7SkAhTjE 2020-04-20 11:15:42 46.144.166.250 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r Unnamed 53g4G9OGtHI4d96DeolfbpwkFgc o/u+bnyJBIXfxxUtLYFh7NCce4k 2020-04-19 20:42:55 174.16.189.60 10002 10031 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3400 +p reject 1-65535 +r stonehand 53nVUffx+ireemDEmHhtGwtDtuY xu+n1GjCj2C22CzLgGWPKVgyzSo 2020-04-19 21:46:48 187.208.190.158 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18 +p reject 1-65535 +r quatermain 54ghh/b6aVRQcZ/Tc41kD73/XUg MKJ6d3XyjJ2A0ZTjF9OkOZvZf2M 2020-04-20 03:57:07 85.204.74.139 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19500 +p reject 1-65535 +r 1001nybrgsvgn17 54uCViU9DEXl7N5EsyiGOrUSMFA lf6iEWai01hMPkE9UqRnk3KofvI 2020-04-20 10:10:32 83.250.200.92 64511 64520 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=126 +p reject 1-65535 +r Sacharow 55pYrw25O5D5e0iWPMRynkz6Q8U 4t+LmpnybrcM03ao6/eJ+mD43Xo 2020-04-20 09:07:44 217.12.223.225 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4450 +p accept 53,80,443 +r snap277 56ffwuieoywjbgpkbkYuTK17hUc 5uQEtZe92JHzGCdWhpsCxBTEOPg 2020-04-20 12:40:25 2.10.138.25 43891 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r snap277 56rqxO1+Ih+uecj/QmqPdQ2IHsw nB9NMGlhoyaydeVmhuKKIBMdoic 2020-04-20 09:47:13 77.134.47.103 38565 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=23 +p reject 1-65535 +r aabbcc 58H6+3UlFJoOkRUS9RHZQrpe6q8 eCA9bY3iXYWTOriw91Nr9nCzWsY 2020-04-20 10:45:50 94.242.63.4 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21100 +p reject 1-65535 +r Silverwing 5+9ztHIs+vDoqiFR06p4cB3l8Zs /coPxs+p5rhES/7TTZWKki6Aeuo 2020-04-19 22:58:17 178.254.22.21 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120000 +p reject 1-65535 +r king 5/wko+ybYjRl4lHl23R1+Vi++Ys 1BAK3VzNCKS7kM91ja5Bgvv1+Lc 2020-04-20 08:26:35 51.75.175.30 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=20000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Gertrude 6AG/6QSBBvs+OaGwdssDZIzpPY8 rqpGQHn1GT5Q5nD3/Pg74beTFao 2020-04-20 07:08:43 176.58.100.98 9001 9030 +a [2a01:7e00::f03c:91ff:fe56:2656]:9002 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=240 +p accept 20,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r SkyNet 6Ab2v0X0pXcwQx3JHLc4KxIG3nk dDunlRid+wYhcxWMu4JGQ9VPHcU 2020-04-20 03:16:16 83.135.138.65 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=179 +p reject 1-65535 +r TonyStarkDied 6AnZkJho8/GcQzYcvSe//cTPTnM lJVTCAn7xWYVRK1HGQZeoCPzLZk 2020-04-19 23:38:17 37.187.162.153 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=63800 +p reject 1-65535 +r snap278 6Autp56jbFYEihT9gaZscJtCJys WcMZyh46vH0nEOyDfkORydzbfKQ 2020-04-20 10:38:00 81.202.9.123 35793 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=803 +p reject 1-65535 +r MuskyHusky 6BR9EGrVJfnwxEF97bHHeNF3ADk WWMjeHdfU8JikQDnS9G3xgwnBeI 2020-04-20 02:15:54 67.185.177.181 9001 0 +s Fast Running Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=370 +p reject 1-65535 +r llutztorrelay 6Bl4159fvGfdDoD26tzoipenlVQ BNwEUpblH4CWkVVcyXzGCeDslnE 2020-04-20 10:27:21 94.199.213.135 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=168 +p reject 1-65535 +r obiwan 6BmT6lK3MoXP/QL+wANWnSFIMAE D0mEO9qTrJ8b3Cu7k1jsQpjEJnc 2020-04-20 02:45:54 78.46.104.112 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=129000 +p reject 1-65535 +r bliblibli1 6B1Wrj/pkZ86QqsREAkB5rrsT8s 7sF19SIrQIbG76as/9rAN7JELuU 2020-04-20 04:34:57 185.146.228.131 8080 8081 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24500 +p reject 1-65535 +r seadog007 6B7lNaJxMAU/1/infbh4DpDEjLc 02muyCp3lx4apdmph7jP2LI450c 2020-04-20 07:16:14 59.127.163.155 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=260 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033 +r Elenore 6DTbKNFVCKwEuuMveVt3gWkd+rQ NH6WGocr0d+XteZa1qKZtRPXJ5I 2020-04-20 03:52:17 46.38.231.218 9001 0 +a [2a03:4000:3b:3f8::3]:9001 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2930 +p reject 1-65535 +r goodbyeapathyBell 6ENOwWF1Nr0w0WwC0Itxp1B9PxE 2jxUYJ7FFa1cJHKiwGSZbfExxTI 2020-04-20 03:08:44 185.82.126.123 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2640 +p reject 1-65535 +r BetelgeuseIT 6EZuAsiTuaZgKiUczqEA8lLiW0s jIOvt+/mqcKoxPO48w2syJhOsVM 2020-04-20 06:22:49 83.136.106.136 443 80 +a [2a02:29e0:2:6:1:1:1628:58bb]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9120 +p accept 5222-5223,6660-6669,6679,6697,8082,8332-8333,9999,11371,50002,64738 +r Unnamed 6FTubzYTYUj/MMulWsZ9vT+AKQE guFHhdqvUR3JTQEecq1VCOOjBqk 2020-04-20 04:32:51 89.45.67.137 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1280 +p reject 1-65535 +r nfsvks 6FWve6lTtlgXgbh+kLjQ0xaA4Uw 0gi+Toaw1EdVrb2EttXQISCGTaM 2020-04-20 09:38:26 80.211.211.72 35785 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=555 +p reject 1-65535 +r tor2go 6FYsfPvrZQHy4C2gAgP5WOixaFw ctCfhRIaqCQfaXuCBekEmMPwwuM 2020-04-20 11:13:34 45.79.157.103 443 80 +a [2600:3c03::f03c:92ff:fe60:4577]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=29000 +p accept 80,443 +r Unnamed 6GSboj9+mbs1NY1bJma7uDDGNhA EfGTNAr+gLj4ITcz8CFJ83HWB9Q 2020-04-20 11:10:49 51.83.171.237 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13500 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r CalyxInstitute19 6GY5JP4qrU4IGhftaXbQroAQ9Hs /WizOqtKiSRvPjZ+ruq412Togrs 2020-04-20 02:16:12 185.220.103.7 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r mailus 6G2FjyqvneKiuVKgv4ZLfzXtyKM j69OeYrpP9PDrViFuo5OBXdvxJE 2020-04-19 22:04:07 136.243.177.133 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1030 +p reject 1-65535 +r Planetclaire60 6I+OchAHCeIm8i32pQNlSABU7NI luCyu5PpL1VOrVWL4p1BQBOo3ps 2020-04-20 06:35:36 91.143.81.8 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r F3Netze 6K2MT9w/4VIVDABbsuqmoJkLdN8 h26DOG4MPczAZKtgf7CCwkIFjYc 2020-04-20 07:03:21 185.220.100.243 9100 9101 +a [2a0b:f4c0:16c:16::1]:9100 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=72000 +p reject 25 +r MoletrixRelay 6LayEQJUdfmJwonyYWZQ3P/QuuI pHLy5V6yJaG3y18MkCtbVHDji/g 2020-04-20 08:39:31 81.244.185.93 9001 9031 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3520 +p reject 1-65535 +r king 6LhkTEh0ZhxWrGsePhZcmnEcqXs fduvSUMaA5BG8RqN68pMg/cm6Ew 2020-04-20 05:11:50 51.89.213.82 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r relay4u 6LrnOTdApwDVCwEN7Z2eyaZrOQ0 x4UHZ2q95H1wwdReC4FqAP2LwCI 2020-04-20 04:05:51 188.40.107.126 9993 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=100000 +p reject 1-65535 +r schimkus 6MEt/aOutrT8kAX3x9QH5veMmBI iJT3agXtbQzt6/0uRmAs6x8gRmM 2020-04-19 21:42:40 43.231.114.52 443 80 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=39 +p reject 1-65535 +r Unnamed 6MGrFC/cNJItEj/4QMu/AaNH170 449d6f5cFmP/cmHdbRwyQ/lvXzY 2020-04-20 05:39:32 89.188.123.11 9101 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14 +p reject 1-65535 +r zizizi 6MgL5spukM/6lBAnZoU569zk7xo yhxBGRViylGo9rfMWfOEvacm2K4 2020-04-20 03:40:05 174.107.191.118 9003 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=230 +p reject 1-65535 +r F3Netze 6MhmfK89UUjlLs9zansgSYL3jqo dDbK9GIY0eA3uQcl2Y/nz+fTnbw 2020-04-20 06:35:11 185.220.100.254 9000 9001 +a [2a0b:f4c0:16c:2::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=100000 +p reject 25 +r libreonion1 6NEUs8eNjm5/6xAEZQ3WMsIUPJ4 RrKLXT7t664Ky+8MX9nEaaYtw9g 2020-04-20 03:04:44 185.4.132.148 443 80 +a [2a02:c500:2:f0::5492]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4230 +p reject 1-65535 +r snap277 6NJh/xrHzQ1pCqHOFWlMghUajDg U3lFx0pn7qfIYpIxkedhrMnYDsY 2020-04-20 11:21:03 181.228.128.218 42147 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=52 +p reject 1-65535 +r theswissguy 6OapXPAXD/ne2RRczHTrQoizRhM muStOWlSTF+/aBubfQn6vh/AYZg 2020-04-19 19:31:29 37.187.118.150 9001 9030 +a [2001:41d0:a:6b96::1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p reject 1-65535 +r foghorn 6OpT+wTGJtyX5jM/YDKLGmgrG9Y vNyCLAl1kGDbYkLcL/sria+SdXQ 2020-04-20 06:35:52 192.71.245.137 9001 9030 +a [2a00:dcc0:eda:88:245:71:1b13:d10f]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=529 +p reject 1-65535 +r Tortue 6O1AXkekd9ktnvsgH63yj/f7r10 qtwXr5LyDxYPtwy2jXHBX6vfI18 2020-04-20 04:45:08 31.201.16.72 443 8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4310 +p reject 1-65535 +r gorgothzilla 6PCuFBUUWKV6OBLvsTmpfMSJyN8 jzLwm+Cv0Sj5JPiYy4GO8MIuFmw 2020-04-20 07:26:26 51.15.177.148 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r tengu 6Posm2kPO8Fq3ppIA84sURMvEKY kVC2aqUYzy44xZtTb0SA08lHNpg 2020-04-20 04:04:10 66.183.173.29 22 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p accept 53,8333,9999 +r maibrunn 6QJa1g2Gh11fEVSNU2zGr2Dw714 Xz0ld9FzrgxLVfcMgrboqm5b9ok 2020-04-20 08:48:16 179.43.188.206 443 80 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r netShelter01 6QP9+72A51IKI+5MgDsFLCEHwaY DB61oE++iUYN5eyYzdVmaPmvNao 2020-04-19 19:19:50 185.121.69.14 9001 80 +a [2001:678:a00::34]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37800 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,25565-25580,27000-27040,50002,64738 +r eclipse11 6Q9S0peIvYa1wFfuIzg0Z5IPwXU jB/40J13e87SNg6JajXWeyakpco 2020-04-20 04:53:53 46.167.244.58 9009 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1500 +p reject 1-65535 +r Unnamed 6RSrIF+lq+YJBquefuUntoCaRsE tfez72BsXezofVnPSZhN/EgZ89w 2020-04-20 04:46:33 37.228.129.29 31749 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p reject 1-65535 +r Serpent 6RbyrLpn7Fevr0UKqE5SgwiDVBg cws6ZlcUURemKQuRY5tcZYJs4Jw 2020-04-19 18:58:37 104.244.75.155 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13200 +p reject 1-65535 +r tortoise 6RkFz+sjCxvqawMJgW+e6cGhqDo wYoV0kgMoYR9xqouui9lZd+aDF4 2020-04-20 00:28:42 130.149.80.199 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p accept 43,53,80,110,143,220,443,873,993,995,1194,1293,3690,5222-5223,5228,9418,11371,64738 +r Relayz4all 6R53y9EyF/lCkwlHT6M9mLlD4kY jtcsqYr1sCUSUmG8/wOqm1r0+tw 2020-04-20 08:08:30 217.160.28.238 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4890 +p reject 1-65535 +r f095 6T5mTSfkKjshUkFzCmjAheK+ydE GDc3dk0A9k0e7sd0+cV1tjUpyNg 2020-04-20 06:41:28 91.247.251.26 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=906 +p reject 1-65535 +r mountaineer 6UB9g3JbOq8qkrnPVVk/RQHFcKw +F8zbHCcL4JIy/VxavtxFtOzYEY 2020-04-20 09:40:35 65.96.225.56 9443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11 +p reject 1-65535 +r dgplug 6UfAKQh/ocNJm+9dQ3KUfFEiPY8 otFDmrg3ArDx010ppm1etVOJceA 2020-04-19 22:40:50 195.154.105.170 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17200 +p reject 1-65535 +r PieroV 6VlVzXqwEt53BxGHjxR8eE/BPTc IUo97YUm5lfWCvmbtw8SWqNXeAQ 2020-04-19 20:22:39 164.132.226.30 22 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2690 +p reject 1-65535 +r snap277 6Wl5uF5TJCLyEtFx6fmCVD9g+fs 1+zMF7L4pnc2sbkYrKno+BYEHqc 2020-04-20 12:26:51 178.223.111.70 37777 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r Spacepark 6WwHGmeDPCyT1098hMmRSOFRgfg cyRnXrAMbdJqXE0KlAbt9zjBEnk 2020-04-20 05:52:42 185.177.151.33 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8240 +p reject 1-65535 +r Schubduese 6XPoYooxQHKaFH/f/L7FAEM3DpU igVi2P6/9MhX+z16xL5pwQu6ndY 2020-04-19 23:24:48 88.152.204.150 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=45 +p reject 1-65535 +r bee4ok9equageh3giro 6XpCfOBtM7w6aEbWwEtFjwfoDvs yjn0iG70gu9/yfiWnKbJvftC+rg 2020-04-20 03:41:45 69.164.220.107 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3130 +p reject 1-65535 +r IVANTICHY 6X11RXcWHCvvGQQvbhkx2PPlff4 1Fttup4T8Am6bVN7HZOBPaya/1o 2020-04-19 23:09:15 185.8.165.133 6000 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14000 +p reject 1-65535 +r niftywatersgerbil 6X2sRe0qtG3YMKJ5vcx6/OEO5nQ tqa9uDEByaKohLiCKHPNNianWT4 2020-04-20 05:18:13 137.74.19.202 20 21 +a [2001:41d0:203:1c74::1491:f967]:20 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50200 +p reject 1-65535 +r dongusvondong 6akLn/BXRBBpW6X1yDVDaCIacRQ INz4LTc43Ewp3ckSat3h+MJ8vLI 2020-04-20 01:54:35 144.202.49.171 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=18700 +p reject 1-65535 +r king 6bD3q/tkxuEAtS2M8ta4M760/0Q l3TzfC68LAY7/l5qjqJbjJXzWGE 2020-04-20 04:42:29 51.89.213.85 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11700 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r apunkt 6bOi8NpEruwjESc5CcJiev94PFs ISh9lTTpbLBGZ5XFkDbH6ATDphY 2020-04-19 21:57:09 185.242.113.224 1234 1235 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nodvrelay20 6ccajwHrpKCtZqi5KHdc/q/fnT0 lScdTtc2H39ubQ0Hiu4zrbPwVOY 2020-04-20 01:17:13 45.62.246.179 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3890 +p reject 1-65535 +r LsRelay 6cplSJF95pYbCbJX0qqAPIpbxlc lkfZejs3rg+RlWhkmRzbb0kft4c 2020-04-19 20:17:44 107.11.191.222 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=260 +p reject 1-65535 +r freeInfoFreeSociety 6dYJgWika6mskHJbUUx4biuL6mo vxZUhMciSZ9Rm6VVQYMrc4ydMGo 2020-04-20 04:53:27 209.141.48.81 9713 9714 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=124 +p reject 1-65535 +r kalleponken4712 6doCeOoP+AqsjmXw17r1+o9pNMM QqVqhPrlBruqwxGfx++L+fBa2IA 2020-04-20 04:01:44 83.209.9.121 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=930 +p reject 1-65535 +r niftyguard34 6d7cIIvFWo4pAcxQ5Tepde5c8bM lVBkEGniF61xKxRdbjk1AKIeQvo 2020-04-20 12:44:40 185.220.101.243 1243 2243 +a [2a0b:f4c2:2::243]:1243 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r Zion 6fYCgAmWA4nP9yyQ/dccvADL13k +NpJmioFl0AQhXNGpi6G+/4hOJw 2020-04-20 04:34:53 131.255.4.239 9001 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=310 +p reject 1-65535 +r libertas 6fcawG8pshEOP8CQFrDlBAdETuI SY3jhFyh2Z6AOAjIDXnTKklaTjw 2020-04-19 20:42:49 185.233.104.172 443 80 +a [2a03:4000:24:b3::443]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15700 +p reject 1-65535 +r king 6hgVSlm3dYlOWB8yuX7rI1hqJc4 nE0AsC9RoYSOTO5up5JcCZN9cSQ 2020-04-20 04:42:24 51.68.201.121 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12900 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed 6hryLpOse4oA2zGXkT7lyuEfwvc gXJUZfetzCx0GCqSdAUPWrQ9jn0 2020-04-20 06:37:14 51.79.86.173 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14700 +p reject 25 +r Unnamed 6iSSrRIqxbtZBK9CeQpkJkmPyrc bdey+v7G8WA+3WCy7pQ2ZIyARj0 2020-04-20 10:24:06 91.219.236.55 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3700 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r outerspace 6kM0fg2nzt1ZUCm1EQZmKMfIplM o+XMGIieGqcykywekQkGKNOLX0E 2020-04-19 22:04:10 195.201.39.78 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13900 +p reject 1-65535 +r nostromo 6kNmvNymFnuM/3DkHYzR7plo5EU 7DwrxnOIZ1fE9cZQP/aivCC7c+8 2020-04-20 01:30:45 51.89.200.114 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1070 +p reject 1-65535 +r Harlan 6kWElg5cgVo4O5G9nAP7SJ/mhu8 UDKNJoEDD1hKcB05jc+ueyr+lRc 2020-04-20 10:03:01 103.3.62.168 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=393 +p reject 1-65535 +r anonymousByPDH 6k3FokCW7l+u0q/N5Q76Cd/dFy4 Qj7ZJmABk5u2dtx/cK7aC86HY2M 2020-04-20 06:05:39 163.22.17.211 21 8080 +a [2001:e10:6840:17::211]:21 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=180 +p reject 1-65535 +r eclipse04 6mJZkXrfTUetXVLjV2AI2QwiLRc AX5tlV1Z95nmqjV7dtKYORMYPqY 2020-04-20 08:19:08 80.211.53.210 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1180 +p reject 1-65535 +r SamuelFireman 6nAeElZCzsCym704n3WvGAHOc/0 LcGQmySADnh+SqtljSWStzD2uks 2020-04-20 07:15:56 176.123.5.4 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3190 +p reject 1-65535 +r iProtaganist 6nUuWdW+oFXyTuSObBCQ7hoJVTo hTE5uJgmRMfQI4BcTZXo/URyxvU 2020-04-20 11:53:59 159.89.8.114 443 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r schmortor 6nZCxpQL9lcSZ/Bo7yibk76C8Wk PJ9PjkAChjr8IY+JVf64SiLLjek 2020-04-20 08:07:32 104.236.87.90 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=530 +p reject 1-65535 +r velarde 6n8mU7tDY7sGOPaWI3IxRgKrI8M p4LPjO1JwF026ELZwMoVnMr8rjg 2020-04-20 10:12:05 104.149.170.162 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=990 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed 6oVCjyJOytwYuEeg6A2yUajWZks oFe9JnhknZSxivyGHJ34HwiBT18 2020-04-20 08:50:43 165.227.32.113 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=350 +p reject 1-65535 +r 0xbaddad 6oY36nRkUcBoBVn9/zSrpU3a6DE RygoHrOvzeslnk5Xuf1d6JJ5KX4 2020-04-19 21:00:19 46.101.9.51 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8270 +p reject 1-65535 +r TORdashRELAYdotUS 6ozqqJOfIBCNQ4i26uhnpaxkQsE 8jD63EI8sCp8PhufM40oljQi5Kc 2020-04-20 07:46:06 50.21.183.46 59999 60000 +a [2607:f1c0:84e:deaf:deaf:deaf:deaf:deaf]:59999 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8900 +p reject 1-65535 +r demmsecrelay 6o1Zj6PpeFZwyFjFlcyWzIQh/qQ 2SMx4vlhPpByvLTwanaLlMNy5+s 2020-04-20 12:36:49 81.174.172.34 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r sorrytorrey 6qCIRAsQD/hAcma11IU/+xaoy2c tXCvZqWcCgYuj7arka/lGu+kuXQ 2020-04-20 07:46:25 109.74.203.232 9001 9030 +a [2a01:7e00::f03c:91ff:fed7:eee2]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=73800 +p reject 1-65535 +r Unnamed 6qgjVS+Vnf0DjprI+ok0WnOLbAA XB2ASpNr1TbIGABeBTehnJpEyM0 2020-04-20 09:01:54 145.239.66.236 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=141000 +p reject 1-65535 +r Laborkatze 6rIL1Ag8gg7IMp7Vrr8SAZp3SfM LaTwfktGKQKi1koxR16sM0ono/A 2020-04-20 07:54:20 195.154.237.179 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=39500 +p reject 1-65535 +r TORB 6rs5AyP4DURXuqXO7lEUVXAOkp0 YDJnUkgfpj+2/sb+p24mZQdOcRA 2020-04-20 08:16:13 84.250.187.202 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=110 +p reject 1-65535 +r Quintex49 6rwt0NR7XbEfLTfrPGDCpNkcEPI ZtBd2Yltiqg2GPQVRGj0u/3cjDU 2020-04-20 07:55:37 199.249.230.72 443 80 +a [2620:7:6001::ffff:c759:e648]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14900 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r ULayerSnowden 6sroPGDNrhDfWjNrNBENsH0VA1c ujRCcn1+nsXyzMoDF0KOiw+PsvI 2020-04-19 22:56:03 77.73.64.51 443 80 +a [2a00:1838:36:391::675a]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11100 +p reject 1-65535 +r snap277 6s3PKjPsMJ2ypkgClhHAApZeppk jGeN8eCFylOYiQlGKOSSUSsY/ZU 2020-04-20 07:09:13 2.44.80.13 44665 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=440 +p reject 1-65535 +r Zwiebelring 6tJQ7m0b2xu6z/0cPCYtWf1VpBo JpOL4mMxj8WWA9a/5skKy7OMcQE 2020-04-20 12:26:15 85.214.196.178 9001 9030 +a [2a01:238:4306:cf00:ec59:d2a4:ac11:336]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23200 +p reject 1-65535 +r snap277 6uNiBQosdFiQRD+J0/6j7bgJ4vU ucMeHBZZNVFs0fJUVxVKqw9Ifas 2020-04-20 06:13:46 84.119.171.14 42191 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=662 +p reject 1-65535 +r snap278 6uhVBzwHCIaIlRHtmMWViyAGoE0 P6fDBGlsWu0W3/yuu9RjYFk4E74 2020-04-20 06:54:31 188.191.151.127 34251 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=41 +p reject 1-65535 +r crazymodding 6u/AD9+W0k91/AB6ViO9ajpzdCM vs/N2oWI+dA4w/Ny/5jhyPSg7LY 2020-04-20 09:44:14 24.134.118.245 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=734 +p reject 1-65535 +r MidgarSector5 6vY5zJsSbxd1+dZvzEbbyvJIW/s GOAhv5ld1LLHo/eGfvxD/BMfRcw 2020-04-20 07:20:41 45.32.240.31 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=156 +p reject 1-65535 +r snap277 6vulQgCnnOcPZhB9Lwacw/wZw00 pjxWCCXrENNPEP1JNEvBkuuMk7s 2020-04-20 08:20:24 92.161.148.60 45121 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r HastingsM1 6wKoB8+m64bC/E6obrknle2iguo Zrz9hoqNw3hsMzDn4BVmc/SdM4w 2020-04-19 23:37:24 109.77.113.139 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=981 +p reject 1-65535 +r Toriffic 6xkFbAOzh7T8E5GKfn1zlDmoSgA yevEzAqmQOKmkfC3bisoxt6aV48 2020-04-19 21:10:35 121.208.44.101 443 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7 +p reject 1-65535 +r RaspiTorL 6xywE43414obnGMUjyMriIArpIY r3DBFuAuEJh58gnMOyfmPMqc6vs 2020-04-20 08:36:45 84.182.148.251 9001 0 +s Running Stable Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32 +p reject 1-65535 +r goodrelay 6yIRYhypDysA04CWMfMGJgkU0pY uwphTR3HXKBO4nnEZr8LmkWzH4U 2020-04-20 05:48:08 35.226.158.178 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=578 +p reject 1-65535 +r snap277 6z68e2gI0jubJr9UqbpdxMAyebY g/w0Rv3T+2AdArZmwGwq5ofkzos 2020-04-20 08:54:15 183.82.222.92 36573 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=211 +p reject 1-65535 +r wrogregpx2 613wEkpewoHoLwA4svRfp+x8fHU LNFeRY0uxKW/U1THMeTZxK6jHn4 2020-04-20 05:01:00 176.121.81.51 1443 0 +s Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=404 +p accept 6660-6667 +r tr10110101 62CjvSXgGvJWTvA5fYUI5dKv1Yo Bj4xMh6E7E+Ub0rKTiLulY0IDEQ 2020-04-20 02:55:23 5.189.170.3 10339 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=720 +p reject 1-65535 +r Marighella 62XMuGEvpn/tF7V9pbaRnkApbdA I95U3oERJfZaGiZbgeLK69wjlIo 2020-04-20 00:43:10 185.117.118.132 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1600 +p reject 1-65535 +r desert 62qHkzGiDT05h0lg4QdqhCH1pEw nbUy6U4CrlUQ7ucZIH43L3tmA5M 2020-04-20 05:41:20 185.100.87.240 9000 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17200 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Destroyer 62uvkCUzZUo+cIvjo4TKZhWnIb8 b4KSl7499nSC8VXbld19k6SwJME 2020-04-20 12:19:49 103.199.161.166 9001 9002 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=34 +p reject 1-65535 +r h3u60WO1o8 62xT+09RxeWIorj6z8d7tiAo0TA gC4CUbrlmSOBCyotqCyMWcuEbRM 2020-04-20 07:10:05 84.58.210.129 9001 0 +a [2002:543a:d281:0:801d:18ff:fed5:db1b]:9001 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r idun2 6277J/KayVEaQkbXq+Gvq/tBb/E W6p5MmU/kt8XUNv5oGjFOu/zaqM 2020-04-20 07:32:31 51.68.172.83 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18000 +p reject 1-65535 +r gollum 65At+EBpGH9/h5dExgwU/TriSaI ArFMip0uA+FoaX1QdsydN4shWYs 2020-04-20 07:47:19 46.166.129.156 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6990 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Unnamed 65JJ0E3Ky2XB/rcL8dAfR//7xcc w2B01pk8FmkfoY3sYUqzXyvh2is 2020-04-20 09:12:50 72.216.141.93 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2650 +p reject 1-65535 +r PorchPirate 67BvcOzlFX7If9sPM4IbTwyHpPs hzACI7x6bmydfuIbmH1Ijg31UGo 2020-04-20 01:56:10 178.17.174.181 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9970 +p accept 43,53,79-81,88,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Venom131 67UEQtHYJtvpxhqe5eCizkTdmJo veKJummT9+zQfldP+x2EVp6qPMs 2020-04-20 09:01:12 195.123.209.91 5092 5093 +a [2a02:27ac::4ed]:5092 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9520 +p reject 1-65535 +r jdvnsjfnHBDkScf 67dtCW/1eHowOyyB4hv/mBbG+g0 Qpa4hsMWXyTi5LSXq+ycoMfdPrc 2020-04-20 02:15:05 94.140.120.130 443 0 +a [2a02:7aa0:1201::b5e4:ac7c]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4570 +p reject 1-65535 +r OperationUrbanWolf 67eZ+t1hXpPKl75Vg+Xrl90h4Q8 sYQ2e080Iv1V57a3PjqJ/DrAuGc 2020-04-20 02:21:51 108.28.83.178 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9420 +p reject 1-65535 +r FlameBerryRelay 68GMQV7rbKNuw1LQwLjayXJ2cEA cSrBG0UDeIc8FoFgqKQ3Lb4yZrA 2020-04-20 05:33:41 174.55.101.195 443 0 +s Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r tecit 68L+Z0kfGghkOQC2R1u3CJetQuM ljKpNq0bJ0Eyg5UTVSo9JLIH6JU 2020-04-20 06:51:32 212.51.131.143 9701 9730 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2580 +p reject 1-65535 +r Unnamed 68u24AMGL8Eq40OESyETrJWcabM cef9hU2m+GDsSmUHdQiTFAh+XPo 2020-04-19 19:58:58 95.216.229.110 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=72000 +p reject 1-65535 +r myRelayFromTroyes 692ai8RdBUPQ/ck5QO4G5W50mpk wLPZvFl52W1ul4yRiVBcd5o24Tc 2020-04-19 21:20:21 82.64.172.55 9030 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7070 +p reject 1-65535 +r jmarshall 6952JBLR8NdTOAU/WlqbbuBT1kI h8Bp9fYFW6b9x0Xx4ZLvPjHky7o 2020-04-20 00:50:48 5.19.162.103 14021 14070 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3700 +p reject 1-65535 +r fluxe4 6+cY4aSe4ikHFwKWT42x8xgHX/g Jv5GfslOnfZHx0/7diSOq0ZQcc8 2020-04-20 01:46:36 131.188.40.188 11180 1443 +a [2001:638:a000:4140::ffff:188]:11180 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=66000 +p reject 1-65535 +r JdMtOrReLaY2 6+doAtCY/2+iJvYMLQsMCY82evE itvMWzxeo4QgwVVorv+2IMj+Tkg 2020-04-19 19:15:32 95.216.136.34 443 9030 +a [2a01:4f9:c010:22::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10800 +p reject 1-65535 +r sevenrelay 6+0jB9CSV6u/KS6aFQpG1aKg/Bs SKRocZZUC3tA1XRZ5gqtalA9Ti8 2020-04-20 02:26:58 85.244.141.60 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2680 +p reject 1-65535 +r glf 6/CeBBNrQDQqm7iUdiDgukAcsWg rb3qh1iEw8lXC/ZDsNiNHDoPB2A 2020-04-19 18:56:39 88.99.93.80 9001 0 +a [2a01:4f8:10a:1d8f::2]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=977 +p reject 1-65535 +r blackpearl 6/mFOZs969rIgJf4FCR10w00CLY ijrrEy2F2phWgkkzVS24tGpCj68 2020-04-19 19:28:57 185.112.157.135 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1010 +p reject 1-65535 +r redDragon 7AHqZ0nJ/0TspPGtCKaqKtELss8 8WZtQ6HayMOR+gW7y2SYa1ELCFc 2020-04-19 21:38:28 37.235.49.138 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=494 +p reject 1-65535 +r mortimerAtx 7Aq6gR5Osz2ti8i3A32GK/Tzqig a+9fHizeDjd1r9LcfnfEWUYlLZM 2020-04-20 05:18:47 136.49.14.7 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9900 +p reject 1-65535 +r SetElement 7A+xA9YDXqPo+IqhAD7tL0PAJ+U XKvQ8rdGraECIBTOnFbjZuFmEd8 2020-04-20 11:30:51 142.93.203.146 4443 0 +s Fast Running Stable Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2370 +p reject 1-65535 +r QuintexAirVPN3 7BXbYtkQFIHzZN5S64MTyDi93Ck EXyPHDJCtrVu9p1RStg0XHuNbRg 2020-04-20 10:12:26 199.249.230.119 443 80 +a [2620:7:6001::119]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17300 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r niftyguineapig 7BmX1RiS5GB8aOgAVJoefkaUAFo JoxYxK/t+GEyLtyuJTgiQF0lc00 2020-04-20 10:14:27 185.220.101.144 1144 2144 +a [2a0b:f4c2:1::144]:1144 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67000 +p reject 22,25 +r roll73645376543 7BqtNcmirHqMEWUQid+IuqSjTgU oCHIDZSNlaGK/XUJzS4c+zOQaFM 2020-04-20 11:19:43 78.54.46.81 444 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=392 +p reject 1-65535 +r sheepdip 7B/WB/J7oAI7SL6qRw6MsmfgI7E Z1QKGHaH4RNMmPK4xv2+oNJc/50 2020-04-20 02:03:39 91.145.82.111 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=796 +p reject 1-65535 +r externet 7DXEx6vfWOPtGXhBCSIVLEmpjlc J8d1qVJhq4/YiZkRctajZ59RaJ8 2020-04-19 22:33:04 213.239.211.41 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r VeilsOfTheOnion 7D7C4mycV7Rmhunv5+6r1LVw1tM FmzjT4yik4ZbaXTp3TbFwXjurV0 2020-04-20 07:30:12 5.39.78.40 443 80 +a [2001:41d0:8:9028::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9600 +p reject 1-65535 +r b42 7D7OPDdJ9u0QzWKTy0Iqlaxzk5Y G8B7gNd7u1PAufMdyZ+ht7T8kFE 2020-04-20 01:58:11 82.251.33.136 9001 0 +a [2a01:e35:2fb2:1880::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10300 +p reject 1-65535 +r MLTorNode 7ETynGM4OIl+aTdSh7N/3p2IBBs vVatIYrOYQ0wvjf9QwjqL/bH+u0 2020-04-20 06:10:09 82.59.205.29 8001 8030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p reject 1-65535 +r coincenter 7Eo6ULycxQLh9l59oWvSgYRn3l8 QcLf9uMNchpFFdLcBW6QHR+yfmc 2020-04-20 11:12:42 64.125.109.103 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7200 +p reject 1-65535 +r SerpentRangers 7FH9OK1ESteoRjv9oDUoJ1W17sE PgkmNsTDDW4g0WakfRDXlRVtqoQ 2020-04-20 00:23:46 119.161.100.138 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=365 +p accept 20-21,43,53,79,88,110,143,194,220,389,554,563,636,706,749,853,873,902-904,981,989-994,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r nodvrelay22 7F7Sloli5uRPQSIUty1z6jKsReE 4Zl6uVhhJlVW3y/H85+TmsTpQd0 2020-04-19 20:50:31 45.62.246.187 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2600 +p reject 1-65535 +r VPNrevieWS 7GQScIdq30hNK+a3IT0h4DCWOqY QTrdi+IcISPRy9CJRRGRunvCCVA 2020-04-20 09:16:09 51.15.143.239 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5890 +p reject 1-65535 +r demoncore 7HKIGhEo6xsoPuU/VJB0dxGab+Q kseYQDb4R3i/YxdG6SPh73SDoT4 2020-04-19 22:02:30 185.15.94.17 9001 9030 +a [2a02:ff80:1003:6::17]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22 +p reject 1-65535 +r king 7HN1PC0DWe5144JfxjFGj9xZ01E lrfFCLkPqrnX2Qpf7GCnnDb/t/k 2020-04-20 08:24:43 51.89.200.119 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r giftfish 7H34YHj82XeWCH6KjTcTHnSjfL8 18A1gAg86HisGJk93tCSUAoWbM4 2020-04-20 11:21:46 178.63.47.104 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r tesseract 7H6ppuvKDp7W8SlSIxMevVWuvic QqhbLel73UDMFKcyQUzW3tL5YZI 2020-04-20 07:01:00 216.71.216.71 7213 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=990 +p reject 1-65535 +r Unnamed 7H/4q0kamGUaTKqor9SmuYVjOak xxrkXzizAJH7yKx80t0a/mks1CY 2020-04-20 12:36:12 167.114.92.52 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14500 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r fr0akatala 7IDuz81ZlhLJp0Z4yAARRkUBQeg 5ctDEiyT8BZGKIGA1ldawsXrt/0 2020-04-19 19:59:59 176.31.163.89 9001 9030 +a [2001:41d0:302:2100::868c]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17800 +p reject 1-65535 +r DFRI3 7ITiMkn3S/+8grTmPNopXMwCkqA oB45DBc+VK/STMfUYwiWXbM2Umk 2020-04-20 03:50:14 171.25.193.235 443 80 +a [2001:67c:289c:2::235]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24000 +p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999 +r arendt 7Iw2vCCbpJkmPpPQgmBGZnqsFLo hdviRqMqKxDmfiGIXCw++DIPCq4 2020-04-20 11:40:26 91.77.162.130 9002 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5730 +p reject 1-65535 +r eclipse08 7JxM20AyBHMRIsnT+kTfrmZ9yC0 /C0dcjfkS4j1Gyzmq84qJP6Xeig 2020-04-20 00:15:36 81.16.33.30 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3250 +p reject 1-65535 +r definitelyNotLE 7KoJcyQmK2A5T+bzzURqZqMxlW4 7xtPpgQ4dwq1Ws1wMh4HKzZ980M 2020-04-20 00:27:30 207.180.221.220 9001 9030 +a [2a02:c207:3003:1408::1]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p reject 1-65535 +r DagnyTaggart 7LChPDO5wLsQEQTghzjBkEgiI5M G9lwR6m9Vc4hJwsjTP6xLBzIZn4 2020-04-20 09:05:15 142.93.190.102 3389 443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=27100 +p reject 1-65535 +r gapcoinclub0 7LGWWKFvYIyO17OuRHIK3navBjs RUPkW07k/Wr4utk0OpwRTaTesSU 2020-04-20 09:23:14 172.104.88.43 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=540 +p reject 1-65535 +r FissionEx1 7LJKMm04L4S3vWMM/b4aDNzgJFo ZNH/Je3HI5c61LtRV9ru0DVhTOQ 2020-04-20 00:25:35 147.135.78.157 443 80 +a [2604:2dc0:101:100::a7]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p reject 1-65535 +r torpidsDEmyloc3 7MF8C6dBE/t6T1ja8v8e4jzl3wY 9TEUzxUyDFSc8bmZP8HggpR5ZU0 2020-04-20 01:28:48 89.163.224.187 443 80 +a [2001:4ba0:ffec:b9::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8100 +p reject 1-65535 +r Unnamed 7NBu8NetM20spPN9t19sr6O6/fc au/AP4IzEjG+7C/yCwf4Ml+0adU 2020-04-20 07:07:44 87.160.240.88 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1210 +p reject 1-65535 +r Unnamed 7NPVk4XYPvw9KW4NK+cwaNrKbaE 9Kprpzs04SqweGOO0eR94HMXFZw 2020-04-20 06:06:12 193.169.86.143 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9430 +p reject 1-65535 +r BESTIOMONDE 7NWWJ1u9SxkVcAHoTFcm20R4PaU Tfw/F7E/Bt+XkkF3OqjiIi1dS3M 2020-04-20 05:36:09 172.105.242.117 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=660 +p reject 1-65535 +r piss 7OkMQVnZFpIffI3fTQiKw4CMUh0 PRMvBDiJuQJd8Orb/2mInOT18OE 2020-04-20 10:10:14 87.118.116.229 9001 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,445,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r SEC6xFreeBSD64 7SM4ysJxGz4zE5Lh7SgxIZt5QCQ CBLXrIUTmXp1QtgmbVU1M0DzP+g 2020-04-20 03:32:38 192.87.28.28 9001 9030 +a [2001:678:230:3028:192:87:28:28]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p reject 1-65535 +r Fuckthahelloutofme 7SvxHLPAIFytyUWW3GiKUVP8qzU fcrs0cI2ytaAHKIvn815ypliix4 2020-04-19 18:51:31 212.147.13.90 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17500 +p reject 1-65535 +r Unnamed 7TYSRRX3Hi4kAdcNnvw8rrCNYRs Tjo5nh+iwsc6XSDk/I0fD4LEh14 2020-04-20 07:18:55 37.191.205.53 38443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10200 +p reject 1-65535 +r Isoalliin 7TrLu4nF8Vl6RKZdL6IDvbjiCPI yz7Zg3Kk7HMGXmRT1jFLHNop0Zk 2020-04-20 01:08:50 195.154.233.183 80 443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=38000 +p reject 1-65535 +r Unnamed 7UI8pb8F96bX8iO5KVIzrcfHYUQ zhmXFTx8No3EzqX4hdgbuzIV+Os 2020-04-20 07:36:58 45.9.250.136 443 8443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1550 +p reject 1-65535 +r BungeeNet1 7UMlptuNV5z/cPWlYw/TaEZLDWQ S4DppDL1Qhymov2JeBDh0Ieh38A 2020-04-20 03:07:46 51.161.43.235 443 80 +a [2001:470:1d:3b0::ac:ce55]:9001 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15300 +p accept 20-21,43,53,79-81,83,85-86,88,90,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1043,1103,1113,1194,1220,1293,1500,1533,1677,1723,1755,1863,1883,2082-2083,2086-2087,2095-2096,2102-2104,3690,4070,4321,4643,5004,5050,5190,5222-5223,5228,5287,5675,6880,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8502,8601-8602,8883,8888,9418,10000,11371,19294,19638,50002,64738 +r vilyaExt 7UZj+1V79ccztEaB9cYShoHsBWk SabBK0/LApf/HPLtH310BxMDI8M 2020-04-20 08:44:00 193.227.196.10 9001 0 +s Running Stable Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=15 +p reject 1-65535 +r rfc822 7UoR0/YY/jDYGi4KZCs+mR0S1h0 9+9zyS5Q2dwqX/qJpp+F03DDmLI 2020-04-20 07:58:06 195.71.68.84 4712 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4 +p reject 1-65535 +r snap277 7VMccwt2JDQ0fG4pPx03o3/IzKs qseGCoIb+ly9GumTJAWqz04oJ+w 2020-04-20 10:42:39 176.250.134.92 32945 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2410 +p reject 1-65535 +r Naname2 7VzNLpDla3Ys9U4Ri5nMGDX/wsE WkfK4Qi9idhZEs/Ut9s60x0Vz+E 2020-04-20 07:56:42 220.148.130.107 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=450 +p reject 1-65535 +r niftyentry70 7Wr4zoz0EmpvM1cjdrbYl3/tLdk QqhKDEL7GeqLuGuFb1GTvP9EFFc 2020-04-20 10:51:08 185.220.101.210 10070 20070 +a [2a0b:f4c2:2::210]:10070 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14100 +p reject 1-65535 +r Planetclaire63 7X8r5dKsf8+CGpCeJIb/+5XWUnI GlM9u0/fdj4iWueP4K38iwwOs5o 2020-04-20 06:58:57 91.143.93.29 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14600 +p reject 1-65535 +r Unnamed 7X/faNUEru1OKMY5az5KTtBEBrk pQJl6me7hmh29ps0GdOwnFNvXMw 2020-04-20 07:12:39 163.44.173.37 443 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=200 +p reject 1-65535 +r tutor 7YYYVcZV43NUfUxOhqNcWjE/pJc HtA+KZeNixHrE8DAXKFn4y4ko0o 2020-04-20 07:17:20 194.160.170.212 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=37100 +p reject 1-65535 +r Unnamed 7YmsKK/zbs8+obmLQXUI3WeMunY sfXj31bMfe0XS2ChORaYkalJv2U 2020-04-20 07:25:59 185.186.78.172 443 0 +s Fast Running Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=132 +p reject 1-65535 +r RumAppointment 7Y1Ol0U9dRCpNLT+z9qzUQT9fK4 7f0GhwMomL0PzqBbJsQEwwbVWdg 2020-04-19 23:41:28 157.131.196.215 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6000 +p reject 1-65535 +r Unnamed 7ZQ9XTKzk1hikWob4z53gNtR28Y 4zowwJamkJBR8BoArHoZn01C0sU 2020-04-20 08:03:33 84.133.84.225 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3580 +p reject 1-65535 +r Nabla 7ZZJrZrEOfcFYO/jNJtKxKr4tqw a18il76abSzH9abikHNe+1szYlY 2020-04-20 11:32:21 51.38.154.10 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3500 +p reject 1-65535 +r TahoeTor4 7ZbA2MTqd1PY8qY7sAr7+WxBmFM PNJu4TRJfPxCSKdGaJ9w7G/o6tQ 2020-04-20 11:21:31 71.93.76.125 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=330 +p reject 1-65535 +r Unnamed 7aklwn3hfKcVPYresByAJ0326j4 VW4CiTJpz3/6EWk8jFsh4WDLuj0 2020-04-19 19:13:49 104.244.77.40 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r king 7a0lq8MI17FgT51zanQSvsFr8NY gUXswCmD58d4rOfxQHzxjPk+tSI 2020-04-20 04:47:58 51.68.201.120 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11300 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Karlstad1 7a8wxY1szzWeoGLGaMcYChcHZEA SdTtqIDvW3jRdQ55aUGh0QXXsSQ 2020-04-20 00:04:44 193.11.166.196 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8050 +p reject 1-65535 +r Nebirosh01 7bkh0Cwj+j/4EO1bSHrXYOSWhC8 RyUbHc+hA+/NjEiXyt+RtVFCMXE 2020-04-20 02:00:34 79.200.189.20 9001 9030 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=31 +p reject 1-65535 +r lkerry 7bnGW5OZQOxenagA7hV08daAQrQ O3odagj4yy96+kzBwA/ffA14fsg 2020-04-19 20:47:11 51.77.50.229 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5500 +p reject 1-65535 +r niftyjunipervole 7cQkP1f5uFa0ADmNX2w1T4QI7qk jGgLxX2RK1jHR2fKmEdgePhFDhw 2020-04-20 09:25:30 185.220.101.6 10006 20006 +a [2a0b:f4c2::6]:10006 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45000 +p reject 22,25 +r OughtEcology 7cieKCXkoIOSxt8fGLOw1tsUhZc 593ROlJAEllq7dcMb8qn6M5PCEk 2020-04-20 11:33:02 47.56.85.79 9001 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=200 +p reject 1-65535 +r none 7cnYMvvq+Un2ENP2pVU3KRtOjyY 6ACKF1vzwS4TWExw9RDImZdcHyA 2020-04-20 01:48:32 213.109.160.48 9001 9030 +a [2a03:4000:36:d1:8da:abff:fea4:41a]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r OZallOverTyr 7dBDPmEyacK+bHnAfecQqH8fdKo tIZH0watiwRw1bFeOaPWw3ZJmqg 2020-04-20 02:11:15 46.246.43.146 9001 9030 +s Exit Fast Running V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=263 +p reject 25,135-139,445,563,1214,4661-4666,6346-6429,6660-6667,6699,6881-6999 +r StandForFreedom 7eoZFy7IsUY73RnjoYd4xXVnEKE L7rstzhn/ngjU7ReFBqpoPlPGzI 2020-04-20 08:52:12 45.33.114.120 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=195 +p reject 1-65535 +r CalyxInstitute18 7e24eXhz00Ayi1/tvXdEp9HfFR8 1wXkt9fU1ihm7k089GklcUAnitk 2020-04-20 02:12:29 185.220.103.6 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22500 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Unnamed 7fvUB2GLhKOIoPpQNUgd5sYQZzE D0m6ALmJ8vExM1QucdWX98zV+0E 2020-04-20 02:44:43 40.85.253.11 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7300 +p reject 1-65535 +r HoleeShitSnaxx 7f1f/p2XrcC6/jCjvYRU82/972k mh5OG7LqZ+plIA+YvjaB+/AbTiA 2020-04-20 11:55:32 207.154.192.183 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1300 +p reject 1-65535 +r luraleen 7gEO+AonrAsCzcK4shSmIBuwLSs M+02eyIOpr/IaOKpoM/igXTljXI 2020-04-19 23:31:09 144.76.175.205 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=92000 +p reject 1-65535 +r ihaveeditedconfig 7iAdJuznqlxJbdzExW7GIZbkohA /zvBMiprzdJlmTCsiWVikyYkHso 2020-04-20 08:18:50 134.249.122.104 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=752 +p reject 1-65535 +r ididnteditheconfig 7jLtmrAqgSCPVeuTQNESXPAiaX0 k2Ot375ij3rUKQEFr0Kb56bcfog 2020-04-20 09:18:00 83.135.84.198 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1740 +p reject 1-65535 +r hashynode 7jZDff0Vv73n1/RxcnwwUOtO3MU vKiM2I5M9Ct8QliOVy1Xkh8qATY 2020-04-19 19:40:25 150.95.177.209 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p reject 1-65535 +r snap277 7jiAbrXMY3angg4kkkfSOevA2fQ Y7xtQB/6X366ZWPrG7qP/9Jkrg4 2020-04-20 12:48:40 105.101.137.242 37885 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8 +p reject 1-65535 +r tor01aditaa 7jrBVfA82mvdiHcXmpHzzusP3gU NL9DKBz4P9D/2XvKFMJ9ppwPTC8 2020-04-20 04:34:07 66.70.228.168 9001 80 +a [2607:5300:203:439c::110]:9050 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14100 +p accept 20-21,43,53,80,110,143,220,443,873,989-993,995,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r gina 7j3fAMGtxWfzM7m6gZyPJSoykzw aSUzCoaHZretZ9y0S6hNNPbz7ww 2020-04-20 04:24:23 213.73.96.131 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2890 +p reject 1-65535 +r Noname 7kBXZA9aJhmzPW2yj3O7Cf+pRPw Hl6Pvw1bIs18PyAq0mGb+pDPogk 2020-04-20 03:00:50 34.237.124.74 443 8443 +s Running V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=0 Unmeasured=1 +p reject 1-65535 +r anonymous 7kghFrKkmitkU2Um6t2N6TL2kc0 Tet7tMGZOCOdcX/NtU6uNwJNh9I 2020-04-20 01:56:09 158.174.14.6 9001 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=7 +p reject 1-65535 +r angeltest7 7kr2MgWPBzTBQmsa1on0dEXKIFY 7KvGZwJcLD52DUuatsy1mcH7UZk 2020-04-20 10:23:01 37.252.187.111 443 9030 +a [2a00:63c1:c:111::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p reject 1-65535 +r cassini 7lSzViTRdcbIV3kT+GF6IXoIhPk sSS0k+yfeZKa5gLPkCGGLd0DWUE 2020-04-19 23:19:00 209.58.160.138 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=547 +p reject 1-65535 +r sqrrm 7lVmJiNrR3pAdwqs3luxQABu+00 9zX8cu5hacV9DONImJ6+TYHlrdw 2020-04-19 20:55:11 185.25.51.202 9100 9101 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6610 +p reject 1-65535 +r snap277 7laE5YgjtOL55NyViVmz/7coVaQ rdPAuW8i6od2TLJLuVqK8RKYkIo 2020-04-20 11:45:52 181.168.146.98 45297 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=170 +p reject 1-65535 +r ROCOL 7l5xqvhxlMtDY0xSN6z/tXu9r9o wuV7bQybQkkMGc29rYkQDL/q8T0 2020-04-20 09:15:23 87.120.37.39 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4680 +p accept 20-22,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r dawn 7nVVn6gO0Q2xAyv/sGhHwyaB1rg wNL/KI0jdrdCh4i+sv9Y6sWDwxU 2020-04-20 12:13:57 163.172.96.222 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3390 +p reject 1-65535 +r RaspberryPi3B 7nagdjLFCBrB879+o7nUDG8k4YA D2QlOdE4rrxKS7xPkwQABsvvw/Y 2020-04-19 22:24:58 2.15.173.83 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=6800 +p reject 1-65535 +r ca001 7oE03RaX9qcAtFD8ORD2Nqj80H0 tMKuzDiKIWd8caPvz2co88OKIG8 2020-04-20 10:30:21 159.89.149.5 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7500 +p reject 1-65535 +r niftyentry67 7oWYSejY7wg+7yAlVVOWpsNVKo4 VibfeCKDbLmsHDUP765oxZ8vboI 2020-04-20 10:51:04 185.220.101.207 10067 20067 +a [2a0b:f4c2:2::207]:10067 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r sandbox 7pQDDQKvWniMYupW1INUDDhGDhA MNHlGIvpRf2sbqM91w05cSbmI80 2020-04-20 10:07:09 176.107.176.31 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7430 +p reject 1-65535 +r sz666 7p07QmR6FRpILHwdQKrwDQbwgE0 IeaIiyA8P1k1YMp/aJtU1CaYWKc 2020-04-20 09:12:17 89.78.16.152 13009 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=366 +p reject 1-65535 +r LisaM 7qUAohbaqD54FfLEZ4ZlKTX9c1E Lmo/gFTC2Qa8iip0wNxysz8feZ0 2020-04-20 11:35:46 13.48.17.31 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26600 +p reject 1-65535 +r niftyexit1 7rj3VUpUqWtRJFq0fre33ZmphJM DzBb5MJwb/adTGSiBsS8Jamu+A4 2020-04-19 20:28:26 185.220.101.42 10042 20042 +a [2a0b:f4c2::42]:10042 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=29700 +p accept 80,443 +r NikowskiNode 7srdsMu1cl1N3+PX5zToJh4OnQk hpoXhFWJF8a4tDCFMfKvhmeipbg 2020-04-20 07:22:48 217.182.76.99 53 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8910 +p reject 1-65535 +r snap277 7toKYx+ruzqGJKcUbiWSf59GHSY PiiFmN2bz+Lebx/8mSbno7mNSPg 2020-04-20 12:26:36 176.202.20.35 41911 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=380 +p reject 1-65535 +r andergast 7tySyOTxTvtiAPtMktT5V7mGUrQ NULN9YKKQQeLq9HHbQl/TYkC+ic 2020-04-19 22:12:31 185.100.84.251 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8450 +p reject 1-65535 +r Tommy69 7t8K8fiSyC8FYGOCe0coPMmuqkE jJzZU04pB+P+bNi53YyyDtkwRRA 2020-04-20 06:27:30 185.107.71.41 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=67000 +p reject 1-65535 +r v205 7wkWPsPwPC9jqGW7vxzlZCxllaM FFmPUxg0ULwVgYMW4BYS/uURN1M 2020-04-20 01:58:17 78.46.192.233 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6900 +p reject 1-65535 +r pmfbgcone 7xIRq7V6pwvDspqFlpmhMpceyPQ DbkjFubucHteh5UQgn2oK3vEQGE 2020-04-20 04:15:12 80.95.29.212 16010 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=67 +p reject 1-65535 +r berrendo 7xqb4jGmw6yUueK/yGmQsWySOkU +/63OeHYFBUs8vSbpWCjiHBw+rw 2020-04-20 07:57:45 141.255.166.189 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9400 +p reject 1-65535 +r pollypurebred 7zfRUPOoUbMtnoQ2BdDqihuTgRc gTL/rnO0M/98vxsnvphPR6JDeS4 2020-04-20 08:06:24 108.16.45.82 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11 +p reject 1-65535 +r npdstueckscheisse 70MBVeKtreQlY+Oyj5kLb+6Sr88 bSpPus5rgtPa57W2W9CGTByB08U 2020-04-20 09:51:56 140.238.254.236 443 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=805 +p reject 1-65535 +r peql293884 702FcdZWnGej6Xs1bLvrwZRzs08 l4aC+5dTUrhokZvpwnuIiVinydQ 2020-04-19 19:02:42 50.39.175.88 55554 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5500 +p reject 1-65535 +r RutimkaTorRelay 71GHfYTOB9Wk+Y34toEosNFe44E 9c+RR0Qs4hGGR6dIyJoka7LZ5rQ 2020-04-19 19:17:15 178.63.40.197 989 990 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=105 +p reject 1-65535 +r GhostLORD 71atVV/YDnvaL6ST2TWa3reBW0c geG0JMtGZ2vzpj/+XCdjl85DneI 2020-04-20 01:10:41 83.223.16.211 448 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2900 +p reject 1-65535 +r flodder 72YEuVqULxx62AffEPk7ngDEems XJn7SLNkXNetRGw0Z84KtbX0eVs 2020-04-20 08:01:52 91.207.60.48 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2190 +p reject 1-65535 +r Spica 72u7kow7pTIBRZGdAdY6xQmPK8k sX6xByG0ENIi12ARhArlKb68Mu8 2020-04-19 21:17:40 139.162.142.27 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=1310 +p reject 1-65535 +r snap277 73QjZHv8V5r4xJA/41nMEwGzfx0 mj2MwA5UYawNHs0vGmjkCeh+3lU 2020-04-20 11:15:27 77.146.26.40 34197 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=24 +p reject 1-65535 +r snap277 73uyeoJL7wtsMYl64/ybrAbSuec RN2JV4aBYdS2pJHIqVVoFc02yfo 2020-04-20 04:50:51 78.235.60.16 38167 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11 +p reject 1-65535 +r ILikeTrains 74kxrNdCbIqD0YgIQnvB5/KjPy4 3VtZEI5ciwQIx3Xvz8w0DslpncU 2020-04-20 09:31:31 31.125.45.168 9101 9130 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=530 +p reject 1-65535 +r PLUTEX 75xGEfqnwhFVqLoqch3cPSeBYDU KUPXm8quVP3eMq0LUoaXCfDaKnA 2020-04-20 05:52:16 109.69.67.17 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18600 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r snap277 757P4cwrwg3RG1c3dUAX2hRHQWw PwLdMRlp8OgBzEUDtasHPT6Xy2E 2020-04-20 09:08:26 93.11.174.69 37581 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8490 +p reject 1-65535 +r angeltest23 76LnsHOqTOLa9xYPI8kNuAWUj0o TAsUN1sYrQNobPZBpQ5UaaED7s8 2020-04-19 23:01:56 81.169.235.154 443 9030 +a [2a01:238:42e4:8600:5f77:4c4f:a310:3b3e]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r RelevationSpace 76MKLmTRJktbaNvROGbSQSDJvNk 0QWyHHbUIN0c72zi53F74lhbf7Q 2020-04-20 03:06:10 93.104.191.165 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=2770 +p reject 1-65535 +r marcuse1 765EcoJkmCIkRF6WIUwV+Qdd7h0 R71CjodhlPaypWCTHnH2PctpWBU 2020-04-19 22:48:49 178.20.55.16 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r Targaryen 78ylhS0YIHp6k8E+80YEWMquqdk eCUGFOTwd7mSpdgeJ3ayFrrYqXg 2020-04-20 08:16:50 51.89.126.24 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r hdbRas3 797qf82H70/jshAtbAD8j/f6u1A 1MeCaFudBNPGw4dfSCQN7vjkCTA 2020-04-19 22:59:29 79.229.124.23 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3930 +p reject 1-65535 +r uppsalarelay 7+RJ4La3plc3a1/mKtFys+xYAKg 44XsZMEia3Lzd7qYr+gqNJ2LfHU 2020-04-19 20:16:19 158.174.114.118 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=740 +p reject 1-65535 +r FreedomPanda 7+SKaioCto0XZ8E7lkb6YuqDELI gZblpMXQz9KhmbB4gWrTG1wT6iU 2020-04-20 03:05:44 190.2.146.90 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r Aerodynamik02 7+rNeBYE64D7wCXt7eotUjrqqi8 zPy4W5dMycjukqoRmDcMLHjOeXk 2020-04-20 09:25:37 217.182.75.181 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9030 +p reject 1-65535 +r jeevestor 7/MuCyuhAiUfP3F8s5iIlu6zqK4 /9MxJ5nSB/lx0IhySXqNktL1pMQ 2020-04-20 05:50:10 5.150.221.137 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2050 +p reject 1-65535 +r jamst 7/ngtbgT5yackQo7uyKGlXUzy6I B8mW+d4xdr65yGfvE4zn2yXnJFo 2020-04-19 21:22:50 98.234.222.4 9001 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=370 +p reject 1-65535 +r Dragons 8AHNKp4nt+Ps0SCVHK+WghOWezE 3vyP1VAtaMhQEqfZ0f9+s3HLUX4 2020-04-20 07:32:46 193.182.144.53 443 8080 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=386 +p reject 1-65535 +r rortor2 8ATFG3wxNtffwgRpqlMpuDcqJjo /cvjNfM/nzeKdn3cYrXrLUL8vSM 2020-04-20 12:31:43 173.255.205.113 9001 9030 +a [2600:3c00::f03c:91ff:fe50:404e]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r PancakeWhore 8A7C4KLKeaV/56CRigh5h3R9dy0 se7024Pr+Zr3vRX54oxt8fcFVKY 2020-04-20 11:55:24 198.27.66.209 9001 9030 +a [2607:5300:60:1bd1::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p reject 1-65535 +r trustytohr 8BKtmgip4LSlxhFVKE/XlbVTs2E OlJTOpIgZf6ME34EcNDz09pWbtU 2020-04-20 02:34:34 185.238.137.167 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.15 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=943 +p reject 1-65535 +r InstitueForgive 8BScuuiVO3FXzFS/xBTbr4WeCzM xQ64Nqfh3j3OS+I2KKQtI9WF5Ss 2020-04-20 00:18:24 47.254.131.93 8443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3100 +p reject 1-65535 +r donald 8BqqZA/06gJduESb1hwFUnO0oyg 57Yth9KcYD3BuavBTCAFugymrQw 2020-04-20 01:35:04 145.239.1.97 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19800 +p reject 1-65535 +r FriendlyExitNode1 8B44LaUkpX8r+zxP8nCiPVzTMR0 GfpD1ELV5hejQrByHEMpETQuPzA 2020-04-20 02:30:33 205.185.127.219 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5300 +p reject 25,465,587 +r fwxfmhtfzxl 8CXvA8HEjTHphBbckbLy0uivdSM egTggQAW3FBt9IwXySEBYeRGRss 2020-04-19 23:05:48 76.66.106.128 45839 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8000 +p reject 1-65535 +r snap278 8EfMqJLpwek5xEFj+yLLyqOhZNg CrVsOhcHhz0aNsC+m0MvkN/jTAM 2020-04-19 22:33:21 80.43.184.176 37362 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r RBN2 8EkwygRs0YhxIlzh0UAWALUT7Tg 1/XrPDYrJ+w8iEdAd148fULDCGg 2020-04-20 05:30:08 94.130.184.108 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3560 +p reject 1-65535 +r icanhazfunk 8HXAk18zF2Ot+54H5NTTWnTil9c BSyJrIm4NwoZOV8pUQ+HDFUTMgc 2020-04-20 02:01:00 173.230.154.90 9001 0 +a [2001:470:1f04:c03::2]:9001 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4500 +p reject 1-65535 +r snap277 8Hbr/Rnjx+YAgpbxzdy32U0HqNY Qyp6CTrSS+MCOan6qNR4ObstPes 2020-04-20 07:37:18 90.91.157.89 35841 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2800 +p reject 1-65535 +r itherzwhenip 8IMmCLDVLntEGOVOZVyhilhd7bg NSpdZII2eafh9KDoN9HJaigtMKw 2020-04-20 10:19:34 83.84.28.61 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2030 +p reject 1-65535 +r Unnamed 8IpSWsqWXPalXwWHv0tzc9mLlU4 ADsQjLd9iw9/J92Kvgz0SYl1l9g 2020-04-20 08:21:56 37.191.202.138 8443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16000 +p reject 1-65535 +r dontknowmeAT 8JDQbdkIyRSH8KZd/9+x5M1mQog w+zoqclLR1x7PHh1Ih1Ejd1YJ+s 2020-04-19 23:48:37 86.59.115.70 443 80 +a [2001:858:2:b:666::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9900 +p reject 1-65535 +r Ratini 8JWyeNWN6ZwZoHokikH/rAf0bqU LSrirh1Kbk926mObYltnJzUNno0 2020-04-20 11:56:29 206.189.131.220 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=744 +p reject 1-65535 +r SchwarzeLocke4 8Kl6rwkgFSk+xj1+ddnCtwt8Ngs GLU3bkH5G782WTt5nOCdW8mz+Xc 2020-04-20 07:20:42 85.10.196.12 53 80 +a [2a01:4f8:a0:6128::2]:53 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4510 +p reject 1-65535 +r Deteros 8K6SK001jzr2t2IiolJrBHDn2RM hvjH9KtNDYlBY1ZHbRYGTRBOFoQ 2020-04-19 20:24:18 167.86.66.168 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=109 +p reject 1-65535 +r vm242tornode 8LWAeYuzA7o27RJoVo4q2TW2xIY KU9QrexAz58tPb18853Au6F3NIw 2020-04-20 10:48:07 46.4.34.242 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2530 +p reject 1-65535 +r TorMePlz 8LiwNx/USlyjsFQRF2rn69WwJbw cYxc/y77XuH6+HNjJhDddpkM1+Q 2020-04-19 19:51:40 149.154.159.87 443 8080 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1130 +p reject 1-65535 +r Unnamed 8Lz+cEGkbAoBdbVvuUIozL8NtNA JXR2NoLQz47q62Fnva1gETpZp30 2020-04-20 08:56:37 82.64.53.65 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=547 +p reject 1-65535 +r goodbyeapathyAmor 8L0e0mTmbZs0Vf1uJ5deUlHmtjY TlpTO408mdGqBZBVQghehtrTeVI 2020-04-19 20:51:42 89.34.27.21 443 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4070 +p reject 1-65535 +r Scrubs 8MlRNTmAD3YuyuN/FjcNfLpeUsI nrVOLa2iKxy1vAJh3sUL6oTBZnU 2020-04-20 06:51:06 212.129.5.219 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=74900 +p reject 1-65535 +r Pinball 8OQNLNaLzuFvprdo/kgGKu8JOx4 kUD2qAZ1R2ke7Z8eCEO3XApNv8k 2020-04-20 04:49:45 119.17.155.241 9020 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p reject 1-65535 +r fractaldragonold 8OpMzGTMwuI9u65yMNxgyUm4ZQo bOujbOBYQwOTQsZAlPvBNIehiHA 2020-04-19 22:10:35 71.19.157.213 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=137 +p reject 1-65535 +r snap277 8O3sCYhnY5H7TV1c7e8GdTE6tec sa5LIlZeHDIDtWoSayIq/Wm3Y2w 2020-04-20 12:09:29 88.201.250.124 34635 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=540 +p reject 1-65535 +r citizen17 8O6+otmlonQqga98MA/7mPbQm30 zl/cfY4Bwkeqdm0sQKCRNaCGrEU 2020-04-20 00:55:31 83.97.20.99 9001 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=446 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r yoona 8O9SvuQAsnQw3KnRRPoMPeAJn+w V8YHVoGt1yXotvEqPAfn29cHDE8 2020-04-20 02:58:53 81.237.206.224 9001 9030 +a [2001:2002:51ed:cee0::1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9140 +p reject 1-65535 +r FalkensteinTor03 8PE3FHMsNHMSQm7CuNXElA6qRbo 2/Qh4I6JTUqcoZEoZnDJ8fBvfOs 2020-04-19 19:22:47 144.76.236.27 443 0 +a [2a01:4f8:201:120d::2]:8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=57000 +p reject 1-65535 +r Oasis 8PKiq0wb/bMhMpFxlgrYeHibyaw VGHVkcalPw9QO9iyQsYdC4mfTGE 2020-04-20 04:42:37 95.216.223.62 9001 0 +a [2a01:4f9:c010:5c8d::1]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r dc6jgk7b 8PUHSm2t09wi4fqhj9bYnLxSdxo GuIF0BRGOd2shazBnHGN9aZ5PWk 2020-04-20 05:45:53 51.15.89.218 443 9030 +a [2001:bc8:4700:2000::4a21]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35100 +p reject 1-65535 +r irons 8PzKbvMqjXxzHVYk5vxk4D9T1XA j/HEADQCISyu97hCWWKhirftEAk 2020-04-20 06:25:03 138.117.148.45 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=82 +p reject 1-65535 +r Unnamed 8QIny5CklfU67aa2iivY3OqldI4 nRDZxq8TAV20d2/cnIzfC2rNRTM 2020-04-20 11:51:49 205.185.113.207 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4300 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ParkBenchInd001 8QveJ5rnFRXdzMxh3Bmsh2X4o8w S+976t0PR56vUM3BNNBtkDR68RQ 2020-04-20 00:29:59 193.70.112.165 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8090 +p reject 1-65535 +r UwUSystem 8Q/Xd98c0D+ktv1RZj7DDMZU8Is yCDVNaZrt0W2CJFX1DlBKcMs19I 2020-04-20 12:39:19 134.255.219.140 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4470 +p reject 1-65535 +r Debianer 8SYB9LcAncsfYaFEZ7DKSmCOdpw KERcAgkVxIr/H4lAbzzd2aLJLKY 2020-04-20 01:50:15 95.143.172.214 61058 64671 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r raisapX 8SlRTUCaEmzjyfdU9UAA2s0/Gi4 emTwEGDLJD4LaSC8wmP7HDSz1gk 2020-04-20 12:23:58 78.14.87.244 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=410 +p reject 1-65535 +r shekhinah00 8UzVAdQUzqRZXPQOz24QkzLW4Nc IiWXvrVXYXYs7qiRyjt/ALh2JjA 2020-04-20 04:14:19 128.199.222.114 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=716 +p reject 1-65535 +r WitchNode 8VoqCL+RAX3PtgQhcWNWYeE6glY dbwt9eleNnzDJdwCT0uCYUoju4U 2020-04-19 18:53:18 144.91.125.15 9001 9030 +a [2a02:c207:2033:4966::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18400 +p reject 1-65535 +r NeulandSchlandnet2 8VqENHTeID1R08REDCE7aYwi+p8 Wm6vACiP3mlOkJvnOkbvWwbXki8 2020-04-20 12:05:43 109.193.71.56 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=98 +p reject 1-65535 +r Felicio 8V1d2hrikYfz76ci8ewaR/4IbMY 5aY5fOCXm9Rb6+ziwnsTtbpL/Fo 2020-04-20 02:43:47 212.74.233.21 9003 9033 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.15 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=422 +p reject 1-65535 +r chungus 8V9bu5EXW4GYD9BwTxdiwEz2rx4 /yADNDw3Dcz8KkX+MemAYWlVQdM 2020-04-19 23:56:42 46.166.182.20 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=72800 +p reject 1-65535 +r niftyguard68 8WJNcMOtNzyEmlsqjQeiDHPAx60 JzSJoz46HYo7fDz3f9gr6TlyhyE 2020-04-19 22:16:39 185.220.101.187 1187 2187 +a [2a0b:f4c2:1::187]:1187 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16400 +p reject 1-65535 +r larrabee 8XSqceGTq6VSG+6t1ebyyN1vnfY UDw0LfAhl+UtpYBqlZ7qT0dV+kg 2020-04-20 00:16:38 110.4.47.139 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=459 +p reject 1-65535 +r Unnamed 8XTvMchedkSD95teAUxNgcbxCrM jdzOXcR/Db9XJhk7eZVDA7ANUZU 2020-04-20 02:11:40 144.217.245.145 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=531 +p reject 1-65535 +r MollyEileen 8XWbs2D2ZraozgLNBPAo6EJf2c8 sOsVB3L5lULXDNXOzKIUlZvUxjo 2020-04-20 00:57:40 80.101.137.223 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3140 +p reject 1-65535 +r sinterklaas 8Xtc4CLBZCAqALNmnvyrcs+AuTw izHhg0SH8NwatyVL76Nzojenz9M 2020-04-20 08:27:05 85.17.172.75 80 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5830 +p reject 1-65535 +r nlpdk 8YVeCehn7NAKTLfTbVgXCnV0wP8 e8T+ZGwejeyoZ6adBbX+NQt8PFw 2020-04-20 00:34:13 5.103.61.111 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=232 +p reject 1-65535 +r shiitake 8YhqpPSJcT8IZzvNbj2g4cIy4uU KM2O85PPaXWAOS8mlbO/kJD77/A 2020-04-20 06:59:23 51.38.180.155 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=60000 +p reject 1-65535 +r notorious4 8Z7v3y+y7/wA63GfxWYRFGOL+4w bTuotNzYs+tAm4klrOB81iiFMBM 2020-04-20 04:11:45 108.61.86.140 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=790 +p reject 1-65535 +r king 8aGysPHJ2u11wRTguK7dTbdokZI r3RPT695Lz1Hh6YFOh14KBh/mk0 2020-04-20 08:26:39 51.68.201.114 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=16800 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Kings 8afOGx1VjcJOObazD/IX7M7s8UE efUofyPW+yKmu02dZg3n/jUAlT4 2020-04-20 10:33:22 178.62.252.82 443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17100 +p reject 1-65535 +r arpalord 8bHhJnqTASRBIO99R81BdP2U/WA 3uid2q8szk1ln0oLODLjpMju5nw 2020-04-19 19:53:50 82.64.117.69 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=3600 +p reject 1-65535 +r k0nslNET7 8bb6DtjGDpxzF68CfnwOXBrh3Tk Ke3+WRPjDVxsVL+IjIwCpCZl4Ww 2020-04-20 08:29:56 209.141.39.33 443 80 +a [2605:6400:2:fed5:22:bfd6:6714:e628]:443 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6900 +p accept 1-65535 +r tortoke 8ciQGlafZ2OHSNe+l5aVQbPsxZ0 1bfRR5BP3YPQk5r2XvLBlcfk8OU 2020-04-19 19:52:17 188.40.41.115 443 80 +a [2a01:4f8:173:8c4::115]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r ididnteditheconfig 8dSWZYZFTfRGT9biLyrsLcbioN4 mERMEHN92T/HXvu/yQmrTqjRMA8 2020-04-20 00:06:16 178.79.163.170 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r angeltest9 8dXA9RV9myQBS+jHodh4rqaEO0I r+vIFEKoqN3/F+kip6wpx8MMAvM 2020-04-19 20:55:11 104.244.76.190 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=230 +p accept 1-65535 +r Geoff4 8dr/6Wxhu9NMsHjpi6UL81xBrwg /9Fj2KdPkRK/bXInrwQ7jOyCcj8 2020-04-19 20:53:15 31.31.74.177 443 80 +a [2a02:2b88:2:1::557a:1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6600 +p reject 1-65535 +r BlueVenera 8eLX4gcX/kz3Gq85WTEmycG6zbc VsGjEXgJYj5xzHNW8UyVxGOSsBg 2020-04-19 23:25:05 80.211.218.201 2681 0 +s Fast Running Stable Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=314 +p reject 1-65535 +r themis 8eZnagVRtNiCYlNvqrSIuGGqyho /bVE2SYp+09bd2TPezJfZowFoxs 2020-04-20 07:49:33 46.38.253.161 443 80 +a [2a03:4000:1:47e::443]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8920 +p reject 1-65535 +r Mandela 8fnR29flb5nGHDcS1fSgIVP9mtQ QPnKvYPjXGXWaHgRjx7cU6dgToo 2020-04-20 10:06:50 195.123.246.77 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2400 +p accept 53,80,443 +r gabelmoo 8gREE9rC4C49a89HNaGbyh3pcoE DQiRzidHJ2Iv5G7LEYaIMRiEfsU 2020-04-20 00:02:44 131.188.40.189 443 80 +a [2001:638:a000:4140::ffff:189]:443 +s Authority Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r niftydemogorgon 8hdg5j/iu0Vim7FPzbD9Z3SF2vg bGQxbvG0yMa1COH7cBResB6s9fU 2020-04-20 08:53:07 185.220.100.246 9000 9001 +a [2a0b:f4c0:16c:11::1]:9000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40200 +p reject 25 +r atorcy3 8hiqbMC9jFiKhv4Cwa25QHCLvHY sD3+Of8cUikrJJd9x8hifloS6co 2020-04-20 10:14:20 178.32.218.54 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=765 +p reject 1-65535 +r QuintexAirVPN23 8h3px94xYB2XFngeF+JDgIh4g9E jdRfVgf9zqRz1qUp0pXKIC8JUcI 2020-04-19 19:58:22 199.249.230.76 443 80 +a [2620:7:6001::ffff:c759:e64c]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13700 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r pangea03 8h37fM1e7z4CEIbslu98/Kpy9PM zD2Tb6MFwLOUxL5U2bqHhBATc3E 2020-04-19 23:25:31 81.16.33.33 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2420 +p accept 43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,873,902-904,981,991-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,5900,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r Unnamed 8i4UI2m6nIe2KGLZrLQAiaCbo28 O4zXL3dx0XzQdmVx3aLxX3Ilo/s 2020-04-20 11:01:47 95.141.37.207 64688 56462 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=172 +p reject 1-65535 +r HookersOnion 8jfawYFwi+7/GAYyzXq0LsoKz5E KQdTrNOWyMBupNM8UQhI5kmbyoM 2020-04-19 22:59:53 23.129.64.210 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5200 +p accept 1-65535 +r oldjourney 8kal9+kp6EknKLegYWGy4x888lU QFsJ8LJ94KKEdu4kxuEk7j1PfUE 2020-04-19 21:44:08 157.245.134.110 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.11 +pr +w Bandwidth=2630 +p reject 1-65535 +r jaures2 8k+L6id5p5ER8z9oMrBivtMGucs grAHoJzJ7zsemZgHQqSsjjoWlGw 2020-04-20 01:15:15 193.234.15.58 443 80 +a [2a00:1c20:4089:1234:cdae:1b3e:cc38:3d45]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7630 +p reject 1-65535 +r hmnij1 8mP09Xog2MGen5yEFQxg96SfLbU J38Ur54wWa0/flgAtuJiGub68MI 2020-04-20 11:51:16 104.206.237.24 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10000 +p reject 1-65535 +r PiratPartiet 8ntHztRXJMvOO0KSbdUvIJHzlaw M6o+IzZrZmPgPIhzA3DgxIOLF4w 2020-04-20 03:27:41 193.180.164.194 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r little 8n1dfSof5N99gm/zIXTGL/E5TKI CCq+M4fE7c0Pv8981JDmmPtdQfE 2020-04-20 07:28:39 5.252.176.20 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6760 +p accept 20-23,43,53,79,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r LiveLongAndProsper 8n+df8bUbg+RUzxotXI0dDV5fLA qb1gKwfvI1mupWUPuayAR3+NXbo 2020-04-20 00:31:12 23.129.64.182 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5480 +p accept 1-65535 +r gork 8omZgeOmAaey3cfd4CwkgGlwTZ8 e8btGZhzz1W8Fk8xWRfgyQsp0q0 2020-04-20 06:16:11 82.118.242.103 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r t4cc0reTor3 8psPGpG1XMt/bNyiodGMY1cfdms TSfvOhK5a7F8ES+7Tua8WmVsKTM 2020-04-20 00:21:33 51.15.44.157 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40000 +p reject 1-65535 +r Gandhi 8q+T0j2R+c/gPFFR3wGwSBv5nhI Dx9l8Cu5jeleb/2rpTpLvgkq2N8 2020-04-19 23:07:25 46.232.249.138 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7750 +p accept 53,80,443 +r Unnamed 8sBgghgBSDRhhMYawAljnAqU6SQ T3CO2Y61nBOkj9Qfv9lv83IMOM4 2020-04-20 12:09:02 158.69.172.229 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=10700 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r csskgrelay 8sYQGgyDEGzBniUM8M11eEVhL78 kUaEArQClM8+Mtjc5s20OORG9OM 2020-04-19 21:47:37 188.117.226.247 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=354 +p reject 1-65535 +r heyheyhey 8s7CXtr+9yj/sSrCMxW4OknHSI8 q9hYZ0NteWW0pgYzFsaqhom0p0g 2020-04-20 02:19:03 87.142.197.128 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=486 +p reject 1-65535 +r Allure 8tCevB8b2Xp+74ltAV1rucaHR1M +lBKbvXAIxfUDo8EoX2pFsDGxSE 2020-04-20 02:32:35 116.203.249.165 9001 9030 +a [2a01:4f8:c17:5851::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20000 +p reject 1-65535 +r anong33 8tbrIRdE1B3EHMtivxwyRtJLQqI DAJdSGY24zpU7WdGuJdrF1RrBgM 2020-04-20 12:24:20 79.244.148.223 443 80 +a [2003:ca:5f1c:ca00:dea6:32ff:fe49:9ad4]:443 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3180 +p reject 1-65535 +r relay 8timze0fS8QspLEWT7bGZEKYvhs iWUCu5ll8Fy+kUDa6jG2lLayXg8 2020-04-20 02:42:43 23.157.160.138 9050 9051 +a [2602:fe2e:1:9:a4:fdff:fea2:d22d]:9050 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13200 +p reject 1-65535 +r AlleKochenKaffee 8t/l+h5M9U+OdhptMEubTsab2ug Ci0/4R8/ToD/QKXvW065WhRRbcM 2020-04-20 07:37:47 129.13.131.140 443 80 +a [2a00:1398:5:f604:cafe:cafe:cafe:9001]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11500 +p reject 1-65535 +r Krombianschniedschn 8uYN4POb6oJrUOthmgFK3Olhk1k OkyWLYvP/patD6AYnyTk2KdArm4 2020-04-19 19:31:03 116.203.117.220 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p reject 1-65535 +r cyberbits 8ufo8wylLPzjXP1fRlpxJO390Xs sTR5YbiW1zMZFK7MOO8SkDgW5XI 2020-04-20 03:17:24 195.154.41.42 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=51000 +p reject 1-65535 +r snap277 8urb2FqKlti7bR+jq5gTSZIOwcc 1wyyKMQS1653AdPzxi4fmPO4W+g 2020-04-20 01:59:33 89.102.239.161 38401 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=785 +p reject 1-65535 +r runninglizard 8u1QMrUgIee627uC5llPGocv/Qk 9/9Sf+OLOBDwRTslLBRrjx0KiFM 2020-04-19 23:30:05 89.191.217.1 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2120 +p reject 1-65535 +r snap277 8vUUdOiepGFQ6Q9kB3qVwkiRZzQ WdTrEd5zjfmfnRIShcTw+BeezxE 2020-04-20 07:16:14 78.214.218.226 32853 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r FlashDeer 8wMX6f0MOlYFiSjWRUBnK1mQLR4 pTYTBv29WJn7ejZA+NJOtcpZu/g 2020-04-20 08:53:17 193.25.100.180 9001 0 +a [2001:67c:12a0:3:24a9:8838:3642:9244]:9001 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=980 +p reject 1-65535 +r snap277 8zUkjzalWFHmm6Y7PTrldiCB/+8 GgoaXhtBdyn9bEHWalExmTlK7JQ 2020-04-20 11:18:16 86.202.144.13 42145 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=488 +p reject 1-65535 +r SemiPvt 80guBGteYR/fJ5r1m3CoioBNFHA gsN83IIhwfJErJ71VWYp7vFzVns 2020-04-19 18:57:05 51.77.39.255 9001 0 +s Exit Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5910 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r kaeferbohne 805oGvgibevJE1pI9h3vn2iWa6U 0YrHpcHDhlwV32hFjKt526NYB5k 2020-04-20 04:39:23 109.70.100.13 443 80 +a [2a03:e600:100::d]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=91400 +p accept 43,80,443,853,873,993,995,1194,2086,3128,5222-5223,5269,8000,8008,8080,8232-8233,8443,8888,9418,11371 +r Harmony 83lYz1dTixDAQcnUZqWLCw6GM34 o5tRybch1f3UguLC5r0iwNuChwo 2020-04-20 10:29:46 51.15.126.106 9001 9030 +a [2001:bc8:182c:2121::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26900 +p reject 1-65535 +r sh0uld03 83mX+JBwhpo0xFai9UV3oydqrLI VLxvqEayUz9IuoBYoV+CtBgfVfo 2020-04-20 02:39:50 46.232.248.243 443 80 +a [2a03:4000:2b:50f:6826:2dff:fe8b:5c39]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11200 +p reject 1-65535 +r 550aca43 84ElGH9efO0f8xw3sK7qcSkmP4I vNXPncYGySkQF5xxEIwa20PQcjs 2020-04-20 08:43:59 85.10.202.67 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=87500 +p reject 1-65535 +r squirrel123 84eYUPnGeXrhSwnqPjhHyynZIyo HKm02H0512eFp6UIuEhWWGCRSMY 2020-04-19 19:02:56 92.60.37.40 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r FlashEagle 84ieLGimc4SMqQlPb0o2U9dpIQk dy9+PXfRfOZba6Tq+vlXJd2H7eo 2020-04-19 20:49:54 46.29.163.225 9001 0 +a [2a00:b700::5:22]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3750 +p reject 1-65535 +r Ichotolot64 84+1WozKagDN0CSl6iz+yzikjhU 4Hv7tLQw3N4VPsvB3V5gRmnMLu4 2020-04-20 04:48:03 91.143.81.27 443 9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16000 +p reject 1-65535 +r Unnamed 85J2+3cnEvaV7hrkYcgB994DIZs 0r5RyeetcyR6COVByoNn1SI/yZ8 2020-04-20 10:18:39 91.219.237.53 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r teeter 87vAiPKA/c2lxb0gYxL+Lfp+LbA Rkvt1ymZCL58wldDq54lbxeNuHM 2020-04-20 10:52:07 129.97.7.34 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5950 +p reject 1-65535 +r king 88fxvI9oSC2FOKDnR26tZ+rDCuY pHxKzUDaRC34LJapo7waSZiP50o 2020-04-20 05:20:33 51.89.213.89 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r TotorBE2 887IftkeCwsdhr5NfekPALYH7K8 p4eEASiqWkeiOvooxNWfP0+1pw8 2020-04-20 11:26:38 137.74.32.26 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48300 +p reject 1-65535 +r totodile 89d1xzvFdkCj6376wxz67dFMnHw 17pgWvT7n3uvxk0lgOU/6ISOkEY 2020-04-20 01:59:58 23.129.64.206 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6700 +p accept 1-65535 +r nott 898kFaXs+1eDXPfmKcOtDh2mcys 5p6+kiaa13lpA77g1ZifQw6GGoc 2020-04-20 03:00:00 95.217.0.144 443 0 +a [2a01:4f9:c010:1553::1]:443 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=32600 +p reject 1-65535 +r teutates 8+seH/RaPN5OAvvU6AXU/DekrVY 53LsLTSEWVHhTn5mTay7rbVpuuI 2020-04-20 09:10:59 37.120.190.6 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15900 +p reject 1-65535 +r Unnamed 8+0QGz8knfZMJw3oWTG/4/tILCA wtb6pyyyFnn7viJ4DY5TH/7J8ps 2020-04-20 07:17:24 137.116.57.117 443 0 +s Fast Running Stable Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5350 +p reject 1-65535 +r Merlin 8/P0kAuHz0prSn+UAlAvxFe3sfw vDnlkZHdD66gvi6bNecMC16dCVE 2020-04-20 11:08:26 46.59.40.218 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7900 +p reject 1-65535 +r PubliusAnonymous 8/nMlV98WZOPJEWR22uymct0Vac YVlMQntGPHz4Ydcf1CsD9FY7bHA 2020-04-19 23:35:41 77.74.96.43 1917 1953 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=96 +p reject 1-65535 +r uname 8/p6Ta/OygK0LiNvvyaPmoIliPM n+yZfU/30O2MsC3HHCkXWi60YAI 2020-04-20 10:01:15 86.57.149.4 1443 9130 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=4090 +p reject 1-65535 +r hulahula 9A5dY4UWlZpvk4kWK+9QUcZtdPg +S3gQdK6e4AS4D2dOwK0vOqEb5g 2020-04-20 06:00:28 134.3.74.103 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=244 +p reject 1-65535 +r TaurNuFuin 9CKTdDsLxKM8gKVCpFHubGSyfek I9FEUwsWchewxEyt62mhKuwQFrU 2020-04-19 22:15:27 188.193.23.113 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=203 +p reject 1-65535 +r pingo 9CSf6Ub5PBuedLBwOU7UYSa0Qmo rZnPcvStNAPad0zocykba0A2tUA 2020-04-19 19:42:07 94.32.66.48 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3100 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,50002,64738 +r EvilMoe 9CYydc9UpoNu571SexMog2pvBuE 8FbZoPHKwo+sryjB3IFK55dJkUI 2020-04-20 02:16:20 37.187.102.108 443 80 +a [2001:41d0:a:266c::1]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9470 +p reject 1-65535 +r fromrussiawithlove 9CtOq8MOtLpln/W7bInNf7sOJyE ccnyoZ7ZPZAGnJCkAloCpnnZGeI 2020-04-19 23:49:46 82.64.170.201 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6 +p reject 1-65535 +r ididntedittheconfig 9C4jSNZgL1K4VjHKbQm8VyvvdkQ PVLnvcnZo27UOgKachvXAvGA4HY 2020-04-20 12:08:02 78.63.158.220 443 0 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=22 +p reject 1-65535 +r snap277 9DEhs51YuTUzZ+Kn3rmI1sIUmBk sNVJHGe/DoNY2xq+FLgP7bdFdjc 2020-04-20 07:50:05 92.206.0.157 39419 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=228 +p reject 1-65535 +r AnotherRelayOnRPi4 9DGI2umj8ixkPNe4s8j+25OqjhI DTDpQ8ZCiYMyHZLqsoqZ132xJQQ 2020-04-20 03:02:51 93.237.150.200 4321 3210 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5360 +p reject 1-65535 +r hacksenkessel 9DxJcDn4Nv4y3kFvTL2XiSw/bp4 vBpxvP6QCN8VwooXpgYwjaqnSw0 2020-04-19 23:10:53 85.25.133.34 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5700 +p reject 1-65535 +r Unnamed 9FLC/efxgki7kEjoOh5/TYZYJTc yaAF74MVTcPZNyeYgGYy7TkVBmY 2020-04-20 11:01:54 185.9.19.83 61584 38495 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=137 +p reject 1-65535 +r freeKleptikov 9FlGCCcsgkB+nRN/GuiaQIzP0oU vdW2OCdukLsah263+WdEo1d+JcA 2020-04-20 12:05:58 77.247.181.165 110 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44000 +p reject 25 +r snap277 9F3+KMuIWhocy+oBuLXNankrQfU lN4votGQUrKWdWaF96Kq4GthxZw 2020-04-20 07:48:44 109.186.3.113 34899 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=177 +p reject 1-65535 +r origan 9GhU7azNFoKP6q/Gxu3cB93wRBE FiwRZm1uJ8NcEJTho5Y0UM8qP3w 2020-04-20 10:20:54 178.32.222.127 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=2290 +p reject 1-65535 +r 0x1ea7deadbeef 9HXlmH5EorexQ6K+4/gSju/X5aM AvpeWqKQ46857mZ5mGJ5eLZACNs 2020-04-20 00:31:46 188.68.45.180 9001 80 +a [2a03:4000:21:47a:de1:ea7:dead:beef]:9090 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12500 +p accept 23,43,53,88,110,143,194,220,464,531,543-544,563,902-904,989-995,1194,1220,1293,1500,1533,1677,1723,4321,5222-5223,5228,5900,6660-6669,6679,6697,8082,8332-8333,9418,10000,11371,14265,50002 +r Elenagb 9HsTv85O9Ize9sTXx6mSCOu5crU Dd3ch/60iwOnTxXbeNcDnIM9HTY 2020-04-20 07:43:14 185.233.100.23 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4900 +p reject 1-65535 +r IobnidnNvfXBcnP4KMf 9ITpAhi0vwuXjAsUbYZp21W57QE 37cW5kyB0stLWDCphh5+7mYJkSI 2020-04-19 21:07:11 98.165.46.62 8443 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=40 +p reject 1-65535 +r Islay 9Ic7PsMyW4HcNsfjitOl7RKy8zk iROl6zNAwOwWVVg4M2gYoDZVaz0 2020-04-20 08:01:01 37.187.23.232 80 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5370 +p reject 1-65535 +r SkynetC2 9I/RrtBoSW1R0ThLx0l8BOSYXaY pOixF6TXvUIFJ9FE4tA2xWbJh5M 2020-04-19 20:30:13 78.156.110.135 9090 9091 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6670 +p reject 1-65535 +r Kale 9KN28tz0Ck4UQXwHo+xfmqg+QKA /fRznknvx2gdR0BS4W5IASvq+WI 2020-04-20 07:33:57 46.19.141.83 8100 8000 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1220,1293,1500,1533,1677,1723,1755,1863,2082-2087,2095-2096,2102-2104,2374-2382,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000-8100,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r XtorX 9KTXjxbpoDU61bvvRjLHAi4g+yA K4DIU8Hx4jpv0zm3maoUwKCQk6w 2020-04-20 12:48:59 51.15.54.71 9001 9030 +a [2001:bc8:472c:690c::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23000 +p reject 1-65535 +r snap277 9KTkPbFFrmaMeKUiWALwSo33hOs dAdpY2fTcqAXsiF1/4nJVUO+uPs 2020-04-20 09:15:05 184.152.24.178 37341 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1020 +p reject 1-65535 +r HeirloomReaper 9LLDDX7nCNUSkUH3eWrP0RsBZfM if4F02i5AY/TOieFLaj42OdYW8U 2020-04-19 22:23:51 139.99.218.3 9001 9030 +a [2402:1f00:8102:100::497]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=259 +p reject 1-65535 +r nickname 9LmjhuON1sunwsZEBiMowZQNOzk 2iW54RAzGfreHfL8Lk/JdA3jkDo 2020-04-20 03:01:24 87.78.133.154 9031 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2950 +p reject 1-65535 +r eclipse07 9Lq9ql2hFd4SLeQVhxLVPXRQvGU oBj9u+RAR8uYHcBc5IF7sRvCaG8 2020-04-20 11:56:39 81.16.33.35 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3160 +p reject 1-65535 +r tornodenumber9004 9MDtqgvw9+wTh0b4/vHOJseGAmU lq65kwUM8mrzXhCaaQUozhGdcvc 2020-04-20 10:52:48 5.199.142.236 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5500 +p reject 1-65535 +r 5672345 9MOwY0wZVuzxQqGFWg/hOpPHxTA 29mwt/I3ibyhl3CjrbGdEy6joog 2020-04-20 09:16:13 94.158.244.32 443 80 +a [2a0a:c802:0:1::1f]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5800 +p accept 20-23,43,53,80-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r yawnbox 9Mg2onvxkvM2SmcWbo7isZaTrtE S0te3481QDeH8XW4ZcqZRVoanDM 2020-04-20 00:32:17 23.129.64.197 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8600 +p accept 1-65535 +r snap277 9M57h7Zreq9bDonQU8fLzrVhZi4 XuA8VEf6OAsIhly+Bhr7r/FjxJs 2020-04-20 11:05:10 108.54.105.201 40559 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4440 +p reject 1-65535 +r romero 9NP70eSRiXjR0TYEeYzste5ckYg zOsDYPw+z73Okg+7UlXLTk2feYs 2020-04-20 11:38:28 185.72.244.37 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5120 +p reject 1-65535 +r IQOnion 9Nbpir4GWA+KNTRwZSA33YZFtHQ pkiS6YBmuDK+OBzS7ljRhxnAhjs 2020-04-20 10:02:40 50.193.59.193 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5 +p reject 1-65535 +r puertasecreta 9PYFqiHEYzzLW427wc7uXFkMbc4 NptL6bgMWgOaxa/ix6AcSvFh4y8 2020-04-20 04:29:54 46.231.93.216 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24300 +p reject 1-65535 +r KagamineLenWoRd 9Pkti4QMLQUxl6w++cWPPc+7IP4 gudguhPkPTbL1cnYbx9lju19vC8 2020-04-19 22:19:14 91.121.86.59 993 0 +a [2001:41d0:1:8b3b::1]:993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15700 +p reject 1-65535 +r Unnamed 9PuagDCK5xyoBX9BWN1rPI7jdfk KqqRca5lcDg8DA6+5L7bw/tpeHM 2020-04-20 00:53:39 199.15.250.210 443 80 +a [2001:470:7:b74::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8980 +p reject 1-65535 +r madnight 9P8q9ssFIkuuf8hEQQEIidCMtS4 83w0Lz9H6p0SGu9YXYnuipyHgRg 2020-04-20 09:12:41 195.201.103.59 3333 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13400 +p reject 1-65535 +r SwissLove 9QMWeTKexKBIy6U6ZQgQUGMv1uQ Kbb89L35DLqFcHchukkz5R7G07Y 2020-04-20 12:49:18 178.194.3.223 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r king 9Qq6Jsci7lLw5O9rnktzgGVb+TQ 2jISswCKX4gczXT7mJ9qUa05toE 2020-04-20 04:38:30 51.89.147.66 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7500 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r flowjob02 9QzwKg5qnZsl9+siD8Jve9G3SZk TKOntdcmIu+8Wq6bQ39l/pIet9I 2020-04-20 01:59:42 91.132.144.125 9001 9030 +a [2a03:4000:37:2c4:48ab:3fff:fef7:4fe8]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36400 +p reject 1-65535 +r angeltest26test 9RqSfjRmLWAFOT8jJ8hw+w0Nf+A HzseVu+WR1iUo2yjZtwkM3YKUdo 2020-04-20 02:00:22 91.243.50.239 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=143 +p reject 1-65535 +r nodvrelay12 9R2hF0vcrf1Y6py4ft/AHda2Mu0 ceD+TL7amqcUh1WZBYRKHUcc+Bk 2020-04-20 08:35:16 45.62.235.224 9001 9000 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=660 +p reject 1-65535 +r Unnamed 9SE6ralaF8B3RRwJEQBYQH8KhfM bPCpZfsLDSpUbmManOeHOVGw4sI 2020-04-19 22:13:43 46.72.31.116 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2400 +p reject 1-65535 +r Bob 9ShjHJnA5VJbFXV9rtMsjST9kyY ao2sBe/+RAuZdc0ksDGKzI6cSbU 2020-04-20 01:22:09 129.233.217.29 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=8330 +p reject 1-65535 +r tdideditheconfig42 9SuMd6xYhVZsBuWtszpaCcXotTQ o4XoMpOpCt5GX4fkTOUx9LbgHR4 2020-04-20 12:42:34 144.76.42.143 47193 36819 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=7380 +p reject 1-65535 +r tributdotde 9TWW1/xBpjn+QQxqH5sjqD94PGo FsoOG7sqFnlGw90DppdkmZhkpqk 2020-04-20 00:54:28 5.9.121.79 20 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1100 +p reject 1-65535 +r snap277 9Tqgkc83lgRzFxKdB3ii3q6ViL8 LyupVG5V3vP2K/9RgzB2E+0gnq8 2020-04-20 09:42:05 90.2.231.10 35701 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r smell 9TvkdsoFm2jTuuyE1AV3TFD3miU hNgDY9k32pWFHMMJMNILQxA7NEk 2020-04-20 02:03:46 51.178.191.132 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9090 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r Wildtwister 9V6GatTLALZxuKMVrTqSibbowCw ku750DsNR2MlYyB77GgG93a1TeA 2020-04-20 09:01:57 94.100.6.72 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=8770 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8232-8233,8443,8888,9418,9999-10000,11371,19294,19638,64738 +r Unnamed 9WMotrGY9WP2VmAoZRNzc89ylbo 92fVPH5jHkvnxD9RmDlX26GAKYc 2020-04-20 11:11:45 158.69.172.224 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r erdbeerkuchen 9WyzP3WoRuxl8sOFWhhevQHR3zE K2iqFs1WS02STsFYSVQJURxqE7I 2020-04-20 05:54:57 116.202.18.167 9001 9030 +a [2a01:4f8:1c17:6675:e661:3ff1:a713:3891]:9001 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5040 +p reject 1-65535 +r Hijnn 9XRvYlff6H46kHU8KgQ5kmxVVS8 d/72XEAgnNtaHXgvpzHTnmPewRU 2020-04-20 08:23:25 82.169.130.61 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4040 +p reject 1-65535 +r relay653 9YANOwDmLUk8i+5oLDRCuBL9Ul4 cu2LtRBKBbq/5uQsGLlCWuj6sNY 2020-04-20 09:15:09 178.17.170.244 443 80 +a [2a00:1dc0:caff:16f::ca35]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10700 +p accept 20-23,43,53,80-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,981,989-991,993,995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,19294,19638,50002,64738 +r hittibuumi 9Y230XWuMZJBHL4+qekmMuzvvIU uQ36X07j1vamVsqizzyRePFfWwM 2020-04-20 10:36:37 95.216.144.113 9001 0 +s Fast Running Stable Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=15000 +p reject 1-65535 +r EF 9ZWaHxFUgH0+Uah7zcpuCWNTV50 9UUiHqTmknWPP6i2STnIRnX7JH8 2020-04-20 06:54:23 5.2.54.152 9443 9480 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=359 +p reject 1-65535 +r T0rR3l4y 9ZowMqeuY3aH6ZQ3ym2oHTWHoOw VKF4XQtuwc+e3Kt+T6zz+mDNC5A 2020-04-20 05:58:04 213.195.105.95 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1300 +p reject 1-65535 +r bistrv1 9bWP7kRXPDv9fRdtkYultAV1Gdc nKlBcNx5fVd3qQOhidtvGgNlRtQ 2020-04-20 02:00:18 212.47.227.71 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r UniGodPowerz 9bmpiFnFv+ft7spowASiT6Kc47M TfbdEvpSBBQgcAFq0fym2F6hHoA 2020-04-20 12:34:14 94.100.28.179 9001 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1780 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ansarelay 9cLrV4uYQgad5WDwD4CLa9NVTio 70vP8l7wA1OG1hdBq6jqskTGgr0 2020-04-20 12:08:08 91.145.123.22 993 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=285 +p reject 1-65535 +r FalkensteinTor02 9cPadkK7A34NJ5NZrojNf8A6mKA TYdrH3Iw93Li3W86vfce03W8V2s 2020-04-20 05:20:09 5.9.43.211 443 0 +a [2a01:4f8:161:32c7::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=45000 +p reject 1-65535 +r Vleiv 9dHAtMHSifo3BIgHXGCOd2E03ZQ RhXXcofbnAHHbQHiRFZutpwvA50 2020-04-19 22:44:45 192.222.248.219 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1200 +p reject 1-65535 +r mitropoulos 9duOM/jTUbYAkyJR7+ZzV0hUBfI /q7SeuSsbybaWfqHl9tKkgHuDjc 2020-04-19 21:37:20 212.83.61.218 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=34000 +p reject 1-65535 +r NEWYORKNEWYORK 9d2pMQ5ZfN6e1HrZ7dU9QAjlPBw Yj3mFjIf/5U6ZeZV1EBKzo8N62w 2020-04-19 22:58:55 198.98.59.161 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4600 +p accept 23,43,53,79-81,88,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r trustn00ne 9eG5a/5wD/i/Cd5aAhgeu0jiGPc +fm+nBe1asx2UzH6gP4xtcZn6ds 2020-04-20 11:58:25 87.248.7.41 9003 9032 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14400 +p reject 1-65535 +r Boedi9Berlin 9fJ/JukGZ4KNA99qoD++nOpWHnY 4HdotQbdyNxf9Xzx6fwPMAvYQpY 2020-04-20 01:58:13 89.14.63.243 32588 0 +s Fast Running Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=144 +p reject 1-65535 +r brooke 9fQBlQkQmgfpDEWgIs7tnsoWQ8g numTPlHjqtzspG9kAyohtPMe3QU 2020-04-19 23:15:40 176.9.1.98 8080 4443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=91000 +p reject 1-65535 +r Unnamed 9f51aHqmeLCvsTmcScJ6yzaxqNw akxIcyM16zobYlg5PPmeUlDHE3k 2020-04-19 22:06:02 118.243.156.49 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=421 +p reject 1-65535 +r oromis 9gQTHcxDA+UduHagF6PcloT9Yms XfBA5WpF9HGNpn/ONL12kdWvdLw 2020-04-20 10:36:06 217.112.131.98 9001 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6670 +p reject 1-65535 +r Unnamed 9jsXWdirnI2PHmBiUIYIL/Op19Y NluLy7ERF3Lj81E/BkJ3BD4Nwc8 2020-04-20 02:49:47 20.46.40.75 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=696 +p reject 1-65535 +r slalix 9kHwQ9UM76B+5B6yhEZkWHiICO0 LmmCBAdWMs7/UpZItPVA7glhtdY 2020-04-20 09:18:49 51.15.105.214 8443 8080 +a [2001:bc8:4700:2500::90f]:8443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15000 +p reject 1-65535 +r Unnamed 9kjI3xGKtEjQyJr2xW/1eRCy3OQ 66RHa5VN0QE88SLT40+L21vkqXE 2020-04-19 20:17:12 52.229.156.42 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=160 +p reject 1-65535 +r tolgerius 9lDAd7uJLhz7D0BjEwLa3Idmeic KzOg5my6KwE4j0lxq+naM6HGhaM 2020-04-19 23:57:42 164.132.43.57 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16800 +p reject 1-65535 +r binaery 9lmQwjqwF6w3Im6yrT2lqOrlXQw mHDqA/maIQGpIIAe7t0ImGhN0vA 2020-04-19 16:35:25 91.204.44.129 443 80 +s Fast Running StaleDesc V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12600 +p reject 1-65535 +r Kobayashi 9mPKInt9KzyFVvfdv8ZlOgEKLE8 RsH3RwQRk9sxy4itQgdwZ7jNpb8 2020-04-19 19:26:30 107.189.10.20 9001 9030 +a [2605:6400:30:fb32::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3500 +p reject 1-65535 +r anotherRelay 9mkePrfKs8h2qqiF5oAbY9yZjDk GlwdEoAbYVhS+2UXQbVJ7fI7e44 2020-04-20 02:33:39 144.217.4.166 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11400 +p reject 1-65535 +r poiuty 9nQN6r/V9iYS+gJaUHnqcoRrH2c EAXqxY9psEtbUY0rOvIGEyLVX7Y 2020-04-20 00:52:01 176.9.45.244 443 80 +a [2a01:4f8:150:61e3::2]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=91000 +p reject 1-65535 +r Unnamed 9oVv4tDMZXQQWlXb4ahVU5WxI4M GOGobFsbOy9GL8k4PefUKoldYKc 2020-04-19 21:43:01 163.172.41.242 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22300 +p reject 1-65535 +r CalyxInstitute16 9op2Ui01b4m+woaImjgiJQVnvi4 kJ4xMOo2meplV6IjtFipZovwt0g 2020-04-20 02:14:17 185.220.103.4 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23600 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,12350,19294,19638,23456,33033,64738 +r yesieditedtheconfig 9o56BKLgN1tXu8DSeU/Nld3ryjI RQCfxkz5rWY7GJGI+9P2mU7dXrk 2020-04-19 23:38:23 176.9.154.247 9090 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5800 +p reject 1-65535 +r Infiltrator 9pDgKE16uqIjF7yHFwxnw2rpUKg oMJVDr5zsl0cD6gp3QBGSn8YtKo 2020-04-20 12:00:51 82.165.206.196 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=69 +p reject 1-65535 +r prawksi 9qNY3TZ7MoLW71gkydReGhnH6BU OjQNDee1jszTAFUXJuqiUtg77r8 2020-04-20 01:28:00 192.160.102.168 9001 80 +a [2620:132:300c:c01d::8]:9002 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12800 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r ifigenia 9s1Nv1hQrEOG3ZpCSRitPGuicW8 /QpnvVxLqyKaoVdcehsAYogBMUw 2020-04-20 11:17:58 5.9.98.43 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=55000 +p reject 1-65535 +r interfesse1 9tYAzxOzu+KpGgZT8eydAOfLOms M/QW3fdN1KdrMRN08cjnJotNY+o 2020-04-20 08:47:09 85.195.208.94 9001 9030 +a [2001:678:d08:b01::42]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26800 +p reject 1-65535 +r depwnparty 9t0A8ne3QeT0ohZTJHbYR2uY2Ww lTkhWQzKUPr5bn1L74dV2ic3QtQ 2020-04-19 23:21:49 209.182.239.70 443 0 +a [2001:470:1f0a:2bb::2]:443 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=1240 +p reject 1-65535 +r JPsi2 9uxGkzzo1PrVzNqoscWjd2hfxSE wWdmGofgv6XnGKrubTEtxGlpoio 2020-04-20 09:51:11 37.200.99.251 9001 9030 +a [2a00:1158:3::1ba]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16900 +p reject 1-65535 +r hviv124 9vWbZLJJTymJnoByvLDms+BwqRc FQ/P6WX/qsw1nlSkPZ8De/h/3BM 2020-04-20 09:40:31 192.42.116.24 443 80 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638 +r dragomir 9wJiRoI8YyKSHzq4dTfrsCCrAeU unfy2WIKWby/UFMK0BvzWHeYD/c 2020-04-20 06:54:55 45.249.90.26 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=155 +p reject 1-65535 +r Visenya 9wPUWZg4dc6c7Wr3R4ill+1mJnQ MjMoRtxhmGWoFJE11OstnmkdZvk 2020-04-20 05:00:34 45.137.155.64 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11300 +p reject 1-65535 +r wedostor 9wt8XNctdMf58tyE+p0g1RuhNhA 6GUmm+36iIXFi2ug+AO/OxeGVIE 2020-04-20 05:22:54 46.28.109.231 9001 9030 +a [2a02:2b88:2:1::4205:1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8930 +p reject 1-65535 +r borisman 9xge0I4aLlZBBcNiCvoNeKEx9OU vJwM5vfPUfHES/7jUXsY9HB1iKM 2020-04-20 10:00:27 198.84.210.103 6882 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21 +p reject 1-65535 +r Motoringo 9yOARZyUdsDi/JmjR7bZRB9oHyU Ay6D/KQHU9VOq4R6Vsjo5QPQ4Rc 2020-04-20 05:41:05 187.244.191.9 9001 0 +s Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=42 +p reject 1-65535 +r C1karin4712 9ziw2KxEo/1CcZO+uNDCG75M1vM 7/rh8R/tRsKw5q2pt4uHgWi9NUg 2020-04-20 09:59:46 83.209.9.216 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=996 +p reject 1-65535 +r rofltor06 90HlEkyxJwDalGt4ybLdF11s0qE 8PXDk3SAk5m+srrz2siXvyjltoI 2020-04-20 11:04:55 163.172.154.162 9001 9030 +a [2001:bc8:47a0:162a::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21300 +p reject 1-65535 +r tor002 90JLTH7twXhKVQVoju+tW+6nufU 8m03+RkDxCHfYdVDw+TaAiS3mQs 2020-04-20 00:35:58 18.162.153.59 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=507 +p reject 1-65535 +r Unnamed 90L8Zorj/u5HiXHcoIuetGFK5kE LEHkfIgtCCq2GJ8jZ9a2gtziJDQ 2020-04-19 23:11:09 192.95.27.143 110 143 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=57 +p reject 1-65535 +r QuintexAirVPN1 90R+metcvU1euRPuDjWsZCtcHvM 2tN/wOR/xB+cL5nArM5JmFPLJss 2020-04-20 01:07:51 199.249.230.120 443 80 +a [2620:7:6001::120]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17400 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r PisMightBeSlow 91VMjcV7rsjBHHzjtmZiMO6QTw8 h9n9yvmWIDCdHXAK+YIRRbNuB10 2020-04-20 11:52:25 98.124.111.29 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9600 +p reject 1-65535 +r TeleMishka001 915H+8rPmexGghudD/XTBzOLEbY Y5iR2f4m0HceNDzCH2jngyzarQw 2020-04-19 22:31:04 71.182.155.144 9001 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=873 +p reject 1-65535 +r snap277 95b58acjsZ5l68uuj4/yFNGDzoc ZsOnQdr1b4vQEuAMIN8TU8mjl0k 2020-04-20 08:34:45 92.90.35.50 46201 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5 +p reject 1-65535 +r ponttor 96XJa7y7Eccrb6iKt/wyztuZHEM ZNQJEIdWX9ck5W4qU6xHAjhllrQ 2020-04-20 01:19:42 134.130.181.212 9001 9030 +a [2a00:8a60:e011:e1:b870:2400:35c:4592]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24200 +p reject 1-65535 +r relay0vpsfree0cz 97Ak2wLGARhcIC4m3/0q1SXBajY DgZwH6Ny6qmqnnIykGuvEDInHZE 2020-04-19 22:49:37 37.205.8.191 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=28900 +p reject 1-65535 +r 2600cityoflondon 97pMSQ73cgDbNe5130TqxU2mXXk CyXc4x+54ywD2jf/5l5Zi7XzrMs 2020-04-19 22:42:01 85.119.82.138 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=18 +p reject 1-65535 +r snap277 98EDGsXZfVLop3x/WO8/6MkUMew 3bXPRilfhaQzzJHSoIAv2DaYPz4 2020-04-20 02:56:34 92.52.6.135 41475 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3940 +p reject 1-65535 +r peterkofodmedsko 99PviIVB3eJG029OfI6Q8kYYkQ4 k7eOSOz59T1TgjWo4aak5SqRdeQ 2020-04-20 02:14:36 5.9.61.207 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.1-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16400 +p reject 1-65535 +r LIDSOL 99r6LZH34KgcmH1l6QYrZcxN9mA 6llmNI3numGtTOoiIrC0rg4fsXI 2020-04-20 04:55:00 132.248.59.72 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2500 +p reject 1-65535 +r MGoBlueRelay 9+rMr7VL6kMa+6aU1mlS2bXuKJQ jMlaRY0CL3hxKIZin/L/o4rwgkg 2020-04-19 21:15:37 50.4.127.14 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=540 +p reject 1-65535 +r snap277 9/B9ICI2iAR80F9ZyyRpxNOLiLs ik+MOX6BvABucNvKZZnpSKvPX0Y 2020-04-19 22:07:46 86.137.230.210 33024 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1930 +p reject 1-65535 +r TARS +A/eJ+/LP2p7TizFFxM9v/p4ui0 vYnS9Pex61b27K/bP5NDbA8ce4o 2020-04-20 08:41:32 213.183.48.84 9001 9030 +a [2a06:f900:1:100::53a]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5020 +p reject 1-65535 +r robcook +BXSpyDJf24bykyaNsZMrU3C+uo mmIXV+TawgipwvYz9PcSfVgj+Is 2020-04-19 20:25:38 139.59.8.134 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=739 +p reject 1-65535 +r Unnamed +BljwK6QiC8SRTzqV7JuZRv0OxA 73wZ2b8rYEMExbbPUAJ91rOl+/4 2020-04-20 10:36:21 104.210.157.234 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2940 +p reject 1-65535 +r IPXORELAYFR01 +B9j/fa1ZtY9OhES/J0+odOihdE fHXC5sGdR6dwtl0rBmgscXprRDM 2020-04-19 22:12:38 185.10.16.108 9001 9030 +a [2a07:8dc0:18:0:e7:e3ff:fe73:8a02]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2180 +p reject 1-65535 +r informationalley +Dpk4PqFvCJIB5GXcv4U4boHzvU Zo7kK2s7MyWGCSbAsL/rX8QajEo 2020-04-20 00:01:00 178.63.85.14 9001 0 +a [2a01:4f8:121:3431:4c84:c8a5:4c2d:c9bb]:9001 +s Fast Running Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=44400 +p reject 1-65535 +r Gateway0x91 +EO3vj3bRKqSjkxKzkhJ60rm7vI zmRMqwqoL9FT9tJWnj3OrpAm3y4 2020-04-20 12:32:15 77.255.156.222 2020 2021 +s Running V2Dir Valid +v Tor 0.4.3.3-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=86 +p reject 1-65535 +r S4C4D +Fq7WVhnH1A1+5E6SmX5EMCZPM8 0L45cLt9SUDGgB+c/0BG61q7pBE 2020-04-20 10:36:02 176.114.248.176 9001 0 +s Fast Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4330 +p reject 1-65535 +r BIGBEAR +GMnW21EXi5Tjg4vTE/qSHjistE RBwbUGjjfEaGvy3TZDD6gXY+TGA 2020-04-20 05:08:31 78.94.185.115 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=626 +p reject 1-65535 +r torushopyard +GS962bIoR4glFaEZJnC+ZVDV5c 2Dk/jWRbSaIMOxrvupArbjxezgQ 2020-04-20 03:57:04 73.241.193.203 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=75 +p reject 1-65535 +r default +GrGVXqhSRGCYn18s4Vc1i0T8mc DFX1/Xx2wWe+so6WMG1esDYGCuA 2020-04-20 10:31:10 114.174.0.5 443 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=303 +p reject 1-65535 +r Unnamed +HjjrVlPATGVoFHNEHK/M9VDojU P3wBQBckzxA7BUEotKrRWsnMi0o 2020-04-20 12:36:56 51.75.162.173 1999 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=15900 +p reject 1-65535 +r Chrysophylax +IM9F1ZCwXxQuFmppVfaRSlYi3o 6s7qz5DHA1erwhKwi83qP3XY+f0 2020-04-20 09:53:20 47.14.68.1 9001 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=140 +p reject 1-65535 +r bwanzie +IchsNGENhrSSxTP1WgygkoOefI Lz7d2J6ImmewqIbsOrKMsdMOVpc 2020-04-20 09:17:59 68.183.163.215 9001 9030 +a [2604:a880:2:d0::23c6:2001]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=680 +p reject 1-65535 +r Unnamed +JV9YeKaYmQAApoDpjSEAOdQJgQ BJ7SqMo6bfYlWD15QCZ/aeQW264 2020-04-20 05:54:41 108.161.139.183 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=560 +p reject 1-65535 +r grahamstaines +J/mAEu7wkvBd+FSuny/3isUVGk JRZHLSAwF9me6+RiD7mGTDL4mFE 2020-04-20 00:33:04 139.59.15.218 9001 0 +s Fast Running Stable Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=679 +p reject 1-65535 +r angeltest17 +KqNjMugxfKDbeYxXN+m5KMaCJA 4ZDSIV1mQ4kIaS7zqHSQ9pywSFo 2020-04-20 03:23:47 5.34.183.29 443 9030 +a [2a02:27a8:0:a::197]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12900 +p reject 1-65535 +r niftyguard42 +K6iglYp5Dg1mf0qS9V0DNEyLLw q1JPUjd9D13sgIgY5kt/NJ00iLE 2020-04-19 22:15:49 185.220.101.161 1161 2161 +a [2a0b:f4c2:1::161]:1161 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18600 +p reject 25 +r TheBlackRelay +LEzsoWnjn+vilTyfBU8jGCSB+I /CYGfE6JiFQdrHdZdM+pNHuyGEY 2020-04-20 06:11:50 79.52.242.65 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=62 +p reject 1-65535 +r nopeoutofhere +Md8FcFOBodDl6DVCNLS9Eew+jE 4aaGBOBveP1L0m85hNiCmxb/lOg 2020-04-19 23:33:57 95.164.49.150 443 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2390 +p reject 1-65535 +r firlefanz +M0HNgKFPrepBGle5+gnDjD0xHs JFR2GHnYQnIdodvASXNDzcXoLao 2020-04-20 12:24:08 62.46.205.208 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27 +p reject 1-65535 +r fluxe3 +NJ7FjuSR7Iyou7mjdi2mGlcKN4 1ocSU9TZLJJFnf+DN4EpKBnMlvo 2020-04-19 23:51:21 78.47.18.110 80 443 +a [2a01:4f8:120:4023::110]:80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23900 +p reject 1-65535 +r d3435c6c49af +NqmLBErKsfzzvAg9EeR60P0t58 TbUaZ824+9UBGSCrX25ZhMrDdPo 2020-04-20 07:15:59 51.81.254.28 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r flo +N6BMuWZoZTiDdtzivZKcgDNWUk 7dsWQ8EjEc/5dwoiZd3KitdO2gQ 2020-04-19 23:16:45 144.76.196.92 9001 9090 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=120000 +p reject 1-65535 +r k0nslNET2020 +ObkAwtugvOxUcO49cO6Men9QtI aclhtIV5Wl2olLIBMpyIxIlSK24 2020-04-19 19:06:12 192.227.215.192 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14300 +p accept 1-65535 +r niftyleithia +OnAw6S2HnWZqnoj163nflurJmM mf4w9LqWL9gJYmLxB4thbTX06ds 2020-04-19 20:26:30 185.220.101.8 10008 20008 +a [2a0b:f4c2::8]:10008 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=37200 +p reject 22,25 +r JustForFun +PIbGSWS4Nn5cSPI94T30JGNdmE B+ARGWzM8lUlGfeVyOq5RwQf2H4 2020-04-19 23:31:52 94.21.138.134 9001 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13000 +p reject 1-65535 +r Unnamed +RLAow3Jy9TnulZsI12hlMRiPsA VRtSeZ7JnpISIZEJJy/SvNFG0B4 2020-04-20 05:03:28 106.104.37.220 443 80 +s BadExit Exit Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=65 +p accept 53,80,110,143,220,443,993,995,3128,5228,8332-8333,19294,50002 +r Feidhlim +RkxwlNDwbBzZBtcRtK92/4EufE SRNa7kiT5vAqNrS9v8iq8+E4NO4 2020-04-20 10:24:24 188.192.138.7 9029 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2700 +p reject 1-65535 +r avarnerdotorg +Rmgy0kNoSu4w0wnP9dl+jLGnlU 9FjYsCuNfBn5Obx1dBTHJtUJsx8 2020-04-19 19:15:35 23.235.6.100 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=89 +p reject 1-65535 +r Freebird31 +SRt7ytlOAcjbaE08q6rED1Yq/4 gpYkZrD2WRq8RRrcGSSHc3zT5PM 2020-04-20 04:45:37 91.143.88.62 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14700 +p reject 1-65535 +r TorRelayHemdal +SgZ+bdL30OPqdouAWPDobRLDOo sfsfMHuGXT/MtiiaaqqUpaxHLcQ 2020-04-19 21:52:27 95.80.10.222 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=780 +p reject 1-65535 +r mountie +TVjP5B1BsMyfJzuK385pUuIw3U ETySmMPSlUVR6FFNvnt3+4E++bo 2020-04-20 04:16:21 91.233.116.119 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11900 +p reject 1-65535 +r default +TXaVC8mJ1GPCZNNa/C9rNcMgpo +SvsG3ePQV0LhaJ3YR366DB9oXc 2020-04-20 06:39:57 77.37.140.23 8443 8448 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3410 +p reject 1-65535 +r qwertyforceru +TnZGmQFpCE+z0aMlws0fJLNuAk gUrmp/g00pCDo2qgIivmVTqPyS4 2020-04-20 04:47:56 185.128.214.125 443 0 +s Fast Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=998 +p reject 1-65535 +r TykRelay06 +T2PN+NcOQvK2fkGnhMIW3RewhY uC4cXnYzFAsJz30A2U7cQvWAAoE 2020-04-20 10:09:17 185.96.180.29 443 80 +a [2a00:4820::185:96:180:29]:443 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21500 +p reject 1-65535 +r Torroncino +ULuc/G445El9hf6hegOTJ5UCi4 2qrURFZ0DTA/P0BzsznhzJHQiys 2020-04-19 19:45:10 151.52.223.45 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4510 +p reject 1-65535 +r kramse3 +Up7rF0ePZNyQ3FB4QaVpiW4tTM N9fX1s/IeaLGdTFM1K8q10zNmo0 2020-04-20 06:08:26 185.129.60.131 9001 9030 +a [2a06:d380:0:3065::131]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=55200 +p reject 1-65535 +r resistberlin +U4tSPLg+DkgyJPk8Z+FJRE1CvU bc5+/tv6HBmyaxxdWXjESdsFJJg 2020-04-19 22:25:59 46.89.209.94 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2070 +p reject 1-65535 +r Anonymous +VZYipnzIyJ89RwVrvU59u8PQpI PsheId6tqUG4Th6txC5MR3SpSSk 2020-04-20 12:36:40 212.51.158.110 9876 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=16700 +p reject 1-65535 +r sanchez +VnL3jQD7UeDVfYoG5bUdmhPQWw +25anZw7Jx2R8TpALbToKklk2UE 2020-04-19 22:15:25 88.208.121.78 9999 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=249 +p reject 1-65535 +r namedrelay +WbMYlIqT5xILLVV1DJJqYdEE9g wzExocTP9Y4UGgOqNpNVCuEqEYs 2020-04-20 07:21:52 167.86.110.254 443 80 +a [2a02:c207:2035:4794::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=19400 +p reject 1-65535 +r Aloha +WdPRaJcqpd+e4coB+CgcMEh9fo qSks7EfOVojv2EYW0Dqtuo58DP8 2020-04-20 10:25:15 95.211.136.23 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=59000 +p reject 1-65535 +r TzBakery +XhrgCEqP0/6+KJf2im/MbuHbuE 75ILGgvbPspMPp2WVQvxUN44BK0 2020-04-19 23:04:41 45.32.194.229 9001 9030 +a [2001:19f0:6401:e16:5400:2ff:fe9a:3bc]:9001 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=35 +p reject 1-65535 +r torlux +XlxSCQN6sRt6+VRMdUZH5JjSRI H3mLyBNY+JCJbJSNjP+inGVrnCI 2020-04-20 01:10:54 210.54.32.93 9001 9030 +s Running V2Dir Valid +v Tor 0.4.1.9 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=53 +p reject 1-65535 +r sbyfuc +XqTGvztAXso9JFZGl7ebBc3bLA KSPmTizHlMEiPfbVbuhlgNQgxf0 2020-04-20 05:26:51 172.96.228.119 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1800 +p reject 1-65535 +r byrnes +YPSN5sQ5tUyXuVjBuWSLS+5gsk fovVMQyCRHaFjEua4OHx0XSgKv0 2020-04-20 04:02:00 49.50.66.209 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=192 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r MarinAsagi +Ypw5UJ7/xEWQAEfeuMeU37PHdI Mzjp8gieWOjXjQQd5CZEk5LQaYY 2020-04-20 04:58:04 23.239.113.101 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=880 +p reject 1-65535 +r torproxy01 +YzkADF5XTcENlAZ6p+KxWrimUs dHDFjxmJyDklsc4tHsvF5ngtcMM 2020-04-19 22:08:47 51.15.80.14 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=54000 +p accept 20-21,43,53,80,443,873,989-992,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r recodex +ZEM4qPp1Gf83Z1SKGlboYJ7AQ0 ExHt0V+eG/VTO26kgmDPON799Xw 2020-04-20 12:31:52 138.201.132.34 993 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12400 +p reject 1-65535 +r persephone +ZFPvtUMmjx6LyIvwWRjKGfASYs BvyULmfKbLwalRuMEets+nySdkc 2020-04-19 20:08:39 73.201.16.196 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 FlowCtrl=1 +w Bandwidth=92 +p reject 1-65535 +r traclus +ZcgEsUrYJzUQAjCwCae9yX9Cus wai9vZAS7B1k0BILQB7Ns7hwJXU 2020-04-20 09:15:16 178.17.170.252 443 80 +a [2a00:1dc0:caff:171::5674]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9200 +p accept 20-23,43,53,80-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,853,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 +ZrCZvJ7TeeYrTXgUH6SzCstN8w PwOXdFLGE41AnYFdvAKPkWivnCU 2020-04-20 01:53:54 5.58.172.86 44647 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5000 +p reject 1-65535 +r darkharder +ZwBViJZuoyg5CuoUPE86Hpb04I joWtMwpxbrwZZH1q2SrM8Q7yjQM 2020-04-19 22:01:36 209.126.0.246 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1110 +p reject 1-65535 +r cxxnode2 +aNULVhjzWZbf/dY5z2tQIMtAGQ 5Ln6lOH0K4XLvuhOn7x4tgRvzlU 2020-04-20 04:17:45 217.79.190.25 9090 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=46700 +p reject 1-65535 +r snap277 +bmcgeR4UPzzz+2vaXRedqp13Ew hHluEVa0L2IRUq4ExClpCyNYT8c 2020-04-20 03:20:57 175.38.44.78 34475 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=14 +p reject 1-65535 +r noeditconfig2 +dlC1qMgd3lAoFHIpLPvPA8orTg PMXEs5/qO5zSLdZYTLDoffmtOsI 2020-04-19 22:09:39 149.56.157.119 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3300 +p reject 1-65535 +r Hydra +eCyXk/0Qwc1oFm2IZEijRyAtgY V9jE20DEqobgaXwa2cOZCKKQyrQ 2020-04-20 01:22:20 89.244.164.133 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4350 +p reject 1-65535 +r KagamineLenTwilight +eMtQFj3816bxPHYw7LaoMRGZmA jO8OufdgQo8BAwGEoRT8s2XU6/0 2020-04-19 21:00:05 51.158.148.230 993 0 +a [2001:bc8:2dd2:2000::1]:993 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=26500 +p reject 1-65535 +r Unnamed +el6rHrLa0jKF/pVVU/WyxZR7TM pJC69dCCMd79va4Qs8AmdSbX3CY 2020-04-20 06:37:39 51.79.53.145 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9960 +p reject 25 +r 2fast4you2 +gFyZq0QK/+QJNwpCeLwu2/Ms/8 5M68S93qynY6qrjjOcfcpd6wFoA 2020-04-19 23:46:02 178.254.1.90 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=22700 +p reject 1-65535 +r arbitraryKenzie2 +hhFwxO4jvSei+HyOwLNCscCtjY cNLirLwfx+qSK/kvInyss1Z3FZk 2020-04-20 03:21:31 95.216.14.206 443 80 +a [2a01:4f9:2a:f21::3]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.4-rc +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50300 +p reject 1-65535 +r vader +hoGdc9XfxPCe82chlDsM63iPPM jWMSO/8SAPBw0NpGqeEc+6jR4rs 2020-04-20 10:30:27 210.3.102.165 443 80 +s Fast Running V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=149 +p reject 1-65535 +r angryrocket +iDdYy3D+ll96KLhXvZ37zHAHuI qOAT41ee+JMuDK+epko3+ncwksE 2020-04-20 10:39:32 104.131.245.55 9001 0 +s Fast Running Stable Valid +v Tor 0.2.9.10 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=238 +p reject 1-65535 +r tor98072 +ik9khqpZNRsXH0SGUjaPhqgf2c u9qPPsrNgh8BHR6C1o7tgUGq/FI 2020-04-19 21:02:33 50.47.140.16 9081 9080 +a [2001:470:e920:1:ba27:ebff:fe9a:511c]:9081 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1040 +p reject 1-65535 +r Unnamed +ilL1Y+7GBM1ZHNKpVLPaBWd4f8 8TyULOO5ueNneGeBJvF1NFv0kSM 2020-04-19 20:04:21 5.79.109.48 9001 9030 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2600 +p accept 1-65535 +r k8r +jKZivVihIPY57e7CkZB0zogaig 2qcmWPOhehw0YwJNpX8DAaHUxLE 2020-04-20 02:42:31 51.75.75.18 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=14000 +p reject 1-65535 +r SleepJeep +jqVzWlst4ByqxJ7isFJfbxDxA0 CtQ20x8lw2bICillcSEUyBh4SCU 2020-04-19 19:47:48 31.220.2.133 9001 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=44800 +p accept 43,53,79-81,88,194,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-992,994,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r athoxx +lZH3pdFuiOcnzTiYlEsmWBUcsk BO2kUCGRoZN0MYepgXUrqtgUroU 2020-04-20 03:38:17 92.35.34.189 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5880 +p reject 1-65535 +r torpasta +loIILTQaPN6ZbgMkxVARVO1oFM yCgNidB6g1A2GJDor6tD1OFQJ4Q 2020-04-19 18:59:59 24.94.7.147 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=12 +p reject 1-65535 +r metaverse01 +l8as0aPgIsvsF8hVcBIGjUyx4c erdi3mScUOSTX06ZaBCZ4mWuyUs 2020-04-20 10:33:09 185.97.32.34 9001 9030 +a [2a00:66c0:1:1::34]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10000 +p reject 1-65535 +r KyleDewbrow +mn3xRBn2ahBaJYsRqykgKkM01Q RD/bRmlY8GmKtoFk3f84Q6lorPE 2020-04-20 06:06:40 202.165.228.225 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=550 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r snap277 +n/7Wuvuvo45s6l8fhOGVclndGg /X/+3MgTGtioTQCMe2BtshNVKBA 2020-04-20 06:29:15 91.154.115.191 39971 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=290 +p reject 1-65535 +r Elfenficker +oJBAcXD0yxQksk5276gU/8QvYw pyDfYgxyL00R94VlJSfyZb4Prz4 2020-04-20 00:15:52 217.250.223.209 443 80 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2960 +p reject 1-65535 +r Unnamed +oxzO6vXqU+repCttSVv/2NiYgM RFOiyDX3h4F41GHtUWeXwMxFTsM 2020-04-20 10:47:47 194.182.71.232 443 0 +s Running Stable Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=83 +p reject 1-65535 +r DonCoyote +pJQH4dfoDGdFkBjtw83w6tufOc A1mB65q42eqCFpMeGpd8fMtv3n8 2020-04-20 07:33:50 107.5.24.181 9090 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1900 +p reject 1-65535 +r DETor02 +qk1sLw7Q0jMvT66lWgatRcwl30 7XFN7pwb6bneoShC0O2oC85rPIY 2020-04-20 06:38:37 89.163.225.7 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21200 +p reject 1-65535 +r fiedlerRelay17 +rpjlMeQ6WgS0zaJ+ukHlvunmqg +ULEIHx8dGCf99bUPHmjJ1Kyx2A 2020-04-20 11:06:48 37.221.198.114 9001 0 +a [2a03:4000:9:533::2]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2550 +p reject 1-65535 +r mycelium +rta6klT+d7LmRmhkRbAPhgO8Kk DYCW2M5UX2ftV+ahb+kBPN7UoAQ 2020-04-19 21:33:00 18.223.132.180 9001 0 +s Running Stable Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12 +p reject 1-65535 +r AIgeneratedPostcard +scODitB/12xhnCNE8BphczBFuM cvcnYRL4TwdhD/YtcjW315oMD/c 2020-04-20 01:59:49 24.134.92.137 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=259 +p reject 1-65535 +r nonanet08 +srp3RkxWJjhth+ps/eGsDBAvnU gvIgkvSvAmGB1/a+mCi9Ql6JjCM 2020-04-19 21:24:31 198.251.83.193 443 80 +a [2605:6400:10:7b4::1]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7230 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r GiftedRosebud +syeskL0/aC9ZQjMuG2rzp6EZ38 C0Fgu3bEBqEpsxd+7YDN+iCGieY 2020-04-19 21:57:34 94.100.6.71 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4410 +p reject 1-65535 +r Gargoyles +uGfZPTDtTUdldF5TNxqatDIy4M /Laf9GVIaTVyus9uWS9YgHPl368 2020-04-20 08:15:00 94.155.49.47 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12000 +p reject 1-65535 +r jonsiii +uYXqBoDYXHdjiJajRVY+aVzeI4 315PyL8fczLzEj0aMrFv80AhjZg 2020-04-20 09:55:50 176.20.196.224 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 +p reject 1-65535 +r niftytreerat +uyGqaNxUvA3HWeRero5hGffvZw M0Dl3w4AWWEwSxDu8ofNkv60yLA 2020-04-19 20:27:16 185.220.101.27 10027 20027 +a [2a0b:f4c2::27]:10027 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=55900 +p reject 22,25 +r dfretlink +vBU3w5kMuVvJi0c2TN674k1Alw 0Xgdy+FFpkEyrHMT9X/TjHY1alI 2020-04-20 11:19:07 5.2.73.239 36701 0 +s Running Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 Unmeasured=1 +p reject 1-65535 +r MyCoolNick +vCbNeubiQxEw2OSEAxSt/IybdQ 3/g3ESmxh9FRNdrXUMtiSx3SjXs 2020-04-20 06:33:22 5.2.77.146 9001 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p accept 80,443 +r tor4thepeople2 +vMjbTewsY2EOMRjF5QPZC4paSQ yhdNHSDG45bXOvXZB7Bask3uFS4 2020-04-20 02:06:19 51.15.235.211 9101 9030 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=38000 +p accept 53,79-81,194,220,389,443,531,873,989-995,1723,2086-2087,4321,5222-5223,5228,6660-6669,6679,6697,8008,8332-8333,8443,8888,11371 +r LittleBits +wFuFrjNeg5T3u8x7YdU5Pa46Dc PLs1CefaObojhGGKlurl0mG1dLA 2020-04-20 04:27:06 136.243.82.188 8443 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=80000 +p reject 1-65535 +r CLOCKMASTER +zcgQ531JLc1RMtB3+2ICiEC+Kc qGFFCy0jHV87NkXhTApX0lCJy2U 2020-04-19 23:02:07 79.134.235.93 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3470 +p reject 1-65535 +r PankyBG1 +0UxgX23MWiwQQrUv+qv4gbxp2M D08nixpLnMEoN2RqVXePuHCsdWE 2020-04-20 05:34:07 213.183.63.36 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4100 +p reject 1-65535 +r awesomerelay +0niDSdF2lfQb+/DiXrpp36/Gcs Tl0Y/zFaQ+GCwhPu79hb/U3nHk4 2020-04-20 03:40:33 84.113.242.30 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47 +p reject 1-65535 +r jeepingben +0sLCmMlraKqOFLSi2gNMlns5E8 4cvhkInwkqgyKzI5JxVvPtEqjrU 2020-04-19 23:48:52 207.5.141.34 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r rortor5 +0vIoXrQFpY6o065gGD0dduy3Z0 oNM3Gu95xeS7K7W9b8+fC+roMQU 2020-04-20 12:32:07 109.74.203.71 9001 9030 +a [2a01:7e00::f03c:91ff:fea3:18d5]:9001 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5340 +p reject 1-65535 +r partyplanet +1LHPItyir3gFNsw3FPRYKceVwg w5L/AVb7XyyOXI0b4V3B2MoEkIM 2020-04-20 10:46:08 78.82.180.2 9001 0 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3730 +p reject 1-65535 +r jjc +2RtkV3X4VMXZKQqsUlBbn4O9Ck Bt3CVS1mwaUGboGmotAKr4wlkvk 2020-04-19 21:52:44 185.198.56.175 9035 9040 +s Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=35 +p reject 1-65535 +r idVDSTorNet +2cMBJ/9rg3XJdbi4OTiYn2y40I FleLYPHAlV352UBPH9JxynaovGs 2020-04-20 07:44:20 109.74.143.42 9009 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=13000 +p reject 1-65535 +r tron99Relay +2kdbj/uNcaXnucq8DpT3YYbTLs UR4OYl1Y3CATAN3Wbh08K86Zq3o 2020-04-20 00:26:41 91.121.52.156 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45700 +p reject 1-65535 +r Unnamed +3TGlBlLJNY/Q1ew/aLtoeV/NIs un9UM9VuhCj13Z5QBIXl1dS2358 2020-04-19 19:25:07 43.251.180.14 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=115 +p reject 1-65535 +r cghislaiA +4BksfiIubR9pZIdXuuSBkfncyY NeaRF94iORMLdlENGnBzp5xkTfU 2020-04-20 07:47:01 91.121.79.188 9001 9030 +a [2001:41d0:1:84bc::1]:9001 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=215 +p reject 1-65535 +r VSIFcopernicus +4VaTjYtnahmGkLTJKtaBtAuOTU NM1IrWkPfyUYSLvzfDzRQHcyxEk 2020-04-20 06:01:51 104.218.63.72 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=4360 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,636,706,749,873,902-904,981,989-993,995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3690,4321,4643,5050,5190,5222-5223,5228,8008,8074,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,10000,11371,19294,19638,50002,64738 +r niftyguard43 +4eWA2Bpu0eH1jn5JoHswv166yI NeicaHitoBwY35CxOflSqnJSPrU 2020-04-19 22:16:11 185.220.101.162 1162 2162 +a [2a0b:f4c2:1::162]:1162 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=27600 +p reject 25 +r vienttorrelay +5et748LhIh4GZN51zOfC+1zmQc 8WlSJZbZG54JehCvbdsoUnxGjb0 2020-04-20 12:47:28 209.182.217.18 9001 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26 +p reject 1-65535 +r smell +7Otv7zpv3ypzDoE08MM05IXYo4 3ZtfXb3wwQCKB13rN9a5Gt5HJnU 2020-04-19 22:24:04 45.9.148.215 443 0 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2140 +p accept 20-21,43,53,79-81,88,110,143,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999,11371,19294,19638,50002,64738 +r theyellowsubmarine +7w71YtHH2In3A8FJlxqN8dwkF8 Nokbpr+JijVwPwnradcEW80HHaU 2020-04-20 10:34:45 45.56.103.80 443 80 +s BadExit Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=3900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r zwewwlLV2 +7zjLhQr57WmQENFNXVsFkS6Kd8 wwCidmd7nO9U4DIxVCtx6BnKxUA 2020-04-20 12:20:45 195.123.209.7 9002 9031 +a [2a02:27ac::19]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6890 +p reject 1-65535 +r BraveGiza +8KFakhwXz7RflBPj8iexkM+0l0 UbVL3YOIMxJjN/pblJNBoFHMRtw 2020-04-20 04:34:06 65.49.20.11 443 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7000 +p reject 1-65535 +r snap277 +8txh0GfQvMfS9FYRMRyWJ0uNbQ o3XBSA0nETgM6QresqYWzrREExI 2020-04-20 07:23:49 82.64.135.204 42831 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=5790 +p reject 1-65535 +r PPSStudios +81dhCjDQrAtlBVvUjWLArPy5Rk mYsqjp53yo/BvklTHKoE3TxvMxI 2020-04-19 19:45:51 73.181.67.80 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=679 +p reject 1-65535 +r HeliosReaper +9IDh/ZNZ+1TrFvS4DAtRLLaNgw 26PMUXQC6dpkZb9rQOu5Q0HCJK8 2020-04-20 11:18:20 192.99.57.111 9001 9030 +a [2607:5300:201:3100::13b1]:9001 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=12100 +p reject 1-65535 +r Unnamed ++BBhvSdsrHt7zzgbbFvKWkK/Wk /+lKAHZBXG6l/0AngFKMzjNHFSw 2020-04-20 10:51:00 84.39.241.66 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4110 +p reject 1-65535 +r NochnoiDozor ++Va+726BGVD+FEXg3YN9B27IG4 SsnfqoR7sjYQR9hWhvD97RlCe44 2020-04-20 08:09:47 79.243.98.163 9443 9080 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=338 +p reject 1-65535 +r SEKI /ABAZqmPZeyIi86X2GjH3slArn8 IjCLseNtDcORkctpBQEei7ZpfBI 2020-04-20 03:04:25 103.216.223.11 2902 2901 +s Running V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=6 +p reject 1-65535 +r snap278 /ASfNJAuLMZr60oDp4Pw+JF+l5g 3szGk9UcNNEveEEvHjnLz1E+Lkk 2020-04-20 08:03:09 109.236.216.147 45369 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=617 +p reject 1-65535 +r justhelpingout2 /AWxz1mCYQfIGiiTlJMXZBAm1UQ 0cketAEBoesN8VgTkJ5XS2SilaA 2020-04-20 00:41:40 5.9.137.167 9010 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15000 +p reject 1-65535 +r artikel5ev9 /Ad8JbjbsxMtOX198DySv8FMnXY wxSmHJ7Ui0sfe0EUabKGBPnelQY 2020-04-19 20:39:22 94.16.121.91 443 9030 +a [2a03:4000:21:8a8:dead:beef:ca1f:1337]:443 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p accept 43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r tetsuo /A3mkLHfOhNwBiMpTW2yw/exAvY UYUG+hm1FM8LNZelsnHFR18LEGE 2020-04-20 11:07:00 185.185.196.153 443 80 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=98 +p reject 1-65535 +r VSIFskylab2 /CHCMZdSJQhGUXPDCxEmCZ+4qOw zpJsE5GcFgrdzj/urch+UTkeHGM 2020-04-20 01:24:12 45.76.197.130 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.1.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2000 +p reject 1-65535 +r WaddennnuunTOR3 /CMuyMNNKP1PxvoAEfh2zhksVUQ uWXoCBzr0k9+8kQomkKF9+modiA 2020-04-19 19:14:00 84.178.228.67 9003 9032 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=229 +p reject 1-65535 +r niftywabbit11 /COvc154KINGiKyOOsomYZFklcY 2HODiHJZI4QDxKtDFJVBpP0gOEY 2020-04-20 10:53:11 185.220.101.244 10244 20244 +a [2a0b:f4c2:2::244]:10244 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=28600 +p reject 25 +r Bilbon /Ce2Z87fME41W3U8E8axEwoaFlw mSo9Uxeaag0XpHQW7rjE8t8ae6M 2020-04-19 21:39:30 163.172.43.81 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3900 +p reject 1-65535 +r N0nam3 /DD1Zue1DZxu1ruG2kv0sHrVLeU 6X0xo/kH4RHDgN5w3T90xEW/E2I 2020-04-20 09:05:26 91.169.179.105 16382 16383 +s Fast Running V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=24100 +p reject 1-65535 +r DxForxDragon /DNvG1tDqYXec3gFGl3kShk5tuQ esV7nEuBvV1UmdS535ez47wfrOM 2020-04-20 00:02:22 47.41.175.138 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=323 +p reject 1-65535 +r syzzzzurp /DQiKS8L2vRwaMdQwXk3EPUBmwc eB0qGUK2ttbLcUM1LiD5HVgCUWs 2020-04-20 07:58:49 85.17.88.174 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.0.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=1 +w Bandwidth=60400 +p reject 1-65535 +r kingsvillagetor /EO7IkIg2JEbrv1MLbSzYJJWdSA RMhuFSOMznRKc7rLJhPMzKDcHWI 2020-04-20 09:14:47 78.34.125.54 9001 9030 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=182 +p reject 1-65535 +r snap278 /E97OpTvcXNpQ77e3hvro3rgiaw vIQxibhYaN7eEizpxYNx/h8pPeU 2020-04-20 04:51:19 90.75.201.152 42625 0 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1970 +p reject 1-65535 +r GhostNetKennel /FtPkNGpu2tYhcprT07EfReDlS0 PZn6gWczqduM1kCw6275zqeJjWs 2020-04-20 10:11:37 85.91.227.113 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1330 +p reject 1-65535 +r lon /GJ9IdWvszwUb3dHSswzzxGaYPs 6Wlz2R0bCL7a9y1ypk/1wlwZJDQ 2020-04-20 03:17:00 160.119.253.114 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=682 +p reject 1-65535 +r Unnamed /GwPQyWh+rmmYqzu9BN8RuUHdo4 QDuc5MTyddlCLNBc+whO7ZGSO04 2020-04-19 20:22:49 163.43.193.192 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.1.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=450 +p reject 1-65535 +r undervillian /Hc9iHhc80zwAouhPFy9MsqyeuI iTDh+tNJn6vnJDJucoFlZfLi4eM 2020-04-19 23:01:01 23.129.64.192 443 80 +s Exit Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7500 +p accept 1-65535 +r ididnttheconfig /HnGZV+lJ3P/s2fSv3xQ2PE2HHE 5eLWW7UzcFkGE1Rz4W5KCifRIL8 2020-04-20 10:23:01 107.223.199.120 993 0 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=140 +p reject 1-65535 +r Sulaco /KNSCUTJ1mLmRh7eDop+kj7zYl0 1Zlot90ocFUImWEmoWP6gCIQHZM 2020-04-20 03:15:03 92.117.160.179 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1990 +p reject 1-65535 +r ktj8rmhy53b16bwqg /MOS/CClwcW16Vq24kc15JPjrrc GGxJXj+dtxpMoNI//agQPGysVxQ 2020-04-19 22:04:41 85.131.16.29 9050 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=910 +p reject 1-65535 +r fairtorrelay /MZVH/4CUgElJC8wx4EfzT2nJE4 6btgpUHe6xDT18Lpn5nf98ttTQQ 2020-04-19 21:12:49 83.166.154.244 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=9090 +p reject 1-65535 +r ChelseaManning /McNP1AMLqYgBBN7ATcgGpOitX4 8NWmLWPrvhrwRw3hybSvV20AF0E 2020-04-20 09:07:59 104.219.250.148 26918 7613 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r shrimpmaster /Mzs3EQnPGf7N0IAE4Rk843fOaw eE+F5iCnPlntddvQkKzxIOX+JBI 2020-04-20 07:42:15 145.239.76.95 6969 7734 +a [2001:41d0:302:2200::390e]:6969 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=724 +p reject 1-65535 +r Unnamed /NCKMaGAT0+OT+07BXjGXnUw9nQ 46+pdORPEFTmsxQ+1dZRqSnnbwU 2020-04-20 09:14:17 185.246.128.164 36780 64582 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=333 +p reject 1-65535 +r niftyguard37 /N4dko/5x4sNDh3o7h8XuWzahKA GozkzNedc2HLcVNuxwC4uZMCEEo 2020-04-20 12:45:42 185.220.101.247 1247 2247 +a [2a0b:f4c2:2::247]:1247 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9160 +p reject 1-65535 +r MyCoolNick /PYcJQk7szuqID2O5+ZUZtQuz5g lMlOXXM8rVDDSbpWV5277AeNHDQ 2020-04-19 19:36:42 51.15.91.78 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=8610 +p reject 1-65535 +r cebolin06fr1a /Pp8XRoamizdUHu+4C89Z+f/OlY ZaStLkqkabJRI4ZfvjJtjPnsxHM 2020-04-20 01:22:12 212.47.246.179 9001 9030 +a [2001:bc8:600:1b1c::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19600 +p reject 1-65535 +r SummerTIMEBlues /RlSsi71PUkeDX487LhcPO9jyrs hye7FRQ8zT0r5CvimdEOZNzQ0Wc 2020-04-20 10:26:37 178.201.218.104 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=334 +p reject 1-65535 +r nova /S+biBrGQBAMQo30fcmoY9wvJTY zI4lkfa73jPTcYeWL6LnTRKkwec 2020-04-20 07:01:10 37.187.17.67 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=5100 +p reject 1-65535 +r lw /USRJ9MNj10SRlPZ73Nu30oStNw VZuQkDosaFJTPWNFZcmamAwX/xo 2020-04-19 21:16:09 80.100.15.186 43261 43262 +a [2001:985:d640:1::bff]:43261 +s Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=45400 +p reject 1-65535 +r niftyentry96 /UgaUl2Gv4X/YW3EfIPN+IbTVN8 mw1ygizULS/G0rH4RkHe98QEtiw 2020-04-19 21:06:26 185.220.101.236 10096 20096 +a [2a0b:f4c2:2::236]:10096 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=13000 +p reject 1-65535 +r Unnamed /VNX6qJI4PToVTa+V5bhTbOMrV8 k5gN/5G3cqx7RVc3o9rClhZW7fI 2020-04-19 19:17:22 54.39.49.8 8061 11164 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.17 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=760 +p reject 1-65535 +r schlandtor01 /XCdvzr13eKBK85aXKL7tzPe9SA RMKn0uo+gvAJuosx5a3AqYCY+40 2020-04-20 11:51:42 5.146.153.62 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=842 +p reject 1-65535 +r dezember /Xm3+SMIWLSOdfOJZhhAxwJREHg U7sDB7hFLth/X7AlQ0rNX0OpOfI 2020-04-19 19:46:01 194.55.13.50 9001 9030 +a [2a03:4000:31:141::1337]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p reject 1-65535 +r Mikedideditheconfig /X7Z9IceLsRgNfxgKWDqzDLgj/g JdkfbSZrFfKwY1UUWX22yFNif+o 2020-04-20 06:01:34 46.4.233.104 443 80 +a [2a01:4f8:13b:3b59:2::104]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21700 +p reject 1-65535 +r Unnamed /Y8RyTFaeZgZiC0OMEv3nyva5rg uQKJJpQQvzBHdNOorUmDSosUpw8 2020-04-20 00:11:32 62.210.85.178 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17200 +p reject 1-65535 +r KlausTor01 /ZYrMAohVXAdRb2RJGcRpuJm7XI HXec3G+X8Mkh6/6Fw+zqN80PIGw 2020-04-20 10:03:36 94.130.187.210 9001 9030 +a [2a01:4f8:1c0c:47d4::1]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=21100 +p reject 1-65535 +r Maurer01 /ZwrRCjj+rDLri1WD500jvzCLw8 8ephm5tcmZNKK1tSLYYVOzMnlqk 2020-04-20 09:36:05 159.69.219.42 9001 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=97 +p reject 1-65535 +r snap277 /aV18e9qEf8VfZhs7jPoOuhoQgo 1NOG6hUjZTJFd4fqUwxAbZ9f7xQ 2020-04-20 07:01:48 89.157.251.8 34529 0 +s Fast Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2240 +p reject 1-65535 +r niftyrat /acOyT2wHjy0GMtpQ7DGhGSxi0w yHkpsvuzFTar+q1OF1GNFgnE9RA 2020-04-20 05:25:57 185.220.101.20 10020 20020 +a [2a0b:f4c2::20]:10020 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=47200 +p reject 22,25 +r RoseNao /as3IqTqaobjXZrIQiLz4R8vbW0 NVUDbHiwxE1AY4FCosCtV9oh0ng 2020-04-20 07:50:43 130.61.51.183 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2300 +p reject 1-65535 +r dorrisdeebrown /a7RXJjP56QW5WdvYUJU94QGEFw I1qkF3ZGOzeS0bnJYsu745NkKzg 2020-04-20 10:31:03 185.220.102.4 80 0 +a [2a0b:f4c1::4]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=50000 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464-465,531,543-544,554,563,587,636,706,749,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2083,2086-2087,2095-2096,2102-2104,3128,3690,4321,4643,5050,5190,5222-5223,5228,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r cylondetector /a9XwJfoywEQtbCGlZjEgZ+QBfY f1FS1nZG+VlFJOIBRZP3xn+1ehs 2020-04-19 18:55:43 178.238.224.97 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3990 +p reject 1-65535 +r fullmoonresort7 /bC/UtTthOY5raiIL/bN8ExNNS0 1O4Fhk0EAFKFOJV/z4ZqUi/oEas 2020-04-20 10:19:11 185.216.32.130 443 80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=26900 +p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r crabbe /bGi2HMOj7lGftvjRh7MwAuxkQ4 ILd+AO/lcT8IeQ4mH3HpUB03qrw 2020-04-20 11:30:57 102.130.112.81 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.3.2-alpha +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=487 +p reject 1-65535 +r niftyguard11 /b9gj5ouzQxgDK+WOYp9WwjUbKk gg5/ef6Xm9WzuJK0RVT5/F6vrOo 2020-04-20 12:45:45 185.220.101.220 1220 2220 +a [2a0b:f4c2:2::220]:1220 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22500 +p accept 80,443 +r mirondal /dQKpXOvq7VIE7tl8CPXXtSal+g eZV+Y40pPITv1UM62QFKqU+fGVc 2020-04-20 02:04:33 185.103.135.19 9002 9032 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2080 +p reject 1-65535 +r QuintexAirVPN24 /dcAx5HMa7CsHCCZqCy8NnrUt2Q VNCd5/6JBAGpAq1QbXYyeQ4vjJo 2020-04-19 19:57:27 199.249.230.77 443 80 +a [2620:7:6001::ffff:c759:e64d]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=18100 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r wollwoll /eztTCylPSjr2MsN3We52PZBCSo MlrJvCQAlW9pfruybPhFHa5vuzo 2020-04-19 20:04:56 86.59.21.163 9001 9030 +a [2001:858:6:2001::3]:9001 +s Running Stable V2Dir Valid +v Tor 0.2.9.16 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=48 +p reject 1-65535 +r kellertur /fsEObc43iZ+v9mgSn2UjUYaX3Y rOvEcS/jIWnropuGyp2x0dcw3zA 2020-04-19 20:11:17 51.15.42.19 9001 9030 +s Fast Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1780 +p reject 1-65535 +r niftywabbit8 /f1nXQUhZUnrfaVF4y7PzuroBfI h9jKDIcf745uTRm0Vh8JkeSl81Q 2020-04-20 10:52:00 185.220.101.200 1200 2200 +a [2a0b:f4c2:2::200]:1200 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=66000 +p reject 25 +r Unnamed /f7TWpGH+4iuxkzJugVxvpuKjVs Nq87LOi0JDQ+fa932EAGC9IoXPQ 2020-04-19 23:39:16 80.251.126.229 9001 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3140 +p reject 1-65535 +r Quintex42 /gCjqDVoDmf7vIlack4mV7slPpc PZYzY5x9y1ZZaHF/tXs6PWiJmLY 2020-04-20 06:45:35 199.249.230.65 443 80 +a [2620:7:6001::ffff:c759:e641]:80 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=17200 +p accept 43,53,80,443,991,1194,1293,3690,4321,5222-5223,5228,9418,11371,64738 +r king /gqpdh577E7yoy6bCi5ywNCBCUE CWqLjftNsuaaIXNblfvISXvfDDY 2020-04-20 05:59:32 51.89.213.84 443 0 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=15500 +p accept 20-21,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r viktortan /hr16QkAITS/+DT0rV4d5yN3kAI KgiozGLA0lejk1L2nZZIpdcK9j0 2020-04-20 06:00:45 5.9.124.99 9090 8080 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.1.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=96000 +p reject 1-65535 +r unnamed /ht0x87gSTYTkpqS+aHYkOWNxkk DQcUMXgRvRON96S4BG2i1uhDqzE 2020-04-19 21:55:29 195.154.237.147 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=23300 +p reject 1-65535 +r Unnamed /hzNuYVCxW0y6Qv9+9dMX32nQCg hv/yZ0SziMor8KJUZn/ChWkWjL8 2020-04-20 11:15:06 51.77.94.226 443 0 +s Exit Fast Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22000 +p accept 20-21,23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544,554,563,636,706,749,853,873,902-904,981,989-995,1194,1220,1293,1500,1533,1677,1723,1755,1863,2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321,4643,5050,5190,5222-5223,5228,5900,8000,8008,8074,8080,8082,8087-8088,8232-8233,8332-8333,8443,8888,9418,9999-10000,11371,19294,19638,50002,64738 +r Tapioca /iaOlSiO4+9Y2mBtqxKrIWz2S2g VlZeTeDU0F86E0Su3L4PSnHLWUI 2020-04-20 10:20:47 200.98.136.76 443 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=130 +p reject 1-65535 +r PyotrTorpotkinOne /ilhgAGIM68DqOrNWJSmFGI9P3Y wGigkdbihjZLymh8k2DX8JONPpA 2020-04-20 09:13:23 149.56.45.200 9001 9030 +a [2607:5300:201:3000::17d3]:9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=11500 +p reject 1-65535 +r Unnamed /jyCfVZfkA0RE7KrN2CFQV02+gQ u6YY+ZKmn8cSAeqHJiJ20I3IvKQ 2020-04-20 02:05:36 13.71.64.166 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=1600 +p reject 1-65535 +r TORPEDO /jy3Quc2dPG8I4JyMgns7kStSuw adU7wU1XK2xOvAh+5BqTKog2jp0 2020-04-19 21:55:58 77.250.227.202 7002 7003 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1630 +p accept 443,1194,6667,6697,8080 +r onionVFUcz /lR+fR0rN5fqB77NXnXIWqlKXko xELUTpm4yBOhxJWILik5Cn8KDH4 2020-04-20 03:22:34 195.113.199.99 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=9220 +p reject 1-65535 +r mythaicontribution /lnBLJaX50LNP3rbr2OF6hyLN58 coV+EHjlEm3k7WUcannJpoA/H2I 2020-04-20 08:55:37 45.64.186.102 443 80 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=523 +p accept 20-21,43,53,143,220,389,443,531,636,706,873,989-995,1194,1293,1723,1755,1863,2001,2086-2087,3690,5000-5051,5190,5222-5223,5228,5555,6881-6889,6969,8082,8332-8333,8884-8892,9418,11371,11964-12966,19294,20001-50001,64738 +r stardust /myRvZ+w9XBliqqQS/i0AAhEZWs TZ+OKyQXMJRRRONtMBJGe8dEl2k 2020-04-20 01:16:35 46.249.59.89 443 0 +s Exit Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=19900 +p accept 20-23,79-81,88,443,8000,8008,8080,8888 +r snap277 /nWuXnEXZQF7P5D3OY+Xpy+kK10 kH60mi8ZdBSWrZTbA4Pmat0VUIs 2020-04-19 20:08:04 79.64.128.101 42973 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=13 +p reject 1-65535 +r volodymir /oV8MENBL9VFTtX+9VxMVy5bcM8 ZC7F4+nDXGbgBEWk337idTVI7iQ 2020-04-20 09:25:25 46.229.55.118 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=7230 +p reject 1-65535 +r simplerelayREEE /pH74BEk76/hT76ooBShD87NrlY cS8MY/n400GCs5Y1LdC96rFIrm0 2020-04-20 06:13:31 185.108.81.14 9001 0 +s Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=2 +p reject 1-65535 +r Unnamed /pyw4GKWNuvY0McfRuOHuUTAG88 Iq3L39f/L6CBGMgJPIOLnzRqnAY 2020-04-19 21:48:51 163.172.63.122 36663 0 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=22500 +p reject 1-65535 +r ADKP /qrpusi2dHu8OhTZ6aw5JKD946c 9oNoG2IKfu+p6JGfxSE3++LFr2s 2020-04-20 09:49:55 185.41.154.130 9001 9030 +s Running Stable V2Dir Valid +v Tor 0.4.3.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=20 +p reject 1-65535 +r theprocess /q/TVTkktROTG9j60cxShhxLqB8 2x+7LHvRg6o9IstngyaVn+pU1C0 2020-04-20 08:58:44 34.216.205.9 9001 0 +s Fast Running Stable Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=99 +p reject 1-65535 +r AltroSkyVPS /s7a87kEIQNcBMGHN6ixiEe1BKc ml54z4kQ8gDJlacjYb6wxadUBVE 2020-04-20 06:28:12 45.67.14.0 80 443 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.4.0-alpha-dev +pr Cons=1-2 Desc=1-2 DirCache=1-2 FlowCtrl=1 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 Relay=1-2 +w Bandwidth=88000 +p reject 25,587 +r snap277 /tEaRsFJBEqIHT7aV3DGxW84ra4 CBPNRQvc2z+Ybs0F0GzxqNQrPvY 2020-04-19 23:08:20 190.105.67.86 37685 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=30 +p reject 1-65535 +r csUniHB /t4xM35OGeBrl9KC8IsKDoucVSY xcou4z9Gq75dbdccpzfMrb/rrQE 2020-04-20 02:22:39 134.102.200.101 9001 9030 +a [2001:638:708:30c8::65]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=43000 +p reject 1-65535 +r eierschwammerl /t9JmJUadQ1deXTfJDA1SZ6EiC4 SUyxtmWr8d0WLuu1cV47oVQp6uo 2020-04-20 05:16:25 37.252.185.87 443 80 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21000 +p reject 1-65535 +r Cagri /uXJJLNGEjpVJedgP+1pqGli7JU 47S8cIq12mgWqV5LhcIGoAOzFRA 2020-04-20 07:40:23 194.135.82.36 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4850 +p reject 1-65535 +r Unnamed /uw35XQR3koGHc/3QhyeeMDKouo K2DoW4a/KiAh10FQT5DyaggyVF8 2020-04-20 05:10:46 98.116.155.39 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=3470 +p reject 1-65535 +r Donatello /u8kzfFbtZtBjRv5SmS9PmK7LPM ZQdA/dGgAg3SSzlMKZL1QK7gAhE 2020-04-20 11:15:54 190.10.8.166 443 80 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=630 +p reject 1-65535 +r Unnamed /vX/SDn8KE59LkgVRGvqN+tPKwI 4skcpCJOoHzvcVk6MDdgXd0kygA 2020-04-20 08:13:28 20.36.47.165 443 0 +s Fast Running Stable Valid +v Tor 0.4.2.6 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=180 +p reject 1-65535 +r torrelay666 /v+XWkXLs1DXpZqL5hoQcaN8UqM jrH04ObfDBBcEzk6GFi2inus9lw 2020-04-20 03:30:23 91.7.113.234 443 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=250 +p reject 1-65535 +r onedilight /v+5YNkvQtUIeX9ACBgCxxK4jP0 pzbOkGZW2j/dIzVJfG8AO0aszz8 2020-04-20 07:36:46 45.77.174.250 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.13 +pr +w Bandwidth=223 +p reject 1-65535 +r hsjeufh24h6 /wbnoGihymbOWT3OheJHeAfEgwI WmsUw+x7MMtzqXJKZjScuRnog7c 2020-04-20 12:01:46 51.15.37.100 9001 9030 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.5 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=21400 +p reject 1-65535 +r BestKorea /xVOAmWtwk/bHYu6NEVeMkyf5Ac zPb6B4uYQe0ZRepSg2YZ66tWGVo 2020-04-20 11:14:15 51.15.220.171 9001 0 +s Fast Running V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6990 +p reject 1-65535 +r middlesharprelay /xqghTAChLparHNBZx5X1T7ED+M ExfPsYlvM2js8q5gxznlYpglBoU 2020-04-20 01:40:51 213.32.71.116 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=17100 +p reject 1-65535 +r niftywabbit16 /x7ZoX9ggd60YH/a9D+t8WuUqVU xuJqjI5ldMcjdpgu6mgw2cv1fxc 2020-04-20 10:54:16 185.220.101.246 10246 20246 +a [2a0b:f4c2:2::246]:10246 +s Exit Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=70200 +p reject 25 +r relay /zBZ535dIvHDsgzL4SVpGtJ1iN0 yjyQZa39cKgSiHDu2A0YVaK+Uag 2020-04-19 22:01:19 185.163.45.247 443 80 +s Fast Guard Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4620 +p reject 1-65535 +r snap277 /1KwaooMv9CjDcnUU/BlT/cnahg WHWYU0TBCud9Awqhmp/VVh0axVQ 2020-04-20 06:30:28 90.76.79.201 45629 0 +s Running V2Dir Valid +v Tor 0.3.5.8 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=10 +p reject 1-65535 +r Gemini2 /1N3TuT5mbw2IxctRLwIYpDh+tU vzOzY7sM4l8eaSN1qmgpRWlcj/s 2020-04-20 05:14:04 69.195.146.154 9001 9002 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=11300 +p reject 1-65535 +r enif /2Cz/JoYbjmIRuCVrDeLE+yAlP0 aMh+QQp9H64iblfXMVXjjASCHS0 2020-04-19 19:01:09 144.76.50.37 9050 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=4200 +p reject 1-65535 +r sofbg /4DrdkjlSBnzdSLE/B8a6edgwKg +hNBSqQ9z//mYd2aYuCfsC5yU/Q 2020-04-20 02:33:34 195.123.224.108 9001 9030 +s Exit Fast HSDir Running Stable V2Dir Valid +v Tor 0.2.9.14 +pr Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2 +w Bandwidth=790 +p accept 43,53,79-81,443,531,873,981,8008,8080-8082,8888 +r MehlTor1 /4fknvMweLBKXeJqrhcN34uuE58 BiB0TCZWMgODY6zZXL/0Q5lAzc0 2020-04-20 10:06:27 188.68.36.209 59001 59030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=460 +p reject 1-65535 +r angeltest3 /5/G0TD6Jq466LI2iGkdxBnw8i4 reaMsCQTBVoQsPC0mHokFg35x5M 2020-04-20 10:41:57 62.141.38.69 443 80 +a [2001:4ba0:cafe:ac5::]:443 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=48000 +p reject 1-65535 +r Lule /6cr1oO8L8+Yg1bmvsHkkPMT+wc SikumV6p4WBjGy3J/eUNXQpN+Ck 2020-04-20 00:22:33 193.11.164.243 9001 9030 +a [2001:6b0:7:125::243]:9001 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=36000 +p reject 1-65535 +r Unnamed /7YFyG1gaZGt7XhCJp+iWgO0pNA 0heGvQ0as0uYnGBinZBzfPBdzC0 2020-04-20 04:41:52 165.227.174.150 9001 9030 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=430 +p reject 1-65535 +r plan9leia /7xpRns31qxmWYu9KV+bDXQRmtw AHIgB9zqJe6W5bNgtWl9h9zRYAY 2020-04-20 00:46:43 213.239.217.68 4433 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=787 +p reject 1-65535 +r tRr /9MtQzCLeew3i6zco1UueqJmnGk J7aeeLKqls+YghrH++xznNfXTmY 2020-04-20 01:33:30 173.79.173.49 12000 0 +s Fast HSDir Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=1920 +p reject 1-65535 +r ddetor2 //eMRLpua291JQlbvhTvfL64l0Q KbdFofFgecV4Wa+douqGjKeHiJo 2020-04-19 21:15:10 144.76.75.137 9001 9030 +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.3.5.10 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +w Bandwidth=2100 +p reject 1-65535 +r nestor00patof //v7UKg6QUzCG0zak6lnSwBHBeg Wxif5ITXaY7h5Oo8oF3aRe145TU 2020-04-20 06:40:32 144.172.153.165 1337 0 +s Running Stable V2Dir Valid +v Tor 0.4.2.7 +pr Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 Padding=2 FlowCtrl=1 +w Bandwidth=6 +p reject 1-65535 +directory-footer +bandwidth-weights Wbd=0 Wbe=0 Wbg=4148 Wbm=10000 Wdb=10000 Web=10000 Wed=10000 Wee=10000 Weg=10000 Wem=10000 Wgb=10000 Wgd=0 Wgg=5852 Wgm=5852 Wmb=10000 Wmd=0 Wme=0 Wmg=4148 Wmm=10000 +directory-signature 0232AF901C31A04EE9848595AF9BB7620D4C5B2E B71116D3FB864E3BBA99370CF4E9611B9ACF569F +-----BEGIN SIGNATURE----- +BcWNRGGJXgNizcTIwXP3lSOFJ0k5byZ2Fy21Agorkuvgfh/KvzXNGpVbCbgDvoNU +YkwBOL4C9ng1C3Ka9WY6cwIMhUu7yfO76VHsL//Ywdkpe3sHAKkMYPXeF/+MMB7K +uC9WHdeweAez62bFjztiEUjejFtlUyODLqBgD6lV35zGBu0Fi8wGyrzwtldbQrIG +VKiXggCY4/J6xm70FyKJ8l3ml8AguZgoo7riTlYDT2X5q2vOlUDUGe4ubqG3Qfyx +LonuLlyK9hfik6CBuiBT8PR7BgxhaKrZdlp3KIzl0HmoJGSvi9JRfdxoBVHy4Ssp +ymQNCLsMuODuOAq6WKOs0Q== +-----END SIGNATURE----- +directory-signature 14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 4ABD14E600065842C3A3D1079BD39CDB1969A51F +-----BEGIN SIGNATURE----- +HS/W4LHrRvROiLjA2Tk9R/awlYU+gwhwqGRwlNFiWJ7qV7M9kY9rEp2i/fYnTAUy +OjhCtQpdRLrrTEf6dReUgeX6eFJqWcKyzQPXvgQd0iZ7mcYjqFA4KElDvPF/DjYn +h7gxXoGINtq7Ys9Vi3XIS1Pqp81Mci3+VHdbNmCP74YfRJ92+F0Iz7aREBF7vz1K +2UGskeP9Wp8vWKtjySzo3V5FRj+2sirC/2Ts+cAhZIankulykBFOhL6k/Qbctujc +dXbr0ppWMGkio2Mkj+zs0OijtU6cD4KlE5iFzEUe0KyZ6pzuBxrrY82oPGwWtjdG +wbNxm1Z/EUezSR9+aWRW0PSx1DjuJircOsBJ4HNqCAyMZNbj5iHsruz3s5nmT5zT +JU5awp8D9UPnQxtqfmXMu3AwJPKyhhVN2tZZSEclSYAjFozR0s5ihG/eTy3kqyCV +P1aMnK5AmUbOh/ElPm69FE8c0Dc5aUuwvkWKczTGmrCfd3Ldhck4EmSdzTholWgb +-----END SIGNATURE----- +directory-signature 23D15D965BC35114467363C165C4F724B64B4F66 509EF6508DD58C083D55BECAC7C1B6B8BED4D358 +-----BEGIN SIGNATURE----- +oE9nr9s5tCl17pPH7x/sncIMZd5NEoy1IQKoQXLE1z/yLQks4zWt4tPHfgDYLmXW +WLkPGQ+kGC2hezSQ7YtoBj3cQXMl7oihSY5lcpXta09wB4xzu6ToLTW4AHPPPeuV +K4M/aX0MjKN6hMec3IhJQObPjtZKDX3aWoL6Qlmfb5Xpuum4nARMm/udrlqi2xxw +RY0fTkDDiUgpCvMFhMm8WzA2j2cnJwemF7nNC3js+37KeOtiofvaUJxiK6HgE7IQ +2FoekXKRh4M3VU+8rsQbZxIYCl5PGou7cvgS0Pn4sVtQvas7DpdfjGETWcj9ZGUr +1NgnLaDWKm1woHOCWOTHnA== +-----END SIGNATURE----- +directory-signature 27102BC123E7AF1D4741AE047E160C91ADC76B21 430B061F428EAE23240631406F9FF0E3A5966D96 +-----BEGIN SIGNATURE----- +b/SKk1Q3vGsJfqCsmW11iqr16FmderlH+k3AZ/DCdfatYVMMBdSKKLMb0hP0Shcm +mZd+/H/oe9AdvAMq1HfHJgujLFcF37EiUYdGQRRcSxr17h5VXySJl+1rrznrkSiO +axTIDzpzaHJEKUzz+xrleSK+pJfGvqirk/OT926cRJ4ldhNd8szrVHfddpix9FQV +K0ss6LkwqUrsekCR2bo7SAfsEc/FtVJhdXu/5TiSgCqEtLMGbfqFvkZXAZ8fQXNJ +J1cMDz9z7PK4u4z/5+cKNirwPUfvldiSPueTKZHPo4BDsMrAa8BDbsP3Aciae0S8 +VDvk79+NWA5if5zqOu5ATg== +-----END SIGNATURE----- +directory-signature 49015F787433103580E3B66A1707A00E60F2D15B 7BB01AE548AC472C2C4CE42C651D37FE1AC0D453 +-----BEGIN SIGNATURE----- +JXNn7bNhLCn16RdRSM1+msGhNBehm3VXNd+DaGSD2zi0WeacEMtRRHAANw7hDzKr +VJ8jUEQSmD+Ik/U/hnc2Oap5r4KMJdz97lrlnEqb9FRwZSwPoKaU8ZCHL5nYCfXN +IfIOLD7QozI+C7Wiz1LjjoIF4SUYU+Ejlzmbf/yhmHYfADKfQXVnRAiloIv+J2S1 +fAtcSHnARh/aBunzwpPlGnOBQ4twg8liuDGw7Sl8IV4tfl5QoIbndHriiPFRBo3U +nWGLOIXWpZx4l9+H3ftK81CMmF2k/D22vpBNuelDKZEfZQ26YVyghbm7iXWBN/Dz +Q9J6sf6xYXitijyRJWluUg== +-----END SIGNATURE----- +directory-signature D586D18309DED4CD6D57C18FDB97EFA96D330566 ACE88AC828C1641CD528F8681F570FB53A65807E +-----BEGIN SIGNATURE----- +PS49FkiqLUEsMeJg3/GkoVZhqtAvBCv76BJ19pOWqO02zePU0nXXQKsp+IGwu2fX +sYZ+ZrPC79JfCxsyBQ/fKIhPoyLbsZYyVknSWe+CAo1TU85WT1uC6W2AZM7GCung +QOpBN1C9f8BTAQfxNQ4hj/1WkzCYKYMll+KER9ovrZpmMvRZiNjZg/w3xds6Q14h +ILQYS6BxAZ9RE+yjOqSxtG6Pp+/K7qpm3VAEynIiv+AUH0G5IhoHRQSX56Xw0WfF +fSYVQ4Yaavmi+4UYcw3+Up7FDdLmPIMGXXOLqYH4JXrI71AOdN6sLKIWkJ+yX03x +N5M8isrc/T9RXZI5Avqv/w== +-----END SIGNATURE----- +directory-signature E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 7020598CED8DFAED7618ABF4D9D8C0282F3A9ABE +-----BEGIN SIGNATURE----- +jL6xnVOtgm3FVrru6OjdCgv5n5XeY5TGMMMCuMgJOE7H6kPIOVzV/lJZ+byhzDiD +Dg4OIdGzF5bnwO6CnrpFbkQ/llbjMtSyTaIesMcc3RxOlMhDaXluYK8gIs5hhKh5 +03r1B2lZ3wfA4AfsfBvxGzjdj9KUiBPL/h2foLLDnCjnY9p10qSIbLA2u6q3UELl +j39p9PGeu6B23M4PC5PChKLrVky+OwZ0xTv9Y6RWma4Xe9gtP3jzq1rRa3VkYt6y +KgYclC8qKpK0kOe06L/kh9xdXiif2CVfxX45HRrbrCOXRQc6eZIfplldEwJH6j5k +d7qef23vIhH7TCtPV+cuaQ== +-----END SIGNATURE----- +directory-signature ED03BB616EB2F60BEC80151114BB25CEF515B226 C4F720E2C59F9DDD4867FFF465CA04031E35648F +-----BEGIN SIGNATURE----- +u9Mk5/HP3jJU6yMiB3nAeO8YyKNJ0d3Acec4x7lwJ72JI8WGCmnVUqdRo7VCciko +K1TklOeCQ/BaTx/LEgs+JWOC1n0w9bO7DQY2JI28lxVCNhmTJVrXLSxuKXZc5BzN +/0HaO2LtjndgaD/shC0m4shW57AztS/l4Jq833wm6+zJH3ZjefcaIna6uwVCI3PE +wXsaoVS0XftVQ0ygn5B3HniOPG52fPJtrqb8ED8p0CszPNIzVQAW/cPZNh2h9g+R +bSuTRN4DRe0S4p55anJA4pOqbBk3M+eagC0DYqHKfMX9vK92bYNkJ9Kbrb5CoQzL +50k27xV8IAaDhXg2OO76+g== +-----END SIGNATURE----- +directory-signature EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 310ED41DA061602C0D3127ED493C2D476426D73F +-----BEGIN SIGNATURE----- +4iM4Nn17e96yCyWG+eN4tuP5OOGzrgDogaSoijFoj/PHrIV2ib0N/Tuix05lYbym +JVm0Ah8HCaD4lG4iJ7yZXjR7Wl/imp9np4z5J+3dyK46ObwlovqeuGjzc2oJpLt5 +0gT5u4OiSP6GJhXSTP314y2Uh8rSddvBoUgakc8dZGcgV38QThsHYIU1PzfP2Nqc +QPWLsWtnDe5NPSPJXO6gh1E8YgzFYSOtE1gGLHDRlB+qSAKg4oLk/8lCPBh1z8Wg +WombN/z7n8xX7hNJCJB4HbVka9T0eDl6JROasoonDis9RkQwSBYnVERy0Taxp312 +g7B5yAc18UfQm9C+Gy3/1A== +-----END SIGNATURE----- diff --git a/data/descriptors_micro_parsed.txt b/data/descriptors_micro_parsed.txt new file mode 100644 index 0000000..266c83d --- /dev/null +++ b/data/descriptors_micro_parsed.txt @@ -0,0 +1,175 @@ +{ + "flavor": "microdesc", + "descriptors": [ + { + "micro-digest": "/oBdxYE6dEsNEuhT+eCKq5LbsJhz/5aE/CQlHeYQqy0", + "onion-key": "MIGJAoGBAMXGxwPQGH9t9pfQSnqrJd7r4ppFaalVCd+HROsS6CA/znvpf/2b9uer5qucAUYRL0Uhr0o6J0TldxSd3d8WY5Lwn/ZrJ7h4U6SDV024BxqW7R4OMT5ISFgh89DQN6p1g8mMslGktwZUrCGeEhL32WQAEB/so5wnv7Aa6yYWBDZbAgMBAAE=", + "ntor-onion-key": "pwiw7FWsyJXlLyAa7kOTSyKgaqG3xV+stOE+uGEvsE0=", + "policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "identity": { + "type": "ed25519", + "master-key": "RVD4e+ZpIO5hJFWZ1mQvPbpp8YiASSsdM3x+eUDPSGM" + }, + "flavor": "microdesc" + }, + { + "micro-digest": "vsIfsfWipqVVIP/sPw71/GVuqFBACo8isd0QE5IHWRA", + "onion-key": "MIGJAoGBALS2aufFNN2vT315425F+PwmNV8WILh08q3aEVmcn2qpny12d9S2KA/tU//ZlJhguqVTV1MMY52FstR0NKETDD9pdzHUFSsFCOzLhOzSdNPRrp7+ldZCV+mrmd2i2Dob3dVcyZP8iGORSQDR0D6c70Cfv2jM9LW5FTnaOZ3Dld5LAgMBAAE=", + "ntor-onion-key": "aWrb8rS++QFQnEDvEnSWFQ5Wh8q7JGYY90bkx05LfCM=", + "policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "identity": { + "type": "ed25519", + "master-key": "3QRD2H4MaOulm41T865Ya4/xJfO6vNMSl+yfOWksCoo" + }, + "flavor": "microdesc" + }, + { + "micro-digest": "sOncg9KObIVQCj2qbmTa166mzTNuYLq/78NnH4j9Rpg", + "onion-key": "MIGJAoGBAMelRVut9suHj0F4uYyAZCsmtlrjRbdmZNvSy7oYbMpdRsKrmEhckXd10UIJOU5oI9+Kf+dWyggcs6/Nx4qar7hXF9nTf18wCYm+UbFtcNzCXLeseaZtDj/MbHa0+ptykcLFb1VkI4a7cAQ5qPlWUG0qpE/yUGa3kifRd78icwWVAgMBAAE=", + "ntor-onion-key": "3nwr7McqePaQrbawf0Lkuj72l61AreUJ4ulxjY1grFg=", + "identity": { + "type": "ed25519", + "master-key": "A1Ly6Uf+PRVV+CeVAQF1FKPYLNrPsWeuXed2h/KLGX0" + }, + "flavor": "microdesc" + }, + { + "micro-digest": "r5w5OtvIDxowqug0biGBmqR6Fm2D0lukwOdAS+3f0nI", + "onion-key": "MIGJAoGBANXWu7tNGp/m326Ua3ZBr78lRfPD2xPn+R5zU/SjWa32/QpkLPyloJt7XzI1JGxMdU+bVgOXuprW51nm+gtfbZ64g6DFFuBEmAEOVfqgCRfgz3yx5J0f9WchdfoXqbD2oYxleVZ5qd0VeUve+1uKsB1t6oOIhBbW5VwqhmNbGL63AgMBAAE=", + "ntor-onion-key": "GXljNcag/Y28zUyMWvwzoGTrY93JtUcNW+E5nx49+Wg=", + "policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "identity": { + "type": "ed25519", + "master-key": "Z79/Yq1oq8nT82SKCdV7f8wyofn57h2GVFNQvr2kAns" + }, + "flavor": "microdesc" + }, + { + "micro-digest": "hXFJseLWgaqAea7Hpd5cBfEbTTISuFv92sTBLOJY6Mg", + "onion-key": "MIGJAoGBALudw0y5z2HX0Yq/jrqjt2lk/GgtuDAIlGaeCa+3Y6Wz/N5UkFfPFb2b6Rlbgih5IsStFbsI9byY+TuTbQVrJJoSzYxbaOJkNqBxItfWy21x0In0k23FgdjhJtb+CKU3pB3Jtr6ggQ6YiO+RDuyBOx1tpckxxVzD8gqWuOldKrRXAgMBAAE=", + "ntor-onion-key": "PF0gSkZSg5tg/cpO+COBy4MuOBUFy0i24UN1ANjwYBQ=", + "policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "identity": { + "type": "ed25519", + "master-key": "40FnzSdF/otItPbTowtcDS7+UzqAw6g9kbmppFeuN3g" + }, + "flavor": "microdesc" + }, + { + "micro-digest": "apfWPB1RoS+VCxl84H7LPEvhTzaZPJo4pDT5ykzNcVw", + "onion-key": "MIGJAoGBAKo/yPehcMW+7t05pCn5afpDbjSQxlu3PfD+L0AhafCHNv0rTAQIdbj3YgQSAutk87HM8MUNPDDSgwvv0coMwfvgAe4reOvtikXoWJSsNq0c4/nZgYbofJms3mmyHAgp3wIf8BfIV9p5yfwPdrpwQMYpcB+WOeEk3zpwsZvK/xIlAgMBAAE=", + "ntor-onion-key": "Gfrvc+6ChY2HVlODeevwtCkYdngLpV+/Y/rUHb4qpFc=", + "policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "identity": { + "type": "ed25519", + "master-key": "V3yVgZOBaTl0S62HZws3zcw1WDVEEu7wx0qEbVCKaE4" + }, + "flavor": "microdesc" + }, + { + "micro-digest": "CgFLrWqo2d17GIiSmHkos8ptM6hAXZsPpahMNsgRtuc", + "onion-key": "MIGJAoGBALZfNLHagu0C7pRHN8XLZJ/X6U/HVXRmnGRXPEDzjri2bvkljoo9SevPGy33KNsztJW370dqvag0ECiMQskdKbI7YTpYfgYkPXL6PhpKWkN2JA/TNKeCZ4QueJke2I/eYdDqolWaFeO/gqVFZJVNuAEjuBM8LpW5kmApRnAE2hv1AgMBAAE=", + "ntor-onion-key": "rHEisTL/3HGQ+BOgmG4C7hEbWCSiV1a6+0NaStxwUEM=", + "identity": { + "type": "ed25519", + "master-key": "4GIxWx53osRVYGGk2RzThPkCcdCNj1njcHhUl7NEu1g" + }, + "flavor": "microdesc" + }, + { + "micro-digest": "Ce65iO65lvDwWdyvlWh4St0qNniQ7RS3XzstrFSpYto", + "onion-key": "MIGJAoGBAOSrVSP4UbX152npOD2+DcZsHtLCEkutdMxM/8+XCjrCrK8h4lo3GkBGHrA5piJadIUwWJzzmWjx20k8vTXvFQDAnVuBTz+QTJU/QrM5DamNhHDY5kwKyt8vCyHIb7TXIeKlaBaOMGuebH/37ePZqzEvwAU31TfADT35od1FtBn7AgMBAAE=", + "ntor-onion-key": "tWQ0zfFeYziPs/nZ6qovq2cb9N1xnDT5tn/iZ6+kbSM=", + "identity": { + "type": "ed25519", + "master-key": "lDbXHVUAjECEijL+rQsmTaxkwAHpAsca81v+Hd/TjRg" + }, + "flavor": "microdesc" + } + ] +} diff --git a/data/descriptors_micro_raw.txt b/data/descriptors_micro_raw.txt new file mode 100644 index 0000000..f2e1cd8 --- /dev/null +++ b/data/descriptors_micro_raw.txt @@ -0,0 +1,74 @@ +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMXGxwPQGH9t9pfQSnqrJd7r4ppFaalVCd+HROsS6CA/znvpf/2b9uer +5qucAUYRL0Uhr0o6J0TldxSd3d8WY5Lwn/ZrJ7h4U6SDV024BxqW7R4OMT5ISFgh +89DQN6p1g8mMslGktwZUrCGeEhL32WQAEB/so5wnv7Aa6yYWBDZbAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key pwiw7FWsyJXlLyAa7kOTSyKgaqG3xV+stOE+uGEvsE0= +p accept 1-65535 +p6 accept 1-65535 +id ed25519 RVD4e+ZpIO5hJFWZ1mQvPbpp8YiASSsdM3x+eUDPSGM +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALS2aufFNN2vT315425F+PwmNV8WILh08q3aEVmcn2qpny12d9S2KA/t +U//ZlJhguqVTV1MMY52FstR0NKETDD9pdzHUFSsFCOzLhOzSdNPRrp7+ldZCV+mr +md2i2Dob3dVcyZP8iGORSQDR0D6c70Cfv2jM9LW5FTnaOZ3Dld5LAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key aWrb8rS++QFQnEDvEnSWFQ5Wh8q7JGYY90bkx05LfCM= +p accept 1-65535 +p6 accept 1-65535 +id ed25519 3QRD2H4MaOulm41T865Ya4/xJfO6vNMSl+yfOWksCoo +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMelRVut9suHj0F4uYyAZCsmtlrjRbdmZNvSy7oYbMpdRsKrmEhckXd1 +0UIJOU5oI9+Kf+dWyggcs6/Nx4qar7hXF9nTf18wCYm+UbFtcNzCXLeseaZtDj/M +bHa0+ptykcLFb1VkI4a7cAQ5qPlWUG0qpE/yUGa3kifRd78icwWVAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key 3nwr7McqePaQrbawf0Lkuj72l61AreUJ4ulxjY1grFg= +id ed25519 A1Ly6Uf+PRVV+CeVAQF1FKPYLNrPsWeuXed2h/KLGX0 +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBANXWu7tNGp/m326Ua3ZBr78lRfPD2xPn+R5zU/SjWa32/QpkLPyloJt7 +XzI1JGxMdU+bVgOXuprW51nm+gtfbZ64g6DFFuBEmAEOVfqgCRfgz3yx5J0f9Wch +dfoXqbD2oYxleVZ5qd0VeUve+1uKsB1t6oOIhBbW5VwqhmNbGL63AgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key GXljNcag/Y28zUyMWvwzoGTrY93JtUcNW+E5nx49+Wg= +p accept 1-65535 +p6 accept 1-65535 +id ed25519 Z79/Yq1oq8nT82SKCdV7f8wyofn57h2GVFNQvr2kAns +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALudw0y5z2HX0Yq/jrqjt2lk/GgtuDAIlGaeCa+3Y6Wz/N5UkFfPFb2b +6Rlbgih5IsStFbsI9byY+TuTbQVrJJoSzYxbaOJkNqBxItfWy21x0In0k23Fgdjh +Jtb+CKU3pB3Jtr6ggQ6YiO+RDuyBOx1tpckxxVzD8gqWuOldKrRXAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key PF0gSkZSg5tg/cpO+COBy4MuOBUFy0i24UN1ANjwYBQ= +p accept 1-65535 +p6 accept 1-65535 +id ed25519 40FnzSdF/otItPbTowtcDS7+UzqAw6g9kbmppFeuN3g +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAKo/yPehcMW+7t05pCn5afpDbjSQxlu3PfD+L0AhafCHNv0rTAQIdbj3 +YgQSAutk87HM8MUNPDDSgwvv0coMwfvgAe4reOvtikXoWJSsNq0c4/nZgYbofJms +3mmyHAgp3wIf8BfIV9p5yfwPdrpwQMYpcB+WOeEk3zpwsZvK/xIlAgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key Gfrvc+6ChY2HVlODeevwtCkYdngLpV+/Y/rUHb4qpFc= +p accept 1-65535 +p6 accept 1-65535 +id ed25519 V3yVgZOBaTl0S62HZws3zcw1WDVEEu7wx0qEbVCKaE4 +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALZfNLHagu0C7pRHN8XLZJ/X6U/HVXRmnGRXPEDzjri2bvkljoo9SevP +Gy33KNsztJW370dqvag0ECiMQskdKbI7YTpYfgYkPXL6PhpKWkN2JA/TNKeCZ4Qu +eJke2I/eYdDqolWaFeO/gqVFZJVNuAEjuBM8LpW5kmApRnAE2hv1AgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key rHEisTL/3HGQ+BOgmG4C7hEbWCSiV1a6+0NaStxwUEM= +id ed25519 4GIxWx53osRVYGGk2RzThPkCcdCNj1njcHhUl7NEu1g +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAOSrVSP4UbX152npOD2+DcZsHtLCEkutdMxM/8+XCjrCrK8h4lo3GkBG +HrA5piJadIUwWJzzmWjx20k8vTXvFQDAnVuBTz+QTJU/QrM5DamNhHDY5kwKyt8v +CyHIb7TXIeKlaBaOMGuebH/37ePZqzEvwAU31TfADT35od1FtBn7AgMBAAE= +-----END RSA PUBLIC KEY----- +ntor-onion-key tWQ0zfFeYziPs/nZ6qovq2cb9N1xnDT5tn/iZ6+kbSM= +id ed25519 lDbXHVUAjECEijL+rQsmTaxkwAHpAsca81v+Hd/TjRg diff --git a/data/descriptors_parsed.txt b/data/descriptors_parsed.txt new file mode 100644 index 0000000..2186d88 --- /dev/null +++ b/data/descriptors_parsed.txt @@ -0,0 +1,872 @@ +{ + "flavor": "unflavored", + "descriptors": [ + { + "digest": "3PwzAvlHnjBMdal83IP/VLRe/8o", + "router": { + "nickname": "test006r", + "address": "127.0.0.1", + "orport": 5006, + "socksport": 0, + "dirport": 7006, + "identity": "DZZkh3UlCcgcxHqUEb2HozksADc" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8AW0IbAOjuA1MlGc16R5kfrmeMZqt/wWNV/qagfCLhPYrAQAgBADdBEPYfgxo66WbjVPzrlhrj/El87q80xKX7J85aSwKijmSLlwSWmn0VMyIdLVhUIzpi8T86kCAEgI3kWxVuYxfrVnpQsyeXsxK1HFGiNJ0IwumEO17D2uoUSeDUQ5aEAE=", + "master-key": "3QRD2H4MaOulm41T865Ya4/xJfO6vNMSl+yfOWksCoo" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0 + }, + "fingerprint": "0D96 6487 7525 09C8 1CC4 7A94 11BD 87A3 392C 0037", + "uptime": 0, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 189440 + }, + "extra-info-digest": { + "sha1": "4D6DD8AE820EA87C2F5D92FEB45659B2EB2D8B23", + "sha256": "8H0dw2JR42GgubX7ukH3G1c2vdvadQwWQNsZAefr0iI" + }, + "onion-key": "MIGJAoGBALS2aufFNN2vT315425F+PwmNV8WILh08q3aEVmcn2qpny12d9S2KA/tU//ZlJhguqVTV1MMY52FstR0NKETDD9pdzHUFSsFCOzLhOzSdNPRrp7+ldZCV+mrmd2i2Dob3dVcyZP8iGORSQDR0D6c70Cfv2jM9LW5FTnaOZ3Dld5LAgMBAAE=", + "signing-key": "MIGJAoGBAPzna9Lyc/l6oPWsS6wbMeiN29QyVFCNx7KlYc/1D8XCjoDhnRudt0l6lhfsRdKcTYRiWk2+zHx1mrLUK7iWEEdNkO3uzIMDBlGgjluyPRSmIY1j49KFV9efmHIoa1Jh4xY5J4OBfq6YiRztqEGXVw26yo+aUxkYhrQwtHdpxhXBAgMBAAE=", + "onion-key-crosscert": "Hkuje2pP0ApipboOWs2lSHnNm3kDOd5p7isgR/yBRYSFQsuRHrQllxMkL+bNZ19CiglZMp3cFCA7PzvIhswzQ18zHnjtW38x7GD1lK3tbbzjhCpdSfwAd0scGwAfkvV2lcnFlfS16g1szg3iBwphOkRsF+dV2FCgRO+knpZNVo8=", + "ntor-onion-key-crosscert": { + "bit": 0, + "cert": "AQoABr1WAd0EQ9h+DGjrpZuNU/OuWGuP8SXzurzTEpfsnzlpLAqKAKigoipXObaMLxcxf4e6NLwM7NzhrQ3pYt1sbkuywsAwVSdTJpmK7u3ZJaG5We8wkmTjYzCiN+5XV/zKn/hV2gM=" + }, + "hidden-service-dir": true, + "ntor-onion-key": "aWrb8rS++QFQnEDvEnSWFQ5Wh8q7JGYY90bkx05LfCM=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "accept", + "pattern": "*:*" + } + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "KjlTgXjrJyfmlCvHHTzbN7su0s209DwWkGRLOrj8P3wytuFMCMVwtVm0FUzfzRGP7cdrXU1yoTReDTkVNRS2Aw", + "rsa": "pMnn6YA9DlPZtqzrkCqbUUbwzOdb7v3Uotg8Q8QemAwN44TAIl4Bp7wdwAvokd2GOtbvln/M5SlsB6f8Qej8pYGQjBX4PTS2FdkWPINZRcAOnDWIkTxV7KNmgf1/esuZbO/BPXNCIJDjFwxgnDVxsTC9z1uGMvj7B1M7uu0v6B8=" + }, + "flavor": "unflavored" + }, + { + "digest": "oFui9xopnP51itNGwljfo7HbT0o", + "router": { + "nickname": "test003r", + "address": "127.0.0.1", + "orport": 5003, + "socksport": 0, + "dirport": 7003, + "identity": "fyG+MaPfsktC+PscyWbZlnKXHJ4" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8AWlxroUvsO7RQFFS+JK7m+ns3LNjMtMJy3UCS4oKipBIAQAgBABXfJWBk4FpOXRLrYdnCzfNzDVYNUQS7vDHSoRtUIpoTpzjZGXWN1htRuEsoqeqdMh1jCTw/EuZoutyIcykN3ZvVeBR68cXhFX6ZOEWAe4VUkCJQ8e7Z/pD14NgmUXqiwQ=", + "master-key": "V3yVgZOBaTl0S62HZws3zcw1WDVEEu7wx0qEbVCKaE4" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "13:03:17", + "stamp": 1587646997.0 + }, + "fingerprint": "7F21 BE31 A3DF B24B 42F8 FB1C C966 D996 7297 1C9E", + "uptime": 0, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 177152 + }, + "extra-info-digest": { + "sha1": "C25E5E4C11398A3F812874ADCC12F3950C24B594", + "sha256": "+sT2tuFtt+Nk7pcrZ8IwNCE1kpZttDuN1oEo1qCyCBY" + }, + "onion-key": "MIGJAoGBAKo/yPehcMW+7t05pCn5afpDbjSQxlu3PfD+L0AhafCHNv0rTAQIdbj3YgQSAutk87HM8MUNPDDSgwvv0coMwfvgAe4reOvtikXoWJSsNq0c4/nZgYbofJms3mmyHAgp3wIf8BfIV9p5yfwPdrpwQMYpcB+WOeEk3zpwsZvK/xIlAgMBAAE=", + "signing-key": "MIGJAoGBAN7mRAhH47fns8JOFzkiNkWhdD/pc0BxamTvjJN2uKH/vaN/t9EmjD+ABmpNDCuGua1LfSxikFb2UuyH9jyiGBzOGOJwlTsz7GkqA4skw90u6vw8NrDQel3pILpv/4L8xGWDSadXJjxdvkiQILBM+i0/GVTffPIY1bAJUggTR3bPAgMBAAE=", + "onion-key-crosscert": "B8TGGDQ7SYSxeDQtk/bGocC2pE6JvA5yZzJ3NrTG6eYG2oGwjJMDMkzMn3CQ1Qid0HMienn/7yzOnrX+SUOICxapBV8FKtA1adgKwaV4ZNSiQCjrfhRgLXyoWZXPlbl7/bUnRgsbIg0DLiBeMBHhqyHPNBS0tQZS+2t8kLAJk6k=", + "ntor-onion-key-crosscert": { + "bit": 0, + "cert": "AQoABr1WAVd8lYGTgWk5dEuth2cLN83MNVg1RBLu8MdKhG1QimhOABVYWMeymwYxTzSTIG6Kb3A+d/Q9wUm4mo4PHFfB7C1gzpS3n3ZsUP2PoAwaVgXOABA0FZxu9RVZj0cuhKbp/QA=" + }, + "hidden-service-dir": true, + "ntor-onion-key": "Gfrvc+6ChY2HVlODeevwtCkYdngLpV+/Y/rUHb4qpFc=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "accept", + "pattern": "*:*" + } + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "TPBHM0+J5l7eGnTkszDzTiTqwQdRMNQKJ4a5HX4LTUNRdMHadDWn98xpD6TEk9PCX9JWUesckGMgCvQtQOehAA", + "rsa": "QtYjMswOniakAAwTrcRR+fpRj4hTIw+x9uagsKEveBL7mq3WzIBUb3AF9dHEQTbZUJ+8KZLEvU7ypmFBcyqh7jQMOhI4VCUesL1GmMLMBmAcHFw7O6Bgv0OW1bWmwErIgpay16p2vt8HVM7mBgN6cBoyzkIifoRyB3ummtM6KqA=" + }, + "flavor": "unflavored" + }, + { + "digest": "nqEUOJNLYa8/uoLqj4SWRRe1IXk", + "router": { + "nickname": "test001a", + "address": "127.0.0.1", + "orport": 5001, + "socksport": 0, + "dirport": 7001, + "identity": "/Vd+YTRcdGVeZ7R61X23NSUf634" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8ARflhB/X8ODKSsuPbmUgm2GGTlG9GUn/aMkbMb4vEZcvAQAgBADgYjFbHneixFVgYaTZHNOE+QJx0I2PWeNweFSXs0S7WPsaUwmUpD7F3cekyDuj/6gVQhfBVLp8WVtGBCkjbdMrNhyPFqtXRW8RgLB39wu2NvngdatO1Zvt+E5sDoFWLwA=", + "master-key": "4GIxWx53osRVYGGk2RzThPkCcdCNj1njcHhUl7NEu1g" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "14:05:47", + "stamp": 1587650747.0 + }, + "fingerprint": "FD57 7E61 345C 7465 5E67 B47A D57D B735 251F EB7E", + "uptime": 1, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 159744 + }, + "extra-info-digest": { + "sha1": "D2E5DF7EC379702F299EB7488DCF9588529A4BF5", + "sha256": "cmFu5HDDJlreMq7tmTaGDTIrS96K9GXJAjyiBSmlYIM" + }, + "caches-extra-info": true, + "onion-key": "MIGJAoGBALZfNLHagu0C7pRHN8XLZJ/X6U/HVXRmnGRXPEDzjri2bvkljoo9SevPGy33KNsztJW370dqvag0ECiMQskdKbI7YTpYfgYkPXL6PhpKWkN2JA/TNKeCZ4QueJke2I/eYdDqolWaFeO/gqVFZJVNuAEjuBM8LpW5kmApRnAE2hv1AgMBAAE=", + "signing-key": "MIGJAoGBAM2l5g/jG5MFSKyx5fUvGW8MORY8bj8hbkzYV8M4Urnp2IuO8zOUUou3KBkcM8ECnmsuAITwF3oZTxFVbJm9O0fMFmq/6WhBYeby2AYWCVWTNJIKf/h/iUsPIC8hbKLtemPjg9aw5bMaM//1X1Qw4Fj+yyEaUHA11+y9YMp9LL9jAgMBAAE=", + "onion-key-crosscert": "XKQM9Ifbsuw68pGTcnajaDiNJqXgNpk2t6pE4UZz7jTXPYiM87KJXWb5PNjI16wfEB2jjw44FHkC3zX+Vf7gKVptL65jPHRq4OMSmQufhudzPY5RfKOJBoMhxZ8nPbwOuTFMtZaIH50eDAtEgF6g5GTKlBrCBRVeIh0vDGlz3Yg=", + "ntor-onion-key-crosscert": { + "bit": 1, + "cert": "AQoABr1XAeBiMVsed6LEVWBhpNkc04T5AnHQjY9Z43B4VJezRLtYAEuC1rDzjUq7MgSfbK89i2aXoOe+RyMyMhF9LcYJht2Ny4NaS2cmKQKPuNomVf4jCF/HA+ZeZ6Uil1lwvbIsqwQ=" + }, + "hidden-service-dir": true, + "contact": "auth1@test.test", + "ntor-onion-key": "rHEisTL/3HGQ+BOgmG4C7hEbWCSiV1a6+0NaStxwUEM=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "reject", + "pattern": "*:*" + } + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "hCXu7qGmcqldIWYmTdzRPbE0hpKWXgfw5TySqUoVY/D+zTbG/hSrEg0yS4sw8DQ7nLgXVtevkw7LY1gFIXwODg", + "rsa": "Do+H9dvTpuMLiipNWw9wgZGovZnI5lNgSuN+38bg0KA5wiBKH5Xe+V3nvdZa3gviTTRCJ8eG690xF96oYLdeDXOx2VarRsJrK/TcOgcXmuaqBhxZgl2vmbhiRBmSNRt+3HWOL227MX5uRL9LuGWcr0qYmL7BanKqYC6jWRmTQhw=" + }, + "flavor": "unflavored" + }, + { + "digest": "gnIFTS4rtcqqKOb0ZQSN6Y9A2GQ", + "router": { + "nickname": "test000a", + "address": "127.0.0.1", + "orport": 5000, + "socksport": 0, + "dirport": 7000, + "identity": "S7wZlq4DvwY/2ZA/WrIzydmmRoY" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8Adp+flIgMdM1u8bxfTBjyuLyzKjAZGc7BVdEGKfZvXC1AQAgBAADUvLpR/49FVX4J5UBAXUUo9gs2s+xZ65d53aH8osZfXGo6nw2oar6vrc0/xUOOIZLMRjH/EaIpCPWoCIScTTocq2igb2I505Lpux0fZtYCf9biQSxS4xsmcXv5tb+bQs=", + "master-key": "A1Ly6Uf+PRVV+CeVAQF1FKPYLNrPsWeuXed2h/KLGX0" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "14:05:47", + "stamp": 1587650747.0 + }, + "fingerprint": "4BBC 1996 AE03 BF06 3FD9 903F 5AB2 33C9 D9A6 4686", + "uptime": 1, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 224256 + }, + "extra-info-digest": { + "sha1": "6D9372261E444BF26567C9D781DFEAC9575EA00E", + "sha256": "8ublGY+pE+AERi/45al4GrzeJbwdeS7u3bacedxf3J8" + }, + "caches-extra-info": true, + "onion-key": "MIGJAoGBAMelRVut9suHj0F4uYyAZCsmtlrjRbdmZNvSy7oYbMpdRsKrmEhckXd10UIJOU5oI9+Kf+dWyggcs6/Nx4qar7hXF9nTf18wCYm+UbFtcNzCXLeseaZtDj/MbHa0+ptykcLFb1VkI4a7cAQ5qPlWUG0qpE/yUGa3kifRd78icwWVAgMBAAE=", + "signing-key": "MIGJAoGBAL51NXLR4J1WUreKNmwYVAJG3e0K7MNC/6mM3UK8CYg04AykYFchRcXZpqFR6JnvxCL603zQ5/AXozLOVPd1ioQKCnAb1AQSMJ0wn34B0CFkJTBJ1TMZGy8/k9L493V4xzS36cRLv5XHpQHiFCEC6R/qFqJm+IA9wi99a4NE4itdAgMBAAE=", + "onion-key-crosscert": "sEP32JDdsB7Tt0H8ObsAXHseNcsZqT9VvghhCAyS0sIGZtENE+bAm1zvQqeT/09I7PIaivX2H4iEl2L5abgip+tGM+/o+SOyHSwLuNK4AXXE01Q8Jweg/iFxW3FyoMt3RUM9F3a9vzCETjfXb9Z57p+JRMk5zDwgjrDFoMhD/tA=", + "ntor-onion-key-crosscert": { + "bit": 1, + "cert": "AQoABr1XAQNS8ulH/j0VVfgnlQEBdRSj2Czaz7Fnrl3ndofyixl9AGwgu2vZXabOLBQkdCzqAPX+WPxJuz/vb7eOD8PE8p3KVUK1gZrCFjsqKVgxg5LzjtWRz6jTtTwj3aXkMbbR1w4=" + }, + "hidden-service-dir": true, + "contact": "auth0@test.test", + "ntor-onion-key": "3nwr7McqePaQrbawf0Lkuj72l61AreUJ4ulxjY1grFg=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "reject", + "pattern": "*:*" + } + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "ddERq8NwwXQqCECtbhNLLGiJDLELtasGJ8AsXGzfSAKpepO7HDpFSrLp1SIbqVwA4E+XAC1ecC0UUFsn0UttDw", + "rsa": "S6egsvA+DEU5J7hAPwTkGth2jCQXx2ACYIJjBTYalm6TutOgSsNRItq52SwUXyxGHcFscDarXSMpwb6Ib0TIvn9KWJVsK9RcYpPudMiFjc5vEqf0J2UmW5c4CZ0agjbDbGMsBQW+YppPf3UjvxxoAxx/GcK7C0dz+QtgNeJAr0A=" + }, + "flavor": "unflavored" + }, + { + "digest": "csdBDdGdl0KWL6mMlgpqB6W5me0", + "router": { + "nickname": "test004r", + "address": "127.0.0.1", + "orport": 5004, + "socksport": 0, + "dirport": 7004, + "identity": "PE+93pE5LeQheWR29bZjhX3zqnQ" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8AYoG/9r512Cml9ZeRg/pkYe4g9q88zoNiZaHBHpUxUaZAQAgBABnv39irWirydPzZIoJ1Xt/zDKh+fnuHYZUU1C+vaQCe43URBPKgztmDxfGlj/lbCMpw9H7RRHx/mhX+eGrcisx7tPSsyO3mOAu5T68CC2BxSncmpjjoWm/g2vwTa6L2gE=", + "master-key": "Z79/Yq1oq8nT82SKCdV7f8wyofn57h2GVFNQvr2kAns" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0 + }, + "fingerprint": "3C4F BDDE 9139 2DE4 2179 6476 F5B6 6385 7DF3 AA74", + "uptime": 0, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 174080 + }, + "extra-info-digest": { + "sha1": "E5E2234DF477A870F6B11ED0887CA785B7CFCC3C", + "sha256": "NVVQEW9XoRTxhzZ4GaynkC8NNiptVwqxqKA+fggtjYg" + }, + "onion-key": "MIGJAoGBANXWu7tNGp/m326Ua3ZBr78lRfPD2xPn+R5zU/SjWa32/QpkLPyloJt7XzI1JGxMdU+bVgOXuprW51nm+gtfbZ64g6DFFuBEmAEOVfqgCRfgz3yx5J0f9WchdfoXqbD2oYxleVZ5qd0VeUve+1uKsB1t6oOIhBbW5VwqhmNbGL63AgMBAAE=", + "signing-key": "MIGJAoGBAKLhsoHCOYO7izilNEnzx2K7zHF7QiGTjXYtlCE+nsa5vSDys0mjwiKoAzsSiMCmMwhHd7/DQLDRwuW9qyzc26k0sPqANe8QLb5URRrEBDIgajhzVw7gZGxM2+tgjl14sU+okyreCLRb3WorEIG4TdN6b6fYZrBbjsaaBhtAqyMBAgMBAAE=", + "onion-key-crosscert": "LH8XjjKXgCzdtbutJqWg/RsqrKoL2b8AtfyQC5E31nN9ZDetDKzYyY/a3lXR0nxdrUsm6bOzDNt67YQYCJ8hlw51BDC1Jue2rmvLhqm+GHTGMIWLmSTYFPjUa0KWziTA35pi3pXStr7oOgyoVt5OQ/Byidv1U1aVL87nOHHPye4=", + "ntor-onion-key-crosscert": { + "bit": 0, + "cert": "AQoABr1WAWe/f2KtaKvJ0/NkignVe3/MMqH5+e4dhlRTUL69pAJ7AKSkGEdPDl632LhYLVCtGT7aDzr6QRfHdkd5aWfAFbwVUj5K4K85AGyrLz97nCCEV2t940kkcmd07p/0Vx4XWA0=" + }, + "hidden-service-dir": true, + "ntor-onion-key": "GXljNcag/Y28zUyMWvwzoGTrY93JtUcNW+E5nx49+Wg=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "accept", + "pattern": "*:*" + } + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "KstXDyPHMNcEcL/zai9sQfwXcAdZ6VkPU76mwJX7IvKGbUaVFozIeYnDt3Oa0Hd2wSzMK4nr67XaW3uDvpNQBQ", + "rsa": "VVDAWwWFfA7hiSTbaTrslICU14AIO/cF0/tsBGtv2wyBmxSlW9yYARvLKkiGPfXnFYqSwH4Nd/MvadF2E+dkYSYsnPYqeFxN9mKN2csNeF3PmeL/1254bQx8RKbBy8pi4mnkeBAA6OqOa44CTkMQfP4A6iSsGpbKrarslHo9uEg=" + }, + "flavor": "unflavored" + }, + { + "digest": "E2Xey5uxMfoMjewSace3TG/+Id8", + "router": { + "nickname": "test002a", + "address": "127.0.0.1", + "orport": 5002, + "socksport": 0, + "dirport": 7002, + "identity": "gwTBYQWI3XQvsEkcal8NUySwsVA" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8AeOCME3/p+dJeC85a+wrBmqz26UzrCRo6Xe8e3SJCQ3LAQAgBACUNtcdVQCMQISKMv6tCyZNrGTAAekCxxrzW/4d39ONGBafrqeRTbGsrdq7TcIyjdxdvNTlBzPv2IRArJ9acR3e4ob/yLUKu1AkAFD1A+jkqEBl0+uMT7a4Pr6eapH8ZgI=", + "master-key": "lDbXHVUAjECEijL+rQsmTaxkwAHpAsca81v+Hd/TjRg" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "14:05:47", + "stamp": 1587650747.0 + }, + "fingerprint": "8304 C161 0588 DD74 2FB0 491C 6A5F 0D53 24B0 B150", + "uptime": 1, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 237568 + }, + "extra-info-digest": { + "sha1": "51BB38ECA5F77F18D52F460B6A00A4C411081F72", + "sha256": "CrUyVdL0IJHxiasJEJN09E7RZN9wc8wRYe2kOsZiFrg" + }, + "caches-extra-info": true, + "onion-key": "MIGJAoGBAOSrVSP4UbX152npOD2+DcZsHtLCEkutdMxM/8+XCjrCrK8h4lo3GkBGHrA5piJadIUwWJzzmWjx20k8vTXvFQDAnVuBTz+QTJU/QrM5DamNhHDY5kwKyt8vCyHIb7TXIeKlaBaOMGuebH/37ePZqzEvwAU31TfADT35od1FtBn7AgMBAAE=", + "signing-key": "MIGJAoGBAKFkXl9LlavRpeM9Ku2Qg4Np5SRrnjkgLwDzO+8iHTV9AryCfDvHJ28kCl3FouvEe5XOY95bOyMVY94XSjMjRbcrn+srmurAedCg8RulfZf83z1Bt/CpsrZ3fUH7WJiFPBY+J/0OKjoYenZpYf1qIONoHU6x+qmtg1smMuZUa2VzAgMBAAE=", + "onion-key-crosscert": "4TJXl8rbc6eGJx9yDWJUiEI1jhT+HZ2FEYgTx/0KcJscR48UNzYd/koTWJgWJ8L6+M9JHqXi6WUJfqPZvpignQ7k++KWe74XCZ1n+Qncbx3hQkHMqWpAO8NYeGRG9qZzVoE/chVH3DeWPTLSEx48vUuzLarnQ3Rwm9hc1RoCT3Y=", + "ntor-onion-key-crosscert": { + "bit": 0, + "cert": "AQoABr1XAZQ21x1VAIxAhIoy/q0LJk2sZMAB6QLHGvNb/h3f040YAEb4mIEsNJbi1ackkJsDkPkNrn40m0ErB5Nvhu/VDb2SJ86O36CRX/Y8vOiu2AWRVIEkQ1bRBt6CR0a7wEzw/gw=" + }, + "hidden-service-dir": true, + "contact": "auth2@test.test", + "ntor-onion-key": "tWQ0zfFeYziPs/nZ6qovq2cb9N1xnDT5tn/iZ6+kbSM=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "reject", + "pattern": "*:*" + } + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "OVaWiTk3zNj3dM0SpS095xzYZN1B3BP9C//L0UbI5ter/1Yszg5df8sQtdlEdcfc3q5o2/HaAvwy44ggYDkWDA", + "rsa": "N5wMY7P6q9zQwKbBfqArMnnl1xE6Q5dLicXNx1cvEn+VBuJwFFlqzYV/vzM7bvBwdTHlVRxxx7MKaVpFuPJKLeezYLArWMnJYalWtfFd/IKBfH8ykhKkKAaPw16XmyF1pt9iQ91c15ogaHZeh/f9bzl9ej1YKleVhJQ8nvM46l4=" + }, + "flavor": "unflavored" + }, + { + "digest": "BZBtDoo3FMkyFg5trmoZgcHWH3w", + "router": { + "nickname": "test007r", + "address": "127.0.0.1", + "orport": 5007, + "socksport": 0, + "dirport": 7007, + "identity": "mXQh1rmHcqj+uqptfh158WA5bfo" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8AWk/NSWnFyEYyp3OyTZVWud6VJ8FuXLFzpmatS+wLmHPAQAgBADjQWfNJ0X+i0i09tOjC1wNLv5TOoDDqD2RuamkV643eNNQ7/uevaTjIY0MpDS7SwP3Oq74X1FePV8jtgI7ql8Gvr/W5zZgmsc2z7hdBn+TaETPlimjU91/3CbHTX3+1QU=", + "master-key": "40FnzSdF/otItPbTowtcDS7+UzqAw6g9kbmppFeuN3g" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0 + }, + "fingerprint": "9974 21D6 B987 72A8 FEBA AA6D 7E1D 79F1 6039 6DFA", + "uptime": 0, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 189440 + }, + "extra-info-digest": { + "sha1": "56FE973CD5A174114589264751D266E281A38C48", + "sha256": "TzShXNTaP17YBiUr17G5yZEdLA35HiqNMMF7Y8KR7fw" + }, + "onion-key": "MIGJAoGBALudw0y5z2HX0Yq/jrqjt2lk/GgtuDAIlGaeCa+3Y6Wz/N5UkFfPFb2b6Rlbgih5IsStFbsI9byY+TuTbQVrJJoSzYxbaOJkNqBxItfWy21x0In0k23FgdjhJtb+CKU3pB3Jtr6ggQ6YiO+RDuyBOx1tpckxxVzD8gqWuOldKrRXAgMBAAE=", + "signing-key": "MIGJAoGBAJ/xoMb6ioCY0tnjCceKn0QDothQfRO0KDvIJWae/mV5nsOTx4PNMqnb+CQ3S2fw6P6KouIe+kD2RbmB1eBWIq5hvqrRAFhgjDZl7TvVb7HmdZzDNzYZIf/4ugvOYypDejtvusV0POxkkm4+Fl+zhKt8AOXDTuEAexxmZZVBjHPJAgMBAAE=", + "onion-key-crosscert": "qggW8Tvd1ruGUDFYT9llbVvJ57l50JKJd9fBrhfaG9/ddLySWNVNGQ80+azoKqumZEb/PF6kmkJJfywUfsbz5dbw0Hm2VROuK5RlHzw7hjjZZYU/f+egiyIQKHOXI9lN9Vu9Y55vTpFnJLyIxNeps3n33LYsoIBktfCCZI7qmmI=", + "ntor-onion-key-crosscert": { + "bit": 1, + "cert": "AQoABr1WAeNBZ80nRf6LSLT206MLXA0u/lM6gMOoPZG5qaRXrjd4ADNCsVBg3PAANCoTDPbwvMrd0TlZO5QfflO6S22BBjPSCCqS/Sx/7nBT3an2cfKq0k4q+osZOhogpzFXEYf8/gY=" + }, + "hidden-service-dir": true, + "ntor-onion-key": "PF0gSkZSg5tg/cpO+COBy4MuOBUFy0i24UN1ANjwYBQ=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "accept", + "pattern": "*:*" + } + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "y17o7UoOY6iU8tQeAYlmfyB28QyBGHRq2eAYMNBatpBnRHqrEQOCi19T9T0OHXsth88IIN17dSde9Rz8okW0Bg", + "rsa": "FDz5y5IDxnBZXOV3dpPTZ5cFKcz5r5N3hwWrf5PCEIx9sL4SWgM6MxtVCDPmcAG9ZFXettHOFUPzqQ30ARgMy5wUhk5pvH7QHp7rsJmQ5rqa8ph26KR4tsNOB8pZm9W7N7KhMfC5/dcMviLEOBSfaeG1+BkPjF4ePv7TrK47zc8=" + }, + "flavor": "unflavored" + }, + { + "digest": "AACG/Oo9Q3PdYwer8Amxufwv44c", + "router": { + "nickname": "test005r", + "address": "127.0.0.1", + "orport": 5005, + "socksport": 0, + "dirport": 7005, + "identity": "nu8OBtyhPu7L2+p0cdzQSZc5hbA" + }, + "identity": { + "type": "ed25519", + "cert": "AQQABrr8AWE1SUv5e7hKhWzVlBXH98Gfab6Y9h55g631DH7y+TTHAQAgBABFUPh75mkg7mEkVZnWZC89umnxiIBJKx0zfH55QM9IYxvs7AWek+i9Ifxwz2VxTrh3eVOXq1Y/6Bdmj5lw96VTDzftYwciyZkZntYZXCdVYavT7wCt+/e7py1SX3G2fQ4=", + "master-key": "RVD4e+ZpIO5hJFWZ1mQvPbpp8YiASSsdM3x+eUDPSGM" + }, + "platform": "Tor 0.3.5.10 on Linux", + "proto": { + "Cons": [ + 1, + 2 + ], + "Desc": [ + 1, + 2 + ], + "DirCache": [ + 1, + 2 + ], + "HSDir": [ + 1, + 2 + ], + "HSIntro": [ + 3, + 4 + ], + "HSRend": [ + 1, + 2 + ], + "Link": [ + 1, + 2, + 3, + 4, + 5 + ], + "LinkAuth": [ + 1, + 3 + ], + "Microdesc": [ + 1, + 2 + ], + "Relay": [ + 1, + 2 + ] + }, + "published": { + "date": "2020-04-23", + "time": "13:03:18", + "stamp": 1587646998.0 + }, + "fingerprint": "9EEF 0E06 DCA1 3EEE CBDB EA74 71DC D049 9739 85B0", + "uptime": 0, + "bandwidth": { + "avg": 1073741824, + "burst": 1073741824, + "observed": 189440 + }, + "extra-info-digest": { + "sha1": "820DBEF5FC8FDD057F1FE574D0CCCF1F41EBEC8F", + "sha256": "dVw7XxBxmgqk5jH2q3O5rvt3hNnZSj4v+IHnP74FXkk" + }, + "onion-key": "MIGJAoGBAMXGxwPQGH9t9pfQSnqrJd7r4ppFaalVCd+HROsS6CA/znvpf/2b9uer5qucAUYRL0Uhr0o6J0TldxSd3d8WY5Lwn/ZrJ7h4U6SDV024BxqW7R4OMT5ISFgh89DQN6p1g8mMslGktwZUrCGeEhL32WQAEB/so5wnv7Aa6yYWBDZbAgMBAAE=", + "signing-key": "MIGJAoGBALlb0Bwo4WAKyF7hHRv3bD/MSf2k77zHB1CF4a8CocSqDcbqscnQf1JwzL/UFzhTcCL24schDUE7itY50bkBTRZFo9XG2giEm5nNkAe8PuHy1GK5HZK0uRWwT3P7B+/PYgw0EQm0x7evDp2QW/I7DLnQCJwY7Ltde013VcEM1W+1AgMBAAE=", + "onion-key-crosscert": "MFKBENIMaIWMa9rJhlAcNMdy+SJnOJ2vCfzkqC8JezOCrJKv1yAQVGCGihM2jre6H1aLMqG7JTScpQ138q0pMJObvv6CIjRFiiy9KB43oufbjGYmVIkLpvQy/T21mgc+PW4qWhNQHng8xDG2Wb6pBhwUASK31g32p3LXRj8P1vg=", + "ntor-onion-key-crosscert": { + "bit": 0, + "cert": "AQoABr1WAUVQ+HvmaSDuYSRVmdZkLz26afGIgEkrHTN8fnlAz0hjACh5/LiYnwvSwy3bgnk7olcN+Wzou7TAqgKZ0Or3TNcxx/v5tLpaaUJ9i4MZAmlNg+IhKhuVKW6CICb05F54oQo=" + }, + "hidden-service-dir": true, + "ntor-onion-key": "pwiw7FWsyJXlLyAa7kOTSyKgaqG3xV+stOE+uGEvsE0=", + "policy": { + "type": "exitpattern", + "rules": [ + { + "type": "accept", + "pattern": "*:*" + } + ] + }, + "ipv6-policy": { + "type": "accept", + "PortList": [ + [ + 1, + 65535 + ] + ] + }, + "tunnelled-dir-server": true, + "router-signatures": { + "ed25519": "SrUQnmdUxyWERZM6KWhjEheb0A7HLQSjGAi3DbhCtuvQ6Ho4RDHbsB5NpzOL6Xu/lpW3YBORnBzkBxQOT7QPDg", + "rsa": "PIrLtjkjB73TqQRsxwIGfZxaUtnDedKnrvs4181L+mBL51uoN248Q81UrtJkCK8nU1qIlxGT++dO3dxVp/KbS8x65/6YXXtynb/hoQBW7L8KkV9E4kabzWT5jAlzggHvE8AVQplUEw8QUga/WmkG+FOvYGenYfKgeudUdSYQsR8=" + }, + "flavor": "unflavored" + } + ] +} \ No newline at end of file diff --git a/data/descriptors_raw.txt b/data/descriptors_raw.txt new file mode 100644 index 0000000..4dda544 --- /dev/null +++ b/data/descriptors_raw.txt @@ -0,0 +1,411 @@ +router test006r 127.0.0.1 5006 0 7006 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8AW0IbAOjuA1MlGc16R5kfrmeMZqt/wWNV/qagfCLhPYrAQAgBADdBEPY +fgxo66WbjVPzrlhrj/El87q80xKX7J85aSwKijmSLlwSWmn0VMyIdLVhUIzpi8T8 +6kCAEgI3kWxVuYxfrVnpQsyeXsxK1HFGiNJ0IwumEO17D2uoUSeDUQ5aEAE= +-----END ED25519 CERT----- +master-key-ed25519 3QRD2H4MaOulm41T865Ya4/xJfO6vNMSl+yfOWksCoo +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 13:03:18 +fingerprint 0D96 6487 7525 09C8 1CC4 7A94 11BD 87A3 392C 0037 +uptime 0 +bandwidth 1073741824 1073741824 189440 +extra-info-digest 4D6DD8AE820EA87C2F5D92FEB45659B2EB2D8B23 8H0dw2JR42GgubX7ukH3G1c2vdvadQwWQNsZAefr0iI +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALS2aufFNN2vT315425F+PwmNV8WILh08q3aEVmcn2qpny12d9S2KA/t +U//ZlJhguqVTV1MMY52FstR0NKETDD9pdzHUFSsFCOzLhOzSdNPRrp7+ldZCV+mr +md2i2Dob3dVcyZP8iGORSQDR0D6c70Cfv2jM9LW5FTnaOZ3Dld5LAgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAPzna9Lyc/l6oPWsS6wbMeiN29QyVFCNx7KlYc/1D8XCjoDhnRudt0l6 +lhfsRdKcTYRiWk2+zHx1mrLUK7iWEEdNkO3uzIMDBlGgjluyPRSmIY1j49KFV9ef +mHIoa1Jh4xY5J4OBfq6YiRztqEGXVw26yo+aUxkYhrQwtHdpxhXBAgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +Hkuje2pP0ApipboOWs2lSHnNm3kDOd5p7isgR/yBRYSFQsuRHrQllxMkL+bNZ19C +iglZMp3cFCA7PzvIhswzQ18zHnjtW38x7GD1lK3tbbzjhCpdSfwAd0scGwAfkvV2 +lcnFlfS16g1szg3iBwphOkRsF+dV2FCgRO+knpZNVo8= +-----END CROSSCERT----- +ntor-onion-key-crosscert 0 +-----BEGIN ED25519 CERT----- +AQoABr1WAd0EQ9h+DGjrpZuNU/OuWGuP8SXzurzTEpfsnzlpLAqKAKigoipXObaM +Lxcxf4e6NLwM7NzhrQ3pYt1sbkuywsAwVSdTJpmK7u3ZJaG5We8wkmTjYzCiN+5X +V/zKn/hV2gM= +-----END ED25519 CERT----- +hidden-service-dir +ntor-onion-key aWrb8rS++QFQnEDvEnSWFQ5Wh8q7JGYY90bkx05LfCM= +accept *:* +ipv6-policy accept 1-65535 +tunnelled-dir-server +router-sig-ed25519 KjlTgXjrJyfmlCvHHTzbN7su0s209DwWkGRLOrj8P3wytuFMCMVwtVm0FUzfzRGP7cdrXU1yoTReDTkVNRS2Aw +router-signature +-----BEGIN SIGNATURE----- +pMnn6YA9DlPZtqzrkCqbUUbwzOdb7v3Uotg8Q8QemAwN44TAIl4Bp7wdwAvokd2G +Otbvln/M5SlsB6f8Qej8pYGQjBX4PTS2FdkWPINZRcAOnDWIkTxV7KNmgf1/esuZ +bO/BPXNCIJDjFwxgnDVxsTC9z1uGMvj7B1M7uu0v6B8= +-----END SIGNATURE----- +router test003r 127.0.0.1 5003 0 7003 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8AWlxroUvsO7RQFFS+JK7m+ns3LNjMtMJy3UCS4oKipBIAQAgBABXfJWB +k4FpOXRLrYdnCzfNzDVYNUQS7vDHSoRtUIpoTpzjZGXWN1htRuEsoqeqdMh1jCTw +/EuZoutyIcykN3ZvVeBR68cXhFX6ZOEWAe4VUkCJQ8e7Z/pD14NgmUXqiwQ= +-----END ED25519 CERT----- +master-key-ed25519 V3yVgZOBaTl0S62HZws3zcw1WDVEEu7wx0qEbVCKaE4 +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 13:03:17 +fingerprint 7F21 BE31 A3DF B24B 42F8 FB1C C966 D996 7297 1C9E +uptime 0 +bandwidth 1073741824 1073741824 177152 +extra-info-digest C25E5E4C11398A3F812874ADCC12F3950C24B594 +sT2tuFtt+Nk7pcrZ8IwNCE1kpZttDuN1oEo1qCyCBY +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAKo/yPehcMW+7t05pCn5afpDbjSQxlu3PfD+L0AhafCHNv0rTAQIdbj3 +YgQSAutk87HM8MUNPDDSgwvv0coMwfvgAe4reOvtikXoWJSsNq0c4/nZgYbofJms +3mmyHAgp3wIf8BfIV9p5yfwPdrpwQMYpcB+WOeEk3zpwsZvK/xIlAgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAN7mRAhH47fns8JOFzkiNkWhdD/pc0BxamTvjJN2uKH/vaN/t9EmjD+A +BmpNDCuGua1LfSxikFb2UuyH9jyiGBzOGOJwlTsz7GkqA4skw90u6vw8NrDQel3p +ILpv/4L8xGWDSadXJjxdvkiQILBM+i0/GVTffPIY1bAJUggTR3bPAgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +B8TGGDQ7SYSxeDQtk/bGocC2pE6JvA5yZzJ3NrTG6eYG2oGwjJMDMkzMn3CQ1Qid +0HMienn/7yzOnrX+SUOICxapBV8FKtA1adgKwaV4ZNSiQCjrfhRgLXyoWZXPlbl7 +/bUnRgsbIg0DLiBeMBHhqyHPNBS0tQZS+2t8kLAJk6k= +-----END CROSSCERT----- +ntor-onion-key-crosscert 0 +-----BEGIN ED25519 CERT----- +AQoABr1WAVd8lYGTgWk5dEuth2cLN83MNVg1RBLu8MdKhG1QimhOABVYWMeymwYx +TzSTIG6Kb3A+d/Q9wUm4mo4PHFfB7C1gzpS3n3ZsUP2PoAwaVgXOABA0FZxu9RVZ +j0cuhKbp/QA= +-----END ED25519 CERT----- +hidden-service-dir +ntor-onion-key Gfrvc+6ChY2HVlODeevwtCkYdngLpV+/Y/rUHb4qpFc= +accept *:* +ipv6-policy accept 1-65535 +tunnelled-dir-server +router-sig-ed25519 TPBHM0+J5l7eGnTkszDzTiTqwQdRMNQKJ4a5HX4LTUNRdMHadDWn98xpD6TEk9PCX9JWUesckGMgCvQtQOehAA +router-signature +-----BEGIN SIGNATURE----- +QtYjMswOniakAAwTrcRR+fpRj4hTIw+x9uagsKEveBL7mq3WzIBUb3AF9dHEQTbZ +UJ+8KZLEvU7ypmFBcyqh7jQMOhI4VCUesL1GmMLMBmAcHFw7O6Bgv0OW1bWmwErI +gpay16p2vt8HVM7mBgN6cBoyzkIifoRyB3ummtM6KqA= +-----END SIGNATURE----- +router test001a 127.0.0.1 5001 0 7001 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8ARflhB/X8ODKSsuPbmUgm2GGTlG9GUn/aMkbMb4vEZcvAQAgBADgYjFb +HneixFVgYaTZHNOE+QJx0I2PWeNweFSXs0S7WPsaUwmUpD7F3cekyDuj/6gVQhfB +VLp8WVtGBCkjbdMrNhyPFqtXRW8RgLB39wu2NvngdatO1Zvt+E5sDoFWLwA= +-----END ED25519 CERT----- +master-key-ed25519 4GIxWx53osRVYGGk2RzThPkCcdCNj1njcHhUl7NEu1g +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 14:05:47 +fingerprint FD57 7E61 345C 7465 5E67 B47A D57D B735 251F EB7E +uptime 1 +bandwidth 1073741824 1073741824 159744 +extra-info-digest D2E5DF7EC379702F299EB7488DCF9588529A4BF5 cmFu5HDDJlreMq7tmTaGDTIrS96K9GXJAjyiBSmlYIM +caches-extra-info +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALZfNLHagu0C7pRHN8XLZJ/X6U/HVXRmnGRXPEDzjri2bvkljoo9SevP +Gy33KNsztJW370dqvag0ECiMQskdKbI7YTpYfgYkPXL6PhpKWkN2JA/TNKeCZ4Qu +eJke2I/eYdDqolWaFeO/gqVFZJVNuAEjuBM8LpW5kmApRnAE2hv1AgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAM2l5g/jG5MFSKyx5fUvGW8MORY8bj8hbkzYV8M4Urnp2IuO8zOUUou3 +KBkcM8ECnmsuAITwF3oZTxFVbJm9O0fMFmq/6WhBYeby2AYWCVWTNJIKf/h/iUsP +IC8hbKLtemPjg9aw5bMaM//1X1Qw4Fj+yyEaUHA11+y9YMp9LL9jAgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +XKQM9Ifbsuw68pGTcnajaDiNJqXgNpk2t6pE4UZz7jTXPYiM87KJXWb5PNjI16wf +EB2jjw44FHkC3zX+Vf7gKVptL65jPHRq4OMSmQufhudzPY5RfKOJBoMhxZ8nPbwO +uTFMtZaIH50eDAtEgF6g5GTKlBrCBRVeIh0vDGlz3Yg= +-----END CROSSCERT----- +ntor-onion-key-crosscert 1 +-----BEGIN ED25519 CERT----- +AQoABr1XAeBiMVsed6LEVWBhpNkc04T5AnHQjY9Z43B4VJezRLtYAEuC1rDzjUq7 +MgSfbK89i2aXoOe+RyMyMhF9LcYJht2Ny4NaS2cmKQKPuNomVf4jCF/HA+ZeZ6Ui +l1lwvbIsqwQ= +-----END ED25519 CERT----- +hidden-service-dir +contact auth1@test.test +ntor-onion-key rHEisTL/3HGQ+BOgmG4C7hEbWCSiV1a6+0NaStxwUEM= +reject *:* +tunnelled-dir-server +router-sig-ed25519 hCXu7qGmcqldIWYmTdzRPbE0hpKWXgfw5TySqUoVY/D+zTbG/hSrEg0yS4sw8DQ7nLgXVtevkw7LY1gFIXwODg +router-signature +-----BEGIN SIGNATURE----- +Do+H9dvTpuMLiipNWw9wgZGovZnI5lNgSuN+38bg0KA5wiBKH5Xe+V3nvdZa3gvi +TTRCJ8eG690xF96oYLdeDXOx2VarRsJrK/TcOgcXmuaqBhxZgl2vmbhiRBmSNRt+ +3HWOL227MX5uRL9LuGWcr0qYmL7BanKqYC6jWRmTQhw= +-----END SIGNATURE----- +router test000a 127.0.0.1 5000 0 7000 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8Adp+flIgMdM1u8bxfTBjyuLyzKjAZGc7BVdEGKfZvXC1AQAgBAADUvLp +R/49FVX4J5UBAXUUo9gs2s+xZ65d53aH8osZfXGo6nw2oar6vrc0/xUOOIZLMRjH +/EaIpCPWoCIScTTocq2igb2I505Lpux0fZtYCf9biQSxS4xsmcXv5tb+bQs= +-----END ED25519 CERT----- +master-key-ed25519 A1Ly6Uf+PRVV+CeVAQF1FKPYLNrPsWeuXed2h/KLGX0 +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 14:05:47 +fingerprint 4BBC 1996 AE03 BF06 3FD9 903F 5AB2 33C9 D9A6 4686 +uptime 1 +bandwidth 1073741824 1073741824 224256 +extra-info-digest 6D9372261E444BF26567C9D781DFEAC9575EA00E 8ublGY+pE+AERi/45al4GrzeJbwdeS7u3bacedxf3J8 +caches-extra-info +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMelRVut9suHj0F4uYyAZCsmtlrjRbdmZNvSy7oYbMpdRsKrmEhckXd1 +0UIJOU5oI9+Kf+dWyggcs6/Nx4qar7hXF9nTf18wCYm+UbFtcNzCXLeseaZtDj/M +bHa0+ptykcLFb1VkI4a7cAQ5qPlWUG0qpE/yUGa3kifRd78icwWVAgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAL51NXLR4J1WUreKNmwYVAJG3e0K7MNC/6mM3UK8CYg04AykYFchRcXZ +pqFR6JnvxCL603zQ5/AXozLOVPd1ioQKCnAb1AQSMJ0wn34B0CFkJTBJ1TMZGy8/ +k9L493V4xzS36cRLv5XHpQHiFCEC6R/qFqJm+IA9wi99a4NE4itdAgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +sEP32JDdsB7Tt0H8ObsAXHseNcsZqT9VvghhCAyS0sIGZtENE+bAm1zvQqeT/09I +7PIaivX2H4iEl2L5abgip+tGM+/o+SOyHSwLuNK4AXXE01Q8Jweg/iFxW3FyoMt3 +RUM9F3a9vzCETjfXb9Z57p+JRMk5zDwgjrDFoMhD/tA= +-----END CROSSCERT----- +ntor-onion-key-crosscert 1 +-----BEGIN ED25519 CERT----- +AQoABr1XAQNS8ulH/j0VVfgnlQEBdRSj2Czaz7Fnrl3ndofyixl9AGwgu2vZXabO +LBQkdCzqAPX+WPxJuz/vb7eOD8PE8p3KVUK1gZrCFjsqKVgxg5LzjtWRz6jTtTwj +3aXkMbbR1w4= +-----END ED25519 CERT----- +hidden-service-dir +contact auth0@test.test +ntor-onion-key 3nwr7McqePaQrbawf0Lkuj72l61AreUJ4ulxjY1grFg= +reject *:* +tunnelled-dir-server +router-sig-ed25519 ddERq8NwwXQqCECtbhNLLGiJDLELtasGJ8AsXGzfSAKpepO7HDpFSrLp1SIbqVwA4E+XAC1ecC0UUFsn0UttDw +router-signature +-----BEGIN SIGNATURE----- +S6egsvA+DEU5J7hAPwTkGth2jCQXx2ACYIJjBTYalm6TutOgSsNRItq52SwUXyxG +HcFscDarXSMpwb6Ib0TIvn9KWJVsK9RcYpPudMiFjc5vEqf0J2UmW5c4CZ0agjbD +bGMsBQW+YppPf3UjvxxoAxx/GcK7C0dz+QtgNeJAr0A= +-----END SIGNATURE----- +router test004r 127.0.0.1 5004 0 7004 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8AYoG/9r512Cml9ZeRg/pkYe4g9q88zoNiZaHBHpUxUaZAQAgBABnv39i +rWirydPzZIoJ1Xt/zDKh+fnuHYZUU1C+vaQCe43URBPKgztmDxfGlj/lbCMpw9H7 +RRHx/mhX+eGrcisx7tPSsyO3mOAu5T68CC2BxSncmpjjoWm/g2vwTa6L2gE= +-----END ED25519 CERT----- +master-key-ed25519 Z79/Yq1oq8nT82SKCdV7f8wyofn57h2GVFNQvr2kAns +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 13:03:18 +fingerprint 3C4F BDDE 9139 2DE4 2179 6476 F5B6 6385 7DF3 AA74 +uptime 0 +bandwidth 1073741824 1073741824 174080 +extra-info-digest E5E2234DF477A870F6B11ED0887CA785B7CFCC3C NVVQEW9XoRTxhzZ4GaynkC8NNiptVwqxqKA+fggtjYg +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBANXWu7tNGp/m326Ua3ZBr78lRfPD2xPn+R5zU/SjWa32/QpkLPyloJt7 +XzI1JGxMdU+bVgOXuprW51nm+gtfbZ64g6DFFuBEmAEOVfqgCRfgz3yx5J0f9Wch +dfoXqbD2oYxleVZ5qd0VeUve+1uKsB1t6oOIhBbW5VwqhmNbGL63AgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAKLhsoHCOYO7izilNEnzx2K7zHF7QiGTjXYtlCE+nsa5vSDys0mjwiKo +AzsSiMCmMwhHd7/DQLDRwuW9qyzc26k0sPqANe8QLb5URRrEBDIgajhzVw7gZGxM +2+tgjl14sU+okyreCLRb3WorEIG4TdN6b6fYZrBbjsaaBhtAqyMBAgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +LH8XjjKXgCzdtbutJqWg/RsqrKoL2b8AtfyQC5E31nN9ZDetDKzYyY/a3lXR0nxd +rUsm6bOzDNt67YQYCJ8hlw51BDC1Jue2rmvLhqm+GHTGMIWLmSTYFPjUa0KWziTA +35pi3pXStr7oOgyoVt5OQ/Byidv1U1aVL87nOHHPye4= +-----END CROSSCERT----- +ntor-onion-key-crosscert 0 +-----BEGIN ED25519 CERT----- +AQoABr1WAWe/f2KtaKvJ0/NkignVe3/MMqH5+e4dhlRTUL69pAJ7AKSkGEdPDl63 +2LhYLVCtGT7aDzr6QRfHdkd5aWfAFbwVUj5K4K85AGyrLz97nCCEV2t940kkcmd0 +7p/0Vx4XWA0= +-----END ED25519 CERT----- +hidden-service-dir +ntor-onion-key GXljNcag/Y28zUyMWvwzoGTrY93JtUcNW+E5nx49+Wg= +accept *:* +ipv6-policy accept 1-65535 +tunnelled-dir-server +router-sig-ed25519 KstXDyPHMNcEcL/zai9sQfwXcAdZ6VkPU76mwJX7IvKGbUaVFozIeYnDt3Oa0Hd2wSzMK4nr67XaW3uDvpNQBQ +router-signature +-----BEGIN SIGNATURE----- +VVDAWwWFfA7hiSTbaTrslICU14AIO/cF0/tsBGtv2wyBmxSlW9yYARvLKkiGPfXn +FYqSwH4Nd/MvadF2E+dkYSYsnPYqeFxN9mKN2csNeF3PmeL/1254bQx8RKbBy8pi +4mnkeBAA6OqOa44CTkMQfP4A6iSsGpbKrarslHo9uEg= +-----END SIGNATURE----- +router test002a 127.0.0.1 5002 0 7002 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8AeOCME3/p+dJeC85a+wrBmqz26UzrCRo6Xe8e3SJCQ3LAQAgBACUNtcd +VQCMQISKMv6tCyZNrGTAAekCxxrzW/4d39ONGBafrqeRTbGsrdq7TcIyjdxdvNTl +BzPv2IRArJ9acR3e4ob/yLUKu1AkAFD1A+jkqEBl0+uMT7a4Pr6eapH8ZgI= +-----END ED25519 CERT----- +master-key-ed25519 lDbXHVUAjECEijL+rQsmTaxkwAHpAsca81v+Hd/TjRg +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 14:05:47 +fingerprint 8304 C161 0588 DD74 2FB0 491C 6A5F 0D53 24B0 B150 +uptime 1 +bandwidth 1073741824 1073741824 237568 +extra-info-digest 51BB38ECA5F77F18D52F460B6A00A4C411081F72 CrUyVdL0IJHxiasJEJN09E7RZN9wc8wRYe2kOsZiFrg +caches-extra-info +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAOSrVSP4UbX152npOD2+DcZsHtLCEkutdMxM/8+XCjrCrK8h4lo3GkBG +HrA5piJadIUwWJzzmWjx20k8vTXvFQDAnVuBTz+QTJU/QrM5DamNhHDY5kwKyt8v +CyHIb7TXIeKlaBaOMGuebH/37ePZqzEvwAU31TfADT35od1FtBn7AgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAKFkXl9LlavRpeM9Ku2Qg4Np5SRrnjkgLwDzO+8iHTV9AryCfDvHJ28k +Cl3FouvEe5XOY95bOyMVY94XSjMjRbcrn+srmurAedCg8RulfZf83z1Bt/CpsrZ3 +fUH7WJiFPBY+J/0OKjoYenZpYf1qIONoHU6x+qmtg1smMuZUa2VzAgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +4TJXl8rbc6eGJx9yDWJUiEI1jhT+HZ2FEYgTx/0KcJscR48UNzYd/koTWJgWJ8L6 ++M9JHqXi6WUJfqPZvpignQ7k++KWe74XCZ1n+Qncbx3hQkHMqWpAO8NYeGRG9qZz +VoE/chVH3DeWPTLSEx48vUuzLarnQ3Rwm9hc1RoCT3Y= +-----END CROSSCERT----- +ntor-onion-key-crosscert 0 +-----BEGIN ED25519 CERT----- +AQoABr1XAZQ21x1VAIxAhIoy/q0LJk2sZMAB6QLHGvNb/h3f040YAEb4mIEsNJbi +1ackkJsDkPkNrn40m0ErB5Nvhu/VDb2SJ86O36CRX/Y8vOiu2AWRVIEkQ1bRBt6C +R0a7wEzw/gw= +-----END ED25519 CERT----- +hidden-service-dir +contact auth2@test.test +ntor-onion-key tWQ0zfFeYziPs/nZ6qovq2cb9N1xnDT5tn/iZ6+kbSM= +reject *:* +tunnelled-dir-server +router-sig-ed25519 OVaWiTk3zNj3dM0SpS095xzYZN1B3BP9C//L0UbI5ter/1Yszg5df8sQtdlEdcfc3q5o2/HaAvwy44ggYDkWDA +router-signature +-----BEGIN SIGNATURE----- +N5wMY7P6q9zQwKbBfqArMnnl1xE6Q5dLicXNx1cvEn+VBuJwFFlqzYV/vzM7bvBw +dTHlVRxxx7MKaVpFuPJKLeezYLArWMnJYalWtfFd/IKBfH8ykhKkKAaPw16XmyF1 +pt9iQ91c15ogaHZeh/f9bzl9ej1YKleVhJQ8nvM46l4= +-----END SIGNATURE----- +router test007r 127.0.0.1 5007 0 7007 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8AWk/NSWnFyEYyp3OyTZVWud6VJ8FuXLFzpmatS+wLmHPAQAgBADjQWfN +J0X+i0i09tOjC1wNLv5TOoDDqD2RuamkV643eNNQ7/uevaTjIY0MpDS7SwP3Oq74 +X1FePV8jtgI7ql8Gvr/W5zZgmsc2z7hdBn+TaETPlimjU91/3CbHTX3+1QU= +-----END ED25519 CERT----- +master-key-ed25519 40FnzSdF/otItPbTowtcDS7+UzqAw6g9kbmppFeuN3g +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 13:03:18 +fingerprint 9974 21D6 B987 72A8 FEBA AA6D 7E1D 79F1 6039 6DFA +uptime 0 +bandwidth 1073741824 1073741824 189440 +extra-info-digest 56FE973CD5A174114589264751D266E281A38C48 TzShXNTaP17YBiUr17G5yZEdLA35HiqNMMF7Y8KR7fw +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALudw0y5z2HX0Yq/jrqjt2lk/GgtuDAIlGaeCa+3Y6Wz/N5UkFfPFb2b +6Rlbgih5IsStFbsI9byY+TuTbQVrJJoSzYxbaOJkNqBxItfWy21x0In0k23Fgdjh +Jtb+CKU3pB3Jtr6ggQ6YiO+RDuyBOx1tpckxxVzD8gqWuOldKrRXAgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAJ/xoMb6ioCY0tnjCceKn0QDothQfRO0KDvIJWae/mV5nsOTx4PNMqnb ++CQ3S2fw6P6KouIe+kD2RbmB1eBWIq5hvqrRAFhgjDZl7TvVb7HmdZzDNzYZIf/4 +ugvOYypDejtvusV0POxkkm4+Fl+zhKt8AOXDTuEAexxmZZVBjHPJAgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +qggW8Tvd1ruGUDFYT9llbVvJ57l50JKJd9fBrhfaG9/ddLySWNVNGQ80+azoKqum +ZEb/PF6kmkJJfywUfsbz5dbw0Hm2VROuK5RlHzw7hjjZZYU/f+egiyIQKHOXI9lN +9Vu9Y55vTpFnJLyIxNeps3n33LYsoIBktfCCZI7qmmI= +-----END CROSSCERT----- +ntor-onion-key-crosscert 1 +-----BEGIN ED25519 CERT----- +AQoABr1WAeNBZ80nRf6LSLT206MLXA0u/lM6gMOoPZG5qaRXrjd4ADNCsVBg3PAA +NCoTDPbwvMrd0TlZO5QfflO6S22BBjPSCCqS/Sx/7nBT3an2cfKq0k4q+osZOhog +pzFXEYf8/gY= +-----END ED25519 CERT----- +hidden-service-dir +ntor-onion-key PF0gSkZSg5tg/cpO+COBy4MuOBUFy0i24UN1ANjwYBQ= +accept *:* +ipv6-policy accept 1-65535 +tunnelled-dir-server +router-sig-ed25519 y17o7UoOY6iU8tQeAYlmfyB28QyBGHRq2eAYMNBatpBnRHqrEQOCi19T9T0OHXsth88IIN17dSde9Rz8okW0Bg +router-signature +-----BEGIN SIGNATURE----- +FDz5y5IDxnBZXOV3dpPTZ5cFKcz5r5N3hwWrf5PCEIx9sL4SWgM6MxtVCDPmcAG9 +ZFXettHOFUPzqQ30ARgMy5wUhk5pvH7QHp7rsJmQ5rqa8ph26KR4tsNOB8pZm9W7 +N7KhMfC5/dcMviLEOBSfaeG1+BkPjF4ePv7TrK47zc8= +-----END SIGNATURE----- +router test005r 127.0.0.1 5005 0 7005 +identity-ed25519 +-----BEGIN ED25519 CERT----- +AQQABrr8AWE1SUv5e7hKhWzVlBXH98Gfab6Y9h55g631DH7y+TTHAQAgBABFUPh7 +5mkg7mEkVZnWZC89umnxiIBJKx0zfH55QM9IYxvs7AWek+i9Ifxwz2VxTrh3eVOX +q1Y/6Bdmj5lw96VTDzftYwciyZkZntYZXCdVYavT7wCt+/e7py1SX3G2fQ4= +-----END ED25519 CERT----- +master-key-ed25519 RVD4e+ZpIO5hJFWZ1mQvPbpp8YiASSsdM3x+eUDPSGM +platform Tor 0.3.5.10 on Linux +proto Cons=1-2 Desc=1-2 DirCache=1-2 HSDir=1-2 HSIntro=3-4 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Relay=1-2 +published 2020-04-23 13:03:18 +fingerprint 9EEF 0E06 DCA1 3EEE CBDB EA74 71DC D049 9739 85B0 +uptime 0 +bandwidth 1073741824 1073741824 189440 +extra-info-digest 820DBEF5FC8FDD057F1FE574D0CCCF1F41EBEC8F dVw7XxBxmgqk5jH2q3O5rvt3hNnZSj4v+IHnP74FXkk +onion-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAMXGxwPQGH9t9pfQSnqrJd7r4ppFaalVCd+HROsS6CA/znvpf/2b9uer +5qucAUYRL0Uhr0o6J0TldxSd3d8WY5Lwn/ZrJ7h4U6SDV024BxqW7R4OMT5ISFgh +89DQN6p1g8mMslGktwZUrCGeEhL32WQAEB/so5wnv7Aa6yYWBDZbAgMBAAE= +-----END RSA PUBLIC KEY----- +signing-key +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBALlb0Bwo4WAKyF7hHRv3bD/MSf2k77zHB1CF4a8CocSqDcbqscnQf1Jw +zL/UFzhTcCL24schDUE7itY50bkBTRZFo9XG2giEm5nNkAe8PuHy1GK5HZK0uRWw +T3P7B+/PYgw0EQm0x7evDp2QW/I7DLnQCJwY7Ltde013VcEM1W+1AgMBAAE= +-----END RSA PUBLIC KEY----- +onion-key-crosscert +-----BEGIN CROSSCERT----- +MFKBENIMaIWMa9rJhlAcNMdy+SJnOJ2vCfzkqC8JezOCrJKv1yAQVGCGihM2jre6 +H1aLMqG7JTScpQ138q0pMJObvv6CIjRFiiy9KB43oufbjGYmVIkLpvQy/T21mgc+ +PW4qWhNQHng8xDG2Wb6pBhwUASK31g32p3LXRj8P1vg= +-----END CROSSCERT----- +ntor-onion-key-crosscert 0 +-----BEGIN ED25519 CERT----- +AQoABr1WAUVQ+HvmaSDuYSRVmdZkLz26afGIgEkrHTN8fnlAz0hjACh5/LiYnwvS +wy3bgnk7olcN+Wzou7TAqgKZ0Or3TNcxx/v5tLpaaUJ9i4MZAmlNg+IhKhuVKW6C +ICb05F54oQo= +-----END ED25519 CERT----- +hidden-service-dir +ntor-onion-key pwiw7FWsyJXlLyAa7kOTSyKgaqG3xV+stOE+uGEvsE0= +accept *:* +ipv6-policy accept 1-65535 +tunnelled-dir-server +router-sig-ed25519 SrUQnmdUxyWERZM6KWhjEheb0A7HLQSjGAi3DbhCtuvQ6Ho4RDHbsB5NpzOL6Xu/lpW3YBORnBzkBxQOT7QPDg +router-signature +-----BEGIN SIGNATURE----- +PIrLtjkjB73TqQRsxwIGfZxaUtnDedKnrvs4181L+mBL51uoN248Q81UrtJkCK8n +U1qIlxGT++dO3dxVp/KbS8x65/6YXXtynb/hoQBW7L8KkV9E4kabzWT5jAlzggHv +E8AVQplUEw8QUga/WmkG+FOvYGenYfKgeudUdSYQsR8= +-----END SIGNATURE----- diff --git a/tests/test_consensus.py b/tests/test_consensus.py new file mode 100644 index 0000000..5475c56 --- /dev/null +++ b/tests/test_consensus.py @@ -0,0 +1,35 @@ +import json + +from dictdiffer import diff + +import lightnion as lnn +from lightnion.consensus import Consensus, Flavor + + +def test_micro_consensus_parsing(): + with open("data/consensus_micro_raw.txt", "r") as consensus_fd: + consensus_raw = consensus_fd.read() + + with open("data/consensus_micro_parsed.txt", "r") as consensus_fd: + consensus_expected = json.load(consensus_fd) + + consensus_parsed = Consensus.parse(consensus_raw, Flavor.MICRO) + print(list(diff(consensus_expected, consensus_parsed))) + assert consensus_expected == consensus_parsed + + +def test_consensus_parsing(): + with open("data/consensus_raw.txt", "r") as consensus_fd: + consensus_raw = consensus_fd.read() + + with open("data/consensus_parsed.txt", "r") as consensus_fd: + consensus_expected = json.load(consensus_fd) + + consensus_parsed = Consensus.parse(consensus_raw, Flavor.UNFLAVORED) + print(list(diff(consensus_expected, consensus_parsed))) + assert consensus_expected == consensus_parsed + + +if __name__ == "__main__": + test_micro_consensus_parsing() + test_consensus_parsing() diff --git a/tests/test_descriptors.py b/tests/test_descriptors.py new file mode 100644 index 0000000..337f2cb --- /dev/null +++ b/tests/test_descriptors.py @@ -0,0 +1,35 @@ +import json + +from dictdiffer import diff + +import lightnion as lnn +from lightnion.descriptors import Descriptors, Flavor + + +def test_micro_descriptors_parsing(): + with open("data/descriptors_micro_raw.txt", "r") as descriptors_fd: + descriptors_raw = descriptors_fd.read() + + with open("data/descriptors_micro_parsed.txt", "r") as descriptors_fd: + descriptors_expected = json.load(descriptors_fd) + + descriptors_parsed = Descriptors.parse(descriptors_raw, Flavor.MICRO) + print(list(diff(descriptors_expected, descriptors_parsed))) + assert descriptors_expected == descriptors_parsed + + +def test_descriptors_parsing(): + with open("data/descriptors_raw.txt", "r") as descriptors_fd: + descriptors_raw = descriptors_fd.read() + + with open("data/descriptors_parsed.txt", "r") as descriptors_fd: + descriptors_expected = json.load(descriptors_fd) + + descriptors_parsed = Descriptors.parse(descriptors_raw, Flavor.UNFLAVORED) + print(list(diff(descriptors_expected, descriptors_parsed))) + assert descriptors_expected == descriptors_parsed + + +if __name__ == "__main__": + test_micro_descriptors_parsing() + test_descriptors_parsing() From adf9f41d5c6d3669a924aa4798320b6e0afd0a18 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 28 Apr 2020 17:46:06 +0200 Subject: [PATCH 25/30] Remove obsolete functions from path selection. --- lightnion/path_selection.py | 209 ----------------------------------- tests/test_path_selection.py | 63 ----------- 2 files changed, 272 deletions(-) delete mode 100644 tests/test_path_selection.py diff --git a/lightnion/path_selection.py b/lightnion/path_selection.py index 762bc5d..edce55f 100644 --- a/lightnion/path_selection.py +++ b/lightnion/path_selection.py @@ -8,24 +8,6 @@ # So to test the proxy with Chutney, these checks needs to be disabled. check_different_subnets = False -def select_path(routers, state, testing=False): - """Handle the path selection - :params routers: list of the routers given by the consensus - :state: - :returns: updated state tuple (guard, middle, exit)""" - - logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) - - routers = [r for r in routers if obey_minimal_constraint(r)] - - state, exit_node = pick_good_exit(routers, state) - - state, guard = pick_good_entry(routers, state, exit_node, testing) - - state, middle = pick_good_middle(routers, state, exit_node, guard, testing) - - return state, guard, middle, exit_node - def select_guard_from_consensus(cons, descr, testing=False): """Handle the selection of the guard node @@ -120,48 +102,6 @@ def in_same_family(r0, r1, r2=None): return False -def keep_exit(router, state): - """Checks that the router is not a bad exit, is not down, is stable, - is valid, does not run an old TOR's version, has an available ed25519 - identity key and has an 'accept' exit policy - :params router: the router we want to check - :state: - :return: tuple (boolean that indicates if we keep it, new state, descriptor)""" - - logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) - - if not obey_minimal_constraint(router): - return False, state, None - - if 'Exit' not in router['flags']: - return False, state, None - - if 'BadExit' in router['flags']: - return False, state, None - - # Retrieve the descriptor - state, nhop = descriptors.download(state, cons=router, flavor='unflavored') - - if len(nhop) == 0: - return False, state, None - - nhop = nhop[0] - - if router['digest'] != nhop['digest']: - return False, state, None - - if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': - return False, state, None - - if 'policy' not in nhop: - return False, state, None - - for rule in nhop['policy']['rules']: - if rule['pattern'] == "*:*" and rule['type'] == 'accept': - return True, state, nhop - - return False, state, None - def keep_exit_with_descr(descr, router, guard): """Checks that the router is not a bad exit, is not down, is stable, is valid, does not run an old TOR's version, has an available ed25519 @@ -204,7 +144,6 @@ def keep_exit_with_descr(descr, router, guard): return False, None - def weighted_random_choice(list_of_possible): """Choose one of the candidates at random weighted by their (avg) bandwidth :params list_of_possible: list of descriptors of the candidates @@ -225,29 +164,6 @@ def weighted_random_choice(list_of_possible): raise RuntimeError("") -def pick_good_exit(routers, state): - """Choose the exit node - :param routers: the routers given by the consensus - :param state: the state - :return: the descriptor of the exit node""" - - logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) - - # Go through all routers and check if they meet the conditions of an exit node - candidates = [] - for router in routers: - keep, state, descriptor = keep_exit(router, state) - if keep: - candidates.append(descriptor) - - if candidates: - return state, weighted_random_choice(candidates) - - else: - # TODO: see if we select another policy here - raise ValueError('No exit is suitable') - - def pick_good_exit_from_routers(descr, routers, guard): """Choose the exit node :param routers: the routers given by the consensus @@ -269,53 +185,6 @@ def pick_good_exit_from_routers(descr, routers, guard): raise ValueError('No exit is suitable') - -def keep_guard(router, state, exit_node, testing): - """Checks that the given router has the properties to be a guard - :param router: the router that must be inspected - :param state: state - :param exit_node: the previously chosen node - :return: if the router can be kept, the updated state and the descriptor""" - - logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) - - flags = router['flags'] - - if not obey_minimal_constraint(router, exit_node, testing=testing): - return False, state, None - - if 'Guard' not in flags: - return False, state, None - - if 'Stable' not in flags: - return False, state, None - - if 'Fast' not in flags: - return False, state, None - - if 'V2Dir' not in flags: - return False, state, None - - # Retrieve the descriptor - state, nhop = descriptors.download(state, cons=router, flavor='unflavored') - - if len(nhop) == 0: - return False, state, None - nhop = nhop[0] - - if router['digest'] != nhop['digest']: - return False, state, None - - if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': - return False, state, None - - if in_same_family(nhop, exit_node): - return False, state, None - - return True, state, nhop - - - def keep_guard_with_descr(descr, router, testing): """Checks that the given router has the properties to be a guard :param descr: descriptor of the exit candidate. @@ -353,29 +222,6 @@ def keep_guard_with_descr(descr, router, testing): return True, nhop - -def pick_good_entry(routers, state, exit_node, testing): - """Simplified version of the Guard selection algorithm - :param routers: the routers of the consensus - :param state: the state - :return: updated state and the descriptor of the guard node""" - - logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) - - candidates = [] - for router in routers: - keep, state, descriptor = keep_guard(router, state, exit_node, testing) - if keep: - candidates.append(descriptor) - - if candidates: - return state, weighted_random_choice(candidates) - - else: - # TODO: see if we select another policy here - raise ValueError('No guard is suitable') - - def pick_good_entry_from_routers(descr, routers, testing): """Simplified version of the Guard selection algorithm :param routers: the routers of the consensus @@ -396,38 +242,6 @@ def pick_good_entry_from_routers(descr, routers, testing): raise ValueError('No guard is suitable') -def keep_middle(router, state, exit_node, guard, testing): - """Checks that the given router has the properties to be a middle node - :param router: the router that must be inspected - :param state: state - :param exit_node: the previously chosen exit node - :param guard: the previously chosen guard - :return: if the router can be kept, the updated state and the descriptor""" - - logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) - - if not obey_minimal_constraint(router, exit_node, guard, testing=testing): - return False, state, None - - # Retrieve the descriptor - state, nhop = descriptors.download(state, cons=router, flavor='unflavored') - - if len(nhop) == 0: - return False, state, None - nhop = nhop[0] - - if router['digest'] != nhop['digest']: - return False, state, None - - if 'identity' not in nhop or nhop['identity']['type'] != 'ed25519': - return False, state, None - - if in_same_family(nhop, guard, exit_node): - return False, state, None - - return True, state, nhop - - def keep_middle_with_descr(descr, router, exit_node, guard, testing): """Checks that the given router has the properties to be a middle node :param descr: descriptor of the exit candidate. @@ -455,29 +269,6 @@ def keep_middle_with_descr(descr, router, exit_node, guard, testing): return True, nhop -def pick_good_middle(routers, state, exit_node, guard, testing): - """Choose the middle node given the exit and the guard node - :param routers: the routers of the consensus - :param state: the state - :param exit_node: the previously chosen exit node - :param guard: the previously chosen guard node - :return: updated state and the descriptor of the guard node""" - - logging.warning('Use of DEPRECATED method %s()' % sys._getframe().f_code.co_name) - - candidates = [] - for router in routers: - keep, state, descriptor = keep_middle(router, state, exit_node, guard, testing) - if keep: - candidates.append(descriptor) - if candidates: - return state, weighted_random_choice(candidates) - - else: - # TODO: see if we select another policy here - raise ValueError('No middle node is suitable') - - def pick_good_middle_from_routers(descr, routers, exit_node, guard, testing): """Choose the middle node given the exit and the guard node :param routers: the routers of the consensus diff --git a/tests/test_path_selection.py b/tests/test_path_selection.py deleted file mode 100644 index 1f95d4c..0000000 --- a/tests/test_path_selection.py +++ /dev/null @@ -1,63 +0,0 @@ -import random - -import pytest - -from lightnion import cache -from lightnion import consensus -from lightnion import create -from lightnion import link -from lightnion import path_selection as ps - - -@pytest.fixture() -def get_chutney_consensus(): - """Get chutney's consensus""" - cache.purge() - lk = link.initiate(port=5000) - state = create.fast(lk) - state, cons = consensus.download(state, flavor='unflavored') - - dict_cons = {} - for router in cons['routers']: - dict_cons[router['nickname']] = router - - return state, dict_cons - - -def test_keep_exit_works_with_suitable_router(get_chutney_consensus): - state, cons = get_chutney_consensus - - keep, state, descriptor = ps.keep_exit(cons['test006r'], state) - - assert keep and descriptor is not None - - -def test_keep_exit_works_with_reject_exit_policy(get_chutney_consensus): - state, cons = get_chutney_consensus - - keep, state, descriptor = ps.keep_exit(cons['test002a'], state) - - assert not keep and descriptor is None - - -def test_pick_good_exit_returns_a_router(get_chutney_consensus): - state, cons = get_chutney_consensus - routers = cons.values() - - state, exit_node = ps.pick_good_exit(routers, state) - - assert exit_node is not None - - -def test_path_selection_works(get_chutney_consensus): - state, cons = get_chutney_consensus - routers = cons.values() - - ps.select_path(routers, state, testing=True) - - -def test_obey_minimal_constraint_with_one_router(get_chutney_consensus): - state, cons = get_chutney_consensus - - assert not ps.obey_minimal_constraint(cons['test005r'], cons['test005r']) - From bc3f18fcf5b4b6cbd89904cc7940f7b9bded2885 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Thu, 30 Apr 2020 10:39:51 +0200 Subject: [PATCH 26/30] Update doc. --- docs/source/index.rst | 5 +- docs/source/lightnion.cell.relay.rst | 30 ------ docs/source/lightnion.cell.rst | 133 --------------------------- docs/source/lightnion.http.rst | 38 -------- docs/source/lightnion.proxy.rst | 17 ---- docs/source/lightnion.rst | 71 -------------- docs/source/lightnion.tests.rst | 78 ---------------- 7 files changed, 2 insertions(+), 370 deletions(-) delete mode 100644 docs/source/lightnion.cell.relay.rst delete mode 100644 docs/source/lightnion.cell.rst delete mode 100644 docs/source/lightnion.http.rst delete mode 100644 docs/source/lightnion.tests.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index ea6c72b..550afaf 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -8,8 +8,7 @@ Introduction Lightnion is a JavaScript library that you can include on your webpage to let any modern browser make anonymous requests. Lightnion uses an *untrusted* proxy to interact with the Tor network. This proxy converts between protocols -(Websockets to pure TCP). This repository also contains a Python Lightnion Tor -client that we have been using for testing. +(Websockets to pure TCP). **WARNING:** At the moment Lightnion is alpha-level research software. Do *not* use it in production, or for anything that really requires anonymity. You are, @@ -28,4 +27,4 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` -* :ref:`search` \ No newline at end of file +* :ref:`search` diff --git a/docs/source/lightnion.cell.relay.rst b/docs/source/lightnion.cell.relay.rst deleted file mode 100644 index a42094d..0000000 --- a/docs/source/lightnion.cell.relay.rst +++ /dev/null @@ -1,30 +0,0 @@ -lightnion.cell.relay package -============================ - -Submodules ----------- - -lightnion.cell.relay.extend2 module ------------------------------------ - -.. automodule:: lightnion.cell.relay.extend2 - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.relay.extended2 module -------------------------------------- - -.. automodule:: lightnion.cell.relay.extended2 - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: lightnion.cell.relay - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/lightnion.cell.rst b/docs/source/lightnion.cell.rst deleted file mode 100644 index 867233a..0000000 --- a/docs/source/lightnion.cell.rst +++ /dev/null @@ -1,133 +0,0 @@ -lightnion.cell package -====================== - -Subpackages ------------ - -.. toctree:: - - lightnion.cell.relay - -Submodules ----------- - -lightnion.cell.address module ------------------------------ - -.. automodule:: lightnion.cell.address - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.certs module ---------------------------- - -.. automodule:: lightnion.cell.certs - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.challenge module -------------------------------- - -.. automodule:: lightnion.cell.challenge - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.common module ----------------------------- - -.. automodule:: lightnion.cell.common - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.create2 module ------------------------------ - -.. automodule:: lightnion.cell.create2 - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.create\_fast module ----------------------------------- - -.. automodule:: lightnion.cell.create_fast - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.created2 module ------------------------------- - -.. automodule:: lightnion.cell.created2 - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.created\_fast module ------------------------------------ - -.. automodule:: lightnion.cell.created_fast - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.destroy module ------------------------------ - -.. automodule:: lightnion.cell.destroy - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.netinfo module ------------------------------ - -.. automodule:: lightnion.cell.netinfo - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.padding module ------------------------------ - -.. automodule:: lightnion.cell.padding - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.relay\_early module ----------------------------------- - -.. automodule:: lightnion.cell.relay_early - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.versions module ------------------------------- - -.. automodule:: lightnion.cell.versions - :members: - :undoc-members: - :show-inheritance: - -lightnion.cell.view module --------------------------- - -.. automodule:: lightnion.cell.view - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: lightnion.cell - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/lightnion.http.rst b/docs/source/lightnion.http.rst deleted file mode 100644 index fec8299..0000000 --- a/docs/source/lightnion.http.rst +++ /dev/null @@ -1,38 +0,0 @@ -lightnion.http package -====================== - -Submodules ----------- - -lightnion.http.ntor module --------------------------- - -.. automodule:: lightnion.http.ntor - :members: - :undoc-members: - :show-inheritance: - -lightnion.http.polling module ------------------------------ - -.. automodule:: lightnion.http.polling - :members: - :undoc-members: - :show-inheritance: - -lightnion.http.websocket module -------------------------------- - -.. automodule:: lightnion.http.websocket - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: lightnion.http - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/lightnion.proxy.rst b/docs/source/lightnion.proxy.rst index 1e24624..e53ea30 100644 --- a/docs/source/lightnion.proxy.rst +++ b/docs/source/lightnion.proxy.rst @@ -44,23 +44,6 @@ lightnion.proxy.parts module :undoc-members: :show-inheritance: -lightnion.proxy.path module ---------------------------- - -.. automodule:: lightnion.proxy.path - :members: - :undoc-members: - :show-inheritance: - -lightnion.proxy.relayinfo module --------------------------------- - -.. automodule:: lightnion.proxy.relayinfo - :members: - :undoc-members: - :show-inheritance: - - Module contents --------------- diff --git a/docs/source/lightnion.rst b/docs/source/lightnion.rst index c159b71..53a949b 100644 --- a/docs/source/lightnion.rst +++ b/docs/source/lightnion.rst @@ -6,22 +6,8 @@ Subpackages .. toctree:: - lightnion.cell lightnion.crypto - lightnion.http lightnion.proxy - lightnion.tests - -Submodules ----------- - -lightnion.cache module ----------------------- - -.. automodule:: lightnion.cache - :members: - :undoc-members: - :show-inheritance: lightnion.consensus module -------------------------- @@ -39,14 +25,6 @@ lightnion.constants module :undoc-members: :show-inheritance: -lightnion.create module ------------------------ - -.. automodule:: lightnion.create - :members: - :undoc-members: - :show-inheritance: - lightnion.descriptors module ---------------------------- @@ -55,38 +33,6 @@ lightnion.descriptors module :undoc-members: :show-inheritance: -lightnion.extend module ------------------------ - -.. automodule:: lightnion.extend - :members: - :undoc-members: - :show-inheritance: - -lightnion.hop module --------------------- - -.. automodule:: lightnion.hop - :members: - :undoc-members: - :show-inheritance: - -lightnion.link module ---------------------- - -.. automodule:: lightnion.link - :members: - :undoc-members: - :show-inheritance: - -lightnion.onion module ----------------------- - -.. automodule:: lightnion.onion - :members: - :undoc-members: - :show-inheritance: - lightnion.path\_selection module -------------------------------- @@ -103,23 +49,6 @@ lightnion.signature module :undoc-members: :show-inheritance: -lightnion.socket module ------------------------ - -.. automodule:: lightnion.socket - :members: - :undoc-members: - :show-inheritance: - -lightnion.utils module ----------------------- - -.. automodule:: lightnion.utils - :members: - :undoc-members: - :show-inheritance: - - Module contents --------------- diff --git a/docs/source/lightnion.tests.rst b/docs/source/lightnion.tests.rst deleted file mode 100644 index f9fcfd9..0000000 --- a/docs/source/lightnion.tests.rst +++ /dev/null @@ -1,78 +0,0 @@ -lightnion.tests package -======================= - -Submodules ----------- - -lightnion.tests.path\_selection\_test module --------------------------------------------- - -.. automodule:: lightnion.tests.path_selection_test - :members: - :undoc-members: - :show-inheritance: - -lightnion.tests.test\_consensus\_chutney module ------------------------------------------------ - -.. automodule:: lightnion.tests.test_consensus_chutney - :members: - :undoc-members: - :show-inheritance: - -lightnion.tests.test\_create\_chutney module --------------------------------------------- - -.. automodule:: lightnion.tests.test_create_chutney - :members: - :undoc-members: - :show-inheritance: - -lightnion.tests.test\_descriptors\_chutney module -------------------------------------------------- - -.. automodule:: lightnion.tests.test_descriptors_chutney - :members: - :undoc-members: - :show-inheritance: - -lightnion.tests.test\_extend\_chutney module --------------------------------------------- - -.. automodule:: lightnion.tests.test_extend_chutney - :members: - :undoc-members: - :show-inheritance: - -lightnion.tests.test\_hop\_chutney module ------------------------------------------ - -.. automodule:: lightnion.tests.test_hop_chutney - :members: - :undoc-members: - :show-inheritance: - -lightnion.tests.test\_link\_chutney module ------------------------------------------- - -.. automodule:: lightnion.tests.test_link_chutney - :members: - :undoc-members: - :show-inheritance: - -lightnion.tests.test\_path\_selection\_chutney module ------------------------------------------------------ - -.. automodule:: lightnion.tests.test_path_selection_chutney - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: lightnion.tests - :members: - :undoc-members: - :show-inheritance: From 4b313006582d9bee456304bacabdc90e2eae478e Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Thu, 30 Apr 2020 12:47:30 +0200 Subject: [PATCH 27/30] Correct documentation. --- docs/source/deploy.rst | 18 ++++++++++++------ lightnion/signature.py | 3 +-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/source/deploy.rst b/docs/source/deploy.rst index 743a443..73b8558 100644 --- a/docs/source/deploy.rst +++ b/docs/source/deploy.rst @@ -50,15 +50,18 @@ The proxy requires Python 3.7 or superior and the libraries listed in the files `pip`. The proxy was tested on Debian Buster, it likely also work on other Linux distributions providing Python 3.7, but was not tested on them. -It is advised to use git to retrieve the sources.:: +It is advised to use git to retrieve the sources. +:: $ git clone --recurse-submodules https://github.com/spring-epfl/lightnion.git $ cd lightnion -It is strongly advised to install the Lightnion proxy in a virtual environment.:: +It is strongly advised to install the Lightnion proxy in a virtual environment. +:: $ virtualenv --python=python3 venv $ . venv/bin/activate -The dependances can be installed with `pip`.:: +The dependances can be installed with `pip`. +:: $ pip install -r requirements.txt -r requirements-proxy.txt To work, the proxy needs to interact with a tor relay, which will be the entry @@ -75,7 +78,8 @@ Building the JavaScript Client ------------------------------ The minified bundle of the Javacript client needs to be build. A Makefile -exists to simplify its building process:: +exists to simplify its building process +:: $ cd js-client $ make @@ -89,11 +93,13 @@ Testing Lightnion Locally To Test Lightnion locally, it is necessary to run a local web server to dispatch the Lightnion Javascript client. This can be done easilly with -Python's HTTP server.:: +Python's HTTP server +:: $ cd js-client/demo $ python -m http.server -then the proxy can be started with::: +then the proxy can be started with +:: $ source env/bin/activate (venv)$ python -m lightnion.proxy -vvv -s 127.0.0.1:9050 -c 8000 -d 9051 diff --git a/lightnion/signature.py b/lightnion/signature.py index b9aae43..f712000 100644 --- a/lightnion/signature.py +++ b/lightnion/signature.py @@ -17,8 +17,7 @@ def verify(raw_cons, keys, minimal=0.5): :param raw_cons: the consensus we want to verify :param keys: a dictionary of keys as retrieved by the function get_signing_keys_info of tools/keys.py - :param minimal: the minimal percentage of the authorities whose signatures must be verified in order to accept the - given consensus + :param minimal: the minimal percentage of the authorities whose signatures must be verified in order to accept the given consensus :return: true if at least the minimal number of signatures are verified """ assert 0 < minimal <= 1 From 14f31e48021e12c3e7c0ab5ec349d9a30465cde2 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Thu, 30 Apr 2020 12:53:40 +0200 Subject: [PATCH 28/30] Correct state object in client. --- js-client/src/header.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/js-client/src/header.js b/js-client/src/header.js index 83a09f5..5f44342 100644 --- a/js-client/src/header.js +++ b/js-client/src/header.js @@ -91,26 +91,6 @@ lnn.state = { * ready to use * @type channel */ - success: 6, - /** - * operation started - * @type stream - */ - started: 1, - /** - * ready to use - * @type stream - */ - created: 3, - /** - * incoming data - * @type stream - */ - pending: 4, - /** - * completed or closed - * @type stream - */ success: 6 } From 6cd080a66ecf61d313e8a7fe46ed1be6cc9810b5 Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 5 May 2020 12:13:20 +0200 Subject: [PATCH 29/30] Add javadoc, tweak some functions slightly. --- js-client/src/api.js | 41 +++++++++++++++++++++++++++++++++++++++ js-client/src/endpoint.js | 16 ++++++++------- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/js-client/src/api.js b/js-client/src/api.js index 6d67ea1..396d48c 100644 --- a/js-client/src/api.js +++ b/js-client/src/api.js @@ -37,6 +37,20 @@ export function auth(host, port, suffix, success, error, io, select_path) { }, select_path) } +/** + * Create a circuit on the Tor network, return a handler to send request on + * this circuit, or close it. + * @param {String} host host of the Lightnion proxy + * @param {Number} port port where the Lightnion proxy is reachable + * @param {Function} success callback in case of success + * @param {Function} error callback in case of error + * @param {io.io_t} io io adapter in use + * @param {Boolean} fast deprecated, always set to false + * @param {half_t} auth {@link lnn.auth} material + * @param {Boolean} select_path Compute the circuit path in the client* + * @param {List} tcp_ports list of ports which need to be accepted by the exit node + * @returns connection handler + */ export function open(host, port, success, error, io, fast, auth, select_path, tcp_ports) { let endpoint = lnnEndpoint.endpoint(host, port) if (io === undefined) @@ -178,7 +192,22 @@ export let agents = [ "curl/7.38.0" ] +/** + * Send an HTTP request by using an handler. + * @param {lnn.endpoint} endpoint handler created by {@link lnn.open} + * @param {String} url URL where the request is send + * @param {String} method method of the HTTP request + * @param {String} data payload of the request + * @param {string} data_type data type of the payload of the request + * @param {Function} success callback in case of success + * @param {Function} error callback in case of error + */ export function send_req(endpoint, url, method, data, data_type, success, error) { + if (success === undefined) + success = function () { } + if (error === undefined) + error = function () { } + var agent = agents[Math.floor(Math.random() * agents.length)] var data_recv = '' @@ -284,6 +313,18 @@ export function send_req(endpoint, url, method, data, data_type, success, error) stream.tcp(endpoint, host, port, handler).send(payload) } + +/** + * Build a circuit to do a single HTTP request over the Tor network. + * @param {String} url URL where the request is send + * @param {String} method method of the HTTP request + * @param {String} data payload of the request + * @param {string} data_type data type of the payload of the request + * @param {Function} success callback in case of success + * @param {Function} error callback in case of error + * @param {String} tor_host host of the Lightnion proxy + * @param {Number} tor_port port where the Lightnion proxy is reachable + */ export function http_request(url, method, data, data_type, success, error, tor_host, tor_port) { if (tor_host === undefined) tor_host = 'localhost' diff --git a/js-client/src/endpoint.js b/js-client/src/endpoint.js index 72754cc..982f434 100644 --- a/js-client/src/endpoint.js +++ b/js-client/src/endpoint.js @@ -175,14 +175,16 @@ export function endpoint(host, port) { select_path: false, - /*perform http get/post request*/ - + /** + * Perform the HTTP request. + * @param {String} url URL where the request is send + * @param {String} method method of the HTTP request + * @param {String} data payload of the request + * @param {String} data_type data type of the payload of the request + * @param {Function} success callback in case of success + * @param {Function} error callback in case of error + */ http_request: function (url, method, data, data_type, success, error) { - if (error === undefined) - error = function () { } - if (success === undefined) - success = function () { } - api.send_req(endpoint, url, method, data, data_type, success, error) }, From 845386515545fb11d2c0a0cf78ba0ea49df1d25e Mon Sep 17 00:00:00 2001 From: Laurent Girod Date: Tue, 5 May 2020 12:15:01 +0200 Subject: [PATCH 30/30] Rewrite documentation, add tutorial for JS. --- docs/source/conf.py | 4 ++ docs/source/deploy.rst | 128 ++++++++++++++++++++++------------------- docs/source/index.rst | 1 + 3 files changed, 73 insertions(+), 60 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c9ef3ba..13beb08 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -44,8 +44,12 @@ 'sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', + 'sphinx_js' ] +# JS sources +js_source_path = '../js-client/src' + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/deploy.rst b/docs/source/deploy.rst index 73b8558..4ac075c 100644 --- a/docs/source/deploy.rst +++ b/docs/source/deploy.rst @@ -5,81 +5,67 @@ Deployment **Warning:** Lightnion is an alpha-stage software which is not fit for production at this point. +Lightnion needs to be deployed from sources. It is constituted of two parts, a +JavaScript client and a proxy between the client and the guard relay on Tor +network. + Prerequisites ============= -Test on local machine ---------------------- - -Any modern hardware should have enough resources to run Lightnion. Chutney can -be used to simulate a Tor network to which Lichtnion can connect. - -Test on real environment ------------------------- +Lightnion is a two-parts software constituted of: -To test the Lightnion proxy in a real environment, a server with at least 1 GB -of memory and a reasonnable amount of bandwidth is needed. In the mode where -the Tor circuit is computed in the proxy 2 GB of memory are necessary. +- a Javascript client called from the web browser +- a proxy running on a server -To function properly, the Lightnion proxy needs to interact with a Tor relay, -which will act as the guard of all Tor circuits build with Lightnion. To -install a Tor relay on your system, please refers to the `documentation from -the Tor project `, -or the documentation of your distribution. +The proxy requires at least 2 GiB of RAM, and was tested successfully only on +Linux. The proxy also need to connect to the Tor network, which can be done +either by simulationg it with Chutney or using the real Tor network. -Also, to serve the Javascript client, encrypt, and redirect the proxy ports, -a web server like Nginx is recommended. Please refer to the documentation of -your distribution to install one. +To test Lightnion proxy on a proper server, you also need a hidden Tor relay on +the same machine where Lightnion is running. We advise to run the guard relay +on the same server as the Lightnion proxy. To install the hidden Tor relay, +please refers to the `documentation from the Torproject +`_, `their wiki +`_, or the +documentation of the Linux distribution installed on the server. Installation ============ -At this stage of the development, there still hasn't any distribution package -for Lightnion. This software needs to be deployed from sources. It is -constituted of two parts, a JavaScript client and a proxy between the client -and the Tor network, which can be run either on the same server or on different -machines. It is also advised to run a hidden Tor entry point on the server to -act as the guard relay for the proxy. - - Installation of the Proxy ------------------------- The proxy requires Python 3.7 or superior and the libraries listed in the files `requirements.txt` and `requirements-proxy.txt`, which can be installed with -`pip`. The proxy was tested on Debian Buster, it likely also work on other -Linux distributions providing Python 3.7, but was not tested on them. +`pip`. We tested the proxy on Debian Buster, it likely also work on other +Linux distributions which provide Python 3.7, but we did not test the proxy on +them. + +We advise to use git to retrieve the sources. +.. code-block:: -It is advised to use git to retrieve the sources. -:: $ git clone --recurse-submodules https://github.com/spring-epfl/lightnion.git $ cd lightnion -It is strongly advised to install the Lightnion proxy in a virtual environment. -:: +We strongly advise to install the Lightnion proxy in a virtual environment. +.. code-block:: + $ virtualenv --python=python3 venv $ . venv/bin/activate The dependances can be installed with `pip`. -:: - $ pip install -r requirements.txt -r requirements-proxy.txt - -To work, the proxy needs to interact with a tor relay, which will be the entry -point in the tor network. Therefore it is adviseable to install a hidden Tor -relay on the machine. To do so, refer to the -`Tor documentation `. - -Installing Chutney (for testing locally) ----------------------------------------- +.. code-block:: + $ pip install -r requirements.txt -r requirements-proxy.txt Building the JavaScript Client ------------------------------ -The minified bundle of the Javacript client needs to be build. A Makefile -exists to simplify its building process -:: +The minified bundle of the Javacript client needs to be build. We wrote a +Makefile to simplify this task. +.. code-block:: + $ cd js-client $ make @@ -91,15 +77,35 @@ page as any other JS library. Testing Lightnion Locally ========================= +For testing Lightnion locally, you might prefer to simulte the Tor network to which the proxy is going to connect. To do so, we provide a script to configure the network simulated by Chutned. +.. code-block:: + + $ git clone https://git.torproject.org/chutney.git + $ cp lightnion/tools/chutney/small-chut chutney + $ cd chutney + +You might also want to disable the sandboxing, we provide a patch to do so. +.. code-block:: + + $ git apply ../lightnion/tools/chutney/sandbox_patch + +Once the installation is done, you can start Chutney with the commands. +.. code-block:: + + $ cd chutney + $ ./small-chut + To Test Lightnion locally, it is necessary to run a local web server to -dispatch the Lightnion Javascript client. This can be done easilly with -Python's HTTP server -:: +dispatch the Lightnion Javascript client. (Here is an example with Python.) +.. code-block:: + $ cd js-client/demo $ python -m http.server -then the proxy can be started with -:: +Then the proxy can be started with these commands (Here, the proxy is running +in a virtual environment). +.. code-block:: + $ source env/bin/activate (venv)$ python -m lightnion.proxy -vvv -s 127.0.0.1:9050 -c 8000 -d 9051 @@ -107,15 +113,16 @@ then the proxy can be started with Web Server configuration ======================== -For a test on a real environment, a proper web server like Nginx or Apache is -required, and the demo files copied to the root directory of the web server -along with the Lightnion bundle. +For testing Lightnion on a proper server, you need a webserver like Apache or +Nginx, and the compiled Lightnion bundle. -By default, the connection between the client and proxy server is in clear. -Ideally, this connection should be secure, and this will probably change in the -near future. +By default, the connection between the client and proxy server is in clear. If +you prefer to use a secure connection, the sources of the Javascript client +needs to be slightly modified to accept HTTPS connection, and the ports need to +be changed to 443. In a later version, TLS will be enabled by default, and a +flag will be needed to use an insecure connection. -A Typical Nginx configuration for a proxy server will look like this: +A Typical Nginx configuration for a proxy server looks like this: .. literalinclude:: lightnion-nginx-tls.conf @@ -123,8 +130,9 @@ A Typical Nginx configuration for a proxy server will look like this: Automatic Startup and Process Monitoring ======================================== -To ensure Lightnion is running, systemd or an other init system can be used to -notify the administrator and restart the process if necessary. +We can ensure Lightnion is running by configuring systemd or another init +system to restart the process when necessary, and optionally to notify the +administrator when the service is restarted. .. literalinclude:: lightnion.service diff --git a/docs/source/index.rst b/docs/source/index.rst index 550afaf..ddc3e88 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,6 +21,7 @@ Contents .. toctree:: deploy + tutorial Indices and tables ==================

      $d8IHM!| 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%0AaLBL(QGy|Y#(Em>^^ zBXA3zvaOkBtcxp%;4XRSJrJ%~qbl$uoM<_|IrK^{@5=sCIw%ls=Wb7()g0{M+ZaKN z_g)$>g;ZMcAd!8KLF0c=#3YR9c;+b&Nay83@JkyHqq34FAj8S^cqR6U0g$G(ESNfF zJXS;aB*3wN#|RUov>v&g8QV0Ia2Fe+fp?_$T&;V=#i~ry6_}^aujqw^iJPwRO zsoK8oiN?!cG1t~9$)qs}kMOLov0XXywt52Fa6c1D==XyumWILpI=@%$`%s&V-Rm{` zMJTP5^>_2Pv1h=q-Zg0{0v>B0hdUFmHrs(dWg~9WI_j=4mO}_;X%$I3CyEvhzI?N0emwH9k)@J6;XS(BbO6M;7N_1Ghu-nR@;tL+u%W=pk}Q{j>pCE@Vyn4)5GYZg5-hyywQ97YT?ztN z${2LP9>k$aY*q1mUoP~_SVEFBWm9k6^YctAQ2xAZhI~GkRui|^P)@4CC{5bRXA#Hv zp{Q1xnJEF6Ph%gqhkgHo{z#4=1e^@x-Su2y9!w85+Jg3*b- zeA9snA<%3bTL-C)083pMs(U;2_(GBdKE$BGEI8PF=7B7=ZykWO%pGn(pH0?HhaKl3 zz-9IrhlL~V*GYp4iFTlfN-^oeb_l9T!37dFEcVfYLgafpO=0x;5xZ|1!m_Ae`p3Sp zO!G#_K;kt~WF42O2ME_wf2cpuS*cMA8m4tZh$DEOcG)`(H$uJGmO{Zo3N%cy;4ZZ2 zA$>?p23esk%-d$ql8G`^g!FIRqsgL))@;X-q&U_XnGmtY{zMW|#9UAG_{CAYEv{k& z7_<_OXT0q8;~(?MUdNAoyw>J|Z2PO8A1#ghG4l?b|IF_Kp@D%805e*G*H&FYE>p2gDB@M`$s z0cKR17(}Vgh9xiL5FRA-M8RIR`Wl{Q%(*Mt9B?k5dLtDYU-+NuY=%D^@;SasiP`=D zm=Z{80i3&Jn{mj4Sw5&;x=ieEqpBUI7^FH)m%uafD0!pB>YnU{U}Ch7hD6DoO#=LO zNU3A{Ceer~0aBaQw9@ci=uuMG8V}P%{1{VW#0=owX5*1<35uGxmD9`AL1CNJTo@d_ zGmj=H2e=EbI_5$azC*B(ts%2mhz)~HyIlRS{3q>I7?iZtcE95u8>Hy@F}Ur8dfhMqA-#dc4vyO9Bf!| zO^@m@A!_wR5soP5z!MTg?o)~e+pD~CuHh!%I8+C=CPIMF2BH&PuR;uDZyi@ebsKe4 zCZNB#y(9`9zhl>l`}O1V8e3B^iJPD9^R!cRPz{g|(ZNVeCt zDKuKfg8RlpC8H2C*s<26vf!p65FVGrTX>4lY zX>!85QYgi!bSJiKhtl{4+>tz3m$;ycn6Z$1FoSZ*NybMFnHrr`3C83HjJwn4uxVF| z?D^yAVjQBKOisD2RZ2YMAa=%tAL)K(7#AR_fX!&(fxAO&kB(Pbxz0 zu%Qc#a9JcMzD%|+WAuZLh*e3`WKDgb2oH=nVxjdgW4m7-vl7883| z*M?e<7FM~d%Mza^Ph|DfnAD60eUl| z>e6wSlQw48{HztFaaEziSb0`b_M;;(19=&nRfo=bo*Uh?24lTa!_iXD2EP> z9?Z7&e5B#z(af>UhS$uJy9Ev}qUU}-i6(t)vy_j&!NiI2?VeJdD4H3zi$29_AUub- z?XmMswIzih1drAdm^KbO2ngJ>!Su1`#x~VtYevNl3zABC?2%xCC82;FsbJVnO;1fy zB{fKQ=Zq{jv)5Ef#NJ!-pM%$j=_Q^SMJb-aiC^9?XD4#LWg^_Ws2D?BHYdqk(jai1 z&q_fBk8YcT7tg-lAGhP)`XDeGIA7v!fvm-gR$;Z6Qmr!b+NsHJI?pYdr+H;v~Vmj$cu|l1fHmm&cO1H8MQX1!IbxLStg)1G(W!Ar!^z#$|j(0DY z#qq@QMx3S}(nq4N{f3W4&iy@zc`nuI*dn8kMCeMq6jKQqTV%^3NYx}0)*wT#0L1OC zOIDXGu7rl|$J+OtcJ5VGrS_vQsitad>%(hSF0O;=Q*7cy!dUnSDi%Z9T|0&V37;(@ zLCf-kVArSJx%+LY0I-B~#ELO8xWkK1+eQJGo>=iQVaseUoP>SGnxw#$S^tn~1JP9C zKuwkKnHQv5L}f2PIo3xj-y&l>B|qGW{Wi57jVc0?G^}7R1JBGbNU2@(GN6@N zh9<+j; z{T6$p>9O%+*!CdJiTG$}Z7**}nlcAuFk#0;X4x8OjDlFZUZ|8jc2}=IMUJwL<&k`XS%=wUNdC?KtR90BlGz!QQ_nBe#fylsVkP6 z<24_RL3SHiJNR5V!jE9|-Q)F=jEm^+eTvYYZR;@KiZThto)MPNxfpxeWT?&aZAy$HN{zNs%fl_OfqFBG%N0vbL4F7+P3m^uhbvi&8mq zQB?@i?yu`_Pdk;c{5d*o*iTfCB^4{xc0qwqw2lC$#y?ZMA#pCjgduli#FVNQIZI$X2N%0S?)sD4 zXFN1X_EM(@4mNeSTADR!d6lmO9kgY}BH%i_l8ct``O)*q?JK@F?1w@dUS=$Hj7XO} z7XJoi?0C^l`fihqM{F3k4Zq3cROH$3GdcAl@WjFE*Z&BGwe$OLm{IomxM}h=xYP#N zyZAWpLZO|$8mP;!Yu%)=0n4R#db@tb+s`h0oqxjqb8yq7LXw|~on9tUym5HjC$kuR zn6Kx-)b1o5kT)Jey<$~ng7?u1Y5VGU;-RxQgl?|8sg3MN(SlPs7z?DuMji(2as`r0 z0ST)_p(e{20if@2j}Ctw;2IVV{1=$h8+YdJ-Au`0GfiMTKV0 z{6C`p_?ZRA^8fzjM<;jx|G#>7>dD_2Sr;_K_ZSC6kXyp(oThk~?WO!!yPPPEH z`OaG4r@1rj^oqeOs)1+6SPr-=(8b{vtVEq2eGBrYcsC=60kbJT$*G>Q6|PAZgDWFv zi~YTIw}Q=&@*+!{QSUGU*$ttmiVwY|Pg(>_D>rk}UDp}YI$W6ClaQN-;*km(PSs>B{qsRdT(c`ONnhc*kn zVBxQoVmT#|{|14ZS1ZfYE?LANk1YQA%mk*_3Dsh6S6^Vvt@uuuX=Rgp;VJmrh6kLA zVtH|?cf*SP=%LV$C+hJsqMDr`pR!UBGVM_Mb&-fsesQaNugiJ2^sSD0gE7d78M3** zTBTU1<|6d39kz@^Vo1A`Wc67f0h)wg;AM&JhyWYA=XS?wtJmrJx!j`g^&+ORsgWmj zr5&M6%3pLF^@N*iQAV|}_G}2QOKy?Bod}{3ZFGFOD=8#igqbM=%)9msv936n{mFb7RDLMTQsF5}_MP{3<1?5w%(h6-IMlHFg}`yk~E%)d~JISNnpl8E&Y ztkI?l^2bP9q*>9eLaoyj+;T@_IRFS7O+(Bd7$ z2zJc@j>jFu{fm(~=hrZ|KQy{jV7k)ayco1GO6cKV1h^701jsIXhnsag=!*a{i z6Y9S0yrzTleBfo7-WctJ6dRy@#KDjupfUV4@ap#oJHm?(P$6zHyhfCXOkldO#;1Wq zc!l=02HNCpqu&UFGJL73g9GZ3u6{(=;g$Q6wAyJSD@4haIGkZ6b*oNcvPN9PJp|e# zd*@<{DrNp)LU&SLN{r|aTKkz9Kpe<{X3!(FFmH?{Ausy~&b=-)N{V>~DU|W>u@F;Z z!3yyd_}3$)oWZEvbWdmQ#L-daX(pd6w00rU4BWgv?5y|lZb03L06F*TUBUh~qqIrW z5~VEn2$j6Xe{w=R4M0hqqwu`4EInq+i~#u@9Tn>F&*=pMoTz=(Q>Zbimq$h0s-Gt- zx<=V;GXf=105j%C#r0?m)YoVnL0e#Wgr*Hwj#Q5k6sLn{BtlO!C&@Wedh^EmC?5)? zQvMlY^d?6KHXg!VarqFujrX$Xa^u?iAnzkw$Zne*4toeHsRM%QmNR-h=elz@G~~v@ zcZKB)MF_vxV1d3(3qd<=dg#leI*xFDda>U*XxFg@5yrZA8uLP%Z9Vs5{)_TUncO^a zl=XRGP>MZkqa8EB^qPdUM*?WxV}!Yn>KWn%*dUXeBiaXVOWhda=b)y&+b0!G^jNHE zg=zP&I82Wlv8B{OHp{Yf@X3B5d`>hvMQ?D>B@0%nmiGU)km0<-8in+Y|jFVY+4CAOA8T1_+uIOJWc(?2PK z_C(7Zit0vaaD@>R(-I zn@?A|HYxq7N~LE;$#o^B6N0*ZJ3_QO=)WTWU7g;>*BF5b&+k6woXd^J=w zR7P-&d`E#rUlE?bpZHuXW9x$pA%89m0yox#?%(+t_uKVy-0R7%=-?2-+hyiOlFDPe z)@FMlq7OlK49{4X+z2|>Y{gJIkhD~JrJ`QK#AR|Z$iMg3Wf?;8H~LTGQ`Vb{U*%(6 zi`a#Z%=k*Xw#w6MHY9e2^JvRaYvYa6GJc?f^PA~Jb%-69*F+fW)}&cTnYk_q&u0a? zI9>os8E2jex3Ti&B>Q~L?0ipgd{2wNLB1{tBcdFT}b;Vp9a+Glo^w*{jU>+e5c;6LN57dow=kp`e!Ka z+tRL$qSf_V{e3@Gld?rI_M)s@{ank);?evf+g4m}w{meciLJg_t50HYxuGM3)X>n& z)a%MG=ea2Y%L0HIb?jt=M17Eiv%-K7;u`&q3XCv;j|lj+xc23geS>lr$m8#iBn!VED=y@W)KM<-N-A_vEKap?0p^nN|k ziAZ(58;y}=%s4c-qbl;_FiRu=4xSvuh&hK+hwjEx=EgFDWw10cXEPgD*k!Ac01S?V zUWlWU9Hk7;Qg_W&YS)muC+NR&i=+;(fPMRTA#JZxkj6Ia4HXv8(=#u{(K+aIJpMjS za(#@KM^IjEA0N(1I?1cBD9Jr@wg-upo4j|NYBQ=74(mC^BhC(gbrW0GRgg~u!O~=_ z*)|2j@Pzsjm-kw$?kN4yJ*i}Q$s4AY8{E8A@T3vy=!%P;hE+6w5BgQh+M_GnZf0^j zC$&zEAb!7cPpC~8i}uHjyaREUtY;+3k3frQHl_9`cEw4>>y`x*?rS>K;ds?+ z-rF;-h2+kBzEG;JfyD)6vBZugSW6MABGDOLHMF)S(LUg|e*jLu$!2kpha)Ia-3QO>?g%Eyv6om;S(S6{lA#_cuET1Afby18D-?eBMz& zN5Y=ftP3<1=X=~S9KZZV0n#CX2W+VGtSt878CsU6cW95`qsR`1y}GM#?tcC9e76iv z4oBLJ7Gj*hxVeIQhyiKvqc1~=uhhO+xCu)wW2g1Td#gL^s{lA}ADzM7J-AB-0a84Nqrd&|=g_+O8T=L%4fCV%%utapg$O!v%@AShI@tQf9J+?P@D%Y4L!KWl~B0;t* z&A|vYMu&>HNr8@nfE(0vDzE}*r6|B;aTq8x#jML&1PE@w&IxHz!}(Y(>oGg+B1J@V zJID}3054B8ISuZRBa-V1`k5^4|KV~$*vV7Ir=2LVoYWoyHg-}rdMNwXAWDez)oCXW&#kcQ`mmmZdq z^?DVlkJsDUlL0CJAV3$*V+F^bU>lq$EWsU9YF8XV$$r`uERSk6M9oW5wbof$3aBZ;vF(1^&(%9E8ri-3)O4ve=78;HzQDS1L&}VZ z-O@NsPpVBoW$F>m$02A$D-!p~6XE`6(EglZ?(H@2rcQ5Yr0@QZB>Y6K(Fz|aVa5Zm z?ES@{16$(-5(omk{mc}C61*T!e=~NChyZfsaufFqN5I!HA6Ed+Kzq@R!|sX~#&q{m z$xE7G2}h-Ya9|08B9UqBedW|(d!>@DhscmQ35G4PoYI~z)|w@8>&mM%A3Wqmr zapo+AKlpf`x1q@uk=#;&>U;-;U|&HLiFFr-&X-4$%8((W(%>@kh$CVx)&*QWfc;zNR&}DO5Z_|Nx+~EWV+@QRI?vjT2%O`c;pKGL&l81OmkyHsi*p;kv7>!I6fxQ&lVCj>b=Q!tP_b|vC5mQ6rYhS ze;lD6Kb#+kLhpP&pI`1~cHa51avhAS{ats%@dn0a#VTKT3K02z#klyi%syIJ*JdT9 zcm^7uRGqCs!hJ`Vb2tbbQFh9+ znfft-DD`i@8C?c8inCq`XPOF$IJcpqm`VyCvla(U*r~U@J~GDKjg@$qhXGpPi!(nM zo}S_08w>Nop!|W^)L=7 zL)EBd4`2tFNTNC-@LB<%YWSWW_U+pSC_k`)g}7()P={WmC%ptE5(U4x~f<@U3I9Yy!9UYRD0y+k>{zFZ+Rc>p}Je!@?g^pp;24u{vrjGa7 zSi}5VmU2ZwF=-KSod=W!xpHYyIW@t+oJ+Uk_vXXaNDDHcQBj^{~NXY9!th2Sd z6@5R4n_)vpfr1Su_kE*Rz zGfAgX_^rh<&zcl=H>+*fPt=Y-9mTEeGVnH>nOAB`+r0Lqj)O=+9u-e7bj>P@eHm<{ zULx3KZ6JY2?7Y{K6XUtg0t-G}~CJteJ)a+5lS=3y3;pKNZN6h)PqS3$ozMKp6Gv(+x ze}n`UE2V})`IT6idTHevM-FeTJ!FRV<;~@MIvgugWiAD>tJkSNqsD^wL189~QiRFG zr|!P~6vT}#;Z2Es^Y-DybYQ*sdA@s0;dy{U1*o$Zane`s4>I?(=rXa*B9Etu;3R0w z2chzV;Xr!{a7jAP^+Fb23V&xjhWP+tpXTtuZq&R6NpXOZv+=iICy2R6L?#^c4vVV* zFbWO&<#1HR`n1@4+PxfYujM%ff|Yve1%M)jz(t7wC{VZ+2+At#+rqfv%VqyWhUr?; zShwb~OQ!*pH|%oxc>FqkZDr8A*g6VqZ*v^rbQ5TcgM|+i{0IZ$+%a|R* zw$gkY&-Zc)q5W7ws_YkYrw#4d_ONzo-ml`gALBFd1`^$&wc3BWP-B=PF z9=)~9>N{oa$MKD$tN>fH2}tUrh{DCnXKfgUeGcPHB5yAab-S@BM}xTRO_v*(ouR1N zs%w?&B-MALEl>5N!e*o4ySxJzyD?ZOZjp8x_=#ZMvr}6W)dMvkS_dO{dB9B z9LohYJwc-@K}5qe%up;}!9txEJ+aH1{IZ>!T9M}@7ZZN?k>9&E@5lZ! z)q$e;r}5j*6W*)LUEtQXAYSN2A6q9&lFGQXg17yRIt8|?Posm=4_yJF*#70(U3Oci zR^(&Ti|PJE$LK^EZZ#fS_m4v#%hgqpM7=x>m+gkkpHoojxyR;Mg%xlEU6a;;B5KaB z+mDx3#g$ViX*1%ejvW?C*2ZaW$bG0ulLbw^RK>1zp}BT|jL^OWSZpG{zNwt_*h0Fk zneN_mR^Rlc8>anzK9@1hrh&(seCy>R3|xIW+8}*9v3ae+XX;7VPfNqCzi*;u=q@n- zVUKwb)-qQMQI4MZdMi=W{wrylGEYKkJx{{~ybi_w55(n3a8ncOC|=m^QW4OXz6O)@ zKU%*=H=B=`?ef?d|7~FJ3eI-V`djXpLH2I?RlK#cB?%W0ZiWLNsvj9nFL<;|;Vg1D zXf3AqLpqBL`2u5y0~w?%l)gDj!6+-dFBnTH|IIol%$g$Lf1ZXRA=ne(hq7x6y`d$? zIw_o1-z&tBzj=WGB_LvHN2kfsFyux86qwkcy_Bzqdbcocbhj}it!Z`^O67N>=|FdF zO#m*R=)K*lT1oM$A3E8}rpS_tGj-y-ncg&;{X}IL!;mmIh05a;*{ZMx*sCvJ+WL<; zhA1?95Kd_4^x2>)9r7-n%7g%fWM6qQnWg|IAWX05jxQbPt`7dY7i5(4cD(Ti9m<(o zSqk%_0?2Cj9bIi&*5n=4Pe&mPN+tJa*{baAvDa{$iFUjqkOLBBHLj^VLK^7#*v9*= zyzMe)zM*z#+4*M*2;%kz%4ri}?;&wyP%rr9v=nD2GfszTAQO{qnN&Ed{#V8Py*GzS zPs(mKHrn}>9MV4jC%cF13%q(fE6oBQVbBuk@E_UzSt{Mc0$EsmND9r~*EBvgz~ExJ ze_r6zA~u)9wS>RIcfmmyty}9p^kRviXmx1y>Kzwj;kYG2G zN|aDR!f>3qk&Ikd!E$7OTRVhsRA+R(5Xx~G<rJVPsldb_FC+_XsK!X>u zsi`Ba5#;RdhEnoMTm8%jp%RyY`LvDGE)2rEPLVxdKW({+`i+I+x};N6@>(@3+W7gt#vOpN1ulmVTXGYkjeV~;L2InKlL z@MxH>1tPiJ;}qOLJ;d_vS}-0(z74@_hy`0xls7o(8I<$oT2Wy@hN#Ut9(7erFw;2K z3yP6d134UeR?h^YhXnYQe*dr;jXBHl=yYn^7f@tRH#!8zZFm<|bxw73YiHV_A5)Ec4}>?z zXUfa1>R~u*x++$8S=;SeAXHh@R0@^u`1YcF-OJsolA=%85IiSfu@8*KG)#>`Y;OCbT(x8?Oj|kow>E4y^#9m# zuXr?L?a0(q9({cutLfbf`s576VxL zsbw>%5r; zs$yG1x;MD$6ZLJ?*fqh-6K8DkQ!bpMu!J4={#-0ZTU~`5Jrez&;4sGj5L~}jUE^AH z_LBnZi@?tRIF(A#)l&*%s@f$iJBqIF*(_$Xh2ii=e0Un~@hf#&3-8{-K(=&=+%V z_LtAE&$rjZ6?JGnLdT6u)pHI2`9~+ zbi3rxmA0}e7gMeGlX?G$Q(}bx-$eBJMQ`em-dLmhS=g>(^htKW3N(C|Md;x`bXp;Iwh< zULAJGtLmM`n?5U}nDfKneSZWyL@8?WW>3&&wi)-2`D&S=*ffrHHer<0=~!KnL3P7V$#caS;zE~?(gZdX(Dx$7+%v~lU%^GBJ$^tR89@}DU` zk5+G<%|0-gDjD6%-VhGXN^xY2$Z;$QRg*HDPzk=X+`OlisBbG0MEwjzsf*&t{^fx}IK zrGQ*s-Fe=|i)zUYdR4Q%q#ukSkUAu;!2A;sFXHyZicA5|$|pF!2=vr~=Bb=t>f*m4 zNlv^pBlNVUaEA?hXwM{9pcy2jB9M?sx&3TYNL-#ZmNR%nz?=_RHYoC&+Ig44dO z_Yw|nuOf5TzELq`bmrb-e=YAiNm7^7&Y93nQ|0%LCE`(e3w0))+daSuKEv@eg7CT$ zGmbc2$=Dxx$oKv4PLAV>;OOML%(`#MBNxn|MI&~xms~($i;%*Lp5d&)GcppT!lM4s z36RSgEwAQ)GNEDZ>=Z8Ak1Ide+uNd3>VWU``r+YZn&iy5TiPE=$MQJaI{hg?@Kb!I z4Zwkrc3Q3t#lF#sHL&gD3R8;Q-}~F+4iDiJaOyz6Wv3DT1jCVR{>&!mNv=U~6O^f5 z+XL3bbiU!)FSA7^Wu^i_u!%6DnqTK*aSNHem)$+bQ7-J=y-H3#zCPdItl@gL?Q`WY z>=Hl%>`#jysr-pa$l&7wy74dDEE1fB{EOO4iJ|!d>@;sKudqYjwweK6f`)Es(n?A- zF=Z=a#ZIeZEZ zxOsn!LcQ3`%cUXr9t42*_-;HJ0O#|2*fAVAN*`A&+w4b7aCoF?4?8!LLI`^qzkuCFDLJYd3tj9S#3lj9JbuUe$kWu2i=hhYhN;* zj7PrLC*qftDChxL?A*XovPOwlUB-TTF={A8#=nN9HBte>rI2vgE12G}1m62}*e^2y zr?1YainG6ix4VUh%!++H?%*Q~!tb70l5J9&`jJF9-t)ZIURTTcXb|{Q1YB0_W2c$32(zxy{dvo>!Wc^=a!c!&Zg1x6tTtM(9R zx_(>!BdmIYIcltJYG9PUq=v((G!6eD*y?-x<}<5|Rk@2#Vwe?#<-2ig_40VICG0+2 z(4o(rCm7gUc#*|_>t@*>6Lg4MD&_Ez42CSs6BxbNfE*ooSLmKs)*=R!bsuGY&q!+V%>$qOI8Mh2#rqGX>jv!>pv(gvAiUOjP3%zt z0)gq^g4w%QIE(9lymP|UIU+XanB(-dSnG(lN!lWCnot^hS+rpYr{TfAJLW-ek#1Eu zdS&zac(dN*V=my`k$&5|7^8!|+k32&ab_RhyPiTAs}9SL?|J%?n6z-5SB!C(#Qv$SkgRZQf~F4-Nj@RPOZGu0i&Jffb+Pr<-%t-n;moLd1aBKSSHV5U zxZ?KL)gI;7HGJiP-Q-5fyW|+DU^{>fd)lWj8)pT($q9_}yCgGnHlKG&wrWI(E@;2u zAv#$kk;KlSrgwtLR*eXh;Ha8eAewFH2n6?nQyC0SWKyfuBcs+>-n$#zSQV8F?aXO! z3?B#}CKkTLyfT#_Y#kNVSt+I`Rpn*InLupC-=TboWC&mECbeip7yl7DTdM^OCUfRKSlNNL$@4N{YD|3Fbl}qpFGYNi@OakMQ!Pa zUVE&;6+FPM;mDV7A*f;cOoQZXZr{NvM-7r9n(D;b!558wP))P#hEr4?;g&6q&DQd>MUBAG~=TIwli{T+j zC&r+OcDJ)5boZH8hl2b6wFMI~UL}E@4i2e&0Pr^0o> z&pGj6`MJ^cCJ_8p+h$4RQ#76c63;k>OTC|=Mw$*K65jW2te+WpiLR39u$x)yJ3A2{vQ z7TX%}xr>Xs57Sj>rts8@Sjt50CFCmVn|)HX_NK8e9?#%Ke`}cmec)JE_d(D%#xmuN;&k&TJl?^}{uae!hngdP0o?omf31 z-C#MSd-SR8z^OrbM|5~N`YBV{pzb-OewmBbf~PL0+ty+dg;=AP#UrC5;xl${SS_;( zpR>ISb&nJYLmypg@)a|UTB5Fp=e`F7Po|I0gqw~04hF(``WN=Fs*U1hbjUcadL1EU#xaB$5q|2Ovt-qsAaEk%}N zj{Ac|fFqeaCXx;A=82fs)5?dj%>It>w$e72ssfYdC6hRL+QT%;j;8aVDDk^tAfxNx&(@)OBLQvdaoc)tCl_aIjir-BLQ9J|L@R zB^+C+27}n^A=wm;IXHfpYb8-Ex-40R2aNJJ>4H^Yfx8v>-9hjLH+U7zjAyZ@K3@23 zUNc8SWc1oeKI+G?E0Jc6PsPkPU#S9P4?OsVVNY47%!`KHOH_+ zcpBq4CPis*!r!$>TnJP7djcL_MEpzl@R>M5hpCybgh+>aSg(RUS|O zF*H*OypZlD-L|)@&0k~=7slgo|AppQlzG6x`ig=jfx8_bqEp7OslPl!sU7M6#2`xh zrxPBBKQz^-FGzWAihsL02jj<$-~2>#z8CPrC!~5HbKSICbH@<^AwU5@0RE38uf5AQ zrQ5At-#9K){Cp8}2^4Ps9a64XSNCJfl+;!1;x`KKoM&5+7B2grk)Wzs2i%f}SOQk@uF~AaiNOd7XPNs?oS}mXsO4Paw*E$py zA#oHNStxY2L0fREERjRxsz&jLg@Dv}MXZId;c6-i;TjbFT||ot?10l`DDo$a(Twb3 zbO&K+m_Ai4o|w3xns9cQMko!|^c5!;dKJxg$x!K&k=lQd@=B!ArJ5csGqKZh-e?0Y zlh8&0vXN*C5vy;wili!giDFfd{|I!0t`yYv#8wrWJ|Re0RwiRdy}4yEXH1#mB*&7P zAVqn?oh!}Ha1)FbwS`ec*wiWXPh18F{55Eu*Dbja+VI z$!BFcr6+^ZN>@{3;v8eV-zjY;x_U=AZeft1Xg{Sj6P5X}`wyMEMahRk`I5AX(QJaU zL8314R85gd0$NmpA?Ptil?_wYJR>N~_~mIDT{84BhVK!k&-~JT)_N|xJgLh=aSB>g zmKhT>IMu4UMr219QBpG`35Hk8f0pU2uI8xXqpXBrarHE}aILJ@Dc#HkGfSL53e<|& zR;5(FL~oIIAGwt!sY{^r(Gp}TQ($z}>I`XzG1<*WPH^bf%FHN2xyDOGsumb( zNuXMJHYEnD3avwtyI6@`)#yfG|CZURf{o;{1QRX&ls!(;s+6`8*F1QOE4KPb8&B;I z6uuPVFr0P}(~gu)L$Ih)FQ(KzL^d*o*oaCOg2zW*b`Y;jW`i+Q%A%}JJmhi2E#9vf zEzV+Ty544S9Ao{&S|ax>y}g9`KJi#T>_)aUXJHQx7JX-twD_KH{8cz-3)CfUNmV_2b%1Q8udv+ELPS>q>9lKO$?Qx{b+ zII^G$!KYkS5mZCi=;meY#}(gFYf8l@Q+hmWR(*BClH6AolWN8nq!EmyDFPet)Ze+# zRZ+St+{S;d1t?V@you1(l`_V2%ub?N$WhU9gv(RP;UcZ^%vO^-IFOpaziA14pRzeg zn+xBn)8V5MG=|+Gly;Hfr__oOtydyVftdArbW=WGeq4Z ze&Lib6l9nPqog6zUvX_D%n0-iIFL?&#`v(6m(bmYUq*nRugNi z%a3`HaYL14=v^vGN{g-(sH9CSf9mWqsSYe^$1Ix85}xt|sZ3K3`BWxxHL0(M==*|F zJR+PSyjF>pe;m;-B`HyIyC~{Yc|$;P$EwsPGXD^)Gr_uVWt~mDsLIOz*`fW$%fQt7 zFGZx7DjuvjlWI8(Ct(AytTbb!8HWCWB^#VLnC>K-GnuNa!jxBt@=9S92dgyZg;bcU zi%2+DHxZ#`@D-&3#VttieYY6h=zvS!0 zRz)@yvRaR)){ymypWGxXS5f*t$W?+0ePRMY6tVK9 zm%0>#aIa;UwMb@n=9^s^u~j4MoJ`b~@PIm~RLk#q+evi$T9RY(*7*-AqtirMcUcPS z9GZ44IiAn=ZzOdHIsFcS<}wX3`Uf>!$_BWWcs%|0U*&U*8*b306RglbRLcxb6P&nZ zLSwl?sUe5#PZAsn61+JykFsIDY0N{L; z+iV}(VXaT|)r(^)vuVoiIYn?suu-!6 zAO65?e%KbRg~L?c{o=VW` zuF&ORnpqK{riMmE^cC%I6Ika>oZ!B*3KHIFf-~$n!|r3KxMR1o|$ySE@5PK>AT6e%lw# zM)1(=2;n4r)k2igQ@2-#9y1SZ#5rWresFZy@mvpJY8>^1%UxUgS^< z@ZVi4p@9H6F=BtJh!gs$fH26CAVaBwBt!(!s2TcU)DQ&+4JhEGU7*5ydmt3P+6!^~ zvJWZ)WIvRK@OyAlJ+uzb7>6&bBsyeYA67X6iII&$Fmi+hmC;Ow?AWA$S5Q>Q%vwRv zB?pB-xI?Tkh%Z**P*~z80)|y468cqhH>!?4qwX;xHU&Svzy~3&jStm$5R|GS9)6XS z5(0kDr84k~F09^L5VW_Vz$MdMXeK9|F|oD2zqk03t?Pv?JI~&Mukom5WOsuIw#N1L z#u%^VcqfmRn2XS_CmL&7zoCuM4kt-6zK;S$Xw7k0r)9jvkty(Bi=L@L`m_L5cgk$; zVHRikd5@UGNf(0p)ss_zQ~;s zE_I$^Y+fHhvQ+j9!yCBEB@(Lnz7kF?YrZaY3RLg|&}-;2p0HMA(=$;7EuKORnc=n& z>#3D;&LWuCG=4!?mt^-RqELGQDZiq;NLUJ@KJa5r&@OwiTYaJ{>F+ z(mjQVXb;_oyM=_@n@(h?vg+b$kHrxEGODCIMR%o@-FN^H( z-AOzB4jeCoz!x7vM1pa`p*X^g6A2^XB!WbeD7^Aci$xx3-2re=n(bdT3Q8(! z8d^Gf21cfH6pdjVPSPwd$|_l=?fPMqD!crdUY2#+=_hk;_s8?~{s^Pp+TrsDf}wCE8jB~AsdOfr z%NL5JG5|twrCO^unyq#RflXHQD*piM^#{Yzcru;M7t7Upv)%38&8M}dO_BD#-UUFl z)YrRx>7&i4t3PdBecCLhv4~gwJ}um9b2JE#w%)&b#LhT!V}@I63~U?D=mZQls8m4o<} zVfg+CmLgS}bQv;b$(92mSDt(Y3KfC&X$oL{o1_%H&!L=#8mJ*hPGNF3l8eEHn`pGL z#&b2(WK$7xGuLcib9ay@4_wh`)gR zI}#-t`uE$(EAbK}O6s~F%cQj3j#O#VWyq8zTaH|L@)amlq*#d*V8C_$;#wcy?R&eT zoBP>4Ngd*TD+?C{JVTpyRvkk3cM>I9OlcLj(kt;2 zBubJjMXEqxkOyqZk_P-g)pF&@SD;XlVkJtwR;FBqN^exDR-;y(dT%u#0KC(vNwXHM z-us|UyN^EU(5cI3Cr+I?cj3~NYd3D)x%c4FlV>kpy#a_Yp=d@$RZU%k<#<7qWbZzF z`tt3^uRs4BCubK|H+K(DFK-`TKmXrYLRm#sOvKiDX%MMP*fW zO>JF$!@WzI&S?J>`0&j~0{n57*&N5c;YMbrHqvw_DxGC?*@*qAA3J9j_{!EpfWJlu zE`VK}N1#=hgbuRfgHwDSHeLVfjJxjlx$ux{3l)xc_*`%6=)-pCbIpCPjotJ#Y*K|) zr=yn%dl=)gtDvwJ6*A>V%*XxvqEUcy7$yn5trKilq)<68InC90U~~WrszI&p8mm_g zM2OVyiqM93%TP5)b-X9~IJ)PZuuZXVZ_xE2rE%Kfj62xXMchjJ^Hg86kNif*=7aX) z0aFI7`MO?O{Ml|mS4E{)@|SwO(=-myXbS-%T*z!866UxfS;T}nE*Da1lPyMs33FT_ zmClwBVUEj%RN7=qiEtsaWdJdu%yGGpN}FsQ!h{N`wArNYa91h9gff?FlPw2`303I| zfP^x~jaLeFxlrjUCQh!dfnaTnxljOv31yDUg;d&PuMlnt03u8%b6hT-^W!rNG@^u4 z@%Q`h!`3FIfs^sOmPvcveuSm)a`y9SCpW>YxWw{G1!d>RY9e_GFt`kPtG#&SH0h}? ziXUBeEh_f0sb92k13yv}bW-Q5A+B1Qy|-Y8#n%KFre|bhctP$We1w3U0wV@RiX0_swBXU``(GmMlJ#XgFKCH0 zn-7T-H(vZPaLXj1^hc|v_5guN?ohd$^1De0T0|KzLu>IQ$D1ybOVARQEEFxw_* zZ0$w`XnTbHPSXECFbpLifFR@rK@^B{@STBw?@*_y&i+>q#RE3-)z3g`5dVUNh_56a zAUOa)0sBv&CH?)HiKs%5ssi9jzFUE8%l+pA2Ds%{%SZY#zp$m{Ewt7=?qr%P8Gted z{R$`u0OhDt*V|Fg891Wj!SEy=D5#IRx=!ir?6b@NyJ?q|J4ot~l$*?uda2>vwa&h#lu9g(3V zvS)P6QR$f+r;Cy(itZ$gnCZS#OkCZx3#gf}XGe3+Rx{@YFW?t1RXtt5>w<998MWBZ z|Jq@Z-fR?J+QnqNDwRP`73NOw)3zKU}qkVp~JLv4F zL%P-;8OaVy%rOEoKSpqzmvXS#nAa?UiLNF1?Gq9HvHRP6} zC%Ec$sf(1#q?cuP1=MxRPk%-^v)3jqLQNn!Y96Twk|eOXXJ6oWPnHlyTL%_oAv)o8 zk#k4Q#Gpe8sKK4MAZ4UUk=OB{Nb@^oY=&ZjRAf9@g27Qj$;_%R9uoP=U0GPAmJbwk zPax(Ae6TCas!H>L6p2t0V2gn0u&%23gl$<(1$ps+ z*%MzYXrf)}GO^d|@G>b9>-b~wwfxek<78aRAI2K34kmc&y!feRY#R2Lh?%n0+qBFx z$hErGE_C}V)Q$<|4k4r+mNW^&U+u~|CeHclUmlyo-s6)XI;>&Ztj+=&?c|F=$2{#< z6WlHFo1q}!l?<2cC!nr7@F*Od3SKp_2_KUdqk!Mr@c!~?eDal34(yww3Re(#TQncc zftKsw-yqBPTaDTntsy&it?8n*Wu%8cTHZB++V37}YkU&&Se$yHUg*2mS5Kd~+8P}R zL_OfE*Kg^(n{y*U%{qL#B$O5BSfuit%Pg-H2Z%9cj;k_-fH37so9tvZ08z9UD9@At z#L-g3lsT^Yo=11Ve|fy2=3bY_+uMuF`rFGb|MKXIx5vTyPuJBRe|}v5U;c$0e_#K9 zzyEGU+PdE8^~EzzNK2e8fDwOJ`enE=>|Qs5bk{06oD~O|!*kC(UJ=q{s{o>ng4RQ? z029g_!KKnBTSJ&o=D1u)rA@XLAi{*YTy0+q1vgV{(AAiD4d5ZdgfhqFLMm;tl>iYY zlsPUJQfZT|0*El7%yGGpN}FsoK!gcpj?0Bq+GJ}0B1|ZATrQ;2CR+=TQ0BPb{%D>> z)*ltOE6S?}zg=NaXHe-%!YrpMQ+;{co#U@LoZWzXV|3?WwjbWb)^>MJXhXNYcYy86 zVYVNFgAE}9gyv~?JikitYu|Wo@SjYL=#Tx+k>d&^yU4_T?>}CuidR;u&+E`IgeOEz!5V#Pc7YW+?Q=|1?UG P?U?@2e~J2cGnfJZ3j5#n literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/fonts/RobotoSlab-Regular.ttf b/docs/source/_build/html/_static/fonts/RobotoSlab-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..eb52a7907362cc3392eb74892883f5d9e260b638 GIT binary patch literal 169064 zcmb5X2VfM{_CJ2h%xrqH*=!Qh*ksd4BcxKpl17IB0TMt+C?SM^^iDztL+==>geFp! zst6(?K}0}AMD!s|L_wbv5fPKg|8r*(#P{^~zW?CtopSfybI(2foLLDagy``h5x3Uq z8JUhLjx7mm7LL1?)>)mqEgN-yG_DH?>0Z{lTldr^t%6z*w&V#Rd`#zV4ddRu60w#L zx(5C81`Nv|G5yArcL;Guf4iaqeXyeu*V(uZE*v&y z!l8SfpWzzgyA3aXbwK{@kbY+YH zwCCUNKC)^~^%@6e*B_Vmgo(TO!*}fZSAT(9b833lY_KoXMzTHAJ|$mqNAe@9i6_Y; zI(##Wyh4WK;dA??*b7Rybcrq@GT+9 zHnxh4VvC3)KTcAmiKH!ELADX0G?OL=3AxP(mP9mrT|C}}NqC7DtM#%MzNNE66J zsgQKQ{XWtRl1(efQo4gA^51c9Fj+1Ild1d&X{qxkY4SCaEVm-9)zoQ*W zl9dqB8Zcx^8%Z;H7w+#Rt#uv>xe%)+sTJoH~e#%{9-YEYeFlkE0{$#jaw`xulmI zK~mToB$qX-`9=B$=d($QZZV0ILrHUKD*9d}t)!Wx7w=4RB@Z%={fz5tBvu+vB9!%{ zg|vgDNM*zc7jv&A>GC1c7x$Xchh&xX8R@}qk~K;* z(ubFjBEFq8mHLy3;#!hOIs27NkpfA3-i(ao9mx>Zlk}6#*q>C=iAiK5y+Q^vGwH{7 zV{dknA#w$ITRubHR?2Zbi8Qr~CGk=Wa5jZ>ma0jnY)6uHoa9T}NhfIvX{W90cT!LO zjl{4`SmQmc0eBZ{SG<6i2c(y79~q@9B8BWaX~Jr1s^tr$9mXkC4iFc4BWcOfYO18( zWH4_|3V8$IC!I`SZe$JHOUme1B#9p+rF0GT`1x5`eQ*C7g7W*5mqp(pi}f8fr&gk=_A5SCGY03h|H@ zU`=hw5Uh2y^bX)DBc*ITsV}`s%={goU(#ZhO{t*5Y>pX>ZUn3*Mz9|iA zYLvxfjGO{m{*)vr^T-g;V>{4Tg54XWx!qT!qw*PPtb_r!&ZM~#1U&wZF;0U%LvauE zD*r&5$XO&wv5;(~DegTb&2+z#j=Cy*_Z(aMGZ3fT2PkPJXKe;_=rOP7ux-O)ofB!I3@17A za^U&^X%3nXS8kFB-C*#fg{0fhA&u=85O>L+MDPQ)eE}SW;Mpd?dn>`4SVy69fy|Su zFqatH4`csAMoB@~qfsP`KOpNQck&u&zJ&frN_0PwDBUj7NZLcf1Yb-41~0u0K5GP= z0vF)5j?!e30^ZJ)b4V}c58{C_yXvY*tP)4M+jRzB$CB>g{~}2xBXsqE<4_V0I&LPn z!TKp_s&LXmu1_4~Wx%Bx2;|c(Vu38P$eEz4?KnQb-kC@&_{aqL z=*w$}QFjt}*hyO1=}D%pA$a6xtScJpKa24qFrEuw@PHnGHmhsd5y)8w$lE@+SBi6J zDY_X#7#d9c$rH#MN=LF)nolO-ejbi!`UWx6Uq}S|f#k7=q$#@sSuzkZb~O0$0C;5w zSth5FWxCy@1M5Q4adhJ|u_ud38s7zcAHcc~18*kKVmax|-vG>yNvQM#=?|XHSB8;d z9U;SXiDZ~Ep9~c;Kyd`lza$xuVdc{2q=j7~DPlWnwnbY9LfV8?m}LBVP3iBvJ`;xhGaZ+Tx+Z=M+ygS zV<12KK)w!zTv$PR^2s=#0$BC9KZ}gu#gJ`Vaa}={v$sjPki(E6^SKVVD*-*c37ONB z)Pvs2fQ;HIZ6M2}k4S%kBhW)PP3J)N%bbjohk$l&LXJ(wdEGT50n%m2`3>ORNj1-e z{1kdx=wA6vlBykTuukYZ_H&J@=}@6Z|Lzca6*~3h13J}B=v5qnY*oz*}~q?bpAiI!WPl&fmJmRu#Vq=x9`zD01gANwonb9!d3uY z!B3f3ORlh6gf5hY?E?FuPLICaa$nnho)4WP>>Ah>|Jll+HM=#L3Vi)n3)_do{t!0M z%dN17giZ3lS{n^PW^1%$YdQ3U*mtoX|JPR7Tf*kiXhiH=t=%PTA7OvJ+zJ~+*c_S- zB52@q;;$XxT}=)MS@3sHZSkry&S$c2{$HL|kb{1?b&Ax&SrP+*vR)t*(TNv|vBy1~< z-_dGzm6#89ouE&RcQBsd7csA}nd;yYeFSU@Y$^>N!H1Ah3hY14{ulC1zy+8zxg>a9 z*hPY_gnce#l8`0B78kNf*b>547rY92q}lect3;nV8vf5#TPL1tJ`sE+ewr*6d@Xde zfJyTS>g3ecnh@Pyk_o+;SqHZ!e*lxPQ-xhwXD8X~NH2$m*elqKnvGW{%LMPhhSg*V zY)S<-pg8|e8Tf*a>SUa-V_jo$B^P_#0xc>ROH8K>u~Lq14&K@N?mZc!&di8pHif=C1*N*?ZrGe06J>1c10 zX++U1Bu1P`ASof6$S$&*yiZP(Psv^KfT+}!>S+iKqp`Fb?MDaG5?V@^(Ko1-KBP6w zmnE}Yc8q<*K4#yrUpVEQ+jCcL=4E^VU&i0yR(^!P&p+lD_$7Wt3XvL08B%Adzx1j! zQJN!NkiL{|Nx#Zec9RVOG@xa`?0`oBzXbeVzoW^~WHbesf=r>NSW~>Isj0as-89Bj zYT9DjZrT+n2O0uB1A_uX17iaF2C*O|$Ti44$R{WuC^D!`P+riWkh4!e{6kXVDc979 z)g$8LOiUyQYkUK1+(S-~kH|&xJ$XoKs2g>sp){N}qS-W$7HVtUME7Ei&zX1a8c$=5 zSFuL&VvVz~#zlNNui*RmyZi({%Rj>!i4-cuN|{oYG(Z|5O_JtGpGsGy+tO2+$@%~i zkP3fG1cZF&Ru=CX*=yYm75Bd9lU{tnsbCtg(0P8uc%&aiF$FiZxbYja2fg z`4v&9+q7fN3EHaWeb7Pzj)piQalkL4VL0mJ2&^&GQ1yxWJb=z!)tjr=SFfp_jnPKej1oPnWgN7oYt{3r-w3IC8^>N8TX1Z^_r-yzWK|nNzU%&- z@y_Wx&+hcP^Yo6xtz1HGW!>t0tK+ToZ~bmH|JLJH{4MF`b3$$+B6)Md&7n7k-0XW} z@y%{G!*0yFzWv688{=<`xH0TT{*8sSxM zgf!@-V_;ne(b57cqMm>INBfG~=rIGI<#k=?I$YhsyiPa}d1NU#&fq}QlKoWItFC1? z>&{+o*+ull@qhVayJ~xJ$%j6nztX4lH~I__no|0ZNla!6(=j`EY}3ee=D-}86LV%R zWCoeZT$vlwGk0cS9%L4o&FV7~3uHme%!0`rGM9z0P!`6*SpzbUKHv}G`#&OOEC*cM zi}hxG*ehf{>&yDFJeJS;vjJ=%8$=e6g{*)LW`%4BD`G=gF(R{z*)TSoy~;+gk!%!M zLYA`WYzCXn=CHYJ9(_!I0jC(*CiVu~%qmzZo5p6cS>#Q!ll?*7VpXh~sY14JnJe(v z_Ha9HPxf*L?ntcMiR|OfWIuP|uH*oBBL~SLuIKLDz&*H;dvY)CP2T4|u-Z@Xdb}48 zBo}xP`4mznn1}FCaPep45)b3Oc{uqTv9HTKf=7}scoexpz9d(9H2I2r&0}~&9?Ki? zI3CXv$iK)np2(BH|38p>-7G6=kM{tC~a5|ybUDZDT5M?I*KdQwC@c|IS&`$K+)N)D2vBtwpd z(*`txMoKywMWbm9qy^;z`5^w7|3VwmSjkSZhZKtAPx!Aio+i*lnnaUnV_v`q^QZhb zUdV???vjB&3lpN$0u+^Ci!GOg=Wx9uJRhblrN*LX&cD16_ST!q;2_1$&;_*tLY$GAbCq( zbP|6=r_kke1<&ERL=lk{@QL={U#Ofy*4qB++P^%0=|X5D=qbcEBqBo>>4+V%Cl17s zI6+#w5Le_X^u(PQhzBtua_>dFNj>62e4)eqNdT!2i5>`6VB2og!6 zNHmEd4M{9%MB)%BNg#tN z)5vJVY8R1GGM&yRBj{qfgbX5M=o~ta&Ltnv1qAVIatJ&>7kWFN6w@-YoGyfB8;V%g zXu=^!eq(lmQ^o$#Vmb_ZZ3vk|m$C@}_Q)i*FO*GluEtvt#McuWKL$^BDJ;>mtT$|3@Bnr139m0`Gjv2sXRmz=yT-~6t* zIp$nEvvkYB1787s?NrfLDaxu#i`)+~Ps>Y3UIx7z`=cn7gY!|gp zmNTq0KRw!NABFKuCaZl~JAne6m{W7D4&tgSt{iX`ZFPt;y(5wS;$r|NvO1>anac8j zd%zoQb&P7CowH9z({qEZ&V$SoqODF*?Yrc(?`FH{8;JV`?Y?u=KH`+tJ!hYjQyQjE zwK_!RT1lFfg{1DY7atDzuu@MTfrn(}?4!U8wj#9*c*V5#5rJlWt?t~{_FR00g=kN6 zv5eLLzI7h(_b1Bs5n?c7>1kGyvLEtRL$?cHku$P$h}FrQYRbd7hn$@$WJYRgS>8Tp zInp{T(l-c;cST2+$Y`ru)IKU&ebhcCTKA}ZT(pL$eUfNBfK|~NqxLDH^^Dr56RlU& zK0DERNA0s0ZM`U~UF839ZXe8D58v^{+@kfv+@kfz+@cM@+@h_IxkYQj+@cM{+@cM_ z+@dvOZqWuunVM_#6B30bJLj3wfY3a#0r_aH!4ZMc*3c+xNTf9clotjfYYp0{BRz9| zW3#EOd(MB}#12PW!(ZT&dRoIGtkf8*p|8Qq%l+%4h$vH{22ErX^tX+^!6kL`iBsZv zP{?+Yo?>piFM=8YRTS0$2}yKh|KS;N=)fjUJdKHVSit_VAz9#j0dP4l0W=n@r8iFjk{KADd!q zV^}32C^8~V);z&SmM%F5n2DQw53o?~lbb3y+YS-}^I=AFCI~wXR0=L4kv1{K(((qH ztvoG%Aefh><@@41FBhDEZuyuP;?SI#-`LlTaWVlt8f`2LVH*lFKp@}(IEl2%*i%`2 z7vIZAmk@1qd_ws7ngetH91*)0C)NWO!YYT>uE*RQ%Z%4u0vglSY@EVuK=VL+7}CJiG>+$9J8MY<}k!q zqrf1Rf4JWYa)5dmtkLL`8f9&WCQaZb1K2ZVLX6j8BOQVP9Fqp*Wkl^Kq&ZG9aYDsO z>!|%yyVC|I+MTwdPYXP1C;Et!_M(qC=^*-ula8WK6P$DseZ)y;(MOzQi9X__i|Eq~ zCtXD!aneon5hvNAk2vWr`lR5bhv*|tdWt^cBuDfSC%K|eQ=Ie?eZ)y`(MO#05q-qT zD^b?C7ijJ)F04to-A_A9##x?5HMrdv7x_`v_!qtViwmvy0PRfl9;ls(u7jei2`{=9 zhzqUjVC_tFE!56L*CA2X#1~zQ#D&&%sCFj07Hems>#(RutKA?g56+q(#CJ60ZhPyQ zuF%7DQSK2tSk(he5R&OuZXRLv$}pMQTV1-ew<_IwL+OFu1xycGWU@e=9Sm z!#YwT_B$!~@W4mzekt5OqigzpCp%rlK82?53#RkBZaRocWb_x3|_Z?a@ z+bS*GC&Rk_@4rgek~ld!H6uKkVEBO^1F&ju_$@U6lJq=Oy{KArTf{gtKAm6 zhxSeFC)i(f@N-CanBj2A(ZR8g;|9muPBBi?obEWMI!|&w?)=Q9oy#hhORf&CF|L`e zMXpO+cePgseZ5etLpy*DYVXXGO%f2S>W}cQ9;+tPUaHx_24$a#lZ)I zpM^w)%nJEBv_t6W(C1;D!nTDy3-1uVGyGbEga$ntOlYv9!SM!y` zpGJ!sU5`tNn-X_A-aWoY{F3;u6Jis_BwS34NSv3%lKLl|NDfGzlzg*s)5bFzUuhEF zI%S43d$Vu_WVeX4lLet({sIw?5G(s?Cx%58L)=Yi;|iou%Ep zcGuhIwg0+9P=|sJmpdkP+|tRe(~8dSoy)U)vZiER?&8s{Z!Uva7nsbkFSGx5t8>4n6aFzMB)2(<5g?&fVOU+-13HucBU;dN=O9s`pQQI`rB3 zO3*9TzN~N8zGwSI^_$l3eqPtSoq1}0ul#rVyY(;Vf4sjspkTnkft~}G3}S;u4Z2y- zslYneeekrwcMC0rD++%a(tOCKfBbiB$kicFi`7>Cm{LJ%)}N zx}vyoai8K@#jA?X4YM0IX_z{^VEE}*?Oq-D>WWt{j7S;r^T-vW*eJ`WKBMN0S~KeK zXqV9`qgRYRHv01DpT>BOi5W9%%+)bh$DSSMJ+9BVS>tw$duQC^@loTm$Ilsmc>I;| z&nB2ABuvPguzA9jiPFTViCGipOnhhJ<%!QH#ZKxpY1X9ulkQFqnw&X#*5oadFHL?v zC1y&&lx0))Pq{s%YHHNf;;9R!o-R>J!b`@K94t9q@}xAOG^cb?>4nn!(~_o*o3>@z z;c54$yG&1?-go+<=@)0D&M26%ZpO`-KKPe2bHmJwvm9n+&YCyt#H?qt<7Q{i-aPy6 z9M3tSb7JPSnX_dsnVU0r)7*#iO!Knl&6;;&-s9KuUMqj?N||R_kFxTzYxCLs@cCWm zPnv&t{Ed-1Bp7ne9JX}4s~ zl3hzKEvZ@>yfkm=yrtHq*Os|0OIkK?*|KG)mOWk`y1du&dCN~PS68I3n6%>fipMKE ztemy-)XJx;VpkQe+P3QUYWLMytLLr0xW;`=)|#?47hZRIJ?r%)ub(ZqE6*&SSAMMg z$=dL>{nxHpdv2||E^b}Ux{`If)?Hn%tZ%%&@A@U{Pp*HqA#_8p4NEqh+HilP-$u*E z5gV6nJhk!uChtvcHjUe~Wz&^69NuXBMxQsPys{*p5FR&Timwc+qP`GvfX`qhwYQLZ`*!-hsTa_J9g~2 z`lj+`(>IIX-2CR1ozl+cI}3KM*?DfK`c~{)1#fM5>*lVAT?2P*-u2F|3%hRbdbZnT zcku4UyF2YJ*j=)F+3sz--`#y-_wC(J_c-hc*pslQ&7Qt{#_TEEvtiG{J!ke@+w*X* zve##C%-;09z4i{@J7e#vy*u}w*n4^J4|}VuZq{IHV`~R%o^_0Mo^_qoYCUDWYW-;+ z+2^q@d|&f@S^Ea=o3L-ezD@fM?mN5h_P%HPUG@j>Z@j<5{=EHT_RrhDZohT^sr^^? z|9n6?;C&$KfaO5;fx-h*4lFsa<-nzbu?PDfoOf{7!7GQzq1Zz`4wW4`e(3IDm%|Z< zvky->yy@_+s&V_tw34{JqD= zO~-SNk2${S_~Z9|-f#Z?g!gy6f9d@vC;U!WPE0tl|HSPN+&@VDVAKa&KDhjWdNS^0 zhm(aT7o2?eK$` zqkxZcKAP~+hL7GoV>z?n%#JfRKMwsk=i~B^FP?Qd+vDt-vzI<0pEUpE@F!L0nw~2; zXFYfGyvO;>^Tp?voj-B@rwgGM`d-*@;m)TXpJskK;nQ88UccymG4tZIi)TOc_^i!m zQ$E}F+1*RQm%3hBa_P+H?w@CUzTxw0m%}d?Uq1GQ@q%dq{Fl?ey8dh3ziwYkx;E?D^>1RoDf#B~H&3sJ zUT=4O%=IDxH}{6Y`Js$JJWXs-);Nu;oYFSeeTY>d+_ev?}NV2`F_n0 zvi>|91O# z_P_W4?D2D-pEv(}^?}QS)Cc1p?09hXVerFA4=+E8d({8Ysz>|r@A9LYup1a^Y~9!d z)OJXSEBae}WZa@Om5Hcj7mkR63rW|z>-CZ$lIqO*c-u#Mi~J2V0Uxr%b7rSL#)lZI zB`S&5!d~%3+%e5!adBkaiD5iWa_y+1IHkEdFiDcT*z1@qyQVo~cxRekKfvG5*QcJh zmnST6OlA9XbMua*f!u5`CkARqJdZcvFq*Z)%#q(>AJmYn)mcAMU3v}m?Yg>a4URM4 zreAxOwR#05>B#w%s|B=t0qwJhZc_8au}IyrKrLXQ6eVvWGTW&pmOnv_NEAu6v~;ou zxFJ-Qg6cCw;!_Dl%#tF5FUd@j3k1RtyX{S6&QV?|%e)Igw~Qd8Uyz57VvM8-p<$t+ zi3v%`iSb5HPop^@)EuN3Jv_Z|;i2e^=ETs@vmm}*zvU^r!S!sdX>htIJa}_MdLTuy&rr$Z^z`J`4f^-E8pC8&hY;G z?q6P%%V$nTksj$-^P^lSS0Wham&22 zEnDWjwsl#T_HDa#ZPzY~H58ZPHg2`c61P;JVeF$}(wfpeyQg(5-LD=cjHTbeW~4Y}ENH9tyUW1WH6ttKSXk{0X6Ih8|0 zy!D9g`(d-NWwKniG^8K8al~nz(-bO6wdX9|9Mm`|D9RjVHu{9?3}UUx+MbCOV~=z+ zDG5tfbY41hm;wX@%W+A`RHul2{hHQdyG*`JKAt(0P;I?lWL**EiojJgxuY_F3xSRvU6= z-psuz7c_5qw?m^CdcZ$@O5Dh0{C48#^nRhaNiF)0w9)A{sXk5D_|)5C1l@v31^srx ziC|GZ(??P+7*z14+(f;L?3keMQEDSrrVK=uKyPtzk{Pk!ww|Q>Q@2Qi8%g%^QkdT8 z=8n~d68$KevR4Ut?d->8Ai_?6u9S7{G*%kXu%>f=0GU%mGV z1^~cqQ3=^lI*bTuh$RU8#N>_=(paD$LUTb-tc!^7XJ~@SO|W^OF;H*T2POvU*D7zDk!?a@YN8BK>4P-EJG#OZ}KOBi}%>x>}qht_etz?+tK6Kwn{?qr`aHtbeyx z8^%_)>3^klyEdz`*8rY!l@6+4PxnS)_VT{SwJOPnwG(QvE``AMxJ%@4u&ZfA516#{t$@ z$lDsgX-`ZRf1N^+3nVmEmNX)!NbqR-!{`o#Bq!^2i6MF~W8lPF-_e~nt0$HCNomsL zKF{y_l?eQ_hHi4hI{buegyz9_We&-RK_MF<;W6A zm)Si`=Mfo?jAN|;Fq*?q%xx1J)GIJKUY}3Dnbv#SkkyOcV>0D;EAK6wrcP%}cH2Ie zxi8+4Gi+t~Lgg4G-|ZX!bD7#t-mbn62r_Ga#4~Gq#IZXZIlQU|S%#SUcJatjYyj?tg=Gdt-=8jOd ze*fi1y$&>td}q{0cfNc_89i^_?77qGbbl|6PYoo_($HPch~xw`+uO;Iy_BcQe{z&0 zIi&&1&J3o7!JyYz3X0u`-AhbP3`|5~H&7p@<4ZsOxT5-LMfE5)<6`wRdQ9=4_sb9a zm6Z4$ew9C}YRY!AM6tJhfWIr4JCJm;w1+~V0sc_mt`vKkY6nzOqC;tqEXf=jO`*Lh ziWCu5=>qKsNQ7Mh}qo3(ajqtS-zDsE1La zc5E0uvfanu|9I=juQJ>JTJhAf`IE;C@!pcnskCIIIyfkrG4<)Kf2mK;o>IomvcA6X zKxP{~udm*$<*!KWy$^D;?JaE}bU@{dI>J(70kA|QkbsT~`$OzG=>{$kY8$qP*nT5V z_w%I$(djV1Fr&fM*-jxo)W^;>lE!&@=|YA1q4P?@{@a#7Aclzn_n^yc6vEcDTOJ$Q za73He4=GaP&3!-o;kOH4s6WuyU4s^dyg6;++@*45kk4{2|L^Zf2`$vepWar#Matdp z6zxTes$cDrKK7HZ&#zhXuGohT;IUwh280}ib=S&9zIlRLVJdMTn`lBw@8KZ?24P%h zPIh-U1j4oql!Db~M;f?Qx-LwTuASi7(tk7b;_UH1eVPr;33mz6cx^r5=Olh5p`_x*)P60JNZ~t#9O0I zeD+yY`GoSvF9N$R5X)?B_=>F5r|>}vJFf2^fcg6tvvAXq&17Saw&XCuP>fb z-LX4Vr+$CG!^V~YElNiWTWVUqaMOzdPWB2Z?Vbw(*%hKEx!<~=mJ=I$;lk6^>Ipsu~&=49Ffi zq<85t&VM*q`SrpviC)V2^R#@~t9{0ncI1?H08?4oylnXu?g|VSoLbwnM$*mh_ui=I-^~mLa7bB_-azMf~LDc6#-Fb)Wi) zTIT9bvuM+tgDGL@pY~U0sd)wiJ%@6R$#mr(&mB|SwHz7+W3Qo4lloI<(Wh6`Pr9|w z>h$Oo<+Mpcl2rZn@NVDkMP=t(YMi=Iou{^sG!Knvh>|WV-Ok)qr|Rm3E8|)^`M5D3 zCzr2n^py<9Y=>+`g^s2Vot>Zvi2}(kq!fyIgvkNvD6wAX@02E7ZTP}^y}@8`hmcB6 zh7#2DArIteg)5v~Osn6dPll>}hv!uv88BS!M?a?*ZYw3OvibQpt|cV~>ZCp~l(1Ab z5`%Kh=J^gV7+}AI2;Hcs0tPOD+89rDqtKCzwIV3C;_#is4%!rqrk*ts3Ya`RCEK*F*fy&N=frY_`dMrB#1aKbSpf+Ol#!p=jJ# zaAs@BODlM#K51e}st-nS2lx!C02@SjA?O6~7eKsdt}L`8V|6A`h}jTg)(i}A2DBlA zQwvH0Kv14!ogWgrAphGZ4=xYb92GLZWz{zIj=BPsK|$N9TJlF18a7wo zuJ)={52Zw3P^-I?(k(Q_h$6Cz=~;qbU|-6Cz_kl1uwY?2L5$l2%PiHAatDEB*n@Do zVZmaz0bm_=U0o@0^>+1gcY_#rq0S0aw~4?bBZ0L@_0mIo!}~@-)SJ|w_Exv5-&SuB zsC<6*-o3N3ReeLf{}DuVg$;dc|Cmi3E`EH0iWmDd8n9|KkY#~a!+<57%uU= zjD}j601Pa)zXAhuT!X+v;}Ou@pVNa&#O#B1xK$rz@zv)ms(<}+a)-65CmaDvl0i!s zKudvQZfDHoPY~JxF)S7d@HQfAbc3Etr`T0N9{PxxOH8Bt9!L4cIX*q4}P218ngSx5D zJ`PV%-&1RR)IZeYaRIcYgHWb6T*+SnSN^22CDGr-*-j^MVn>OeueXRbHalq)b{1YD4B8im_jGZB`s zO>dhm6SKXTz&5ZpAhOihmw_11ND?fK4DOJOl-q+E#Ns#ukrd*FFd#vi*_Z;mp?!J; z8A4E%mD^`S80hK2he*UOt)6@GGsw z@nFpDN19raT^t=md_hNv8({FM=V^3@|G-6P>F=@ZX)ydrjQ}H_V)uRW*O-3mOHwz36W)rKR<%uU2obS5o4_WYu1{t~U6jJizBF zXu!cegSK_KSBmzG+Ue)%$mQBTu)90?W3@Wx+ zIHUN}WQHyh^97J(OM;iDi!-zaXa0Wmyqz5Fbas%pLivMZ@Rk+ih@d#8nRQ0JKEzX~ zFBI~csm@SKW6%uo!l!#deDW1pZ7@@9AbSX6sHmu-7Zv&`-K5cmw21yO5+BtE)Lu4< z^DF%$U)uPB61Tm~7hWXV5`n<62n``H#HbUrYAVcW0hcgA5Cg%YyiguxG}ICbKzkW7 zja}uhDk`hf6&pO2?3hwZEzd!gtg7(~K-M#U8bpIXMmi(zngdxP;;#QQHbMd+)`hY` z69!=}RFN%GBIl^f)$8hAbra2_J~W69tNi853*Uc#;p>O&yn0gYV^cLP=r*;N`XN(k zEA@D_R}E3$hx&mJrOEh<*e^YdLg*eizC_p?aJyNm3y8QCbQ*)CvMj86DSV{ehiSd4J@HTS=+)lu;~9jj1(?xZ4aiCbuS6nzd_iN=`?Jv zdMK_a`5(}BQa#cC;)I{v-2V@_lf&e_BnUOph$x#h3yDbq{yz0wK-N69KH>>5ku+QF zWecg+VxuIoL5LaB*i-LHf@q*lbG>UVBN6%cGQ!B!g6DsWR3L8L@bN=}!eWa?=a-F9 zPt_rpZ(X%ywR%t9`}xVDEe*r0)5oS+6lMCRQ6tAMQQc~BT~a-+Wa8*K;8_u;D+R6_ z2pg#ZJec^*vL(Atxb)+NLYwaQJ6j+$qOhom~~;H!HEgM z!cLb4tqh4?HDLXYx8A?|K)v?1mvh@fYfR=#1W($J6zTG1RB+2E^op-I=;P5(`fMnR9}H_ zVK;$mAv@}MySXCTf>&gyCN~fX6;TS74H~tDgy3r-!da(eG+YSf5-(JaKv5#D;#up8 zW96GqLuyo1sGmH0q+Y40(6r5ot#9qz#w|jVR-O2Fb@ji+xozEe^GIH*@ol&z#1(3X z!ukLdzzG)43dPFn)(j;zDgK%+C!bg75}$a(oe^#A6nI$K1x0H z+Ftd;vGju6$gAr5Vfr?Ir>f1-qddr~wAA(ab^dtf%qkZ-$W`cLxc0KJEqqC&C0t7k zy1PLwBk&K!=O$=F2zKE#X+cC!_#i+HT&6nBYXhuS0gEPbCf%SG&!kt!0?^R0^j|a8 zV!D2o+F-PLN&RfB8d~DX+OZa%rKQeldwR&ZwA8cu!|KDHB_+=EglciN>0#m1wE}K5{L7@7;EshF zKdx8LFn?uQZDfRFcw}%vlT6D)h{y>2Gctmlld%1n|IwrBG&)WG?)Q?lx_7j3f{|xP z0o=7Y2||bBHWD^kPQnmR&B5=oymw{m@1NWF!Am_u*Swe)9xNkxj|Mgl>nIcka$Ssy zER2ZAAod!V7_T>b(dlaGv17`#XKmIhGi>9uW?%6j%xf=lM$kC|{z9=kL%?0ga|on} zA&}{yW)AADK1?I$(1^p^+!QzV75lQf0jZjEuODq^~OA<>ew3 zgYRTZN9j+H#S#&@7~H7MuefWe8#7Oir$24{o!><_Nr9d$gzWa0IuSG8$mwk9;DtnH z7<>_35O@=2CkPD6TSTrQArShn^=`coXHgW=%?^n-VGf4`6A}>~91{|Qfy_vp2ZuO# zLNKHm*Bn=@;832cddOxR~8q_}LbcNWSUdSK(4EzU>bW1CDL}Oth!E}QA zi2%HYc-$xeXth9!P%NuW8BkJB_+c(W5Flq00R0biCPHaKH8ALXEw1HNr&(bUu$KK- z?t^t-z3ZpnpZ_@H({%gwk>=qUYiG}zJuydF@D)wC7x6t!?9u+=&Y*}Jn2xJ0$k)i`Kg}Ddv*Qf)IYluLmFsuY%!uIs^ z5~?d+2q&t=y_5A?RL#ia5?>#5`o@hjdCL=oZ>a9C{$|dCoC#r}le#aQJH1^8TK~Qg zvs+rH(IbAP&u93R&?gnAv)a<9=~?%W+Ti7PfKyLfEr`JxdyhbpFiC7t`dq}gZDD!< zDncUys~}@5KrofaFZNFfJ{WS-HpaTM4g12jldum`Heu3HEVra z{goPyeSNDsmGd>P4P2evvFZC;1}t!6^p`0{8vQWpdm67kyEa)~_i>ZBX^lJbGuumK zpD}oqRnUO&XTL(d<`NnptlpQ zHdst>R&DOZXhdGCR`zGUd1!M`MufL}yl>C!+qZ>*!gnltZTEYQ4yz<(aR1kqRXrAB zpSx)Lt+waC0Du0_hG`ayg0O2yFq0K8kf$5OJ|cGyzSQI}|=23v_o-R}3g^Kn6Wg8R1nS34cfh)-VCde-E`6?q@s zsVrNVD@dTn!UfD;?0!~C8+gr*Sk1lyAeJHIS>Mxt&O&Lr3r@;n#&ksG<(P%BClJ=^N?0HBTviC zXdYY&T-d_Kn+NPUA+R}mRF~P2I6;u&Td?}FPCYJOt$rd<%3S75>zGGGR#sxqWP~mA{7U4` zA4Bf_0vlon#@BvdCtpR-GnzEwv|tW;L!Za-vizgE`e4B*fFN@=}Hj8lv6&6wMVw6rw$!7K!!85l~A z@B{048$I-H&Io28dS4sNz?W))c@Z}9gk23mfw+x6zShQjIhKK_UkWWO`F;ScoP}Iq z@5yS*LF%pPVh7~cORFZ(0GLlc>Mpgdw=kay)$L*nq;Frq$J%PR*Rnf8YT7Wb!J*;X zP#ZO>-EK@)JGKxrwvi~_StYt$@JFmIhA5Gk=%|q3KvR7Y7IQ)zfapbJOjQ1mZot3T zP6R%+zzB#d#29S$K%U&Tsal5A)Asq_RE7orNpf-6_iX2cEycxa!{T?0*apgbQZc-E z@Kgr@G0|wZRcwiwo9v?sKq3kgGU}} zydGY9l!MtAZ z2oc9X%t<2k10d%l17)%i>I23$NLOsB5PF&rwkcvELG(O5#B2;Pi)frdlN%ad-1WBX zeVC@^YIo8m{aOJ(9o&=F7JPi;X63-uiNFmXzhqJNgpiQ&Jr^udZ}>@D{7PrF>!g05 zJ~zUQNJ~}c`<3!HkNngjwfa$7+jFoVfG@y38*m$8ctJPAt|9(@h$_2^REskLc8mk+ zI?G1W%RCzZBRj_MDzw0*&CvN%NZTac-wNj&XZo#3a1)`!iiE|zPv5AVv!Ltfu&^2BlleoVm1{A!cq*uSU*3BRUoN3!wPX()Hc?>ZG@o zwyD+21$lAV#{1)7XC1=awJ{1Rdx-iULtC}B~Rc;BogwKr34x>oWD?}+mvKJ|B5l{mu zLUm}Hss&!Xh?iy)2%~_)Lo(ayptM{j!a;h-bUod7{(Q>>pH`l}e#J=>7QOYB+*18x zS@o+OQtaiq?p{mRvZc#FN|eOH_In*Ua$gc6)dw3dMJo{(HmVQ$(RKW& zXZ3e8XEJMb*0N>H7Xbm6s%~ugVS1=~7~kz8f+#kdX1ul^|F8Ij>p#UO41ZCoT%>nX z#?Y4PCu8W2{%1eQr*Dl>KcOjO)ttP`m-E#gC0=w9osKw(69Q|pV`-_ETB?rnDk*WK zZt6ovTWrFtwwGSf@P!zGuMe^oB4+PqkJPBh%KYg@3Ihup1;VYhJPaP5A;GXb5UddL z2IV55nsr?pWda@rywWTA>c9r&GrZb)cqrW*TXynqsIDDA4^286tlXMR5Avg~f9x5y z*->6gm0_(%@KtW5r5@Gy%h)ClZ9hjq?tB9H{x2~MfCsVqKVlfY=(}#)tG2SX>KK#? zC5RYC8TZ&mQ|D-V)KXo+HYzRP(}h`r;ZlHf+*}#81VCQ5#2ymbS>OPA4fzher>Ln! zA&~Ho6NOofx*&KLq5@iExJ4Y7jsI|KK~Yh`)(^vnzmna(d-f~C)fLGPcb*?Hb@}9x z7v6f1Jl1?@)`cOPqGR3|e16sec;jO1RqA6J{~`v0JECH@E(U_+5E3Kn*Q<{eQSayr zm?vv63#$~+(Nx%uM8Hg2;;R(Dw}A%E2tno$_43R$5;9qX)&{&V>jkv&M!0$cc;Di_ zz53$6;_#DO3x*CY*n0A5@PS$9hi-~&uxZ$ZS%=JHlOMcwVdUiHQ%9WN`49mv0rNz< zRJzB_FiS;zR7886oe+wFq(}F?ZFo8c#TBE8%D*(0Gt~M7k%qE3v{quW! zXXGyL-n@UKw0;ZUnw7Jvd$WG=srl^AYiCp2#l{x3cc1q`MrM4>sE$IPE>g>AH_!@4 z1nO@qh)};=8wL^>6vC8ttHhsL#xGH~3t|n0HIBSW4u!Ye)zTRyqB8fcb?hBcQiKw# z|Mc!T^1fUaKgo;7ozWn_30PPLCH0XE@GywP8wsYte|q?~f_}}(w-x+*{l(Ak*nj1I zCVjfHa{rMd`zs4~H2sUCKlz;Z-G7JDpfeGbG${PLYffD(e>(hBB(0=u#E?QoM97!g z*~2-pvsdixkfMfCAT-Z`Do&0ldlSiOdwZ?O#v@Gv@Pv28*4Pq&p(GSmaeV{yk4W5m zIHT;w3v_{apfO&D2pY&I4EW>PZs~NjZ!8!Bjr1+0zCR0d+fHd!BZr2uO2vAIo5#-J z?S%JA`wtl7Kr7hbmAxvOZQovA?tE(S%C*$x+`Z3sDdR@1oUJ}yEB3K(&3AH^^axf_ zLt?SC@bPwcL&!4F*Hu_VL2&JnRpF`i^k7S~&c>FYF4Uo55yIevE{ll@5B2m2l29^j z6HYpaC+!W3u;f~EB-u+VLJhw5)7#y90Uo z``a&DuqvTRV(g*?Rihv6+WF|w&Rvg+Q&L-{%r0Bd;n0ABW1UvcUzXe=rSZxIuXj2! zsQ-Zui|4b+$JF1b{jqnco%#&4)eLdqWbkwl$*`oF#QQ7tK&kd39*jU1L(M4x_kve? zAy5mq3aia^p!W8N&1%XjDA3mjn}O0-1ZYJelulHXYyUL64<)eLzn8+yz1M}&-J*hAC?Lm*ojXbI=CvTs$OITgICT*Y0ni`>1tAAtmLaT~B z5%NgH{{?TEEhbQzkTczd^`cd1itLIG$$WI+dKvEsfWJ`d9=}Sk*JJKo^#eb{@IN#V zWA#w=(ge_GJboJp`x^=dvn2a-iK6ls`}h)z0ShS50ckS)L{M!U%|lL)iU5cgUV=OuZS7%vNcYxDKjYQ)!HOFx`B zgC9=QYFg#*!)Wstgf$%x5?4g!2xB=I1N1)E5)ktF=ql1`@; z-f6Yq_Sp~yMtkgHLY!cpAQOi44?&fL*%3P4%TuU$p)p`0zrd!@7|?nlZd%o-C>kaB znXy15UbRmYmPmWoZ+h>&P3x@^Th_Z*zk-5(y?RwU(VVAGXpXw$$y0U51iAq~-W7&C zOTPNGdR6VuvX#~AFYg_{`^tuuO23{9M@<;Jphy4N>Tjs3DyH@z`XY6;`V7C$WmU7( zO7)c5iQf#S?caeq8H6QX{?=qv$^LKkw%rM8ZR)qqKKc_|eMhnLHK0 zaHVVoxb+)HYD#J|ox|()Qd-B2Yg+Z{)PE-X>aTP~oBs#h?N;~jt}{zo z^sDbv)V^_pRz^2tmx!b`=`(1{#%&?s1tQDk06z2|Z8uR4JhZwY`%Dg4Ci*ing}=`x zf^G#Kh22scHvwNl8;E=Xeq2tVM2njU284wMZcMHdc1XcYSv{n1<;udMRWsTqCbVvy zkl0o_QM7h#QSr)^#mQ~jBqz5QsTIuC9;|Rf`UP{jk_bx}Tp|z;R1V%(!V3d3%Y{_X zUT|<$gsmk0+{Ak!qEJsG16ZC|0h>q*)bjo6EIMUB&8&J4^qNzy4xsDH>DoWsp~VFr zMzXc+to#vTiil=HE@^IG2DsAjY)5W_oZo;QP&e67!ut$*tsa>=V zF?)8l+Dc%>Bj(MHYA#Cjosx)gK8JA*-QwA)UHYRJtkhzM0V+dQ! z?#QR%i)LH8;HSw@NYfz`zxd%Oxq^azO|_lWg^{?W@(erICC>o-Yi|ZqjgH__6L`h9#&`t-r?xh zrtNHLWRrxbCb8j4-|^#zC-?U8?w9`RlrgU=F-@Aqwrnh1Hms+gbd1(uJ+?d{xL&9c z_y)E-VZ0Y|)n0d*`pa_pw4zqozLSbr(=FJ>egw4=NKts8UV<|pMd)jWnhDLh6ND$C z5(qF+{5~zbW8?#0B!5D~KmmUZ3TUM%d{)%7Zf%OgPgPW$8eTA9QhgEOR(B1vqz0PR zMsiCLQ-80lZEIHcQe2=Dl-IA|5jWwdqgtO(%?yI!jK~BQDKaN@H4Mm;I|18n)J+1m z5idmW@Xw+!*7UxrQhtvf)ylw_9p#^WO63=2U&A$=ZDb?pAcR={IUg&c^K{VZ(`>|L z;CQgwk#58{T?yVv5wwfo4Z`7+iMPk9HJGy@3 zv0XVmyXE9&XXi@eRvi8RNP7>!sH(1O_@3J)J()}V{popSUL{Th&U9nd(C;!^#-bn(2KHvNMzDjrqnN#=Kd+oK? zKC))o+QWy}_8m34&$OOn#!!@xw`i2KL7A&OBT=0OzQ${GPo#v`=pLvmqLY;;2R8u+ zNxVj2-HN^IB)+J8k^KA^^9%6{2@1sDvqb1IRKM{YeBmqbTj=NFYblkzF7=f+;MeKQ z0Ya#Sot9A?M3rp_SdfB%Z;zd&nkImvA~%5*(`m(Ye7am@sdSl<-15~t5Rbv?uv-0+ ze4qL2O`kcPB}2o<{A_&YDFt|y)ZWvEWJjYJvA1+Mx-!ZZg7IPb0scrh;d3>7t_sqP zil_=%62ydXr*xenKgvRp8M9gK7AKxz%ylNlxD9p??>WAt8NMw(^|Ue_C*8u{06Ar| zG|w|PQIWw_VLG1BV7)F=13_p-whIRiV_+6Ua;WB`NG>o~4Gx3>4Up7;F1WEi8*Z`q z_kbUVmm@e>?-2rE#?c}ONSAM5k@jXy8q}|sQ>S)vQbK%e4SVy*=3} z((kbrZYf)8<7pXbgRW>MJl+ILAL9;71`~c16~- zrHYI%DzBYD^H5-yLg{`{<&c+Si43=+G&ePs5i%2Qb;9}0fqRUI*=`U~3wN{{vUcT& z@eE|tKHJ)~TYJxh*<}Syb?-ZM?rC-D$MX4kxfopCsRd`gH0Y_dYnJ{xoVg#jGf-4B z(`LUmf}cAi&%fA?m3K*YGY<+t-fp8jn&1R&Rh&)a+SNy}_ja63*2Zc`4KJ$_qkoq=6? zvV>J#FLxX`=8=t95uBSLPy#DOKBczQP%4mydIrTtMqspcGu?`6(Q5*QP*8q?q!2V9 z^!_18w<{|A0#$Xi2=Mj-&dm7Gy6sA4{zh8A((I|U6s-L~)W=O2AOa_GoeFUr~%N2fed z*K=URdtZ7R$?W0HMGHH(%zLrCW5?Z@S7$7~TNyBUNg($g7MYxK5k_o(tsR1B0LJANMH$rY4H`8x7;iu#jxCIQ?#!Pa;X+d@gkVL9RSQPEA zBhP{AQD}R>gEwPorGL>B{^`X_{A(6*p~u>KYDCY*{KrneC3nhb(&7FlUw3+$xpquj zuw&P(^2l>hCQg)F?LR#z{`b-Ljr5p1f~ zDX*b?!6%)>KXR`Z-#c9{pEk}`VZ}@}Nj+R;ll*mAlVF&jw2m7}E)J{_Y!d3&EShQ= zf%~D15lK$`0Oam07GLhp73qp1n}qN~q>Hg!Fhhh>186V|ln@y)?T~JF!ali#eX5^J zN#wlYS?%T*^&N~%a=n2W?dA_3G`uV|Rc9Sz3zCsgZsv08{Q2lc&Sk4aayinr=4|_~ zmQ#W`JZ#OGw%6D6TUSTk9%j9=uiNrE-lE{3Pf1T+mZITH_XZb%^3AP01r97AUSO3W z=d7t=@I#PAu>#No&qlBls`yG~RWAH%Bki1mw6l*hVer$c<(y#^APj?};bW^sv!dMf zLtp>old`)vP|mqjzOZt6FC?93An6Pag?C@ewv`#@798$&NvwWv`Le^`b!y@LtwjgQ zI@9=TW2cY9j=Eu~@P;NiiM38lW(%cssUE@)?`Q$uO_XXX{h)4Ru>`dU)W{L(=BMN8 zSMmuYDLpMU1wRRtJE}p%e+VjuWvwDG`S|NNH@V0Nk=4boDD6NTsU0s}uz;pw6cFv$ zLG>=8uBd#b{E8PW(303w50!r+xDRG2k>Y&l6iw|E{_7q8FwF^EJWOmj;v1nxM2z1m zeu&6gfm?eEKcvv$hal}t3>+idY~<*6;^#!sjYlyAc9EgJPGynyFoKa(z?1aem{n7h zNE8o@%?kPp%(sv3Q;h-R0)9fdy3$Q-P;q%7JFyTKw(sok`D8+51?8id_hAV^M1R@K zJ4O|=Ux@r7=0*AwRKsJZ8Y9RYQOX@hi%G~Q11*(gIHnRpYOp^fcs^#Wye|ociswk6 z2B=%f1MA%MW}tW>SPpXc((Bi$l;_5mrJFWk;kE2o-n`@Pj^1y{ZHZ+Uvv+5+3Sym$ zbrJlVaEgaQO+gi7Bq8J?;$K02LfK5Z$coVi3RK$sIPCW$YuD0NuUrXgpfalA?uOp? z#J+x#w>wWBWPDC*-a&gG^GzluN0Ku!Gz6O|=BrAmaaSYZ;wc3veP{VNjr6_)8mH?d zi1(nbMY-L%RSYmjGZp1aMve(aSJ2mtN*?jhQ_T()H9fW|p&kn5T3Va7Gzxl*r~bws zSvf+-?eA5@oLZ;(jV$b^_La+93Jy*o@~6Y_mbz(wkYbkHc>faO71%ad0t^-7tK>z1 z`X`1;-WP^yN37<%{^A)VVy#ZL%^YSm{t&jTko5?zzy0nfUVeOIVs0!(8s4cin0f-&JkC%FRx;vSg$SiWc z1R|)a42F{oKzJ}BQn=50KM=n_v&5B$W=n7Yz4|?22*j%&AB%eZbxsq$+71ug!YzJRZdIZD`%B)r)T$tTvC zza`cliUSgf&=LEA?#7D0+%LfNWN?Ta5PI^tIFLiBn_WLQyJ6jiZg(bxhm%%q`0%@?-s1URTRx|;~L0h7W+0jr=}DIEOB z7DixdcP9hS#Wom8R*ShAxTg(E1%a=OXeuy8<_-Mloz=%V4{7Rj#1S> zO=t6FMqLq{p%MF<=hxg?c(*I%cEq~Yp0G(p_wP?E*xKhG1UsxLoKKBEzllB59mhb->4@G!ufmBy@U^tutv&Fmo=vT*R@VY#TuV)hnO~$up2_Vy&uw z>vQhjFDtK}6V*@`5QdHNRY<8<8C$nTd-pSocd@S`imIb_@87@MsE$G`g1x^>U5WQY z+FQNBu1*62oZ)EgXgRCV35G#-IuMc0~FH zje8<)`#;E0PPL{!vf*M`S@anAP{B8Iq*!m|d6^BFrS00LdHci`--a%Qf#80Xga3O7 zzK2yx_BcaBEC?!y<0{UraAJJ8BhD(W@jofQ>`=8!gBVtDeZ`AKTwj{4G_vA5R4NT{BCH{IHMM?y8;pIb z6ETgfeg<`k?~i=+sr-_ntbbtmI`Hd{J~9OSdLA-I?ZVIgQ1dH(hB5u}Y;E%!jkD)B z=v3ZdcZn7~4Os;6G1P1FTiUn4%TSYp9&ZYq?E+XenbK8qh}<$f94(FDak_w5x%wz*W|aW{|qduxLac=5{C?)`7^+6&|L6L*{aq1c*S(@ zBU+y|;lKS7K|f=Lx(h#pYN@d|7Qp4?^WZr|Vw&7BDi6YEp}a83=Ax261MjM=Do2kq zb>{<1c53pvR_)ui)(+}ZSFM_==lAH5kH3bWzd`+yO~TJNwbhUS#$~GF`(RL$KKMZW z5-K#Zv;>LORP74lH-~gv4ER5iMN4M(=`~|UuRb$JHp|Rt(j=p1Q!TdVz@oDPn?FYAp+6;n9(LXB1_cVwz7f9qc#44e*tFJN zYURY#uHj7X(`4YxnI-iG)z7FC8aUe)J$_i%l?^cG67@5sp7slVKKRST5DE~d9i&|k z7^Pra8QCuwYP{@}u*G^f-Oeh?5QWVKUx=JKrQY}POQaWkZ;o$^Oo*kg6fljkz%CmSYe!i;l4%8h1C zSPomV;NW3=(*PP5Lyz1S*go{Ozo~Z4_x%t;b^ZG6i!*cwFGX{^#p-7jjj{f~;42#A zo?4{s;_VDFqC9_z_s;YU+%aYE=o2t=|1%mJF4G<8vyQC2&{^@9=NAqePQPW z15N1$>nbU&@DWsp8)3yovB6kSZY1@IFo ze#8^N2IKhp1YFFh7NyFSB`huow%`fu1htgJy`fw(+(f{kW~nsoPXe%oiNcOqBqtb% zu-CX5q(3OKd8|8@4Y4>)S6nxS3(Z{eeS2lk-v^kV(uz-n#N^*yH=%bKt)EXTLBXq- zKpbMs#lWdlqxKKh!H24lTLd>#tRrCyRleLmqyUs-Twz|evAQ3}lBz2xtll*Ezcmz? zR1c$>hWUol*s7~F$rz}Nj0sJgEDZq=@F>J;`ZSst6170BMzJgV*p<UBs(gdnMBZ1C;Ag2r@mUspnoUB@AzUpDA<$r)C5Q$|2;mUj`1zCesHGd&7C>#V z+=@x-^YbJ8z%SGwHjw$^PV%#sCnkW8AjAe9IRldXfUCCg3KUgv{{gUprV5*JpidqH2|)b1sOxq z8o}^T515vg2!X1!I%!#%=_$zxsfnq;m+h!zB#8}_hX$iO)JS|2hDO3;Lzq-~+IRdUYxJETeCVQ5{X1}3UIp+Eu)uHM;pg}JmHF*?;e|aHSlp+d zu!L3wakS!BKlzk@)|e23#>$Z6yLP`MpY%35w!8Egt$Cg#=^m_ks+8@i4V;7M;wTJ* z3<7KiLQbKB031r3I-GYbPO6lW9vx+BAdvSDH~{Xx1hGA!fO)woQe~ZiLx56hgHnCv z<3u31@(m638ov%&!LIvt%t7cP{3+YcJ}%oJd~^SA{9@EwG}bdwEbTWo190H?`_96p zwHR2^T{t731MhHAwO$AvLOe<^DhBt9I1da(7=}HHOtCsra30+C4b3c)S&0azK|0Me z7;Ff@SqmBlzmFlK{3P(Bd@Sc}pJSTqkUi)PLn4S%83(Ju|l`6p3j zn+CAX&*mX@Fp;n1ALTvEpB#V;gAw=50ag(UW(x9IF-%vIU9zNy_~An16jM9`1{Ik8 zKpC+C0*!$yE=g%A&IJ6mSVAcL;I-UTB_cwU%1T`@5eV|~)o3bzr6v1W^{DtJ?luGL zxtoiqTKDdaxmNFoi^HjK~Zak3cDcMF?6A5h_et1z;ACPwFKjuArlhvu;*!<2SBcx$CRn4eK*~ zq4$mM8yl4||EFh7ojY#KLp2}lJAdth2`jX+kDlnip?1v^^WXixW^LX?JNU?T@A{de z2Q6DMy8PvwM%(92d~7q$cLZ?#RJAogE#k;T1xq+08cq!%2jYEHpcx1BNE$(B2l2Rs zM+rK2?qr)$2Z14ql&A=S2m$jIlc=e^`HN-zvk<4#KPWytx=TXawz2O3`9F0ZLnTW{ z`3j!Q&MCE09kRAIFtkB0@8X_4<&kzHW*buRotmM?N>1>h@p|hp^$8ZFJ~1pfR6sV6 z+%<3>fo{lViFssA*bIRYAj4K!Sxl_g%A6E&WD&HXl!I&rRu&~%_RDWP)nRMbnhjUA z?lEXc@%eKCFSv1di8^>p`&G-AJ+!U(!PV-o4{WQQx+v1!u1VIQ%=Y~2H|<|RlsWw? z`~LEzz?9|QVY|+s-(_ELIr`#GEE70b72hjAsvU7kgjO+@6XSLhIkReQAtr}ZHLWqJ z$yL(1vCw$WNDR_$X$hTTCv zFHL@7>D^Ojj-7J$?2MTY+%xf^7f@0E`}1$yVA=iWCAwy{TVHx$sor|%pcd_Wt?SjN z-Q5#A>O1#8jwxUcQ}}#^^k1A517gJy0-`nqt}*@)>`M`^;cKUaa#96MB|G>Rh>IK! z07xK17@jWJqZo5Is$`tG${T#&{7Lzp7i}CbPikJ2U8`-^!u|IxU5WIn7XmM{dH;=9 z9~v^uno_IP*tU)o(Nx+}--sI_a`43@u_)zRn?Cfs0%S`&68p6bkCJR}x}P6>E- zkR3Oz20@%A`iyc%{4F%h2Da&TkutRjGh=*oPQ-uhblXHQZ#|io6p<5LGrcIc``sb+ zw+%b=QrYCGy=JEJP>ycJ1Az&#Rx_cvfw_Vs48j;oI=N{jjl5<@xi4BnBVg^PI^?R`&BB5E=jI2`?i^Y41EgBY? zlkOkq&#WD53>gy34u@wZ1z9Z+;<67NmGzAtugX8vuPHyI`gQJgV@GzHyh-)zR04X+ zR9b_f;P^bIy$W9iyv#ayYRG(~;ssL*kOzcrF4lv|eP|!WQ%U6%xO6ID4FfQ)cFAsc zxQ%Nm1fP`g&BoSWwRY346)RqRWz*zID`&`)JR|c`TlZ}6@yEN@Ok2qOuC#bCOVg~j zF`Y+F*}Qef>~%Gwk~)rWyDzu5r$uf?W_WPUiFa4Oo|Un2(2i##ArH)?4mexeu!j!f z4iesN2>yZW4hMzAxdm7z1Iv?1iV3j>A~&AF6EKf-}4rZ$u34S{QB+J{`qD3h``keoSx{*2)Jflk*KA0C@x(*X)uyOwc0pq`}veSpjOiQ2K?h2qiPbJRC9ztYEFGQW8rdBIV6Q{+o>y z`8@T)<)$xwt;$c%n)1N1#}8~Skta7FSwFR9uOEM_P&>c-q+Yc6i_IDLJ)f1?b$px0 z>h<=tte2T#s|WgJ##Po3Yc&e{v;g}QhR6+(FIgk;Heq{ABY=CB>vE?UlwV(J-w^CD zl||@La=Bnf)dl?9fy0pzLCOR<6}dtAej{r7$LyOq{jSn(?PcdWnkLG;ypZwtE&)NNrGKGzvI2-#hi6?2(unsjOH!+kD=}0kA zA>`!{U0?E4oflmFP`RbcStHtJ#Y?6ogM<`LOJKosW@L{j_|U8_8#(ocRgmxF*Liu# zyfHmGt2_7V+or#QdRNQXo<`{ zr8TpnV~X*xkxzg(*UpyjTBeuj&mC0q8(?SoPyBM(FZ@sA*%jC(OqBO+~)Of%QuxUzW6w5&B^CIP*o2 zqfwO576d?{R1n7>IZteOnv|9d^%R?%O3%@r+<0&?eB%q>1n@o^DNl&S!;3jp&`};f ze(2PbQ-+Nnp?36~Y0}~Nnd!UI(|1pM`&j#?YNPvkMaj`0b{=3g`S}Aozdv5Wl*OZY z`KAi~{Pd|)X0Wyuo0&QapKtUGc@91U@fp!o32h7j9l#@mUr1FXpkDw?tRyc|I3eCA zG&5k5%NZ97+D%v>Ra-{0Xh{E1!WqhghJ$D~N=K~LJj@6FE}dc#N65=}AC-Zuy|nJ( zXZbsSeb3)7d*@}*UOdS8C#KK z?K^hdxUm=-a3FQ7b_B8JEKg9h&=Cnia{;-)sJy9xv6FDJ(B`Wq=ZxbU)8SwcYIAP$ z9e}pP0gt)e9||}Pf4yJ7=MaEI7~YfNF&JrG3oxDAgd<9J&g^bUb!#|udvH>HE5C4p zpAWC^46&<@sJgChv+F&HN_+LRF|e~2ni^f!$-HI<6_u% zy&le3q*PPN_0$DV+k#VO0WaF37m3%{WC>Fjugd5ZCoIBhPj-j-gDB*J(Kl4O$iu>s zs-K7V7;Z)?ath`VL{BVn1oe80gTtSe3K(N7%0 zK0TDJ-JTte(=}u2)ETTDAO38&E#5!-J$u){XZzAQ{QK_%JFnCD8S=z`Xv8H>mfCq* zgE%V3M@NAR5mzGwYygU0$sht%GZJIS5;ErB4fJX(J%Nuz8bGxyT7KB<$>9+I9s_7b z07+>ZNaZ|BMhIf$#7r)XOEj#w4D@tOxAnQdvvBWqP2Raw-m$&e#?~vjU+FKQd(_qH z_(yq8Wc<$`ynjWJAKb8V#rkNw_a{O+)Y$;vXzlAECVUt*APP<#kU$sQO7I(S-VmPx zy9e;-lZ(eS0eV1ww^{3p!RtM6kL-F&BsuZUnH4@n?-Q=)9mUR-j^0D)?bPkxB+up5 zo67!G^jwyjNRnT7ta}ZN9cn`;VgSji0P=M*?mKb+(Qb^QKU0{H63PsEWCEy(iHUK= zBqiCME^BfUwORqK$)`Q*1pEjz0Fi@@Jaxs#=hb$VvXNggne(r_=Q$k4i#O_}ty{=S z)z|R{tMLyppYHzSyb3WEV8H13)YxK3tW?wr?t6 z`}kOMm8|4W#Ee6Y4X8?NO1>LZ>lJ7M-4|e(WSv8 zyuqm^u`R1{jm<-U8?7yxia7MAap?DU+*GD#5W48If^(4#IYn5Qa@Dz{74>nAOsF^fH3kgG)8etrS7x| z2(RGK0rRB@Q_#|28V#9zA;(G@=T7Z2pw8RMysHFUN=q#maRfN?jclZk_0Bab)Mt;K>=U;nMDG}rCj;&v{Y7NcD`)49#Vx_yXo+Hm7=-@pz6J&hspV`2HYRuXH6Gpcn%fh=S|b@*74uUOO20Wwf|{A!iI z<>$Kax~tei{(EZ6tjJ7zTw?p|9wn_=(sEq#QZPo7S{3)I(>^iIo@uYsG8L@w;#EAS zGh8WBfR$%)YjAO~T^_;qG|ti0C3Z*GNj!!9Ca!-VyELh*!@dN4O&aqq-cmcss{Ozd z#RdBmYfk+!2EyOUq|=*1^^jm4nI-r>k~ZEFxY^WngaA7dvi7|q6jx$Z1bS16$yKk$ zuOvTE1P7~ZBDWS;1MxtrZHvdxUBoZ`_^v3rKe%+;GrP9$+O=uTqx*&~ua&Z-S@|PB zun09}_#<^Po|yak)%V`gCqKM)#-jOK7EGD6qG|27pe;K8eXY?rxW}+u1|EdWwKfuGTX0&#EXa~+iWCL!Rxqzo zZh?Lk@XkTMVOk-Kf>9xYt7tqLHX9we2;diaB1Q5a=c-L9aj3VkcHL%l$;wZTi%E~j z%FpDlv1_7vz?2s;cAqihI3p9gIU<*8mby)NNAEuBAi%EE8NqnKE7W#iT^*F2z{`M# z0g5QFX=nkXMnZl=&ZqD}7z>y*SQ4Qc>Ql~lKylMWF?7|lY$zD{PJcm^?bx^V((aoO z8ns0|CUSn_{T;zKY+^RnOOA-CTvcEHi2C4nMPN*E#LuqOD?(6z8@VE5Og)W53ZK8; z&2mM83XF0u+*Lc|sYU+;I5C+~MU1S-0{yI!ZOlSr7hrc?~-AaWB2~)=P0^u`j&+_6tw2oS%PW^~b~& z7srj^Z~pi*KRuMb9;zIC@0sV$E0N{jy!YJG7qI+vNBIt|T%0BJqM)oH@ej}vf)chu zK+br%+Z!*pfQn2ZCz~zTOx41kR=(RtOA7PdKKkm72)d3q`IWCWw}5SL7Hd_$*@gxS zq@$%o(!_>dY^0r(_8@l!KS7R<1C$3#2PYcgoGc9>r&IV5kO~8h(M|`*oktyjOf(pG zQN$*6F?}`3$`hr7o}BgLpR{&MHWnQp28Uu4PWP|yYhI44arQdP7WVn=-6gRxa=g!S znCpc4#^*4;c=B;bKFBD@P-M6|v0z!^^2K1REMF-07}Nr-JIpeY$mrVw&k{b4VJGMT z5}u9utIxWDzk&Q}Df_Ne4k%^c7-sFybvG{-Su>;3&B(Z$duVwbV{?+vNEJ}zgW(Yd zPfdYHGi@Yxnzi?{pwTh>FT<5Ew-M8GN{M(mv70t>+{uiQBO!_rDz{TCB8@u7@?7cD z5eNQiYiuk=OD`e~S2z=kxqj>Z`i6{8k_kW3M`5hg!wR|-Fr|QE$u|S1G2HOYRLDdQ zmShB{z$=K!8O-yAF6gH~_3C;fi?L-0s*|Nph#T(_)ij(SR$a2B5l7DJ0n$ zh=R16eajqCAOV{|Ho4NzRP2^qcC6YI;ArNFX9YH(e7P~76W9pvV^tpK-)AasTWqoX zvN1RLhmu$%sT2vdo5EKPMP*Ga#oIA8f`e2Els`NVs5Vq+R@ejN{sy4@08a)c1(cYw zF_=?ybQqxj=-BAku&6MH&1%fY|DW@z+y^m-CvKX9xe>Px+~+ErW5p|m*m@8ABA3+B z(+&mNdJLpvP@!N7M30St9F&mdRf}THbVtJ9FpVuY4FNd*72Y<$%x5 z4qcYzUZVciWj-IwkJ{0vZqU50OgU4l8H>B3ZPKo>_$FCr==^6@d}*1cy^Pb8PPbJd zqH_%JD!qmssw~lw=%9(2z}#WY3&qGQqg4g9o}xu4eB5v-01*k=h*NV!FFi4XLJHo5J5G- zNy3tJqoOc@r=_N*W~62S?XcR@2tzQcZKyLKsYRKW!Rl0mnNKB99??yb&T{kYJ*_d; z^ro?Aw(MfzKgsu?XUBT}!H3z!9WwG_S?ygLSqT4S%TBhZ^l?qAQ;Xf5^VYg|zA!vP zxe*`Ns}OZBmll-D&DY(SUmOb-2<_Eq_~CVREAB;x1Ql@`UZNTdJ5~VPhT85Kyi(-$ ztJv7|Qn_7m8Sxq5sOwTJixmxIsuKHX(GApDaP0x40fBZPy=o>=fj!Gp&-}>CKc!qs z(3Rpz8)W6NBM-bBsWyJ9>4PgpUPUSA-(QUUn!nG|zFx*WY)&nQr=5Oqe4=CbHm!Nr zO~+S8mYzRf8oBZ~=AcMJ@L;Y77I;(7K)8vhLN`Rmsdpe~_y6b_D6n&}O}OTF>={^% z3SvAMfKPlq1I@_7B|q`rcLRD3pM3c>?|6DNSjPB?6UX!SzL;B5QvA8vXzkjL(-Wc} z=(}NysJScgZs$jPbneu1eftibI@9~s785ywIfM!ZEPymLm?LR68Sfg3xfOXZIp^Kr z=Mv&C039L42B$zcw(w36yNgTlZK={Dab5^tK*wI$7F#0oZ)ca6)8RJuynw%=z9!bI z2JLx(Kgw>=aTqCkxFQsf3m#@@3)Eu42@wP~q0DE-Z`rMLfQp(n&%crvYlw7UPrbp zj&c=XPIRL=doh7hR* z!Se=$iH#$W2Pt7ll9l-A3XYA-!AqGrDwWIdEueed&SH_3dW45=#bbcx?Ypz2n4T?fZ1yF6M*#s@ZV@vJ?T5g@YAXWfBNNrRS z>qYxBiH;jBseHHWm5eKBtS!c(9>sY}lAs0{j3gDZY#}&o3bl$LXw{*C8T8Kx8MniX zkgasOsKUs6r~d5(4Z#CdbfxLEcD0+N#NwQ|+r+%fdM!n#;#Kp+Z9PKRDNaPMzK$rI zi281%;|51po(Khz8d18XcKUIyP@>ccRW zIErb|B_SC8iNu7Uy{P5JOM)R&fKxl~n`x7&vjMG>@0|V5eJHCcs{f}xl(d@+ z$n8lQ9?)b`(WhcqY~gFHVbxl(x(2dLyH|Z&HezuQB!h78Cgw8o52gvGAP{d8`eNRR zvpfX;@sr}z^LTu|F?-*-C@R@~`b<1BYG>?IDCK1TrC*tN60toP=q>%qd{&UsNNVT3 zpM2OvX?SM^d|S`gEi_`;g)iweA2T;hE39(uEYmdlDoIkhx-YN5A z>qJCk#oRkptsQEG!}yo|JAO4Rg#S#t%mRW!SloAZ_=C+tf>=BBe*Edh>;8V_KUpkq z?0)ohi$w|7{k}U&{#I*#O#Ku4V2AZk0U1p0ENHABHNlFv;>5>Tc(rkH?5=xfp~vvNsvGoG zXvmp2cF{>T?~e|a8&(iF92&C(2Z30Gm(LL)Fp4N!B}PF!4X}ZI7zNUeHYZFDEHzmi z^a?RRiYoInM4%IM%Gg|iQCk4Io`+CiUXS^y?T)j09{cI;s*| zq9*WU`)DUc4-Y&TBD>*3mM|2;mZ-?{HeiG~F#T%j6A=gg&VYfT)SDQW90*N-@^X-N ztM8#XI*iGvgUP^{{@?Kj-2STM(7)mjP%k3C*hSB8r91o{@CTqxEa>=q7msX!K?0X@N%;-w)454ol>BRRylNJdODM$GGf#T+mlgzo{iBe)`Ld zulbuFEYthW6z9Gbct^7_k7z^@@a8ZBa7h`VC%Ouu90f{xn5_!Ot&oBolr)H7N=K=K z4|PDXxI4*O)n&)(tPeJ@C^L2?Nk)Wa@Nxw?5OHlQIwj0MqT;PjMclL8(Q)HvHbAJ2_L`A zP6_XdpBy%nMe*`6;{g>1@BzhkR@=RO)T+aVFCl;5b_5$bM%cUr=#F&5+g?lR=INZC zCR_YmQ1pwFvD--RqJ<2O3;ME9Z%}MOAu{(>_<y865rO@y z8VNFb^n_S*w&R$BWvL6syF`YBCX`Z{WrzVZq-<~?=G&!VRmt5j`J*kZG>7Eot- z(nORH{)TDcWI&??0<6Sk#XX>vM^y}DO3-{B6QPyYFhkO^M=KL>*@$Zd+7a!98EVlz z5Ss#CCFtHHvhE=IplGz0#FC7AK*$IR0|d*JVojd_KLln)n>e}8ZJX^qcptLRW6^Fw zTYQ_Qdqvg7PoAOp;jU6OYNa$V7GKQfp*P+O7u0Tmb; zcQgqsJWg04E;H^4*bqH%qR6P~I)sn~(FIRzI4EnFf_e1qI4Zu2Vj!V{Q7FRVW~B!Y zl1&QYzuu$nKhVm_11lGTX!F8eYW6=?vN5R_zVD10|6+SAy zaSXs27$ADLx|_vp$OE~}YT{d2F1{R)l32zq;%yZ^DaGtOh;Lzc`_>fBmT*bQ(V~x8 z3A;W3*lVJ}90p8KV9_a#q%Q81vc~BpE&vWsqLfGsiDZ}PVPr_Xm>Dx4nY5BsYSjmP zd1TzateiuWp8l|GLjSRg-kf#!uvyx{8y8QV>(je;pL3_w^cxq87cM9tl`w>;!W>M*R4H9*=hP?B0Q^GP5=h*;!WBw|(Knlf!y+gRq!4<=JCx+q7wW z>{8HRQ%#nt824=VsTI6IVD-wcSO>xCXf&!V8 zfae+kp@|v@-7{#2f;UfayQ~xf*6{BU=<7|PLm^x63A3|m)l5g$0Q--$M_7>HLsFzC zn}!t+Iq=FH3KA2g$_#?ZyrA>~Y_Wby@C)DiAzYCYPf7WhbcbLD5E9R7Sk->iMh-)>gx4EJ^`VM|#Z?=J*K7>P_?i^Z~{`CY{t z^u>8j$2*fH4f71HiS$#Z1w}exz(^26Y8mc0RO_av$bPy`*e^v|@V)T%fY}ODfi9L7 zNl2wItO95~gz)+G2w;AGcE6Tcwa}izm%QM~aO3mgC}GjyHtTOD2&6=?Xz5^l6VF?FP91WGWx`%sTW(b zd3)KtZQtjqEV(#b4`(U-68&2otQ;us7F^6;W(|Bi<}|!@bFeO?hX`*f$q9Y>Kn52& z2A%`t5RHDLB!>|w;SS&&fc`Hjh0sGIdVrs>gCh8@5~-*ao(Wtzoj*g6YPFH0S$$)97pN$;bhcgJos!%;CqTFRT-Y*)YF@ zd<<{P8LvCz{e zBoGz6K~lp8b+c>NN=IN znm23Ogb0^*R5ze5#YRo2d=4aTl$hC_w#--r-v;Lyt|hjyf$%Do+5G%%x6o>CGFV>) zSOo29v89y{NDcP=9XB+_x9tN~=5igv(6zC{GPuE#ALUu9L~^n)I$DM}1>_2H7i)LB{jYXL2CT^C@0%xr&UOZGsXS$wEKzS5 zys{1J=O}&_;+LW@8fO|_f!Z8_ke_9=wz{jJ%Y-dY?MT0O?XImWem1qil!hgfiylmO z?fa=iuaBP{xvOUS!IIanHqLF`E50Oa*M#}=)=povc(bzGR1l-}NWgjw)?>ta0An-O zqZTBIkTn6Ii|7uQ$0zZR{68FhQce)44m^Akbs^Duc#UwjO@tq37MCm1z|E212sAx3+5TX;xhXrw#I59A+E zX~3u|EJp&)bJL#2c{<1P&4!C~$)VCpW`C2*n ziXlhOcCltcik=85az6j;s-|6K2{%SD>nED_F{h#-p)U&kZ0d1Lo<8t-SZsu1$eqAP z1m}ckWMa%zac|BPU24fwv541Cnht04+2^W}nYn?k9UM$d(oJ ziyuU-L%JNeLMVm$@T}aQ_|(IzG;P&krS?-xHErorQpl@FOYQ*m!u#P&AtdSjZFBpSytDIY#wZ{&8PDQP(=hV2XW<|qo`0@o4&AnQr+lCEiyQ>Eq`Vt+aa35cIqTMN@fIvu2-~r z8RdtK&afB;w4|nJef3=Iq6O>WqR1MS21JIz$oyE8fgp6L@*rF;+%Qwm6bl19!!$iY zUCOMM68$5=@4x8;-mDU;)JE^SGCAXp8dK^)w&<^BXwv%Te=AMV_=_r*;OsqHIezd) zfQhM)ID%rog=PU56|(@QG)TZOFdiZ@(R#vo*fm2Q>y`=BqrO^zfF)q7w}{xv%V`3T z8>n^+EBkSy=yLMk=h-Ay^A3Hv73qG&Se-3>p*QXU|8I<^sC5gpl`qJT#JJ#i3hfW% z-2y`V;q05*A3;(;NKiokP!^2nQVRA5L`D}%!J7bQ4scmz9br~htCm@wtme(AJS3-X z9V%T7M_r*c40aG@8b0*WgdXbEcQ~lKsaeiig+Rb3LZ73gWbsbAM75|2hcGWS$F3gL zpZMtVQPWY&S=Cxe0Rcfhq@bV>09U?MgP(Zw zs2$NRO0LYGeo|gG zYuMeh-dr@c|Aev+pPqCmCu`rhBVXzp#*Hg3{)%8Mg0F5|ELmXuS_N^5SU_M}+M%j> zKt$}8d1&%zV;%eG@)Jqe>Pe|%{=@)Yy#Ei;n4wLh{g|q zDto}n!nWd&cEi-6q6D6)(fN(4<8x804XXqng%DL4cQza>l<*T5`3;u$#~;jvX0lK1 z+I`~0ZhRD*7{|K*4g@Ed4dQ=&pl^JV|6ay#yvBd0u@phG=L?aK`q#0*Ox}Jhz6^mm z7K1~XBR^jD%;|~`pS=!sj0c82ux!cFF&N0?1eST4v@bp_)rT&FHpaGVn4I9#sU5Ut z$OWf*kXI#|2{QU{^k`wiuo9FK!zmTee{=-(l-4Y61@SlG{z1ySQ<7 zCckiRZEfS6@ne(2>(!rgFP5TMv$H8W8oo+a4|O}h(?=RhL#&|g*-#kZuoNF*jk{?d z&0aQ@mhR^7r^9A^zm2|M81gg1GTRHL!p8bZHTelknRWoUQv&e6=Fk!xBu$V?q^~_+ zfB*vJn{Ey(@=PO#q&ijqfa#O+ven>_Hu_|jMaedNt91-C$0I@0SM~l;%&!K+jtBIQWkK-_b!j2}vGF(w;gu>^K`l}f z;#{FxF#c&dapK^?UAuZbb?PK067hXv$;6VmvuDnjHf8XH!4t-f8C5iVSl2;a2i?`b zU*BFmJY76pI(2B*wpEKd&FeI8+L+$M#H_@uTAArEY+(sur~yDK-i8U2JaHNfo6%CS z@=)LUd)t5f`K{moU%$Wg=P8M@HgU+{Nyunt*R7kyzL2#^g9lGmelWien)?Z z-(~T$H~rSz=cd2v?S((B`bpgQNxr|^^roMy{-SpoIkJnM*{D$_hig)VuWL5M*Zx&s zd;hBXnqSkqju_Du-_x+BR-@YAy~Fq8DUq`IFv}!h>nfBuLvZ7xfxNl!E}^Gfk~30K z4I^pQYW^C`1%9R)u7_pf2D)rY zDzs)E+9m1_>TLd<4pWHhV7`X%Kbx=G3_28=vyFa|a*| zqDXBpR;q~xp$a>M`d1qg`bcMiQwi2CnP_DGk#I%|8hJJ(M-b#0GKS`e1%Xmi<71;D zLD2G7A@~AIhg?sd;?pA#@DuUCY$jFRseU+xFPVDp*G%EwulZ?04T-3pOSSv_wA{Uj ztt(=$|9Il$b>7_vlkQ#h&@lo+`#$rueEl0-yp2za8%g+BJb)A#2du1e}If z7MXIm&6JcA$bpd&ryvXRZ^YnpMS+9m#%K*14hjTrVe;L~+EYhPW!fW4`ruDo3|^ z+ls|hM(Uh9j6z(qPG8iPE89_W8v;H%x=;dFG02zrAVYh_As)qn;mdLHs8a4Sx&T;rO9cXJA8R zExOzwBdsZw++kA5gQPFO1C)yc0}|8*S^;44*iDi$Frav$yx>F~K3a0&y%x0x$Vgiq z(2vfOd+-e#H<^}V6SrY%alyAV^eY}aK0?PY(Hovrqzep#H{F6@nQ*|-!LOf;q zfkjENF?d5QNSY8RNgi}Qoqw4P#$xCe((^>glZH0Ac=X9k0iYAT6m5_}aYAN6B#J5r zMMY0xvQG;|q`4|3q-P=}*W{P0y1f2g`SnvXv4;lOO8paS^0&ae{)>O5%FEw8_Qp9c z7vw|iC%>k;v3`l9W`K+a!?6c97tUn?c2|Y3fFUCsMvewdNuuFv-AMir+bV!%tJ{`| z6sr(~1D%NCUnm$riixyZs-@wa_8jF96>-eF!s6stj^)gsC_lDLki-EaA52tSv-wvQ z(nm}ASFW|L%~MwI;)iKXX`^MVE7iO$)Q+IOzO$!;o!S_|n8(3Hq^CiV37&&eK!`68 zP-ZDagkGr&8@n{EqYw_rZpu4(cSRJ- zvp)P#6oq56i6uczB|BkWT|J%b76qK@Na`4-RiB$$eQszIqs!>P>6_#KGBd=Qx32{8 z&8*Ov*}#XR9<4jIgURMk&x_m1qGs?P`7bpe9w=sJ5E=N{bLT2K{k3Z2T=j?mr~lY7 zs`J3KFfY`4>hEH|QYnh0I(?NzAsI^93v@_B_7|}?0vS;?3WQqL`+@r6)21=d2~^?Y zN2N-sM$x`gXuSB!MgKz$;&kX9MJxS}%KcJb8R?xX_vr?S`Eo>CD9kV_piQntCdb_9Of_E(GeL#EB8v`oZ{1;5`aC1%}E$k*LLA zqP!CR2+|M8m{C&OtV9-d(quwYeM!G+_B=-hL;96cRYBj^Cc3DDH`>+V?WSZb_h)~= zsvdhpRgIU2nVssy3j}^L#zHy1LoZ< zS&X;9at7-xG_jC_(BWSg%`Wja2jdk`3X)aiBJm>N31Cp^#WyK(9|^^;##2DU#-X87 zbP~m?DjxmkGl2AzZw8$p`rhEC$Djc{=!U$JA!~HI_khm2@3j}>?**rw>gwE53y&ws z2^UV$C`(Ky1^fb(8V8WVDLoMq96H!8^Jy^G8GquYW`?#*lExK9>bHF!eB*|9=hQ5v zUB6{%^g_&=BtN^ZD~()Kg21~|#!>+kipnZJTEf3{txbA(^6K6EdGSt&$`IqdAirRA z#T9Lh_6jn=4aqM+7Y#WzS_aDwOAXTlhaN?{MG)0iWQ5uzAWJ8@lIoNa5tT*=C@C_T z9apjBD8xvRfuTUnoB%6B*wbYFA~%);N~$9VPoD_Qb-T7^!fU--KirG|!1v!M)7kW; zSC2ZIC(K%K?YZZ!O&Xaqxw&`2vqlww2L9Wb((m}Y z7RwM8wfE!iS!4d@ufJ^NzYGcqmK$vRu4Ria9{l}@i-{Bu|z<nzZZO`rZJ2E5g8v5Ak zhYl1pN$s2cM}D5(uvz;ydd<2)v2ji(>srz9Ert%7>kmB8_{EJ|E7Y;pM=V&R~;P1d~gzo@VK$s7oE`(1|LlhKQ_J(eiPY~@= z2x@#4vRAZws1kzkX=(@!Iws|yAH+4>H3uoblLQMgw>StOmLP0`(|D&L8b+&N6Y_Kwi83zEUD2Sg>|Cy z)fje{-V6oSY>p>3F(IZ#xD}#pOhIdR*jrgmaw6bB8+Y@Zxe$lr4FN<6!zaTWL!bc9 z;{XcH;p2)GjqxPk{9Rxw-R9f+dHhA0l<8(#b8P=98xp^D>&iPQhp;B{OXZ9HT|R_p zFOup--4M-J@R+Es3Fs74V7QV0)MUd?CI&n18a#bW6s48IRo0L<8h}tlL_gx4R8=)u zb)l9hMF^9@`^-Us!+%s1m2cg;?)F7RSL8gF^q+M_jWD9a;++?@Pq5#xeX!L+)JarA z;SGY*LSzBCKNVUU8YrNt;eW)t4z8|Q`y^DRZm&p3j4Qcy>EJ`N3<}TE4Wo_^r6&`G zgxbMkv_XxDJ@-94L#iyx-Zd{S#(R~%#)B?=MOkWE@wN86_9_s>G&=pbmKY1Tk+FDi zgo=#F2qS(X6#@}`1MU`eT4c3IyA&3Qp^YYpF$i9)p(sB~UymoIte!q`pivg;oAz9k>p`RtD8 z9jqU#F(Tr`Che|S5h@F1L;1t})VRUt_}{ftmL@k>3KP%#!GAf0lO6zjJQDZ<=_`mT zXP8(t%c~Iq$BH6CIyM?mCgSEHw9=J+g1=4`5C(qkn-}R3xsphUC<-O9p~1kephE=a zy++m+<`wM;4a5ONB{Hyhm@qR%B)%~_`Hd_5w^5@Xb|$&`HluImh6ku`W}{=f%pRF` zR_jM=(%zEBePf=zTGc1BK_}()%D$Mb`DHCfoF!DEI7t{5*bVZIg4zdN*>K!;niHZK zqiZ}ae;=GHif6@LhX)e{!&FsQ%n)<2NXcFm&ied-*07o-vcGo|pY%Hm{goox1@h}} zh$@s)!+%MaCzr(VWCuU@w;9!*KK{m8E*n4(hEd45I$QXOsAGe486qm`J*+T8mk6#G zDs>RvB8!iG5%QA0kk*!EwN-V!CA$gsFouf812;#u2%0d`o)EIt*YJuLKayWQS`SXk zq0Nup6f3b)B{g_i>?cPS@!yixB|bD}<&KjIE^dBys6(1L_-2qvVPn)DboixdoD+|WQLttZnvhYFf0nr?WUn%u@ev>W#J~UO zIR93YU)nHp$@ZPwR%>AzoR%5f9(?t+N+rRKD>mUnnbeU_Q^RmB;-wCrwkQSBqkscz zB=Ug4BLAdn0KO>T908XL-qi>kVjba`Xf!~1FZ>jwF!5h>)c`_+R3?=^+-ao7M3j#h zpL*e&n+Ljm4I82G-cUqsG=tm1uADe|?c!;D;=^n2*|dBUxCM`}f{F^s!^fzk5tgLJ zc+iPidaOPE%g#RD9MIA$tWL#QsjsIO#wiijsrspC)hjA>;F4hifVHvql8VFMuL{7U ze7FEwanvmqK{>PP6vQRjlHAEe{k7Tyk_hNm@cD~XstuwpWG<@H!uCQdB|!GqLV&;d z#{kiST}82{K)Jp3Cx~wBno(l#_xkHqTok&kx(NBCc*?NQlQ)x1q8vu2|;Z%_{ej zG##70+565jTlR?#+1)!ogX!S@pqCihs2!BT;48QAc*vk(^+NIDQT2vOt7ceSaXO8- zgR%gKJFHf8TaLCyMT85ry)YIA9Uf;=vJes?kPha|VRw^!5IIhA!>@S-lfGdi$&3M$ z=-rQWH{=5~Cd9VZlZxF?xlojZeS^q#;v31w98MEg;L>Zm?AO z+;j94l_kU@HDquSX(qrIF(> z0N8TrK4JPQ@qrvGRi7AHdy0Nja+OPR|4#RwKfEkd23{4%Ld#aG&U*tdGLYj8B=bjF|~Cgux>2X_Nb6p^}NQ*iuH0E`_J6Nmi+ z)3YaTA=(|e9ht=LOd|USuMb#%H5pY=zDtG3#BsG7tAQ3yaBgWmWLgjT!UI!|-S_C~ zxeI&Tn;x>2wfh=G%j>q<3dYrzIWnH(9a z+fG*fA}LwczSy&Li9TxRIr;f%Qw9N>cv04`K6m7;p?3{0WGQuqj8X&q2mdNx8L_I( z#V?e}^E$w4Qv-2mFE!evhbOFNLC_s$F z+~UOCGBf^dZh}&1*lz+;>tx}F{D0Ja2YeLO_W#_O+1X7mn_fuS6i9#op-7WWq1ONc z0i>7EOQ-??l`bf~gepaf*u{cid5Q>jefEOwJ+Su%?BxGF_s;CjZi4#W&)@I!`THz+ zI=T0pbI(2Z^pl-RX9(P!S3k45Q8N#0)+su$6EBS!Hhyqw=JVMx6GyRM1!C;s?PL0s z4U_4po;kX$-;Ft`OGk}tG$76yKe}*upCS4UUc@+GwyL>kABVfwKtkWzs4#?qQt8<% zj;7fmMR@z5GLh*k8IeT@RGIas0$f;;*}2(h(8Gg6h!M&B%0UBxD5rRf^^*CdjvA}i zf9q0<2Ah`cSK+~DgGs=Ig$=%j3rqd0=Z~InptJ3l`b-_qcslDO$C9wWQp!b(dua*k zkqqIY-1j8Mp{VAf=EfVFOWGc}iV>Yo;aCL1&x4f=9p(W(si{6p;ct=Axa+TEO?htdSL556yaJn!e8>^IF<^2GMjKR z9r;6uDj>u zm+x7zNevFZ?q?>-T!DTW zFThukMU{+Rm@_EFuoln|Sfm!=_uzAh_W_Ned@kYsrP@p}H3cqTu2l%2mHWcN)fW!_ z8?WB`*WX&usNjau)wgWkJiHfz;az@~6H6;w>^{I+f0p+NYvW4Wn4ET@I&b&CSik=9 z%@RWZDg3z5186>QI(hV|D+4R0LN0}ZJy=AM$5GL?9nJUov|i`{MzT4eO_$O!xeVUg zD2h_?0RPok9hQ;$B8CI}6L)sSW|BRv9?x`f?S>fQqlm-Ym3tMgR!(w{F2M`FR?$uh zel7SQ@Zwz!UZ^Kr@R;DjLdcHCGzfac$-!&^G{gI-N0ApdL;2T{h`S&o2aSMxY!-`( zPh#r(w*$;K$ti8qBdU5WY;)pSTs*l8wY5S@FL?D8@algtM-sdX z#p>#FB(pGe!J82WE~qs}GCgbJtt;j)XHexnV$E#q<|< zeex4sM?1wWRd?kzxnt~^x8J{4n{ey8>6JI{ym8sQ&AVo5FTVLHpW%JGyiz@{xFnk4 zjh|U3w(1?JU!nUC=Xk^RJ1DQTePH|^ex~2MM;bToPk-+Qy+TENn{37#C_s&zrW#cG zN=1q!(foQu@xYAba8a6xXXK0*v)xB1SJ+Z59~o^CZZv_ECF~}ROrY#alo-Nshs@3q zBl=HoQgB*5Hu}v@UAu0+j%rUDDIYWHQ4%B}kCT3n;%=BlPrqr=ZOTUWn-2BGHe$@1 z9lLejJm4|nLzn(C>n#25+mn8m@0sn>iaHDZpx3CkI(6%^`MSG7pFHf@3wsh>>F3UD z0$U(SPcp#Fvq`;BB(h{OXYo70Pd*3y=y&ilY-uP5u%#;)GB_ls8?6x$CXn2qjWjYb zQOs1w@3m1rmUkL^;b;8bgfRNO39LJQFV+q3JN;e<`aPg+{H9E}$v1G^&{NutTv@mn z#8)E|6OjGu!_Za>S5_E+^PML0*b;ODnbcIsn-D3}od#`y1|E>2Lm>=YSgzvG$r@AA zkG`&cNm)RyPE;(AgnA( z6`_7Gyd9;;ZZ!U&ZZedj#5XZELW)v`nnjz0+K>+}(9Z?&TCq+NGjxq^LH zU~pzO=o%)`Y*l!KSNzbojQVA~CbrhSquD=`{g673izrM0& zhbNCRF@mAm1>1%I7UTq>vCR-EB!ruUF}x9p*B0*GvrDI<4)l(}7S76~l59=~?o#JL zOY)G=aPWw+Vc*|WQ?I(T4Z_c__w zv%0Q6;0Zgha`k}&D_0#DZ@{fJL0D@`giY7k!eC37i4)5AFR-+sTMbq3V@Z`gT$ln8r^(4kX>H(8FI-@9e-sxg3P;W2Q zY|`Ihxtru1eI{GxWYqiu9d@K`ayVZn$L)eEjIV?25d62E_=mX?zJ*i5sX)Y`S{3QG z7g(2hm%qykq6Un=B#=4N~l#vT;pzPY^6Pq_5(_5?T z^!<8g7N&(M6K;IukrDDD&jB`{C2@GR$hRnQwiDv6($bOmn+#_hrRO6dAF&P2?Z*G% zQ8P#()R6K~9R>^G#!`$)v*QO=FD+|oryEv0*tw`h7w3bvJLkDOZ{4Y@?7eYAS{8WD zD(OU5xNp@-z_Fo(o+7C%I0UB?9O4KGc0jF13NsrK${b-}Ylpo&oN1Vwj5rd!f*~P6 z{ZOqRQ^GHg(ifT$5+m;s+)n+CQMOuW&uBp&Ab3S`=`Vf> zye~L)a>8Hij9f2S&W$|8*p;Ti4GYvG2ejSWY#*I`?tN5|EFLv_mW|zkMwx5}d$iw{ zmWK{iSBKs;ZpUpqHoWlptH-oCGdC~Wfd2;(0$uJ)tqgK73SD`cNz>euBhV)TT`TM? zm+HFVW98n$Fct#MKZFWhAZ5(7VU#|C_UPNM*~)@p)j$~A?Q(y#d8726WVnWsnp4gG=~1- zF7k~c4`|oMO`A6EQg*%gVu$8QMRCa~lUvTa_0BtO_x^tR%&+=*@{p=Gq*i&-4&AWe zXr6v~gJ)WgYlCbnqT|=^kk@aZbELDz+#uyeu7e>LD;3>r>M;!|i;$l*h?m-qX}}N> zmGThsnu}IxhNG89L1kk?IX_=C9mC;9qfmkOmas!}6yZS9&2g;!FRD`XspvS_*bHTr zo+7JvZfrfhFy@*C?Jww`ZonTb`9j;-#W5{rT(jX$_N5-nzJ#%VL^@wO7PaUOur2CBzqAbiKB>rPY%R5y!rZ~_+qP(&n;xvF_2I{l;}jJs zAztRQMo{R6^G+t}nYeKi4-NyH6dF9t7$Br%OwfL^P7IRtI zW8C=e%Gr|3w~}m>r6TmE?gsdi5sP*l&rXYw<@))Et{{yC%+LbVj56VpdHkO8S;#BO zCzHwtwKFd@9b4FHOyfPb+_3Y7dq&PqZ-jas?Ybdhvij}op`oDXjsCZK)#{;$}!SYeC9a<3$UFpd&VH#u|Xo$Dp|0O~M z*zyt~uOP}LCbLn?0_uRndzLz8cwUtYJhwfzd-uu5cI`QNtb9Pf^1=Q4m;bc?w5QZa zu|6%I)F|hF!g_h`rpF%JG<)--k8U0~apJ(){U=ZE&pIF?_@z2VzH*I-1fnx6x=}xC zy5)p7l@-_nwYvugFlf&QDUt%R^UuNkZsnyz^!%qy<*L7RlMowvY%dl2$S=Wo7 zu-^K)3kCWkEn2s`R>>=Bt$)etHE&P)&g7b(wZ69dN!On&!6WgU6ecgnKj%WTy_p#icK89 z#|`{G!9NS#>5W4nlnU_BqNfwwwn4TIg>rCMBNh_ekU2u^M%GUkuNT*5$9!xQBL_*L zYEURTbV+KM228{7l!XO*ox6}>)VdN)XV4=VFPNhr!dPJrlMH{)dMHj!cK? zQ)a`44jRz6PmgY$O50qMS3e7#eNuP_4Tr|^<@|^w!yW>C?FqJfy!3sc=8AkPr!SRM zf`8N~{1bXumJ9UN;MtF6L2C2*plv2-n*rKt25mc{`HBDGn zi@bRxUmj16MY~|gP8FF2F%p+=yyqE$Zn;h}Iz%KcCXRiHOr;Y2qqpAGKfmTNIKdARoUe%l5NcD{y=eR% z3^4p2L$3|kzi7z=Ll_z0$T6MkIVH#`nT^{M#qb44S@Z2WLrE-y{uk8-~i4F2u z`Q?o$QL%Xtd1q3!yiy^bjMoOB=T7SzG;s~5{edw7fsf%FZx?Ruc!WH z8FGDev|zWL^}M(Fx09?3>))@RI`mQ>dDc$+F6xh9L!QDLB5cUuhnwcPQX*spYgk7o zBa4-EB+=5Bn|9HyFm{~Y`3!pQ@$|=04p|HPsY@^3@lEftZ}z|R`)@BE__nO~cXvF0 z>Gzp8FJAS}IP+$!Noz9E1+-_N)GvTM8Byb##v%P+aU@*d(~gLU(cT zfU)k5MGFgJ#D6Jw7y16ng!ZNQFUrKyUM!(m!^EB)@9x+$v0<|W)~nRR|6SvRo}KQY zf7d*o_38*x;M_M#2bDL}k718#4@5iY+zXNN2K5!K5^(aZz$wmnCG0uey#rSc{LttL$4SpJ?xfRS3@$d zs=4gB0W=8<3DV>S`S>1ID(c_G_hhk-m(s!eXD#2)MoI`8 z6vNXvRQeGjUwZ&~-Ozu0Zmpr^eWw)^oLoHaHTeEE4wy?cYlORU2>g>l-QLKgKwh!z zP2#7TG&39#SAxvvRmE&i`ug-->EnM7dg9+S*UT5D=uXpKA z%2y480;`Z&@w8%+I3=fjyz$n75 zFl-|mE<55Vh+yMiLof>;l#yC5WI_vFPwwf~p}1Q& zx4XM?qE-E7E&I#bgdt@UhyMP|jAv~1&rJJm3TyF01%)k|Rk28G_cmOAUmky-kuN3J|1H_oY_ ze?;jvi~sTaHDU{ONP2Gl`dhA4UAhwcdzJVHZmi4mhJCkV6kd#a;76K~27i461Wq&3 zLgD(c)z1$?OQe>q#DQdL@l?woXotj~*mxJ}9l?40uk*?iSBkEbsu4-`y9_(BapfUJ z`3Gy8-?D9CUhlT&&YkOyLS1CR^}W*cN>k^cPT1cM;kSn}7WPHI$D{HW%$29MDnTM;~3}*1{hj4LG7AV4!lD>@vDRlCw>T%4JI5r=O-xJdfLC_Y0>ri~xT^ zbf>&!f&8_n8GA<7+u;63>7&^h_;pFX+qnNvaI5dR!wvXlLdEj2r6Y1P>b1&j-?CHN zlIFMd7(F%7xgaE>NnX=|jj_%MY>+KYw&)PBK3VqZ)A;wV1MVg2yYg$=Ymmw=!0k#D za#^@0c&a$PtWJKz=*1VlF#31$Ia%AgYUS;Ac~eQ(&Yd<5@6viAi-Z=My~bz1krY`*75@>#ozJ=3u#W>E4o6Svs7x4F65xZk-g zTIRS~iNnMQt-K&fnC;$XZg(@Se8!A&ExJmH zPtsD7`}Hbr(aKH%9>Vjyd|tZ+d&Xc-XJnmt=2BZSyffN?)oTyf<*glibm=s-THZ6! zcCS`Gb7r|#*r7w=d$15?X{!2}(nEU_N^=UZDqqJ+T6Moxt6JUT8ivNjHQI?2+R|leQhH|k zutDA0yY0{#CAnsx`l`}fTZZ*Rv3^L96$e&m!-Z9P%V!Q9dRAuXyY&?tpMOn#ivVS8 zAhdB=nx}rI&d|1bf8Tu51r@;WF1CF)%b+FB$V$%ZFKpz%&CDM|SLdM3XlU8a}jq`0kfwG+NLqH*BcXiu(2~QqO4M_r2;Gc7qlVsii%j zGUx>8#Hhr&_Rb#}d)k)%t6qc16VVpUPt*gruas-*I3A5ER-B)&3o+DnNDh{vxFXBg zu1DFxPAbh9r9jbD2l{85tq$G^6XAfnq$$;6-3a9{)N^*FSpQ^9bSfQPsWo zR;g?CA76d#H62<8p|btTffKj9zUnc;0c&G!$y(f2?SW8kPa(X=?J4fZ;}#V{{=+e6 z@czidR~lnYr2vTvy)bexT3>!dr_lpg6Z5O|M~wA;#ClO!FOuveqs1ucTSAEO{c2w&Jd4Z0gZFkT%9qXV?v)AXwoo<1oZG{~847GdXA0E7bR!VX2 zT+lW7#Lg8rAG&wLgjH#}hdsNiXbNlg>(HNAi?h45u~R?0^ZL6#%}c%{^2b2~TMl5R zbByA=%=3OJKgsO3Z>e-mL*}pC(mS!tbB>-FH5@5A`UW#Dl?OiN^Ujx!q~hS9l){GMLrG{h!?X z^d}f{KWEaQIhYHrhNpO@A3b~jQElwl`J?1@FrG2_0en<}wYXj9gTd^cEIM3!CpFfS z+4lY{aX8ykp&w_{=Ih1R>z|C??x``5-NUAbEk;4iB)v^iRaF?9px=glg z`MX-k9mAr`8THVGi4ogaA5|MXX^A_JbNv)(*m;Z{2#AoR3K}&#?A2Ep;09sk3K3{P3Ap&wlvfvqC-$t;tsx zVIL>=^*^bsi!c%Ryssnessgfz{^$RI2lk3{_u&#GrU-c4Z{nWWL`3XLf zUr~x6xT z6Nj~-mDhLcT9)5t=lbfyM<3B9k3qv2ZvPE6_!RS7K{sAsEAAzwJE=p_HGo*_H&k`3 zr7?Yi%?FEorkI*z{x4p?-1y ze&Qg{&IN03StyU;S$;d8e*gWa>1V)(oC)=PtWB~sl+(q|t#`gI40`;NJvoJi#B1>^ zWC}YrU9Wglub9S;so_pfxX0j=Ul(dgNldS6B}o@wM=~KsMV5SGzN|6+$HV zo3SS1CdRtUwz3Z%{(x;>#_lZF^@l#zK0U5`%4zL*Pn2R)ZoaZWvB_V@FJ2sWxkedy z<%r76+`e?ceLeO`#y(Ek2k*UT_w6+HF`DVq^nvs$)<}PU5!>JW#L2GgV3qy>YgnZZ z>w5Z`Zu$@mPRkC}pABNiSLui8IQ6?$v4_-fddcpOSiCsKv$sZ~OU#1gfiWN#=+zr<D-gf-PGX=!X|=-MYwxPacQ$ zxnD-mIm+H5n{Xbo{~k6AXhOD@%6l^|d-$^ooXUYyC4PtAfC%E(!WNhUX~YvPN&3{m zxG-uQ+cK`>(1BxTA{+ms$L={hd-rb&8yI5nmPo*VNc|9!RC^#Ti0+6&H7eXck(tv$7FU}~ZF{a0 zG_tdK8QC+hIsU?H@7@2cjh$LBdd|%0W5$n;Kh#MMi#wdHe6F8M%$AjNkKX^gIe2O z#T!e~+sy1XZ%5PH2Az2ByT>2x3T0W{`F3t?S)D+SS!hthpMFVF|jzZ!}B#H@n!e_;)1E(+Cs&@vL zXDB~iz}Wh)AAJ-FzFW4F5X2vfGzd662OQ#I-xf&04>!z7Pl~}P1WQYEWHrEfVajzy zynLLVem@@^J8<0mUmpEO&4P(TDn5Vk&QJH;sYidPk^WJ-sU)r4?4bh}CN3L2ZprKw zo2JfcR`~KgcYOT&)B2I)|4vHSoD|FUcWc>d;h_yf$1NurG8}(fqcr4p64!$=5Q}b+ z&DPw#m^G4bTON;ZW&qH0_=esPv=gn5l)I~5O8K1UUe>r{{xxk%y525phu5yyRz7RH z%qHB#w6@*zn_UazeDsIiY(uha7?&>5b{8jJf`sOGP*p!&sJ8$WhJ$I}E(EIw9 z_Uh5Iq^Kl<4Q6MSJsOqBE#ST}W|7Tly|$Kv9$Oen}gZvU(({5<}`eFRVY-ADFe zi^=)*a{Ctco0v7W!_rO1*R6f@#l`M^;R8!M_v@xKbVe?Yj2PCdI5TI>4YM~MUGe6M zBl>`bIl;X~c5BxGW~Ja6`515w1+M(vLDCU#zKZ*ZVAHYX(~j*Jq>q$)%DZeJ1BqKwL{l|kFMG93=V;hIKJB=LCrKmiqd&~BH z`nGG)UGCF%NOH>P4$~JdoZewfO45+F6Dlk9g2IyG=FQu;XB!)}Xx_MSYqYONj00!) zrIns_-a((7_P>K$y9`h3-+2AO@87v?@9=>*u^w~#mvqUmsITUuZN3w*zjiiYsO0IiEY~+JF#`! z$zy|i^%_*(yJtB|Ub%bEiZ7S%-MgIi7%-s6SG@)d=!LV|h}dC_5*Ry-p)yt@cBn|z zYI}LIHXT_uk$885A5L_J*%j`qAU~L0h#(G5E6el3jy*2FJ@@8uT{@2$)4A)|frVL_ zO`B$B6>8J9``+#{e0Y~GLx*;8HEoiWE#fq?G(nvvKW}>rvW8+m;X$a2!d-I~#wxCC zZ=yF_J>!+nuGh~G8`Lu|_kQ&zRuZc})o;M91#Jr^bb`hMdfkG!a9`vj`O}NrEmR?b zetS{=dW+gu_k467&7BpRckt}SHMeZobjzCca=!k#{uawaWm-A1FdL#>-4}VMo_O-4 ze%-03o_w71I>KTy#euClj7{h;Pw&^?WZy!GS(J(q1h=-l^hK)Bdj>o>~s$rW<+ZHEU<*}P+oc9Kc|x^M2c ztMuWJ(NZPwcVT^!nMvU!Gs(A7r_iib$IiALyLHa;n=5a@W|y9O{qoG2t7homzJ5l( zY*S9IU9f!n$_>Yq!kgwSx@pC9?cjyC&J2E_Apen>XFhxD5v_9N%4I8-fGoJniF!9R z4l!fuZ`>0+)3x}T!n}BTPhAk!#$AC}0K;%(0f_H;rAJmUc6Ph`L%x5ae$Omc=~%&k$l&sWzJOYW>~@$^@VkU`m=*ww*nD+A~wW z=~d4X_87wKUsUV&vOd$4@2|9xA7ceLuY)+Rbgbk5HgLTyn$N}+%~-sLXg}Fse#i4- zLE{tl4bpukKfaOIroe<_vU-IuX(T& zvU#Kp*sGND-XFXTVpm>H<@Ywo_jTV`(4gt0E<2xa9~l1h#a~~1Q@_Ys9UOaW_R%Ht zm#?#(&P>{xn0D!GT&oWH4=;ZLS7A%^{fR>x!=avOWgX|7efPy}>rT)e9R)asgFm9V zZ$BlL`xdyhkB;Y&B5|WoK`J$uC`cqg27wlHNiJRrI3SA9_CVe8zq{@ccjT&p3SkTkb3DhrH3_*z>R2=|pxO&zHX& zz54WXA3u2NyiGnichrP&gIB-!+~+4>{ss;!+lEmS=CZV+{%QG}s+OMk$1Pgt8AFTQ z-BKHFUA*r8*VbqgMqUSeQ7@*ZV(&~uml1z*C6JE;At&&*;QT_wSviiTS_7LZ9;N%F z&k^b|aY}Mfu-y92k%#ZQ{MPgHCXHJ3m~8*y)FYoUxsT_mQTtr4&AYX{VJBDDk#}v| zanGdT(?*qObDlYQkLTCe`Y|C@>xLDdo>$fdv!!|M+7-Y;{;6;~PzF)bg zIrHzU-!Fan`1j~Jzh=^oWlQ}g(4yu1=v&V3%e&(Py8oi4?=bj`cse@a7>8z5C3;q1zg?UVZJAJATv8p-@jc#=h(m$DmQdQyMwAD4^sm@9Za z;fnlSbqV(M=PTZW!8=5NPk$mc)hcn76Pus70QYYEhu^Yfu-1{?8+RRj;@{utA6%eoG#p|E%w2BUlKC z8;o{Md-R{>=TOcdJ*QtjS0mLtZ=UZ%*v}F>pjM4yvt|9H%AC#T?7hltfw)*vZ z7VVTzCEUK7CMfLLo4{VvUe|x{9j9J%Uc3FMdD=$~nETP$TKwte*%pF(#CBIZ+V+=! zW}!*)$)tU^-|=FdC;QzQZRu|Bxn>3NbA>vsybQVQ(__(>1yjqTqn*%Wm6v}!njLvM zBKQ1Lo=D|BTdaOsPu36b+QkN;*^JEdt`un@cw->ozN%eG{P0)oO0{75%$s-V-@JET z|9<<@nK%9R{8@eH(Hn0*uy4iEgAF!JpSfmj<&4|Z<}>fiYxLNHb8ozHZsB7M8yuVY z|M?Yq$I9wX$%!(*2}dCioxx^jbM= z-Q7($4SxMM<~aEov+JMytH+)WsqGfen6e>#}27{Y(8I z{{Bj8y{&19%rmTO)f3M=wRH=<1vS6n9VLG`)ipSdCq#=lFIRzFbw=Z-ocrR7bNY`^ zt@iEP_bdyWJ#XG@0}W^z3e1DAFJe;)Va zIZ8wg{2?Q~nCCcE%SrOh@`L<){EY7-@Smv$jDZy`^*&Kiq81Odgd4%u0eevPIjqY_ zrlA-C9q)>fO^IRzxd>@}&}UJpMGe^`46NmCzG$8h>W5JG4_AJ@)a1Arj2FXr4m3(a z5(;{yFkD=qQpyN)za`q)mcTXjh|38JB`@L<^yr&EL6a0-cwaKy< z?kdCe${%Ikly~U<7hXV~|99WjHBtNGjuA-g-|=?c6SbL?4IZbSW$~1!6&@BGgg#`f z*z8b=PAn*pM6EmKx1l393Uq>k(89yaCZqn8)GQc(Gy7AbX40CY6-ACN^*mhtr~dtK zau2`xrhd}spQ%sX;klnKh1_cg+rTTWS&d%vrF^fg1Gu%s?T$qHJu41j!BX%<1ot%o z3QELKjur$)MXeC(EsY^wV4F1JRjRnA%9$uCn;~eBJyk~$5S7nFvHMlJAN8gM1(EoT z+&tvCX&B&$YPpFp9MN)_QoWH;ugWm9jA}DnFRE#yj65@kU#yQjCBOA6r66R+*Fn9UEc7H18wVr%+PiOP zz`hmIk2oKL!_D(CPKEcGMpRPU%s1h!-D* zWdEQ(gWQe1C;<_N7UV<4Zs#=;aV1ukK(2Z)ev5pYf^E#-0zoha)A!pJHcI|aH$mol z7z*l;lV2BZd;M`^ue1AD6RDrOj|Dd>e*yo|lu}!e8btib-dH!SkKzPC+K&PR(UM-~|S+q@z-fdioV)%63)3g9iN%j&-9= zge0TH4iQIYqXtSbs3deaMDqozM&SvjiCSq!Mn;p2CQ*rKDgxm^4covgH0$JEd!~2a zTydABpV{@&FgKd0%HRhKN-o9&iC$uI5l$}%Gg&3fWW~Rc!O9rVXVXUDeMajeYuh;L zsL(eUy(_}(r3{0mG2%Cd#c)=NiVMjABYF2v3)sJs-Ho!>y7zYkVe23XK>U6Cw+-08 zTKa+Yk;c2nkSuTnn^aJIR0wtiPXw9&Dj7mdGN5!bF+R>hh)@v1ONX!kI4Y!7IEPX0 z;U)x@bMV6+0}(M`9%qAIdUc*ds0lzya#CVKyx&=b8E1ifD!I&_PB26g58{MKuGgGI zb1u{-V=$Q=BdcJLNRaG`tW1QCBBKV3dZKbYDLN)Ln%Y7DA9$PPN_#4;)ycP3r8J8T zti2ZaXd>Xof_1Kyfwh*~Thm$@zO|}r9%a3#>wq&d41H)U&_QA&0d*p^2KEOpIyN@i zmPYW^T*R8&?C695z0z+Q^+}S&bFb^N+PiJ@ml`J_fc_$Zzto?HzPx!+QMw zVkQA-w-?&uNa~lHh*BpPdh%s5S%slV1D-IoNs&V_SG2ex)7+5nR29oB=y1h{P>MLZ z_TiO>*@)|tS3fs99ZD$NHE7)w6O?M~OZBOP#9Q2(@MtQ|jJ1ZWrzvb`;XD!jlT@4) z=DFgSM3NqS0nG+r^QhPvsVhAdO@hHjC;*!X&*@bGjE*4)?HN?BAmHQgsb$T*($^3|rI?-o8s~z>IcOoJ z6gLSVDxpMt?c%0qw)P2Y)*)dsIj-f}WUCORd}ht!R%~o1XMa`qpZPvpFZu zrX8IP-b}hr2oVjHFrPIEbzPyDLg~P%6#EVejWHR+jRIT3kxBgx8Oy-YBi$uAJ3GgY zlLwq)ZGKjkwJR|Qa8T{Fy$AQ7tj*8PvUW8xMtc*T#o1Y)$9?l1Bbd4t_-I6dLVW`P zM=H@-z|ZMy*`q@G2DHKC9?R;i*hh5Sidu_jxiT}-q4OHc)6Ky8q@Q%L`*g^*oc5LM zL(r$0y8zQN(DF7IeNM3=Dl$l*sgOVDC_Yi0lHVY^Ag6$3u`G06$jS+&?S1>d8?b*Rq+pCR!hL<<{@5HKa2)|pw+{}7 z1Kedal#Kt&Ab9crC1C$*)Psab6Wrrk7B<0K=?4YX`#XZwU?Kwu?FUA1FdBM#!3gD) zz!U^8C1{X)v!(&G2=k+b7U2hrChhH-A}w&wYl2GCHp~&!8Xa!^;L(apSg^YmC_zEN z{V*RF@HiYH{ZL$LB~TcLEYt#75#|aLZ~?G|`@v>=E&#TQ1_{z=_Xt0Dz$F1>!7J_v zD#LS5Hl~+4wP9$5piv=OLi`~NT30_9?9y)OEmV2otgZ${uoQ%5m^5TU@T^h54CVX} zVChuqzP8OZe?kxKdVg3@xp1N8YiXW)Heds4;O+_?e z8;V)Ryu#Y(2n$~ht`Y|Qcp0dB*N!C}+P7|1$CZjqBN;SUFIB!FzrUJ1nC>%TM!3&& zSz*nu(irzhO#OqfmssNr*)HRxFwzFv58WfQW*G4wEFJSUsauI?<{u29!_wrmkR%QR;vSy~nZjX!KJJw%{oQ3T;n0m@q3V;2wc~-q z{x+2P*uHgk1jbt40IdR z&&hUW1|ke13)wlC)0y8%@BW%ZcM{f>cVAFhP#4n+&`1Uj79uh_mG}{v%sFFMoN6{b zK!N*)n)@c;86RtVpLi^RcnqZra3mBz6HnR%#=e3Vh{uYlOSXbg6j+JB{boO|XgD27 zr6&0gr-{74_Kufd#afjMoq=m%AuNYC3K}HPuWPLaSnF2X&$LzpA6(T>1(S9b6%Mro za=?I2E`}d-XdZhRcco)imHwSl0s7t6qEI6!hkIgx1BIIwXZ=p!&3H8aTzZYnc61 zyNb0{l~egD;9E3o!N;5)zPl*)sc4%ZHFoDyovvsfca_!rb?hcsYrD8#O^D|P8fWzY zcn&&tVr+~v2>ml@#0?Gz*Bb)O2B|`VjGA5HZpi3Du8J!iO@32uZV)}h+Wfv*)~;le zkquwh+E^IN3%>YkYxDbOS-V=IjD-@no6gW?_lI6VcTgMN00N(ChwIn^(Jz9Z9I0OT z`F-^60h!l1o_ZhquPu|3ZPU0ZgkfHv@< zrX*u%DTBEYg$4`?#5BVLim`|`P4;Pmbbsgua{0u2uqMJJ#jujN>}*(koL9s?90%_{ zz@bAt^-iyI7ek@4;!|rAjt*@j`c;5d!k?*-?6UZ@r%K=9bp^GoK0nhXX@|{z6^|)j zUwE{!wy+zXptZergC$qu_0ISkhgl7%4x|XF~@J1fN>xMH3P$s0>3Rf`Yf+I)~C*1WuwqFs~ z@juf&Y9YiRrg);+9tA4w3?X5Sr9rvE5FLmF>H>b1SVf8Xo+P6EKE|$+w_o@TD)c_; zWT8uX&)6>Qkq=`p_z}HGmo#yqRpo>NOn5K6#Gq0_o$QYQq>b}N z|26n?n-k6!KXN7enoXsS3F)|r3+#DBTD39$%zBKzbLFg!zmj6y{n!g@htpU8TJ-lTyt<%c4-IvWZlTGoSvGb(Ck%3!dP?|si8~>!HZf1 zEs8s9CEG-r2`Z+_L7_5qR0Lfk(S3)!aw*A?iIEA;C>V$layZ=-Q%AEkL=2zfEai|t zAChu|@`^26!o;+^$Oza34Z;x`PpcP$DM+zQ26oU;WSKLoX_V4LJA|spUP>m$F@3or z?xcG05^<-g(sI_HX!>XI4g`SyDB9tTIt4^J5Op$m_A?uQk1e(!y~pUjTZb*^V~_ zxh`VCcMqbRK~jZ#EFFLSSY)u->cOf_gKD6986kiJ>OOhS@m@6{DhNRXS4K*bM=~i!W9g%2SJR( z^n*)Ofln36iHghZV1}^JY=GXXWE;uF<9@e{Aly(B3;Fv(u2@NaPEao z8evb$ammSsk(PkxBMMQ^NC2VX0ktFE4o?nZ77*^_XQj9#Tpl(XH%Vg2yTEmlM7b2b z<|t+dVec~YQ8>On8${r{lV!pN8SEaImn8=|Ea+kiH$QL_)gZ~vf)GCu5mFi!R~u!Q z%hk-)tVv^7BLZ*!wDI<7V1{_7H-HG_XIxyHTS? z?HaXfbB!~{z@CFZFo^T!v1ZG8?_y6O)(l(Oi#n7f6KABkKn}p)3g?g*kXIXLVUhz~ z(Z?2~H(*ImpFxdvOWPBdYGAOWWg_64+qKfw^B73WGD5?-F|>PsSL#fKN$zz*nJ z$vU^-m761@hmVOI^0g-YA!Zm#&6P~UkHPWMrqF%i?-j?39YBBb0iL38=AKG`yzH*g|JCb^{%+g`e{$ArG!4UrIOQZf=A;fai_& zLQ`Eh2D~m#w7ruR>_g@ooI=p@aPz^U#?^@DZWTB-qp=hDHMxyi^DR`)1NOc|NBm^w zckHd14!yYqvkej6h{uJGgQv`r|DeKXRNb(M;SxqKR=fq6kOg;-H|qoLy&RDV0Uz+M zSoxS1?%iWG$7OHLJXGw%{=|e`6{?~VgFU?dV6_-y(-4(YxG(`4vdrxcaHP-EOuP7e z!!;MM&m(r(yAN(VWa!kIo~*Cbz@1}(AHH=3Fb8CB7?~<0BRE~2v_0-!OTav}<~md@ zV=XV7;@tWh|Aw{to?wnBQVDxN9xYcX^#Y6B%aH3aK=XaT0A){5!|65E1Om} zC~bk9+{~OW5^ciy5=)T+(7Y4qQf3b(x>(@fg|wN$|0yp>ozTbsl1U56ydw?eEdt*3 zw21Ify77t>7lL#*B^a({y7AD;kU>xZYIBkxVALO}3Y0vKW6TW8$aI1#I7WiE9KO@8 zCQY!1ph*w;cI<)t%zCMUD3B@`muw@~ED?k3xNx+wG!K%$zGSl|su(qjQDJaL8U1&$ zM_atPYwQI?leR?nhMexz>v8NID+|1&p`h#i7b(lM6~McIbs`c(VNl#lk8Adtsf$JLUW73L0A}b$ry$i z$2p-qk_^twkhKoT!_X$xDS{K7&N#?m?q;TauJs&K_lYy%GPtL)PaplLgb8)YI06aj zZ$Kgx8zm*i#iErbHiC3a3)~2_;zBH<#E|zXv{_WN>C?vBqK>d96217_(wLu3rBsPG z9{NB?FeU?$5{%6dd85nVHRf@rVdsy)4mcNvPK3w@rxykGUQ9G*L9oauXG=;E;yB@6 z47LxYeK=0NjD3c%Ew$vDB?Awz8`*poxz-u<8DTjG4l~YSBj|&ipxQ8tapVTL7-BTZ z2eUyH1~M8DYdk0DTF*Y&xEDTn*#@bjzE`U6&h`p7RvZy7%QRq9rd3UNQ=HKXUx(Az zcAr0e0qgJT<5GKf8#HqRg)w}2o6B*P7* zKtPK7%Zl-62LLG65HR}eLBRvN*!!O6y!6CVYvBRhR62S1rqPSvn~7-Q06aq$4lv++ zI}lFTx#K+#OUUQLwO5ca3T6Xy^G6cbo)Ys-f_fh|x`$jJ^5yA@{KiUjcQ2<~9+1D$$vM1q7MlM+G*e;;ep!6UP1QCMsA_o^) zBoSV{2l5bV4_!Ed-E++Lj)iwQ>^QGq!Mk|hYQdh0*&!Vu&oQ(n0QSrb19C8|ILCIL zL+W?Jp7z0xwb$wgi7s`)?#h%=+yN0dsW#w=9B$)X6EyeP%Yx=R*bvyuxN~VKiSYde zKo5n&aQ%Vw2!;ERp3(@DlMED$JUmW&ZVUV1mv*oqFdB4tuIJVfU8mw{~$iLse5%lI*Ghch3>m0XLG7_ z4)PRogRTq|3mT(j8c_r-&JQmdw`u6P0iTGtzt1ly;?h&EiJ;p;%14=x-SFFfA%E*S z0v>MfTHx7TkIOG|cF5QRjEpE;Zs zn^wgCcS`GF)B4t@h4H2j;a#we6Y@fhQe$*YD6M;a0YBGaE%4vY7Q;7(tQ9aA4jo)p zH$`D{SaM(q);2*oNlUdUyjT<%0Bd28| zhN3fal< zgnL5vUrema<;!y+`IKwpGc~wAz;S{M`3mw0_U%=0YTAVB9SjPN6(^`dc*49mwQS*! zk;8}$m3xjU=|XP#aKc;L#*m4A_#iIKBzJNW7mM_i2O^Y0`0zAYE^ql6`Q(;3qaD(> zkX!JtabJ@bh!vTcI4Lt&LnU2Sv?yL;L5osD3*ch59u^OK(f;DRek6I|#Z8lTv~iHe zNSd!rt$k+X<`idUaAP2jkY|LY@utiNUoRH<#q&v?wJ`W_6Y`6(OCH{SDDMirRJ=sU zFZcxFs^h@lW^@heo)PtocILV8rx<5LxXhux2!i+K&_350`?LY?L08PfBCw}b?1S12 z&2B?>1?UD##9SUy3iY&QaDd>Uyvjz{N8rPKk`{cbrMKaOKy0*W<9zr#Osv4)b;U;i z0Ild4ffskL`0)Cj&d7_GCRJC3OPCvG?j~>(kx`pN19IL#rPz!6#aKn9?RS?h)(*E3)r74=jB^;IHxXHE6Y&(Cj@-zF+iU~1G?&CxsZ zz7|$IDaW*fsOu8v=TQI3zVQee)|Fyf=f3kj+iK$rnNp!|A>F~mS1vASOkyMeUri>n zsSf^37Rcce5N~?6*TxNdq{08k_b_?$PxtUUJHI^yU-Eng%en24K44uy`=k6$rWrtRt$4W>j3ivrn-cZJDd-RcyFQ{Ph<2MR4_Ij!q-p)n~G|Qu|9k% zIq;Zr`&oJe>m!bf$g#|dq43%}09Nu>+77lQAI}y>0x<-Pp*$v# zcQz_Ii0e$*de7SMgTE>71@UPE{=(+IPmM#AF>MN zicx5n9F-oGPUULCOaxXTl-fh`qe$;r8!u_DL~ReTZx~u_<|fIg7s1oT@sg2JFORTd zMoIPpHHw?@1V*IwBqpL(v3_FxOca&)kPU^WiSL^YJ@&l48PU^sUf_?fS!ePS#K%N| zKMbs8YwCfCdmzd($V#=5&S)=^!AAa45oCX{)`deA*uQPpk?#zrCZV4lbbP)K zSP}LR#b&KY{?YLf9Yq}uuc_ktKl0$9+w4X6mJvipU)Cp6Ej2l6o#j<^Rp&HrNFysV z(k#_EoQ^!VQuv82xruwnCzBROb0c$+ONmM@n}4374IA6*%<3h&ieyeRXE6g=z2H<| zd_>^N?F0+1Q>8Cq7Qha);0OEFFdFKrn6gwGaaRk`QRIqpAF>6Xsiol(W~KY%fVY}b zE%}RF8)_rZ()1Mxn7J)sfq5q@g)M=1ncET;z~$l~f3u?YnWUyNMpi{066Q10jdKY$ z?OAay+{f(2!;YRDyTE;2-JP(XUGql=%77ge5q8^; zz>U|CTX5UWcA|!SzdOu=mRUuf1>FV$5y3zs_ZUNdAi(^~<&4_#Oz*b{q9N&*N-6`t zbpNFVQ77(XtgvaL{M>9mPBzb7+))d?c0&%0lhFObpH!r!A)CUEYzl{iD}QkoYMFeC zVQO{pEw{%kbh@4Gg*_HnE9W!LYNLxr$vKo97g#GN&fG?F#)8A`((lkQ>&O(QM@>9D z*0VODhrveg1HW}7U-T}vbHevxfqf5q9QqGpTb46!k_wGG2fZP1^C^=k;Iv4)Grj+e zkx(&M7gvzZ0r{5~Rj$8UaM+_{fz|xZp$Rgk@DRdI%mq`Z+`(#<8{}3uE9SFvI40&@ zOqMWr+sZVrrG{23D+?~T{DhtfV!)MvD(yOz8cHDy1aG!FwNAElCngu}y?t zg_>>haB`n1Y-k)l>Lqyr2i6w3+dmUuxd?|LVr}Hj1(Pl%;+nN{xG9UwW=Ds4LC{sz3kXmW;>e7KUWb{+!0iaG*e2Z;@X=485!;P>iFN)Cl(G1M5l z81e1t@Gm@X<8=npX%Fnl_vj??TzbnMrj6&f1GnsqZNSNOZ$odCz=hMtg3B(}AM~NV zAU<6D);F_3>%xT4FfrjWUEuO8ow)^7{sjvjJ5ZzD zjbdA|(Gk$WOl4e`LI~GTU}WSt2zC&b4%aX}CmltMy7CZYves4q*<0qKQ`NlC?g z>T=2!)Pj-y0C5Ay8(mZC$w5_Z=*i*Aq`7%XiM(|YC6k1?@Gt`g^d8gp3xE7bf?=tE zL0$!ae5HGOYJ4nQT!jsDQ1zoVLZv7)fUr8hav$HbNk^xhAD60PoZXTQ z1+tNx?(j8g8h5#%8-g!yD%$CaYlyHoPpAPM2G`72GX)*E?{bB)XBp^F?jC^9uT8?n zFl8X>QLPw6@?ApMXB?d4$OguSsvX0V$3cuKlSGOQxgBv5FnDRgI}Qf*{jFMJV^;$0 z?3MrM0LJI?0N+%c0ohZCd%jk)x@I9dwx%RSMItzhsf=`9|H-%DFU*|gIv4R5dl>6# z?6nEMqr00k%7L6-v1TN`J77Cc^p2$O4szU!r67S!~NE_qZd##vPLjLuW|j%6hRD|Sbw_S zna^!95sksCSXQzdzV)kYlWd8SpzG+0?BL;mR0DUn}EiTM%{f^Vt@*UNn z#ntg0r>o^VswWG>cd7CI>v39nzoVKkI@Oe<1ni4bMZD%?JR=PReE2DcA$|ipx_B)? z7a4|0Z z4gJ3Mcibmy`3|#Vkq3pjf~o%NJs+@d1-c6)1DnkBdf3@KqZr7MEw=Z(-=5?!RvuMQ~e#-Bjp+>GO3M+~W%=uE>buGy6JF-uYLPM@4YhV-5yfA+mwnr(z)rJJg zu*w=fZ_V}GH%#^qfPysi$m{XpMwUgz%t{7&0pQ3gL;FWLGY2-(7EX}RN5OQWze z-Ehm@RlXOr^nNF7{c?O6D1**=_ZG5h7i))UKi(C=yJ`9$KJU$hQGBDllykZ!dL8Bug5S-$T)J5`zwXYvC74u0*ydNsbw%Qn{|`I94L8mAu(iGhtKeZ^&N zPI@#+NyySCA<1S7Ic1S)duxigoJx=5(huL^{>rOt{M;BX8l*idg zoSWsloi%fD2fR|3pGO~gp5T8DAIWCaBqHZq!guM3#(HQONwVH|zCwoYilx&vcI9s& z&5J9xab36r-I2QmzHByhVR~a?Y~noXc@FbgaG)RMK(c%2JJ7E{zXRXpWJC!(XkX>D zz?Z{!FTT^H${v^TRZJ90iOe^~b5x;uZzf;SceGxJei&aS#_%r*Us_MSwbplYlpS?^ z7qA}qV33FSz$tbX>)DDeZ<}~uC@+Oxx0FQleM$2i<#XOl`1p5#?;wXSBgOk2y;qhy zEY_o33*!6KB=bA*20TG{Sl)oC9vaeiPsM-eK`wwR8yYu;X}> zJnwhV&1e>!NmudRTy`DT%?bk6<2f;weRn{{+pu0E?|OxvBeisC;>*s+O(eeL+BEox z>)f{QX)Wq) zy{aG%K z$B|JId1bvt`xL9NlbwmC7AOeNP&FbFC;WQsl2gm5Rwo#0Heu};t%}yht~pZf7^3-+ z8Z;!7cDkdHI)mgxYu`^%$6W|tBYbirkXXbW4Gy#(?MdziYW*2RNwO9{gHeT<>~1cx zAphS&Bs=J8ttyRQ<4*Uw>Njg{1HZJlz@BHoZU^k}^?Iu^?AEFb*ytb+oD(Q(uA?La zxsJRd!|)~6Ah%vVt}XJ?C*Rluu~^E1q8xBlk$9jF5x8RPjBH&6URtj&l-fh0ECBaE z2z>x2i*pPjS~o?ra!on{7Y1dgq16EDXURwN2ia--%x2-tj%jneFtrsh>0jYKQ6EgC za&phJ=xv9jXi5vg*}xka;NUcx+5tBFq5dvl<9u)&un`~3!~esY5javiI1HpiV>?2R zXZgqQL`#McF;ATWZ^h+A#peotX3eYUU%g2iCE$er=y86pj@GoPd58KpM@C>mk&F)3 z62QaVP*9&ko^X)|#sk6JjfqNNo&rX!%M;wq+8ll_L`x-;47*;?&B5s3?+QpVITAaGQFXoxYaXRr*~TTKdm{a7W(92Jw!CUcg(Ny39Hw2 zx5Uj7IhMRuL#)?{;LFE)Y3>xW#DwQe<6oHph1h87;t#w)KVKaHeys9(%=t zPc!@;-8b|hpt}L#KqC)Sq(dSIg|G^mRHJ5;(mXgDBQPPe zv2HfO(-P}KHh6PW{8JkcyfLylD7C?x)L_)U@OYD0i{D+uXrvsst9ES08j*pxLS{dI zJMnj0nfU#Df~5_9AH9irPh)t8z(>evS6C$F%uq@=lEmsc;9SS8Gu~{ln1M@ti31FVOd&;yqLd_8W=1-i z_oTU;z$u8=$)(}_nW0T4oXD=^?+@PFiti}n*zfg$bVc^la3C3hoZ14D9=a+`2lB;6l@C$#)t^0MMf7bK*$gk=V>Xxvp;r$vmd9B zkLQe1q+?xZnuI;5{&Sy*U0*9Hnsf_zx~032uB?JXq$?XA7bP?333LWN?ZsPQux3pgO|Gzt0!-E$OG#fAh!9wy`U zBVok)*$^2#mXgm(fy6dsSyqqPQMEoeKDDA$6Hf?p^GA;G#b z&jG_~{E|AIF)>_csyTx*oNGHnXUKU(=nxe()K>mSRoISyq(A z^GLV%EdTrrz2_(DcSSz_6oS=~<9>wA20t4b9?D^;aNWEeKKfhh1_ZBhzV*TfU5wp= z&Wgax6pIm=-2q9nb>++Q?9xar)*P|sH)j4V>e$WM zjkb*5b@+ZjZH0Q5w8}s ztC}q4k=^;}gzmU-IG_Jg-}>9%NUBF2Bi`+{Bo9!JN<3|;Kqci-l%2w02`oD`3QnOS z37)f!w9QxWtP>&3uxUu-jtn+%M9S`072r z&rZZkchcLKla5?CZ~6-QFY!KyXnBn^ILi5l#S0~iE|m?*EJK9ii0ft+)25}RHBM`c z26{+hX`XH5i~s*<+wl7*&KAA^jqV@WV|CoSx^ElZHLDK$e_e)eXe0(UIFNX#$ke#Nnq$c;tY8{I(Iia^R-nrTrGz&lX_#L> zhh?(#gxJ>J{7UHP|Eo5~|I|MFZ*32v=f@TvxKHqaU4>*tr8IOI8ErCTB&xyqfduvn zT*?*&)nJzS@xcFv9mD(K3A>8h`mk$we*;K#xFSi5^Gb9S-pbYr9iu5F-a*m*j+>Aq zU;j?q=x?xXM6Xey`yqQylS+UidcPzv|JeklY%=@2dz)?|eTOFCQ5yp!=}@o9fIgFy zoDRI9^Z5EmVIT0dRN{7fyC#8{(BDz$50%)zdp5aEur&3G3hWa_&JwIW61?OTv5Ju- zcfU67W(IPQflFoz?j|_~g`W#bvK&sg61D;_c%%$yl%#^usD8n?mC4DBCFdn0={d`l zUJu=X6Juj@=vE3`)Xe`vUoL{aTqS<5h-lpxG=RPVo>!&xG^Bf}F_;|}2d@x7L_QK( z+hmhM+qKz5#g}2mWTXAG%d2k?ZK*GPJ*uLKMxiCNYzF)SIw*SE3KB)l0x~8gB0VfJ zJP2J8qgE7!M#?{qp2ZF^`AaKyxiN5IL{^$gYp5ZPyE)v_0q5 z!@-jRkuGHUSixMkSrh&S+prh2If$k)RSb)Yqs1J(;FdQmbiMl5i%jZC445~>UhLo?hM*xPsqsC^Ti z55EgSUb+4sd2a$=WpO?HKQqr=l6!A9AnZ#*SOf&J5+bNcAS{ZY0wSQ+0D(k8f=O`e zuTZPi)>`-01ytOSDplLs*1gt>Ytf2J)uL9>5b;6+LF-a;|KC~ek_EN>yzl@0yr0)N z%yXY*X3m*2=bSln=8Wop#sd22CeDR9MeSzktS80>2GvEmu+a3BKs%=qIN;*id3#==5Wf9}h@7Q7orwR=tya+tp$>w( zb>0M^&XHhrnLaRfA=3wXd?mn8EsmxS;y6-$0C^gxf92Yn#1W<4yTF!jy1|rh?3UT8 z4-)+4%f(1>+F{N}B94nWs7;NBsExi?;u%TC=U>xJ!dNJ0ty}L`?omDv6rQ+Aac6(! z(B5qjKthRe;kS5(iRthPb#5@%a0`~!oc^UmKGj6Y5Il*CR3bd+B?LutTRiFVyx2GC zeBqtW|Z(t6({Lp?|y}EIOiyQ9+Z6A_ z`&M^`$5xBPI7#E(_r*yTHm+TtsG)5crKzk5I>&MeNCU(m&9C$vBq4?Z>mF+UEFWj= zv8U`X>mMBCi)Xj$CA|)UrCDteMaN3fofTgbA-aKH717gZg?H8={ELkrN4|o4o~`d) z{5XiEhke<>IL&Uf>?{>T4;NG^GJsrpRbyU;A8T@k`8t@hwN}TnY zMlNd`J-Rk{yj{?{-*m=OROjZT(11EAG^Tqe2DzWcc~m;$JE2^a7XB?~EJa4Da{zsJ z#b}E)BYdP@>v+t0N$F*yvrs~ZVEdBgY_Tdu3V6<9%vn2Rr!xTu=vau#WUBfO`;mWx zZ@em(%TW%x4&`1enJ+t4rOQSIC}Om5CsbFnOz!$tFdZPMoKWfbBoeK@fICRdxlIN zq5L^o}FrJ7+MENuwj&o3z0$7N=px8zCa@|heC4H9a1jAa$)udT8o8^ z&7|jf#&=rVwv|rpcg&f0UCxU7Uv@qf`kS}6@ypTro0+v$35lkseiBo&xt7yMj_%jr951NG zS_yC$`nCU834BuY)wsUf`I#7@^!+}{D1op?cF=8ZHQS0WEn)J580n@fo%90L^EcN^VToBKAa{k02Oh$_fq~9ISdLnCys2I#@S+xYaTBd-X zBwrLi+Mj||B|-z)_=ZaKk5)@nF?i;693PO;HFE0I{LWeGWuJz^Gv8i_!^>R*Ki25=?IH#C+saNTO>ZC4CaKIakwc6xl-x&e)H9w(| zIA%p?4<0%*IXQYpw62)Y-75SMXH&B+Y+!mS!pSGb$#LeKIt6>T^Qpx~8KMo?+|@c# z&o(qReF1iSZN%@7*6Q_`wvq1Fh~m`y}+i4m8>`L&?ZKiU&Nz_iEjA zKq^YPRP0FE7Pal0wR2agPb+yK=>t?WXL_GL3?@5wMb1g<-|!##$FPR%f7QgD)v*)b z&|`3uTq#k|Cc}#gBAZ5_S%Oy-sQV})+heicl;t=5qt2n zOG||)omV>VgyUz=s+cB@6~|7UGPzjI#37+keR?q)*K1y*;qN~(^YPJYynJGCfxrJL z&N-!x(~brgqXzfK4j@P4HOji+1Rn@d=*Z>Bv}71lckmTrQc_XxV_4wGM~j82Q-zp% z{M6%TvzxK(STRM=tipn5!+Pn4LEHar-zxgt>eqYL5_H=CN6v84u!q#xN`SrEX=jeA z_AIlofUg!DP}!Tc&mU7@m^z%kM?cuXgY<+A(%jHEAKaN<4v=^WJYJ!vMj-0;Q#HjQ06jsgJ>0v&xK#HA4%y?)y{3i zl7j{^(Ir_(K!zlcwnX2R)~7@X_df9xS@7yniz}ne$)s6>2lXE|U|9SNSdJ!z7p;nf z*{d~A)wxR1z>Uzrv{K9`)J1SzC9o2!P)iK`V19Nf$5wHe^&4Hb_phdG_%CHMAgjj> zR*}|vs6pvq(X&>ywN(M6PNwc$+qa&zYGhzg)tev#t2v`+sq;$dkZ%xwt`&b{(?m+D z2+5R?@<{$JlJ8r;NECYC`f?|E$JBV{jEd>g%F9Z-$-0bAvd-Ax6J%YrSjb%ItkPBA zB<9%56^9Y1Ln$W#eu^?-^&sPfPz^cun4_n5lW)2)(3DzVJ;V4x>anf$W9WE3yqf*; z->e@KjSI7-KbdF+-F0NHFWS$~8(&{k^IT}` zzdEHRqN z6<2xHe@dUpHS%5g0EkS=hAt?ZnW)l}T*B|`b$RQL7^^|^^&X2=3a|ukHBXcY-GyZRymnHbW)j7Y0m#Ouq=o!CJ*Eft0 z7^t8zwG++Dn$BW1%hk(7QJ*))lX7;$xD2k%T9M{sISSUL8rHh0scQ7cN{=m=CKRun zteMvLuuP;Yu*V0h{xmRXUX}nuwex^or#n0hP!rtYFi==H%vz~|L-Vl&IR4k4QEXt* z^S}gHZWGJC6&3&i9O8|4?-3oZP4!6vEVw8z-eR!$o!fM*Yk2=R^@6Ljkx68z_K7Ouq887WN`cavx=QBH=Z$ievL52-gjv1^OBs=O{8%J4x z8O4wq)?Dm1r-8YcL%-TVV`5CQRYnLa(}s&|ku_3z6S2EQ^WR0x<)->IpX73svpd6a zMmys?#tu;}+TfRHC1Y?r7(58aLPw4s5yTlmmLHK5!lk>+@DNTW!%HKDF;B=IU#d5R z=> zm!q7oxINmr%!92&@o>=qK4{Zu-6EeOM-DeF8kMbE6l+H!W3g@0=F={1QaY02FF0Er zzD?sgpcgae9jE%{DAgA6l>2UEjnXr^?dkD3Be3Gia^)$bv{Yg^os4N!g^k5jJRcJ1 z?Xe;4M~+bYeUgli`Y|0oPt3Q7dN5M!dOY8up0xj<9;F{#W&Bt4z6ev&XiMYnKXik0nrvL?~V9xXL1`kHDedO2E-=21ja5z_=wKD} zHZwEZ?hmQ}cP|*ftO`|stHs?S>gVjfUKvFG^5~Fc?2XLUO^DTO7{E8zJa8aUi^mKc zGit=JA)NojxemH!O|!)v_xG@tyHzS(i52r6Y(MDGY9#~59Tj$6`ANlM#w*qk-2e?< zt2^%RVeNJ+z7>vw>)ZS#)wZXkg@^s>}o6;d)_mO$0pdcw#Z@Z zqGwNNj!5>!U_%YGb}cqr`F%-P@O=RyM)=ru6$Lf{N^>ZC24?|jV2!;;+qZl_QuW2` zTYhH?bHtF-P+EVC2qtxc7qucP$1x2j1(KtOvoB2*!C=yS6Ui(Fd*ZUSGd+Gbd&%VD zN%?tQ+(%<)vunHF?>gf^+%5vFo-2G{%JK@78ZZCb)Szr47B9R>Gij5GR9ZIeS@1CS& z{Oh9FK?Nh4>ry8ebmph%zE>^-47eC>QZ-$eXU3g&>Xf5OiYFBow=ft zn4*nQcE$%%NOa{@`p#QOAspOvsgC*V6AUIKwGc!?8<#!KXG@G^wJ@6d_%Phoii z)9P&}Haq8*HWi4ZU^l!3h&;$TQ6QL9&5nLgAgKrB1OnfVkjcgBK!@%KG5ux6%kC~X z*$lhrrF;;M94JGb28=H`l|4eLrF%*+7RDwyWs5B`MaDeOD``GsVUP$FjOuALFg;c ziN5^hb3{rhWED_!755IaxWv{G45Z>d6CH$|>8vvn6$+0d)@121N3%531FdC5t`e$+;Mht^+X?q}s3ZWmRyC|YyqJiX2!pQKYF5}P0 zB(IKR6XnyYZs!_@BaIy+o0>|`o>Y+QcEJ^!j=JF~ikFaz61os~BE6JvuLHUhx_oWUPFOC1-k!f-}$lEl<7$#+^$M3k91hLGg? z+;Wcbjgpb&*F$_acA=qL&P{dBFFhwu1fb@G-3>^uPzro0C7ESR0-!=Yr$xtGe2}3= zC!eGYyvd-rMbuE9((i@{F(~7a3)19F`Vewb_wI{4mMjab2gWz zbFO<*q7X9?R3^pH5&$i%u?JYRwv6fJxD=J(8}WL57rfqa!BFRg z(mus`GSF2J8VE`aYC}k#(3$@Yh6k0F#fnG{DXIRS_tN6hk>9POqWzSl*PIgiiMVfK zmRb)UJ4ObAg(w_3%=lwO3>o>LT;G{7EC z?t|IDP?EsC#{>05wUJb!@TR837-H|VUO^A!t=dP^V&Wx3Q+v9l_R>;=#?li@Pdsk+ zteNFyit48-F_Yhg>ifiaq|)7z`gP$2o5TsCLXF6gA|*5tjy?gDcH#@(^2s7pnhHli zW$-7(1vD%w5Q3Ex0@j~`pf=;6M@f^JspQ|0W5b zUR5g6QjZg%l-VG*8|Uzs6P>se!D8^3=7f^dLQ5@mM)68Su&C0nc}OqALpo#C;Pj+< zbLZd@P<~iG(%bS8HP7k1z7OBm>-#a8!<lGlRW5viYIhqwr23g(Sv+W2_;O8;+!_MM^3Ajl@5!cm|ULO z@lZT|4)aiBx7aFn;P=h>^h;1WI389u8 z5<=<(jSuXSj{D<#-Kd*2Y>kz(&<%(c)We=PJO4~(4j!G~tIhv7DMh!wjldhJ>+-2S zzzn`X`S_J;dt$;G`4;heT-wp&a+t40;dNCo1{X7BSr>St6St%kK@hy4GQ%4Lu$0ES zg>v3kkcUhlp-kN76u{ zvlDv&LmaiE4bP$Ys;+h?WX^1GlAW#Atg~~obCq2@XLwiKD3i3}nFcot)c8)o&1Rw` zR66ICuFDj`z%Ur*P~vb$aYSrJi=!h%p!6_!0!dCVY3VnkNf6#CC!6z2`z4?#Mcc9s ze$rICV)!Ax@9e=&eQ9mBNKP7uaAC(*982EvLXlL8bkP{XT}@A{QPO-q?f89IR4GK| z=T01tvXs*mO)T!4{sK?l4F7|j@g#2NWS_w*hWkMHUlczHG!#rCo_tb>tu~?L&{=A_ zk{k~$Zz8_+Oh+k(j)YK}tvVsP(>PL8MBgd00kJ1SbGtA=S?87efv)Q>{^mZ;Oy@)w? zYHWZd5Kwf&+ZiX(DO)gIq$USbW6THwjjal%10& z(3F~!W6PO53d=wu(yV0wdJ16*V4W&Dw>5;dBn>YJJ^1=e!*{b2d8HWg8aq}Ezp*7_ zOO%0+9sWI%S-SSIq5t6HdOjEDRpM6XcOuKVru538%zlqx_B$F~33>}e>CG48S9wf; zA-5z_ojA38u&K2@UG`dICPxeEp)*ACAR>P>2PA zxq346m=r^;ul#5%2#_IL0euN*jhYOi<5tn-VGyg(%3N!bI@Ysi+SD#&nl_a#V9w!* z;+64xlXFmK_|t8R&f%5L zP+eLzdPFw%gBbqI5tjycQCwN8fjZ*yza7eq5AAd6->$~-48`XdHQ;EA^L--u;uA0k z)gdAF9(D{C*>r?MNrWLsd6;QkK`%F@q@)Z^8BAQu%w8&*n;Cyt3afkuM6$}#>KdR-yG*JX?Nf^`Mr5{zTZB1mFsp4e?n z6O>f-Fqe&amjG?Fedffr3_R1-ri(al@C^6qbp+klrkz{FD%KJ32k2bBGOlW46J6X> z%e&S9t(x}hHGz2h(OEuZO@Q_fSBu#ATX@vbz)5UGP4Xt41tkd%(e4Qb_Q05vsP(21 zD=YqD?EbO#WA{J#P33QpSb7rumgKEgBY=%XD_NU63=o~GPfyT==0l?`I25K;UU~C4FhtZ*iC+G;O53tcMYgRBMmQJ)9 zpWjnW*-U|e!JZP;0||AiLcw7ALEGCC`e8FZ*S#EUpM}F^KoOG1AMksy-Y})YZEvaL z4~l@-AHZKp$28~(oKd4j6^+6q(nsxcR-_g4dr`XKB4b-m=$p-zFFWk4=~5#V1PHf> zXQ8c{iUZN@G@WS8Mv(2P+8CVLUY-EwtpyPgNkmnc^IMDQ!TKl=n>|xgSkzd&IYuLj~ zj1M@eLmeJO94=J2LFyP1f^nyVq1tlwlvm7V&s`e!re{+_A!8?vV6&!gXS6X5ig zA0_;yF<6u6v?S#2VL{CvnXM?oZgPaC4V>Dh5Q7t&!ivGhn>tz}?uZszTO(qNh(S2v z`7~1mvtDm>)xIZ?b;Sx=B`DQc>UhX|udk#FtXn18yxL11?MFrHoUF!S#D@h5^&~oq z6g(YUJa>71qsooJqx2kg20P_Op`cvh5d7a3-cyT}+7ll;Q_;h^pE0^s=A(xZt2*I~ zQ5cy~%5a13au%!*%6+)YnWFc5ZZy6xxr(RY%%%0RB1odBG{4)~uBO3iNfdoi;R2iXFqU&pQonD5kr*?82@{9ICcvmxJO2|HpXvhR7SYbBAmBG& z1pJ-*5}JvsBuWv)ny03Y-_WHaMvN#JQ850EsfWdht=IA_g#vkfFY{8IjSL!KeAV}yIC25&P-qHeNqX1z1i7= zT*m)y1Ue$?TuJO}?}86+d9l(Kqc}lL17&zPe-lcI3i5Na2?eLoVSKj?E>cxL#BhNO zs2Sv}D{UBswL2GE%tV3sIUL0&p|&csH?t*$6^jkLqyqDeQ$SLZc0oy`j3`=^?l^v2 zP821ohZIga?)F{f(>~P+IN2(_@Y`vnn1Q;C@hHqzrR#BkYroy-09WI?<3aD~o~t^+ ztz-oXm6Gv?g_iLRBJ@bpqZ<6w3C?m6Aaj~vCL=zUe5922QjI@dS(QX{~<#~CMTAM!-I z&l52ZNfHf$MET0!XO=(iM`+r+MSO%DAqEu|I=5?^;kXDuA``OGp&Wf&U#F8n@R=Ri zcO>qE#(7r5aJ=VqGZqtI*dkUl7TL`=9nH;<8zlLb`lCt4iGBUTh(Ra zx9Kq!gOM@zy+O|RN>5`o$xnH{Bhc)+L+UHfS2|vF3BCu7s~fngat*0AOE5O{y2yR_ z4G+OO$N9y**+)YViDWTy#6UMGc@S?T>AiYB6<7l2RvrHiFGuS+%=r}a+5Vw4jWMH% zT0rdT-W+<@f80o)FK4(cDoXFA;z}3g6crSWF3Qd<$jr&;mzgd4sL<2J8KXw!4EJTa z`9(KYJ@ejs&z*T~;a6YXA*%oU=Q}!n`}I4QTz=|#qeoq^@aLCac-$N@Y;Pu`t90hH zXE!byyy4)+f2R#zFAm-D%!#wbXVXvI`zYK6d@kwO<5BRyvvfQV=ZY#Qt5Nb z`d+BKT=9zb6SuRgS2Xm(7MmrCZyE<%t-VG;Rl1;ck{*AgR;!e!v=+?NJG0|P?Cs&7Ze*^_PHv3s^|EE9L}R{SE?SxiSZD}+NLT);Ydm{hu;ufkb{U~!38Z$ZzaGq z*2454buq?!I){b$qu&Zq{InzL03L5|!>2Sn2TUCXO+nA0i6f%i+4a^7>_-`~lSMf6fkJ>| zE_KW`aLiS8wA(t4{BCvV=6_oqst)Eb-S#YafeA&|v)XK0K&7>N79`9Z z9@N*K9ditA@4iQ2qpM=dervh3{BY$?p}mh7yvO(1Feb2HILPWA_u0TP5fdKoYB&%5 z5ZhwIMpzYmQxU1zWn*m@Wwd>_XNnpR@jW(-2hMCz{H(`4Ha@k-22;#x-f^k$G^ke3 zo7AR`Xg4#N87{Jg-d&TV&u(!J1CKlRe?L5ORuKD1@&EW)AhSAdbRRWiVwM^cAKUULP(FK8 zFeBO6v_zw1%fHLS_)OFHu%~ED+Juge1*T=ZL9_l>y^pGXkMFk^8+|uX_Kt7ZZ=aGJ z+i#D>CbSwhn~E1zO4lGWPD%<9<2py08T$=iV8HA2Md>%ajKY@qGVx^wm@V$z_S(mM z%SLzH==+i3`=b>uKQXxUo({akVLJR?`xN5qd_%i23nn&2h#q&@(+qHabjNkxhrEAL zI9D-21u+kljB|TMzEb)akvY&Dh3g%{wlSPwJWA*|{?%wh95RRFdHmdaHQLlx9cO;B zQ68i|;bSym7zYhtA6$AMS!Bs9<&;FdfsS8#R+&A;0aY&{B~`uBANg8oNg);?sMa?q zlf}cqre2gLqLWpd`WfQ*AF(ghF8rxud=l!;8fNyRV!arhHQI)-P7*`qP{L2C`hnAP z$mkUMjGW`ZIp;^P{Z%-GIO*LhEtP$*1Sx@v33jQs$r=4fDPRZgd9HnbSHj(4{jT0zXnc4ZC%s!r+?4sfft9NB&Wam#RDjb#LX8Mc7 zeS7wZReOc#==k{SygOch9gRz@y6&25u6z0p&ovu2Hb1?6-}=Gs=^HN^yy5GNuix5y z!8zB<)(wMULI1b6UpN!#OU3gt9W4K-ToP*#x|bu%vHQT`T$aP!Grc%V;lnOC)HuGA zO&@y)e^X4ZS5m)m#TvaCsI?h6qq8%tYJ0*RXs@2EU!`?8=(1mbx_+=s+9=)}yrJWX zyE~59`1R+5*F(O}Na*1Ev}1%rWYE67dnqNvPrM!GG;GZrGLYK+NiJ-cRw;|>638aW zkGUE}oNaY#FI|d%`iLBqL!}~S^g`!04bpnHUuoKz1w!fEY}iEQE-DsU^*hA|w{FyhfLZudb z)dU=cK@ESOFU2>V0W;hgu5?_D*I@r~y%VMi1--ii09B8E36kBvfBl~2V*AA%yT#J) zcN|;Q@&1Lh{|?V38&4a&;a?j&0%B;&h7AKdwsp+zzkYp+sP4FX@OtPvto5}MI)3cC zv-24oz_m$m1_$%xRBuh>F=tijis)G!>LiZXIUMOp&fo#P(>;O?DxM_8u>qp~`&ijY z0y)a^6+H|9)G#?mw}_t2F?C9}(>a1R9!1BGy>GIQFRIrQcT%^9a|cv=JU7#x%F;8U z=MQA0vppHqF58}I=DW7{R>vf9Xs#P48@1m0$JD(YB4rJ8R zU&UK172I9*e+%z_Sy$|2vaWRjm%l9mE_i{$t?&21#h%}I?BM|^NdPcpU?>^R?3Rzn zQDKZ-$;nhIrlGRg>KJZhy4fIg}or++5( z5UNjMPb%34>rwS^R+(H0Cqh=z(^`-Wz_C9wJHysfLO-oE@Wl7$(of^4hxu7-e=cfU zd~fcM!2qLd+;)Sms=)5bb=X)wJUhAv*RRj$tDt|bG_X`Cy`$B@;#oi)=!l7Xa8)%! zha{G+dZJV5sML0!Eu}+j!q}03VURj?ZU7TvmUry(44gR zL*n(p8^+(41q)%h930QDj0;BWshe`#%_2|aZ4!sR-*N9{@A~if`m;OUytrfA1>%r5 zulLvY$&-6;*wFjypKVO-xJmH_(X>&n>rMDG;Y8yqW-BO%4jPz7@E5^sigE5yo#V3M znLUpxvPBXzb?0Q-t@bsW)96?-WWPm5dUF49-kc2niV9q9>+p}BL|ov${d)H+D7L(< zz^(sa``eF1QnRy@LqmHFm^Wef%CT;px~zf~gJRhNQ!G!BQPqR5M!3 z2^8BUr6bKmj+GKoVNn#59)<@OxCgElYcB2>)7Y`I!i@&e#jb8|Z-ZX9Ux9nWF9~q4uH)1* zUwf^x(>WGdPiGu{rY}lx_6^jjOw>x zLx^L~yul3{`gOeRHT+SZTWMmV);O-ud4$`Xi}@|*RT}R|wFc{0S1KEam2)bihg6za zKg_>8+swFDXSO>>fH1$<8QI*iLD`bjyiD!uhZf`WGRDoBsAnF(+Gt=5pK4`0?%Ybi zYdt$-ex`$?!+Yff<~S<0JlA4|`04%5%9W+~d6jY$Gqs+eOr^>-#Hq;0P^aPY zpHy+^#RA&rQjt2_k)JBwy&juU8-}8OPj9Fyqd-x=Sg@V{#Jld!FHiidDlh(@|F_H< zD$bmqr*CD6OJYxlsgm_wfyH;2y_VEE)?T};M&;RS536sp?6nvBuG$r%{_}A%{r&dZ z554`_UbBzgX|~t6;u6``ydR>R&+K)IGXXzzb3fG?D~j!PdO~|L657*Cx4~tgB~$Y; zf)I!LS~z|2y*1YoXN}+6YnSr>Vy`{UC~?4Ed$H8_v)4Xng#44e_B+SP-S#@!3Ay9# zbJA& zSW{n@l{XZ@z0`G|9JCzKRU$j=?0x4gJ;OxF0?tjSs9 z8?y59v&PTl{oJha=Vj#;W{p2LYxwZ2@rz8gsyX9rEeQ?Ds%gxs%xY?=Tv4^AvSD>r z{YneU1k-5q?}X*`Yo=8<)HF8LRMutjc~wJGV}0G6n&nk>ja4hM*43@3YRGD;uF5J~ zTe+OfJ~=Wg3Q+!p-0G&LwMR{yc<#C9PN>vxO{i~JHL=!|(KvC=>}eHq=U0s9O=pHv z@6PL{L6sU)xDYB~4TI_EnLPK~n)2MYCcCim+3RqIsoE8oe5*bAJKxwnkeM9PAf z)bjl@?pE>UI{mAm)0amb=8L1grNpc*Wu8I}4NfENQ?1XUEfYw&{N-a(Eg-B;yp8I* ziNBS!ZJlmuHQyPSk8sZ6n+Z;dQ^>yxs_~Sw995vu8N+wufg#J8tgjmQH;;GJ-I@HW z-p@%Pc})FX{ws6g%U)z|u1gvuI-@rKtXB0@h0Ur^;DF-r%g}UOn)1 z?v)9hFrC<66LgQRai-Cis!tm!v4)Zq=1lDhn@!wT*qp<&<UqJa^hu8pbZUB&qOev*p5c- z%yDJ|LxnRJN~@q3Oqp;uW)$kb$XPVAhyOf-Vcu+vgX3^wEIcxab(H{oGXz&kb<&)4 zCj-vh8;eLL){uVqf(>v6q6ZFUEovy-KFh%)4I9Y_c(&Rja|FaO7G38^8Zm)}slkvB z*%dlPkY6zbQv!%noT<*yXcxyirJ$>vrcbBYGw7yS0CJpjJOG^lF!P)f5o{*|)BBu)bzjE$$E)y_ z=Sld#{RZi>1&4*82r)%W6=}|!&ikD8xyyOS`KR-i^BxNg8N_ew&7QAJ&LQoGaz21~ z9E0!`8X|@gh%HNGi{Z|#C}1PRNHI!`=8%9fVyqY^juhjajbehBC~{GP^YIWV6h-)0 z7K_Pv_8mne&8gyOaSSHMQc)(##WeOLSD*vT6tl!^ahy0_%wbpUTzoQ56eo$3#eA_q zEEK1RMdDPkSS%4siA!+0I756-oGB{BGO=8&5LIHOScNsIMx4b=x>l?ab)sIZ6=#bE z(I}e4I&qFTSDYu#7Z-@{i~kWn5bMPT@k4Q;_>s6sTr7SpE)kcCpNOA|%f!#b<>Ke! z3UQ^lN?a|j5!Z_AI92zT;(Bp|xKZ3hT=q@kW^oHKCN_)Ph~9FCxKrFEwurkq2Z{5% z#l2#i__erC+%FywzY)I`zY`C#i}4TQkK!Tmuy{l~DjpM$izmdN#FOIB;wkYL@wC`3 zo)OQA=fv~k1@WTztJoo45-*FtIlpD!%qz|xoIg5Gi=CX=@Ox*w^CRae=Th;ibFcFZ zr+oj(c}%<}UKekOzl%4;TjFi;59e~ROS~iA74M0Ea^B8O#G-9=?joYXCg*N+sOvbR z>tXS}^Q8Dd>=qxga^5WVh!*j&*vo0MVX;r_7p=tWI)EQ(yEr616`zTJiO=z<|5AJ< z{w=;19U{U2!ybg?(Sv2)$EqgL)nz~iC2?eBs!WsVGDG%~y=5QVKKsgkvcDW42g*Tm zupAOAKH#NqdyA2|O*MC$d<51k9q z(H@cIa+;hjE94A0)A`!zkhA1$d7M1ni7?NZBTtZXRkB*v$g|{XSu5AbI$1B*%ClvIY?MuM zojgaLE6oIqnE|q&vzT?H=KdamTvj+#}ub?gV$Do9pJe`EG$* z=oYz?++ugKTjCz&PI0HYN4v+k$GW9%8P?Ki?sT`po#D=OXSuW8VkNX36y}QBvp?jhGBljZrV)w`H zCGMr}Pu!onm$^T4FL!_LUg2KpUgcixUgKWtUg!S8{iS=odxLwUdy~7--Q?cv-s0Zs zZgy{TZ+Gu-?{x2Sx43t^Tisu|_qg}E+uUEf_qq4G54gW^f9w9vebD{A`v>=r?nCaw z?j!D_?qlxb?i22x+$Y^XyHB})ai4a#yU)1Ky3e`KyDzvex_@fZj1Y|yVw214ZHi? z{cfw<<{oely6x^E_fz*X_h0Vk?icQt?pN-=-LKsaH{x-yn@j9|9=5Mw=w**gvM1mP zdO|GOrh3vm>7EQvFJk2N;XL=go_?PGo&lbLoyrI4>b!}BcP5lZ~@usSVsuiAD%PJc}t5-EtRn^s2)~%>n?pD;Ta;xfA zd28$IRyBI(Ro6GvdF%DR3-!P2)W5pa{DNX{R9{!$n6jdV<}@;AP`{EZ>*|}TYO880 zy)!GJjO=;)VxDD0yzD8ACo>ymXQ{_7U zI`gT!mKv6m`01@*Q?<%~TrfS)z%xDH=96?@m}`C)<`&xDB{na!dAZGJm^{yvQ2PmEx*W?Uu4TKvgH)na*Av@MfUwkxd#487Vb$F-bwcRNk#U#ZRaH0 z&PleNlWh5uZ26OH`IBrrC)svRvhAE?>n*nJEVlI(+xm)aeZ{uCVq0FZEw9*?S8U5G zw&hK>a7?yvOt$4uw&hQ@t4%q39Spdk>KrUgRVx(D=jZ0zGK&k7>l)W- zG1B0vt!b$At*vTQ{Ip_SL%n`A&sLw8XPT9lHz~OaYtWj?rm7Xm^>tNM$_iE;YN|%; znCr&i%9?Yc*P%u#u8TfEoUEy=T&^URDt$(|0eVKo42_%_GiGSykx%!XJfU&T^0mn; z>(@2ttMuhq+-k8JDbZ6~wX!J~z0p*&Jaw4@FeaW-^iTDo5@6HpgTqm~5`e=9%myouy)UT!m(!`UMR5=9`BLOt#Qur(*%K^o44Hy0FlxOYf=)m9kzih9j6cj25l zzQzfSjkyKBN|P-&8J(_f(!VOBM^r|yHRcxj^s_?qtk9xM6&x_I={huU>dJSb#$QSl z>zdHDAj>VA?wbzCl}(;%fc7j<|1|MWpezP|pfYypFEdJ{ztZHsGF_Cf(v(a9VtT1eeFJbZ>qyROu{Gf!=7CL7*yj z>94RgSDD;bVM?shS#V~&?%=BUwP{DbVd;7Kd7+sJ!!Wce;YV;*{HtJf{Mt8LGXr0Z z&iu1&%VBi7<+Dx8YYcW~+cwsiJTN=fd^!6#S#wtKxOlXpve2A_N1@t;AHF#T9kn|1%%NgWE&urDn(yn(_j40I3DqV1@Xa;f*BNxyRj#dX zY-*@qTV3U!XF;yFAkQ-(*Xt~0UiCT#QNy}5wX8>^)F=M(oowoEFm<1tP+h1Y;fL>J zQ+I>O=9{k?brzf-$5OB{eyuw;KhMbA{5&Ib^Ye_%&9}O9-XxQnQWoy z)ODs)7g`9{SqK*z2-oS%yHJe{?>hBw%ECnWQr0E@@-MWVzs}^rMe)`K&rP^qoN#@9 z{Mxs~zR?4eWv2Q1 zetJch%2F#jRS=w=@ZIc$M$Yc~-R#ca&5gG?I4_}$c?o6A>rzH=Ui_ofd7aB!m{7*T zgfbR(DI;}Z=kFHB-wj!&Y7k;Ls=f|cerg^}i+_=xz*x^^c51R;ur$C$LcSt>K;KTgy4^ zgM>mY)6@^r;v7@|PETN%`bI_~r!-|54r!hy@<;nL4qLL~isr82isqX{o@k%OzX@6H zXC4^Vr>}c;VtnSY;dlBvBaz$Lr}0vQhR5mq=?NT8-$5Z{@WZ7Bk1E`IeC67;mGXpja_%|=p02|^xw_t6fPu(X z<4&ut38|N(MW@*Z(cb~B@tLMsdzAi>L{0i4Sv5>w^|3~$=%@OoceQGSzur`@C0s%I zG+DPUln78-mrq0XeO*MzKGZ(~+KQzwbzz0McFJp~w1svmTWF`Ug?1`iXs5D;xpsYznZ_3HDrUo>Jj_DCH*HGroFs;rvhKsxk z0}Z*xN?wJT_>=3_=glw%FXqA;3UX`Mum*}kYe*<8ve+oH*eSBw{ zVhepqG`IK5tU;vA8luW9*2`?~O|#`sv*k~-y*JH1pKhO9!)c*4oEA>Ey)oUwG2Qmc zblbk^wtdrW{nKrGrrUN*x4kso!a3cxYr3ts!nUKr)>C2Ysj&4_*m^2#Jrx%23R_Qw zt+&F~S7Ga`u=Q2g`YLRFwm%DJSUk+I_0O>N&#?8+u=UTd_06#L8Jk9K;S5uLksX~y zc61e)(Un(W3~J8LI_I~A-_SX~E&PVg`EB7hbk1)JzoGNI3Pb1Q7Jft5{I>AUu=UNb@ESVj zc?r{fWp_~QFF!ZRPD*t3xrHSf{Mpd!t*cx0GT;{t%N8!98v@LX%@4B?j zX`4fb(oPQCr?0jJ`}%H4=^r{2tPW0PY4eG|-cUnub7+h2&eU4pZ&PbiYePGOn*+N- zU#6}MeW{+L-oRGFZ6U|^knaiKbH0~+ukozb_qMN%eKLdn!~LiF&+xBEZAfkKUz4`k z|DgYkR2ERF?c}u0!9S>4lLo4%Npq4;Njfv>f|M_lE>B&Vv?b}W;AW!nk4P>}F6HVd zl_!@{*Un(IsyX$BlrJgcwl>X|^w9EV(oJ#w?RQ;v? zsQ)Tea%dZOIi@6ZRba2K37o6D!M-W|)1IJzH}kJ*|CgkzQg6^tp@!fe)K~PZEhX4D zctuM8R1c7CQT?xbe@hC`2B)e&Rk!H@)nX03hFJI16}n}cQ$49GsXK}tg$w@FT@4$h zQtOw|r0+-H{jPZz{C3B;f<2DQZr3{%E)5SQ zsO@j~*d2|J-8=XMzK6%%an5e%Bm4sQ;Folwv!B0(c=mmYUm#vX_yvB2r_oZjvPkC) zJoo(0nfUAloJxH1`Z>$+w;ShF;b%9|saD%foEkjnW;tgmKR9PKesF7?HTbOE;HV7a}Seu~%9&*aaX7Ws3$ zpgxvY;sdo8|EH^+Pw;@c)(PVS^$TYoUQjnV`|*I<K3P6e&ssOA^eAWIbY%- zlqmxE2MrKGJcI^`5FSE9MT+te5~+9y9VycB3Ca}%@CYgvgOw+c7>*~cJbsplN%;JnCW@8EkC=?F&q{F=-acoGDayA;RN&il zftabhdBpK}@?0WLz?bI=F<1HSh=us=JSi68Y4eo$A-*=Rhzs$fc}rZ0AI&at6`nNj zimUOPX%*MtEpt%ZfWOQkaU&ixpNX54&kVbzJJ{TNGk!82aT}g8N#b^VWJ2ODykt_v z7JOuSiM!P(iDWTK7DSrGmdKOHxGnh1x(?nAI z!$TkE8$n5L>VNOytKE^;`2D=_MLrTkBD<;KX)z`8zL*nvO`O1&b0d4iDUqGj`aH6F zH~+Rr-sA0ky!{DpzbB4~e5~JG6#1uqqnS7U#*>#Qr-gF%P{uyWXr_$6QRC}iY&Y-j zb$aWXrbhlLj-|%wlrx9&=0@J-?f1l~;LGa_;NRVm13Wp%lY=}t2+Xg8?cI@P=flV$ z%IQUod#G^_<$WZk>ROw5yV=&dhu(NS@&Ug-)K~9=&kyl{Hdx&cG>3rZ04222##T6E zJ9m6QpHEs8`Bc42tJ}f!7nG9^JX1-F`0W(~z{3rst)y+h@L=Q$*!I$}wHfmScYy&@g@vv^!{q_NOcXM|) zeY+PZlDPi}P`nIm|KO_=d44lJ)h6bF$3>AjIEX#O)gwUuC~zvuOQt;sf#e{N90Zbs zyz!)X7)p91@+@z?$yyLc> zI%Pcw{<`giS922_a{7mk}qO+c{hzwlP(_BBPTstE`4C2GUX~9ybfJ2j@(Hp2Y|Xa z&)X^cfW_bxpne-@768rFK*P>e=pzkTmW3qCpr;lC;qM|ZI?qQwqzvGs#&}D@w4I3l zikgwlrvSl*$gNPw_TOuz~ z>c_Nf4=vjRoh;@(^{(P!8NB;};$yt~7VkdDyKnLCTfF-gVi&M^7HBC_jNS zJpg?f&eV&x+=uM$<+P|V9{IHsj=bS~8F|m?fQxt->jU5nV-+W2N4-?V8y`YAZv0E7=j+MVBW?@v(h>->hxQSU#& z-RGoY#W$W_oco5M2Z2eob$FpWaLZgI6n#4sAUQjQ2xZ57QS9(-#jT zp&p|@6c;)Gp7z0`_ac!7fbIUk^BVB9As6@Ae*dSImd`^AFYw0eP}&~kW_#rCwCC@% z#n7F!v#){FPGv%GWRQb*tteTam5X=wZb@{NO$l`IE`G z`;f0bq8%TCt=(Yj17;IR{Hr)iDDtw_kY+*03(!1HAy?YcYAE%B$PTD?GZ_3c7<`hp z{muC!&mX2|AAyg-dFlC&q2xEfW($=32yOou3Q)ZAZ7ASbaW*}E18v-bezcX*yp8Jz zNe?l0A0<78L=fy-QuCb<`;e~l+~YmcdylV=?-YMi(pmgHm!$NwkP~1IldJbH9nA<- zdy-CpL!J(llYyfIN}Iwi&Av__nd&b6)`l2cKb<;?_NHd&X?kv)Aq&fUP zlbxW|MOl1XWicV#*$ zgVc-Eo79JtN$MN7)vt(^qmP`7H9; z{zoCxbk$zA5Bk5t%qol`4e90H_6{3f1CUtEI>L$`jqq;>0hMJNnen@jNB{7 zk;aoIlD>-E>$;>dq=lq9(pu6Dq?<^aNVkwSlWr&7NrGp(TS@njwvq0m-eJxpWW{9k zf)Zw$QzGv;FY$XP`g&jZdmed7Aq{7JS z?u3a1JtyMnl@3>CTiM5O%G7hCT8YG zB4vsr`(=O>B!x&Rq$Q-El72?|Iq6E$)ud}9``uBbU8HyUb|x|<9jzf94&4HWZh=F$ zz@b~<&Mk1_7PxQ=Tvu`27C3GT9JU1x+X5GDfqS;VHCy1AEpW^hxMho|X0}m7T1~1Y zt#Q)fa4m4S7C2lB9Igcp*8*p1fh)DZky_wJEpVe2xKRt-s0D7+0yk=b8@0fRTHr!0 zaG(~rPYYb4g;C$ah*zV%#hvSv_SPOSo12NANn4wguzM}tc1Zz7_5ZBN*Jt!!Acmc zguzM}tc1Zz7_5ZBN*Jt!!Ackmguy@<41~cz7z~8LKo|^!!9W-cguy@<41~cz7z~8L zKo|^!!9W-cguy@<41~cz7z~8LKo|^!fjSJ-VW18Jbr`6_Kph6^Fi?kqItP%|OB4v|?lX6HSNOh#Oqz2vw5;$}i4jhI{ zhT)81xKJ1l6o&hR;XGluP8g08hTDYUC}HdnsgaA(87@YyUW{D57`b|}XjJ#0<}lP8 zhML1ra~Nt4L(O5RISe(2q2@5u9EO_1P;(e+4nxghs5uNZE1MD)0d%Bn=NgXT*e_pm z@AJ&^rTYHKs>YkFY5XKu7yK~vht%iN*7wfpb4g}t<}-aq^lk2U+TeHl)%AaJV8@`W z!IK6*IQZQmD(F@=w%`ZUE?w-vYA^0~Y`xF31664nYQO2<*-QOTwHs6It7I?tUUrgV z^k>g?MWt`%FJphN$GU`NY%_FYDlX|wWKwXgGlstBzij%vK;isWKt!+Ye<)oE+<_<`h>KP)Jh#C=wj{YV(sW*?dW0c=vM9M zR_*9j?dVeN=u7SBNbTrH?dV1A=tb@5MD6HA?dU@7=sxY}GVSOx?b1i`laffuB+5jm zXh)xDN0(?vUuZ{HXh%&>Uvqsw=?!K(0c6=B z(x;@)NdF>zPWpoMW#mJo%&SP(50S1PB3(a3%Djq{c@-)9A(G}*B<+Vtn^)cR$WA2A ztL_+n7jZp@>xEjrz3Q&!cOBPjN#}EYE$IfXZz63X-9p+-x}9_2XNZNBo7<$WS=JP$1j^WIKRt2T<*RGYo|@423fcg)gsULQ`LFB_olS#*sjwdZ7Rb!K=A+09WlGa4tMqacbFWQh7ZODr@ zUMYwdz-?SgCV zLO!)2pW2X5ZOErK;*NX)udX| zn#g7_eE>`!0MiG+^Z_uv9ZYWrV+X+40Wfv|j2!@D2f)|?Ft#0R9ROR~!PWt=bpR}F z2SeMz&~`Ai84PU(Lz}_QcCfM?ENll0+rh$iAUXg<2Y~1R5FG%b13+{DhzJX;zDR~A+)#< zT3o0{EiQ}sTsCPqDTg$IG{y~hi-r0=3B zvZ95SvllIAFIvuCw4A+YIeXD^_IA=D-{Lo#r27fw?jyC*7a?Z}mcY|UpG5Y_jij4N zw?_84N0Vwv7m%(aeG%E`5xl3qILH?V`Qjj79OR3Gd~uL34)Vo8zBtGi2l?V4UmRox zbSidk_0>}H(~y=Ak@Gb)e+YU$1U(;uZVypfJEgT#n$kHALAQr=sTJfWkSa+vq-ZUd zaeX=I3X-bv6Y_neR#LR~^BH+BF!EktCbW~8&}+!ALt1{#i+tgnNIIExD$;EUJaQ@d zL!`&J_Y&{#B)!4={{ZrLBkwyObN>_G+ef~i)J8f$I!OAI^e@uqq_0R{N4^k})R(ot zen|H`v`vgq@PmPWjy~G z`Q_w4C%=OH%EAffDy(hqYE0})*tUm!pTft~67<>W@ zJ^==wfbNuJX$3=1fR$D-(F(1#0&OdhwgOEnkhB7Y;^?ikww0E)(!wX;>XV?A$yjfX zg1V=WFM*?@K~ZxvbaN28*$>^cKr;uRgFUpQnU*xu$9rf+Gp%T*70vYH9{O+(eYgib zXb*bOLHckHeYc;MHPd%$d>x>V_Rtr5=!ZS@ff{cI=mRz84uJdp;C(+h-w(c9z_l8O z2f+0n@Vo~c@1fPr;8l&y1K_mm~Iy)0E zsj4fF-*<0UZ*+Ba)748gBE-=U6pbLO8lwUtf=X0mV$AoU&WMPt6BCz+EP`7!s0fH_ za9@CO{M0yVa1z|2Ah>ioG6`MKRjEfCsvIb`2HyP6sRo(`Oq_b(dGFM%`(C}}-gEwU zIq%O^HgT0rT;X~%lkfA8`N&f8E@Qi#?P`Ai1bq$qr|4g@l^T;_yNyvBkM?(nHhC%A zDBBv+XoG`;)8ODVI5^GSX#xwUxkF9fDDqu`zLjkb*@kRKb|5>ET}UhKaE=LHPJ@@z zwiqcv%7gXx1lsy1BHu^24)Ajt{G0|qr@_x@@N?SIw*Y=l+lk0zWGXT{XyU0f@l=|4 zD(iVF>%r7%+sbhQ?wASIJKpLKzE1O`*7KCsyPkYMneY4uPpgTiwBC&-Z4BSX^8G5d zS0mSuK8f@x2=@^jo(6}fwRX%S-vZJXB8!m42)!!qG2{tk3Gx*34DuZE0`d~F452Rs z9G?cqr@`@QaC{mZp9aUL!SQKud>R~|c8$oF$R^I?D`Ydmv(XyX%2sOGo}j6q!tgc| zglpqnWc_873>%oYn^~Up*JcglZ=bRi+xR8=I@)M8jPm!UoDV`q1v#EVmb>{ick^rR z=GWZKEO#@@9n5m)vXpVLQ(4OR7Vg^DYM;P@+_A0PsjS)``ySrh}e$>L5?fP zas^qgAj=heEw(~!Lq(9|th2O$BaD9>NBQfC^hQoWuyP>i6bL$HXgk5h>*E1@`WTXU z0Uy+o0-yQVkw)xDBV|27Sxk>d_07Yhw$+bzS&Bi9NTTdlXwarPvPS!d_08@GEdd!0 zBMH!vv=Y>blQW|n*?Y+<^4M&SXU#Pk=7tVT}e<^ z64aFhbtOSvNr0qM7Vl*1kQhR{)OHJe+dW8vrjnqkBxouLno5F2eXytx7WKiRKK8T` zd)i3-O4vT^$2|u9OFK0|3qabc30eUuS^+6q0V!GmDSIYzHp0jz^)Nw8K-#hidoJ7I zY`F&NWWtVQJC6Stk4!+WLne|wiSwAub_(06Y^Slki{E~Q+>6XZ?nmY$i#WF>b3ev7bzlyZ0k#XqbNxPoyFOVCM>ExS%P`=zO{$n=V+en|o zb}rxVBLAX_Qc`d<1(XxCl%{+9bYDL2g99ll*rh_aMLKF5)%a1EeoN7LsQXvKV;; zc?@|1S%N%;JcB%kynwufEJHT&A73Gxk!{Ehj1sikWtjBa(ZcI2OF{88?oLS zvEI$x9qFx+o|@pBO9^aN$!Y@L^NZ$lc16$mfOd2`&e!t%bmn>Cmo}x zTuC!m(#(}Kb0r(G-bt)?vVdb2R0f+k^JaQH`!nKws-E=*&bpbi-oRNmbJopmXWhbC zGiJ)nmqExVJ>w0W@dnO#182DJ>^5+Aa#qrB)ZF2$nmMax&Z>no*}$1Jb0*E4Ni%2C zLjN5+`AUeK>m%9Sw00zU*xdMIc#qZo0`Lp=CGqVS{?2Clylh39Ck2=9n4_|bJ&+0_9cgX$yzTU8XJz>@K+Z~}N?6AFF-Ral+4sr}aKOsJG z6@Ksk*W*QhAU69>V>K`wC+OB}=!2d%^ztqar7 z6Q-XhOg~SUex5LM6|%MhsYJkamOEvmNHxMJCdefYa*2an;vknesHK4?)W8#J;0ZPG zgc|nu0rg^^laP~5F4UT?Ko?x6O*uWEvxAh6d+w}>B=@SamClq#vPerch`!A3ikXan>Hnwxw9^5|^$964eyg$oWf0l9nEMxpx#`m-CN#tqd zS>$=-MPwWs~^%P5Ai)BQPyqjUtmIUKj3N(ynE0f2w6-^;SuC9q!o{Cm}BAC7J^zL z=oKKA&TM;<))xfRkMAS-KAP`i(XTT<_1^gf6K4wXVA~SZTsIuXTHH< zKS3is4JNol^YCoZ54o>$PlE1;Nxxb1uL%Aa{G1$9_x?TjoKkh*$yUklhx<@|BJA2?ieSScj%Dv;2skwj*iTrRSbc{(0qh2)gavLCWXII{hu5 z1NJXIl|h2p$d%09Yiey>#&`&2A$T+Y+=H3?l0V!0+U%XkjCLa>Hn9`vg7`KDUm?(FnDi6WCd_FJ_45hU%~e|UO&v_tniVmjx559f2FTB^V8e@Y$m zGOt`dkpowy-&qmMA?pLzwg0JTjUUBF@69XdqiVZyIbC{e*vMonQZ-2P_wX{#k z>qkmIkTZCY*nvYnV#yeL<|F4Rb(MC;A)nyVLz2ERp?x{b*Q~u#&OQj127e0#f3zSROU>QVA1wBV_8vD%CZ(%td6uy;th&x%%5C#DALyZ_d zOCyE{YsBynjTj!P5yR(t5-~hNBZfz6#PIn<3{Nr_2v>#~t+BsjH1_w$#QxTs%QWhD zCQ-kG%{-N8r}PXM)$s`(Y-HebnjA)?p>zQ zy~{Pa_brX?eOse@f2YyCD>Swzxamv`9p+`AQ;s&1Q+{HQObkmk8iN#PS-A z#XD1@ zcxP!8?;MTdovTs2w-ZNqs+Qocl+qGPq?BN0QL!9NIXsqmi^s9R`^DlY(LF#u!f<0L zlf7usoybx`ALU83Cxq|DQYL$ovkyxr%6)%kXbxa0qf8FOmkna6piF9SF{Ls>nLHhD zJD8=4==veVmPorYs`aEs>q)IL;V_SsrH&eN5qYG})N7rIQD-iLljkQaF>24{)Gmp> zucrRI1U_5F;sUH#y|P-btk$b; zTCciky(-pv)kW)7wbrZd)T>rzt?y>3*4ouwYgc#bRWm{q6RXXjT(5g)iW4oDJI984|b;7G+V(_Z; zBF{lt`L`_as35wuMioe(fyA4e;Q|U zIxY1YSXh35eg-Y}8v8@|SVHzpdnWo>_AKD|DpMO&rZ%Vo8^jm_Tq}#X=MUM3&==dqrV`$jhs{y?=7CE1R~|)| z_YYLU!}2)#Zo8Yi1fvOO9@qe`QHnQX3lLlIhM16px*K+rLQ^RWC&t2YLd_PQ6ZA4y zM*gr1(??bA%Ap8le1v@~bcCeR@zx6%P&$($*05HsVVzpTm|DX+tl@V!{xR6ZB5dMu z(_uZa46vk7ieO6V%Q^IO z{TK)7@A{i6SW^ZN5jMyTq8H{=cdDs|Kjk!{b55rpE(VXv4@?)hR47I8slX(R{T)jB zIqn?#sCc6SYu>29dZZi4Rh;k6=U2E@Ojj)OMXWD&lph#YF5&7fb(ivwW84_dinlIs zp1gH|Bad}s>D#-4UcH#Sdx7&DM~@LPYecO@;9MC``n8Ud<0j~c(RJ=R&T68YNXle4 znPX0MQ(6Da{fuK?Pft?~w*CgzH|nU;P3|W0&vY~S-&t-JSIRpaSl{8WT5z)5$vwP_ zKEfE>EO(>-in(MlI9l#Ozn3{>F+7BfLd|#cInG1wA^z)O_b}^6-J`4@caO9Fjr$Gj zC*6~*pLS2Pe%3w9`g!*}>lfXNte3i_te3mxtm7`u*}hEQR}CyK|B3zzePA`Pxe${M zqsy!4uesOIU#Cy326mUbIkJMJCs z4{xPlz0$4Z+TV5Wa@Fs-_t4*W@1uX-wr90nQBbP=CwYVoOsrW-sm^aAiIq+(Md z{uRT^TQXSlmJGa`^){=2Ey8aWoBaD_itv@R>eSaV%Ev;~BMWU#aG(JN{tI45ysuI3 z8^ZT~54|T#-uoK$zDMDEPbOVFZb&_@0R^6d-j~I|IoA(=DL%MVeQ=@r;4<~WCF+AK z@W7{WF5-i$z=dbCmw4isdSZhg9)>4Am&MS(I~+ZaTZN&{7>NfJ3_D6vGaBD~DT^^~A{2(a{SPblT3pw&4{JmlPc`0{KynYD$yc|6a7n;#G??hoodmUXc zwKZ=LO>5dP!P}q$Lx1&3j!85y`g<&$h|ySuE^p*1g)8h6j=6@#1A(t4o!Nz?e`dZw z7bIR`B#Of*dhoyw>v*=plV@Pw`zz0TJ+oSj;)Yt{J2s&UDz7HeLt0{gC*Gr$zH)ir zMi$<_TB1LsWhj_EN*qXzlx-}|Y$qn97PPU8Uj=Q{D%vo-0ca2UUPEVvzHBTC{@^`g z9t3Qr)^lC~=`h(60bS^opqF~3rZdcbRp?PKO1fZ_V#O$Bicu_Ves!cniA|n*uO7XN z*M+#&qr9WgyYlW11Iyph=-uegk9yrb%A_KgQepH%@9XvD-}`y}(Fb?~$T`phCBX1E z$dtnJN2!C^Z!md=c*D@;%|x~E`wd5jY<4M9;M zZ#VeKD1HhlekxS_#Ap`yDF%M32jz6J^xn3^PsQ-lF~dMnl!c$}1md9uOU2-+I}u$F zRSdqm@1qN@iYcxNwZm1RcDO3k4p)WR;VNTKW&9(m=*lR%iYmG?imsxHu8g9qsG=)l z1zklIT^U7JQ9INQ1w)*}cuCX_v%}EOW!xkROWknv^Xz%(BkTzDk&L56L1WZbMOsI} zPIoo>0W4+OVJXuNONA6m6)TnsDV8c$EEQ5LRSaw04IJl2dn35&CW}Xex9(>2U)o=y z-(qh;pKhn4-)e6~pJ8X9&$KhqXW3ck@^+_Exb1G^ICJbA^tpB}y1ePB6t25F(B*wk zg>c?6;-;9a5bir>W-Br)g#V5i+KSH#;lP`RF7JUVgbVL}ba@+8A)I*g(dC^`C2-?m zZ4|eK6}MT%ZDGZ2Rf^l{6}MF>ZmU<^R;9SDUO4pFcZprXU47D0b77`yr6lYI$r(j* zAw_awVW~5?HGo}b;i^LyJXZyt>x3>CE+mX~=z`wDir$2~u96f%Z(%s>s=zBOq~wuY zjjKVgbd)LBq2Olb2cU{RNZQo)z@4BIP2j>~Zc}FSEGm7&f zu;2CM437uf8O3%X;lD!{Y!^~&SE|^qLa|*;v0W5ayn$dZL3qWA@M_y3JgW$=S`l7U z5ne53>X~Tk}-Ds{w5MfLaVF>oUpO8}!VHEzopYp$O@R2gsjRji>I<)RecO}1G z<*wp-Vddjj!Hc1GcrmPa(JEdviWe)K;Kgdii^ffIllWgjjWIXHO+gpz7<1Fy&p4W3 z$Ef?c`#HKG$fy$pSploxO&sB7cMIv$-E_|FR(C7<3^xN^kYz}bWif1jv(ay3gfj~3 z-yC$on#IEYM}EPY5yhHTv1UZErd6yNQLJg<1^hKwbDo<=k-X2{$6oil`}r5apcRTi ztKkd87sDC20NlTj5!3>DFBWkvf=y#^2rfn!gc^fO@DX&usWCVOA43QwN+FdR#a^jRfiQ- zTbLN>;fINF3*|(xwSkcl^r8s66lTWlqzKNgfT3|GC3%#t(39dZa4ZKw+CJD zw^96EtN6P@@pm;Wj-|%H+}H^eE|}ZE;21_1C2jN$h%mJ^j8bcDgf^lnxgB*kGsP364D>jM_!+A20|Cq+nm9=j~OBi zLgqXn5CRFyaplM!_%i<=vZjH~x;<$Si!=ec(rZT3B7-bZujG{nm`G$_4wa_u2*%?C;@%6*gGmgMAl9 z*!N(B6;4=Tg%w^{VTKiM*j2E@u7)307-HAJ5Gx$9pTQFQIXtn#6x#q-Y@RJv_+o`I zRybpYHCA|Ig*jHZW1C=)75-RZkQEMDVUZOcSz(eDE?Hrd6+T&Elod`{VU-nLSz(qH zZdqZM6@FP^m=%s$VVTYI%nH-2aLw+tPw~{lwBAnVSq`Q}Qx608Y}#UTSo&#SU4QR? z={XxnZ`rx#W;?=;G53J0CYZ(aKTU_TcqYh($QF8f-k}y{X+h*mjYN>w=gS9Wr_6hR ze;VP--!SK literal 0 HcmV?d00001 diff --git a/docs/source/_build/html/_static/fonts/RobotoSlab-Regular.woff2 b/docs/source/_build/html/_static/fonts/RobotoSlab-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..e2621bcaac6457d7e2eb41c2ac93892564977b79 GIT binary patch literal 66512 zcmZ6wQ82Hdou-cc1^_oN@CIjXWf&s?1q49tz^j zKmZ^hAOOfb5Ym4waH{2heVhN8`)~OFFW7=OK{e30;jZ9@K#A6noKPu9NRZGGV}ju~ z$}oxCKmc}NQjkJ>P(rX6Du{7$*dTZv1pQ{9;)(SxtTPaYiq0gy$GOnYv8pVTeze>%&nc6LX<|4&(&$d}-_+flepF#TiS$P5YwkdU#n zp*s#U6qcnnodiZx*RDK!_^g4w@oxG7Mpo3DJkX?nc?)EM-N&q&4W?_Do? z^=N5Tfw4mYyQq=SzB!qoEe5I>t$O}*-@iI5%v*BJV>Q zY6!Cz^|%FaQ9j@15TEHE15*8hHH^=EdM;l!g7&UDhy=jZwLc|6jSRi7`%%-4-1trg zSHVpo8ERGSTL744P_S%~!i%wmyRkhyTX_5z!$vzBND6g!>H^1Roy+G*x+%J||A=Z{ zTAvvUsQ24E+HiYxhr%VO%jD#B$5!i@Tk=#12xzcYO;5u4YtMML@p=?iDvO zg2AVcN=dS9RJPB(nK%HaJwSJQ_5}uvhOm9=Pj<(FWd1v8!a=JO4A-T*LjLkPG@tj! zZB-}pKYB5(0;Q~a8;dv@ku6wJp9qcWtxl_texbCZk>6FJ=+c^M7EZo>zm51fIAyd19>K4~{=aFB{qu{mJD-~YbnW6g zQ%YzAgLxFi28}GPp1^shBEu zkj25A-swBtK_Rar2VcXsEA&zULL8u*9lJtx`F-!pMZX2! z4%dEKsy|itHXJZQfs;o7z*y+