diff options
Diffstat (limited to 'scripts')
31 files changed, 1647 insertions, 814 deletions
diff --git a/scripts/coccinelle/ceil_div.cocci b/scripts/coccinelle/ceil_div.cocci new file mode 100644 index 0000000000..00843e82c3 --- /dev/null +++ b/scripts/coccinelle/ceil_div.cocci @@ -0,0 +1,6 @@ +@@ +expression n, d; +@@ + +- (((n) + (d) - 1) / (d)) ++ CEIL_DIV(n, d) diff --git a/scripts/coccinelle/test-operator-cleanup b/scripts/coccinelle/test-operator-cleanup new file mode 100755 index 0000000000..e7822542a4 --- /dev/null +++ b/scripts/coccinelle/test-operator-cleanup @@ -0,0 +1,11 @@ +#!/usr/bin/perl -w -p -i + +next if m#^ */\*# or m#^ *\* #; + +s/<([,)])/OP_LT$1/; +s/(?<=[\s,])>([,)])/OP_GT$1/; +#s/>([,)])/OP_GT$1/; +s/==([,)])/OP_EQ$1/; +s/>=([,)])/OP_GE$1/; +s/<=([,)])/OP_LE$1/; +s/!=([,)])/OP_NE$1/; diff --git a/scripts/coccinelle/test_assert_int.cocci b/scripts/coccinelle/test_assert_int.cocci new file mode 100644 index 0000000000..80e86b4f3c --- /dev/null +++ b/scripts/coccinelle/test_assert_int.cocci @@ -0,0 +1,49 @@ +@@ +int e; +constant c; +@@ + +( +- tt_assert(e == c) ++ tt_int_op(e, OP_EQ, c) +| +- tt_assert(e != c) ++ tt_int_op(e, OP_NE, c) +| +- tt_assert(e < c) ++ tt_int_op(e, OP_LT, c) +| +- tt_assert(e <= c) ++ tt_int_op(e, OP_LE, c) +| +- tt_assert(e > c) ++ tt_int_op(e, OP_GT, c) +| +- tt_assert(e >= c) ++ tt_int_op(e, OP_GE, c) +) + +@@ +unsigned int e; +constant c; +@@ + +( +- tt_assert(e == c) ++ tt_uint_op(e, OP_EQ, c) +| +- tt_assert(e != c) ++ tt_uint_op(e, OP_NE, c) +| +- tt_assert(e < c) ++ tt_uint_op(e, OP_LT, c) +| +- tt_assert(e <= c) ++ tt_uint_op(e, OP_LE, c) +| +- tt_assert(e > c) ++ tt_uint_op(e, OP_GT, c) +| +- tt_assert(e >= c) ++ tt_uint_op(e, OP_GE, c) +) diff --git a/scripts/coccinelle/test_assert_null.cocci b/scripts/coccinelle/test_assert_null.cocci new file mode 100644 index 0000000000..3d66e1ee0b --- /dev/null +++ b/scripts/coccinelle/test_assert_null.cocci @@ -0,0 +1,11 @@ +@@ +expression * e; +@@ + +( +- tt_assert(e != NULL) ++ tt_ptr_op(e, OP_NE, NULL) +| +- tt_assert(e == NULL) ++ tt_ptr_op(e, OP_EQ, NULL) +) diff --git a/scripts/coccinelle/test_assert_zero.cocci b/scripts/coccinelle/test_assert_zero.cocci new file mode 100644 index 0000000000..09feaa5fb4 --- /dev/null +++ b/scripts/coccinelle/test_assert_zero.cocci @@ -0,0 +1,5 @@ +@@ +@@ + +- tt_assert(0) ++ tt_abort() diff --git a/scripts/codegen/fuzzing_include_am.py b/scripts/codegen/fuzzing_include_am.py new file mode 100755 index 0000000000..fda57d2ae8 --- /dev/null +++ b/scripts/codegen/fuzzing_include_am.py @@ -0,0 +1,160 @@ +#!/usr/bin/python + +FUZZERS = """ + consensus + descriptor + diff + diff-apply + extrainfo + hsdescv2 + hsdescv3 + http + http-connect + iptsv2 + microdesc + vrs +""" + + +PREAMBLE = r""" +FUZZING_CPPFLAGS = \ + $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS) +FUZZING_CFLAGS = \ + $(AM_CFLAGS) $(TEST_CFLAGS) +FUZZING_LDFLAG = \ + @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ +FUZZING_LIBS = \ + src/or/libtor-testing.a \ + src/common/libor-crypto-testing.a \ + $(LIBKECCAK_TINY) \ + $(LIBDONNA) \ + src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ + src/common/libor-event-testing.a \ + src/trunnel/libor-trunnel-testing.a \ + $(rust_ldadd) \ + @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ + @TOR_LIBEVENT_LIBS@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @CURVE25519_LIBS@ \ + @TOR_SYSTEMD_LIBS@ \ + @TOR_LZMA_LIBS@ \ + @TOR_ZSTD_LIBS@ + +oss-fuzz-prereqs: \ + src/or/libtor-testing.a \ + src/common/libor-crypto-testing.a \ + $(LIBKECCAK_TINY) \ + $(LIBDONNA) \ + src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ + src/common/libor-event-testing.a \ + src/trunnel/libor-trunnel-testing.a + +noinst_HEADERS += \ + src/test/fuzz/fuzzing.h + +LIBFUZZER = -lFuzzer +LIBFUZZER_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ +LIBFUZZER_CFLAGS = $(FUZZING_CFLAGS) +LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG) +LIBFUZZER_LIBS = $(FUZZING_LIBS) $(LIBFUZZER) -lstdc++ + +LIBOSS_FUZZ_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ +LIBOSS_FUZZ_CFLAGS = $(FUZZING_CFLAGS) +""" + +POSTAMBLE = r""" +noinst_PROGRAMS += $(FUZZERS) $(LIBFUZZER_FUZZERS) +noinst_LIBRARIES += $(OSS_FUZZ_FUZZERS) +oss-fuzz-fuzzers: oss-fuzz-prereqs $(OSS_FUZZ_FUZZERS) +fuzzers: $(FUZZERS) $(LIBFUZZER_FUZZERS) + +test-fuzz-corpora: $(FUZZERS) + $(top_srcdir)/src/test/fuzz_static_testcases.sh +""" + +########### No user serviceable parts will follow. + +PREAMBLE = PREAMBLE.strip() +POSTAMBLE = POSTAMBLE.strip() # If I use it, it's a word! +FUZZERS = FUZZERS.split() +FUZZERS.sort() + +WARNING = """ +# This file was generated by fuzzing_include_am.py; do not hand-edit unless +# you enjoy having your changes erased. +""".strip() + +print(WARNING) + +print(PREAMBLE) + +print("\n# ===== AFL fuzzers") + +def get_id_name(s): + return s.replace("-", "_") + +for fuzzer in FUZZERS: + idname = get_id_name(fuzzer) + print("""\ +src_test_fuzz_fuzz_{name}_SOURCES = \\ + src/test/fuzz/fuzzing_common.c \\ + src/test/fuzz/fuzz_{name}.c +src_test_fuzz_fuzz_{name}_CPPFLAGS = $(FUZZING_CPPFLAGS) +src_test_fuzz_fuzz_{name}_CFLAGS = $(FUZZING_CFLAGS) +src_test_fuzz_fuzz_{name}_LDFLAGS = $(FUZZING_LDFLAG) +src_test_fuzz_fuzz_{name}_LDADD = $(FUZZING_LIBS) +""".format(name=idname)) + +print("FUZZERS = \\") +print(" \\\n".join("\tsrc/test/fuzz/fuzz-{name}".format(name=fuzzer) + for fuzzer in FUZZERS)) + +print("\n# ===== libfuzzer") +print("\nif LIBFUZZER_ENABLED") + +for fuzzer in FUZZERS: + idname = get_id_name(fuzzer) + print("""\ +src_test_fuzz_lf_fuzz_{name}_SOURCES = \\ + $(src_test_fuzz_fuzz_{name}_SOURCES) +src_test_fuzz_lf_fuzz_{name}_CPPFLAGS = $(LIBFUZZER_CPPFLAGS) +src_test_fuzz_lf_fuzz_{name}_CFLAGS = $(LIBFUZZER_CFLAGS) +src_test_fuzz_lf_fuzz_{name}_LDFLAGS = $(LIBFUZZER_LDFLAG) +src_test_fuzz_lf_fuzz_{name}_LDADD = $(LIBFUZZER_LIBS) +""".format(name=idname)) + +print("LIBFUZZER_FUZZERS = \\") +print(" \\\n".join("\tsrc/test/fuzz/lf-fuzz-{name}".format(name=fuzzer) + for fuzzer in FUZZERS)) + +print(""" +else +LIBFUZZER_FUZZERS = +endif""") + +print("\n# ===== oss-fuzz\n") +print("if OSS_FUZZ_ENABLED") + +for fuzzer in FUZZERS: + idname = get_id_name(fuzzer) + print("""\ +src_test_fuzz_liboss_fuzz_{name}_a_SOURCES = \\ + $(src_test_fuzz_fuzz_{name}_SOURCES) +src_test_fuzz_liboss_fuzz_{name}_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS) +src_test_fuzz_liboss_fuzz_{name}_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS) +""".format(name=idname)) + +print("OSS_FUZZ_FUZZERS = \\") +print(" \\\n".join("\tsrc/test/fuzz/liboss-fuzz-{name}.a".format(name=fuzzer) + for fuzzer in FUZZERS)) + +print(""" +else +OSS_FUZZ_FUZZERS = +endif""") + +print("") + +print(POSTAMBLE) diff --git a/scripts/codegen/gen_server_ciphers.py b/scripts/codegen/gen_server_ciphers.py index 0dca8a6734..7ea39c540d 100755 --- a/scripts/codegen/gen_server_ciphers.py +++ b/scripts/codegen/gen_server_ciphers.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2014-2015, The Tor Project, Inc +# Copyright 2014-2017, The Tor Project, Inc # See LICENSE for licensing information # This script parses openssl headers to find ciphersuite names, determines @@ -13,13 +13,13 @@ import sys EPHEMERAL_INDICATORS = [ "_EDH_", "_DHE_", "_ECDHE_" ] BAD_STUFF = [ "_DES_40_", "MD5", "_RC4_", "_DES_64_", - "_SEED_", "_CAMELLIA_", "_NULL" ] + "_SEED_", "_CAMELLIA_", "_NULL", + "_CCM_8", "_DES_", ] # these never get #ifdeffed. MANDATORY = [ "TLS1_TXT_DHE_RSA_WITH_AES_256_SHA", "TLS1_TXT_DHE_RSA_WITH_AES_128_SHA", - "SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA", ] def find_ciphers(filename): @@ -48,15 +48,23 @@ def usable_cipher(ciph): # All fields we sort on, in order of priority. FIELDS = [ 'cipher', 'fwsec', 'mode', 'digest', 'bitlength' ] # Map from sorted fields to recognized value in descending order of goodness -FIELD_VALS = { 'cipher' : [ 'AES', 'DES'], +FIELD_VALS = { 'cipher' : [ 'AES', 'CHACHA20' ], 'fwsec' : [ 'ECDHE', 'DHE' ], - 'mode' : [ 'GCM', 'CBC' ], - 'digest' : [ 'SHA384', 'SHA256', 'SHA' ], + 'mode' : [ 'POLY1305', 'GCM', 'CCM', 'CBC', ], + 'digest' : [ 'n/a', 'SHA384', 'SHA256', 'SHA', ], 'bitlength' : [ '256', '128', '192' ], } class Ciphersuite(object): def __init__(self, name, fwsec, cipher, bitlength, mode, digest): + if fwsec == 'EDH': + fwsec = 'DHE' + + if mode in [ '_CBC3', '_CBC', '' ]: + mode = 'CBC' + elif mode == '_GCM': + mode = 'GCM' + self.name = name self.fwsec = fwsec self.cipher = cipher @@ -74,42 +82,50 @@ class Ciphersuite(object): def parse_cipher(ciph): m = re.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)(|_CBC|_CBC3|_GCM)_(SHA|SHA256|SHA384)$', ciph) - if not m: - print "/* Couldn't parse %s ! */"%ciph - return None + if m: + fwsec, cipher, bits, mode, digest = m.groups() + return Ciphersuite(ciph, fwsec, cipher, bits, mode, digest) - fwsec, cipher, bits, mode, digest = m.groups() - if fwsec == 'EDH': - fwsec = 'DHE' + m = re.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_(AES|DES)_(256|128|192)_CCM', ciph) + if m: + fwsec, cipher, bits = m.groups() + return Ciphersuite(ciph, fwsec, cipher, bits, "CCM", "n/a") - if mode in [ '_CBC3', '_CBC', '' ]: - mode = 'CBC' - elif mode == '_GCM': - mode = 'GCM' + m = re.match('(?:TLS1|SSL3)_TXT_(EDH|DHE|ECDHE)_RSA(?:_WITH)?_CHACHA20_POLY1305', ciph) + if m: + fwsec, = m.groups() + return Ciphersuite(ciph, fwsec, "CHACHA20", "256", "POLY1305", "n/a") + + print "/* Couldn't parse %s ! */"%ciph + return None - return Ciphersuite(ciph, fwsec, cipher, bits, mode, digest) ALL_CIPHERS = [] for fname in sys.argv[1:]: - ALL_CIPHERS += (parse_cipher(c) - for c in find_ciphers(fname) - if usable_cipher(c) ) + for c in find_ciphers(fname): + if usable_cipher(c): + parsed = parse_cipher(c) + if parsed != None: + ALL_CIPHERS.append(parsed) ALL_CIPHERS.sort(key=Ciphersuite.sort_key) +indent = " "*7 + for c in ALL_CIPHERS: if c is ALL_CIPHERS[-1]: - colon = ';' + colon = '' else: colon = ' ":"' if c.name in MANDATORY: - print " /* Required */" - print ' %s%s'%(c.name,colon) + print "%s/* Required */"%indent + print '%s%s%s'%(indent,c.name,colon) else: print "#ifdef %s"%c.name - print ' %s%s'%(c.name,colon) + print '%s%s%s'%(indent,c.name,colon) print "#endif" +print '%s;'%indent diff --git a/scripts/codegen/get_mozilla_ciphers.py b/scripts/codegen/get_mozilla_ciphers.py index e673ec7dc6..946957ac77 100644..100755 --- a/scripts/codegen/get_mozilla_ciphers.py +++ b/scripts/codegen/get_mozilla_ciphers.py @@ -1,6 +1,6 @@ #!/usr/bin/python # coding=utf-8 -# Copyright 2011-2015, The Tor Project, Inc +# Copyright 2011-2017, The Tor Project, Inc # original version by Arturo Filastò # See LICENSE for licensing information @@ -127,9 +127,9 @@ for k, v in enabled_ciphers.items(): #oSSLinclude = ('/usr/include/openssl/ssl3.h', '/usr/include/openssl/ssl.h', # '/usr/include/openssl/ssl2.h', '/usr/include/openssl/ssl23.h', # '/usr/include/openssl/tls1.h') -oSSLinclude = ('ssl/ssl3.h', 'ssl/ssl.h', - 'ssl/ssl2.h', 'ssl/ssl23.h', - 'ssl/tls1.h') +oSSLinclude = ['ssl3.h', 'ssl.h' + 'ssl2.h', 'ssl23.h', + 'tls1.h'] ##### # This reads the hex code for the ciphers that are used by firefox. @@ -155,9 +155,12 @@ for x in used_ciphers: openssl_macro_by_hex = {} all_openssl_macros = {} for fl in oSSLinclude: - fp = open(ossl(fl), 'r') + fname = ossl("include/openssl/"+fl) + if not os.path.exists(fname): + continue + fp = open(fname, 'r') for line in fp.readlines(): - m = re.match('#define\s+(\S+)\s+(\S+)', line) + m = re.match('# *define\s+(\S+)\s+(\S+)', line) if m: value,key = m.groups() if key.startswith('0x') and "_CK_" in value: diff --git a/scripts/codegen/makedesc.py b/scripts/codegen/makedesc.py index d4ba21efae..8d9d4edaaf 100644 --- a/scripts/codegen/makedesc.py +++ b/scripts/codegen/makedesc.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2014-2015, The Tor Project, Inc. +# Copyright 2014-2017, The Tor Project, Inc. # See LICENSE for license information # This is a kludgey python script that uses ctypes and openssl to sign diff --git a/scripts/codegen/run_trunnel.sh b/scripts/codegen/run_trunnel.sh index d2669931e9..428804342a 100755 --- a/scripts/codegen/run_trunnel.sh +++ b/scripts/codegen/run_trunnel.sh @@ -5,7 +5,13 @@ if test "x$TRUNNEL_PATH" != "x"; then export PYTHONPATH fi -python -m trunnel --require-version=1.4 ./src/trunnel/*.trunnel +OPTIONS="--require-version=1.5.1" -python -m trunnel --require-version=1.4 --write-c-files --target-dir=./src/ext/trunnel/ +# Get all .trunnel files recursively from that directory so we can support +# multiple sub-directories. +for file in `find ./src/trunnel/ -name '*.trunnel'`; do + python -m trunnel ${OPTIONS} $file +done + +python -m trunnel ${OPTIONS} --write-c-files --target-dir=./src/ext/trunnel/ diff --git a/scripts/maint/analyze_callgraph.py b/scripts/maint/analyze_callgraph.py deleted file mode 100755 index 8ce5827f07..0000000000 --- a/scripts/maint/analyze_callgraph.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/python - -import re -import sys -import copy -import cPickle -import os - -class Parser: - def __init__(self): - self.calls = {} - self.definedIn = {} - - def enter_func(self, name): - if self.infunc and not self.extern and self.calledfns: - if self.infunc in self.definedIn: - #print "{}: {} or {}?".format( - # self.infunc, self.definedIn[self.infunc], self.module) - self.definedIn[self.infunc] = 'nil' - else: - self.definedIn[self.infunc] = self.module - self.calls.setdefault(self.infunc, set()).update( self.calledfns ) - - self.calledfns = set() - self.infunc = name - self.extern = False - - def parse_callgraph_file(self, inp, module): - self.infunc = None - self.extern = False - self.calledfns = set() - self.module = module - - for line in inp: - m = re.match(r"Call graph node for function: '([^']+)'", line) - if m: - self.enter_func(m.group(1)) - continue - m = re.match(r" CS<[^>]+> calls external node", line) - if m: - self.extern = True - m = re.match(r" CS<[^>]+> calls function '([^']+)'", line) - if m: - self.calledfns.add(m.group(1)) - self.enter_func(None) - - def extract_callgraph(self): - c = self.calls - self.calls = {} - return c - - -def transitive_closure(g): - passno = 0 - changed = True - g = copy.deepcopy(g) - import random - while changed: - passno += 1 - changed = False - keys = g.keys() - idx = 0 - for k in keys: - idx += 1 - print "Pass %d/?: %d/%d\r" %(passno, idx, len(keys)), - sys.stdout.flush() - newset = g[k].copy() - for fn in g[k]: - newset.update(g.get(fn, set())) - if len(newset) != len(g[k]): - g[k].update( newset ) - changed = True - - print - - return g - -def strongly_connected_components(g): - # From https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm, done stupidly. - index_of = {} - index = [ 0 ] - lowlink = {} - S = [] - onStack = set() - - all_sccs = [] - - def strongconnect(fn): - index_of[fn] = index[0] - lowlink[fn] = index[0] - index[0] += 1 - S.append(fn) - onStack.add(fn) - - for w in g.get(fn, []): - if w not in index_of: - strongconnect(w) - lowlink[fn] = min(lowlink[fn], lowlink[w]) - elif w in onStack: - lowlink[fn] = min(lowlink[fn], index_of[w]) - - if lowlink[fn] == index_of[fn]: - this_scc = [] - all_sccs.append(this_scc) - while True: - w = S.pop() - onStack.remove(w) - this_scc.append(w) - if w == fn: - break - - for v in g.keys(): - if v not in index_of: - strongconnect(v) - - return all_sccs - -def biggest_component(sccs): - return max(len(c) for c in sccs) - -def connection_bottlenecks(callgraph): - - callers = {} - for fn in callgraph: - for fn2 in callgraph[fn]: - callers.setdefault(fn2, set()).add(fn) - - components = strongly_connected_components(callgraph) - components.sort(key=len) - big_component_fns = components[-1] - size = len(big_component_fns) - - function_bottlenecks = fn_results = [] - - total = len(big_component_fns) - idx = 0 - for fn in big_component_fns: - idx += 1 - print "Pass 1/3: %d/%d\r"%(idx, total), - sys.stdout.flush() - cg2 = copy.deepcopy(callgraph) - del cg2[fn] - - fn_results.append( (size - biggest_component(strongly_connected_components(cg2)), fn) ) - - print - bcf_set = set(big_component_fns) - - call_bottlenecks = fn_results = [] - result_set = set() - total = len(big_component_fns) - idx = 0 - for fn in big_component_fns: - fn_callers = callers[fn].intersection(bcf_set) - idx += 1 - if len(fn_callers) != 1: - continue - - print "Pass 2/3: %d/%d\r"%(idx, total), - sys.stdout.flush() - - caller = fn_callers.pop() - assert len(fn_callers) == 0 - cg2 = copy.deepcopy(callgraph) - cg2[caller].remove(fn) - - fn_results.append( (size - biggest_component(strongly_connected_components(cg2)), fn, "called by", caller) ) - result_set.add( (caller, fn) ) - - print - - total = len(big_component_fns) - idx = 0 - for fn in big_component_fns: - fn_calls = callgraph[fn].intersection(bcf_set) - idx += 1 - if len(fn_calls) != 1: - continue - - print "Pass 3/3: %d/%d\r"%(idx, total), - sys.stdout.flush() - - callee = fn_calls.pop() - if (fn, callee) in result_set: - continue - - assert len(fn_calls) == 0 - cg2 = copy.deepcopy(callgraph) - cg2[fn].remove(callee) - - fn_results.append( (size - biggest_component(strongly_connected_components(cg2)), callee, "called by", fn) ) - - print - - - return (function_bottlenecks, call_bottlenecks) - -if __name__ == '__main__': - p = Parser() - for fname in sys.argv[1:]: - modname = re.sub(r'.*/', '', fname).replace('.callgraph', '.c') - with open(fname, 'r') as f: - p.parse_callgraph_file(f, modname) - - sys.stdout.flush() - - print "Building callgraph" - callgraph = p.extract_callgraph() - inModule = p.definedIn - - print "Deriving module callgraph" - modCallgraph = {} - for fn in callgraph: - fnMod = inModule[fn] - for called in callgraph[fn]: - try: - calledMod = inModule[called] - except KeyError: - continue - modCallgraph.setdefault(fnMod, set()).add(calledMod) - del modCallgraph['nil'] - - print "Finding strongly connected components" - sccs = strongly_connected_components(callgraph) - - print "Finding the transitive closure of the callgraph.." - closure = transitive_closure(callgraph) - - print "Finding bottlenecks..." - bottlenecks = connection_bottlenecks(callgraph) - - print "Finding module SCCs" - modSCCS = strongly_connected_components(modCallgraph) - - print "Finding module TC" - modTC = transitive_closure(modCallgraph) - - print "Finding module bottlenecks" - modB = connection_bottlenecks(modCallgraph) - - data = { - 'callgraph' : callgraph, - 'sccs' : sccs, - 'closure' : closure, - 'bottlenecks' : bottlenecks, - 'modules' : p.definedIn, - 'modItems' : { - 'callgraph' : modCallgraph, - 'sccs' : modSCCS, - 'closure' : modTC, - 'bottlenecks' : modB, - } - } - - with open('callgraph.pkl', 'w') as f: - cPickle.dump(data, f) - - - diff --git a/scripts/maint/annotate_ifdef_directives b/scripts/maint/annotate_ifdef_directives new file mode 100755 index 0000000000..368d842e2e --- /dev/null +++ b/scripts/maint/annotate_ifdef_directives @@ -0,0 +1,74 @@ +#!/usr/bin/python +# Copyright (c) 2017, The Tor Project, Inc. +# See LICENSE for licensing information + +import re + +LINE_OBVIOUSNESS_LIMIT = 4 + +class Problem(Exception): + pass + +def uncomment(s): + s = re.sub(r'//.*','',s) + s = re.sub(r'/\*.*','',s) + return s.strip() + +def translate(f_in, f_out): + whole_file = [] + stack = [] + cur_level = whole_file + lineno = 0 + for line in f_in: + lineno += 1 + m = re.match(r'\s*#\s*(if|ifdef|ifndef|else|endif|elif)\b\s*(.*)', + line) + if not m: + f_out.write(line) + continue + command,rest = m.groups() + if command in ("if", "ifdef", "ifndef"): + # The #if directive pushes us one level lower on the stack. + if command == 'ifdef': + rest = "defined(%s)"%uncomment(rest) + elif command == 'ifndef': + rest = "!defined(%s)"%uncomment(rest) + elif rest.endswith("\\"): + rest = rest[:-1]+"..." + + rest = uncomment(rest) + + new_level = [ (command, rest, lineno) ] + stack.append(cur_level) + cur_level = new_level + f_out.write(line) + elif command in ("else", "elif"): + if len(cur_level) == 0 or cur_level[-1][0] == 'else': + raise Problem("Unexpected #%s on %d"% (command,lineno)) + if (len(cur_level) == 1 and command == 'else' and + lineno > cur_level[0][2] + LINE_OBVIOUSNESS_LIMIT): + f_out.write("#else /* !(%s) */\n"%cur_level[0][1]) + else: + f_out.write(line) + cur_level.append((command, rest, lineno)) + else: + assert command == 'endif' + if len(stack) == 0: + raise Problem("Unmatched #%s on %s"% (command,lineno)) + if lineno <= cur_level[0][2] + LINE_OBVIOUSNESS_LIMIT: + f_out.write(line) + elif len(cur_level) == 1 or ( + len(cur_level) == 2 and cur_level[1][0] == 'else'): + f_out.write("#endif /* %s */\n"%cur_level[0][1]) + else: + f_out.write("#endif /* %s || ... */\n"%cur_level[0][1]) + cur_level = stack.pop() + if len(stack) or cur_level != whole_file: + raise Problem("Missing #endif") + +import sys,os +for fn in sys.argv[1:]: + with open(fn+"_OUT", 'w') as output_file: + translate(open(fn, 'r'), output_file) + os.rename(fn+"_OUT", fn) + diff --git a/scripts/maint/checkSpace.pl b/scripts/maint/checkSpace.pl index e90f5b330b..9929932cc5 100755 --- a/scripts/maint/checkSpace.pl +++ b/scripts/maint/checkSpace.pl @@ -1,48 +1,59 @@ -#!/usr/bin/perl -w +#!/usr/bin/perl + +use strict; +use warnings; + +my $found = 0; +sub msg { + $found = 1; + print "$_[0]"; +} + +my $C = 0; if ($ARGV[0] =~ /^-/) { - $lang = shift @ARGV; + my $lang = shift @ARGV; $C = ($lang eq '-C'); -# $TXT = ($lang eq '-txt'); } -for $fn (@ARGV) { +for my $fn (@ARGV) { open(F, "$fn"); - $lastnil = 0; - $lastline = ""; - $incomment = 0; + my $lastnil = 0; + my $lastline = ""; + my $incomment = 0; + my $in_func_head = 0; while (<F>) { ## Warn about windows-style newlines. - # (We insist on lines that end with a single LF character, not - # CR LF.) + # (We insist on lines that end with a single LF character, not + # CR LF.) if (/\r/) { - print " CR:$fn:$.\n"; + msg " CR:$fn:$.\n"; } ## Warn about tabs. - # (We only use spaces) + # (We only use spaces) if (/\t/) { - print " TAB:$fn:$.\n"; + msg " TAB:$fn:$.\n"; } ## Warn about labels that don't have a space in front of them - # (We indent every label at least one space) + # (We indent every label at least one space) if (/^[a-zA-Z_][a-zA-Z_0-9]*:/) { - print "nosplabel:$fn:$.\n"; + msg "nosplabel:$fn:$.\n"; } ## Warn about trailing whitespace. - # (We don't allow whitespace at the end of the line; make your - # editor highlight it for you so you can stop adding it in.) + # (We don't allow whitespace at the end of the line; make your + # editor highlight it for you so you can stop adding it in.) if (/ +$/) { - print "Space\@EOL:$fn:$.\n"; + msg "Space\@EOL:$fn:$.\n"; } ## Warn about control keywords without following space. - # (We put a space after every 'if', 'while', 'for', 'switch', etc) + # (We put a space after every 'if', 'while', 'for', 'switch', etc) if ($C && /\s(?:if|while|for|switch)\(/) { - print " KW(:$fn:$.\n"; + msg " KW(:$fn:$.\n"; } ## Warn about #else #if instead of #elif. # (We only allow #elif) if (($lastline =~ /^\# *else/) and ($_ =~ /^\# *if/)) { - print " #else#if:$fn:$.\n"; + msg " #else#if:$fn:$.\n"; } ## Warn about some K&R violations # (We use K&R-style C, where open braces go on the same line as @@ -53,23 +64,23 @@ for $fn (@ARGV) { # other stuff; # } if (/^\s+\{/ and $lastline =~ /^\s*(if|while|for|else if)/ and - $lastline !~ /\{$/) { - print "non-K&R {:$fn:$.\n"; - } + $lastline !~ /\{$/) { + msg "non-K&R {:$fn:$.\n"; + } if (/^\s*else/ and $lastline =~ /\}$/) { - print " }\\nelse:$fn:$.\n"; - } + msg " }\\nelse:$fn:$.\n"; + } $lastline = $_; ## Warn about unnecessary empty lines. # (Don't put an empty line before a line that contains nothing # but a closing brace.) if ($lastnil && /^\s*}\n/) { - print " UnnecNL:$fn:$.\n"; + msg " UnnecNL:$fn:$.\n"; } ## Warn about multiple empty lines. # (At most one blank line in a row.) if ($lastnil && /^$/) { - print " DoubleNL:$fn:$.\n"; + msg " DoubleNL:$fn:$.\n"; } elsif (/^$/) { $lastnil = 1; } else { @@ -79,7 +90,7 @@ for $fn (@ARGV) { ## accept double-line lines. # (Don't make lines wider than 80 characters, including newline.) if (/^.{80}/) { - print " Wide:$fn:$.\n"; + msg " Wide:$fn:$.\n"; } ### Juju to skip over comments and strings, since the tests ### we're about to do are okay there. @@ -102,48 +113,52 @@ for $fn (@ARGV) { s!"(?:[^\"]+|\\.)*"!"X"!g; next if /^\#/; ## Warn about C++-style comments. - # (Use C style comments only.) + # (Use C style comments only.) if (m!//!) { - # print " //:$fn:$.\n"; + # msg " //:$fn:$.\n"; s!//.*!!; } ## Warn about unquoted braces preceded by non-space. - # (No character except a space should come before a {) + # (No character except a space should come before a {) if (/([^\s'])\{/) { - print " $1\{:$fn:$.\n"; + msg " $1\{:$fn:$.\n"; } + ## Warn about double semi-colons at the end of a line. + if (/;;$/) { + msg " double semi-colons at the end of $. in $fn\n" + } ## Warn about multiple internal spaces. #if (/[^\s,:]\s{2,}[^\s\\=]/) { - # print " X X:$fn:$.\n"; + # msg " X X:$fn:$.\n"; #} ## Warn about { with stuff after. #s/\s+$//; #if (/\{[^\}\\]+$/) { - # print " {X:$fn:$.\n"; + # msg " {X:$fn:$.\n"; #} ## Warn about function calls with space before parens. - # (Don't put a space between the name of a function and its - # arguments.) + # (Don't put a space between the name of a function and its + # arguments.) if (/(\w+)\s\(([A-Z]*)/) { if ($1 ne "if" and $1 ne "while" and $1 ne "for" and $1 ne "switch" and $1 ne "return" and $1 ne "int" and $1 ne "elsif" and $1 ne "WINAPI" and $2 ne "WINAPI" and $1 ne "void" and $1 ne "__attribute__" and $1 ne "op" and - $1 ne "size_t" and $1 ne "double" and + $1 ne "size_t" and $1 ne "double" and $1 ne "uint64_t" and $1 ne "workqueue_reply_t") { - print " fn ():$fn:$.\n"; + msg " fn ():$fn:$.\n"; } } ## Warn about functions not declared at start of line. - # (When you're declaring functions, put "static" and "const" - # and the return type on one line, and the function name at - # the start of a new line.) + # (When you're declaring functions, put "static" and "const" + # and the return type on one line, and the function name at + # the start of a new line.) if ($in_func_head || ($fn !~ /\.h$/ && /^[a-zA-Z0-9_]/ && ! /^(?:const |static )*(?:typedef|struct|union)[^\(]*$/ && ! /= *\{$/ && ! /;$/)) { if (/.\{$/){ - print "fn() {:$fn:$.\n"; + msg "fn() {:$fn:$.\n"; $in_func_head = 0; } elsif (/^\S[^\(]* +\**[a-zA-Z0-9_]+\(/) { $in_func_head = -1; # started with tp fn @@ -151,37 +166,38 @@ for $fn (@ARGV) { $in_func_head = 0; } elsif (/\{/) { if ($in_func_head == -1) { - print "tp fn():$fn:$.\n"; + msg "tp fn():$fn:$.\n"; } $in_func_head = 0; } } - ## Check for forbidden functions except when they are - # explicitly permitted - if (/\bassert\(/ && not /assert OK/) { - print "assert :$fn:$. (use tor_assert)\n"; - } - if (/\bmemcmp\(/ && not /memcmp OK/) { - print "memcmp :$fn:$. (use {tor,fast}_mem{eq,neq,cmp}\n"; - } - # always forbidden. - if (not / OVERRIDE /) { - if (/\bstrcat\(/ or /\bstrcpy\(/ or /\bsprintf\(/) { - print "$& :$fn:$.\n"; - } - if (/\bmalloc\(/ or /\bfree\(/ or /\brealloc\(/ or - /\bstrdup\(/ or /\bstrndup\(/ or /\bcalloc\(/) { - print "$& :$fn:$. (use tor_malloc, tor_free, etc)\n"; - } - } + ## Check for forbidden functions except when they are + # explicitly permitted + if (/\bassert\(/ && not /assert OK/) { + msg "assert :$fn:$. (use tor_assert)\n"; + } + if (/\bmemcmp\(/ && not /memcmp OK/) { + msg "memcmp :$fn:$. (use {tor,fast}_mem{eq,neq,cmp}\n"; + } + # always forbidden. + if (not /\ OVERRIDE\ /) { + if (/\bstrcat\(/ or /\bstrcpy\(/ or /\bsprintf\(/) { + msg "$& :$fn:$.\n"; + } + if (/\bmalloc\(/ or /\bfree\(/ or /\brealloc\(/ or + /\bstrdup\(/ or /\bstrndup\(/ or /\bcalloc\(/) { + msg "$& :$fn:$. (use tor_malloc, tor_free, etc)\n"; + } + } } } ## Warn if the file doesn't end with a blank line. # (End each file with a single blank line.) if (! $lastnil) { - print " EOL\@EOF:$fn:$.\n"; + msg " EOL\@EOF:$fn:$.\n"; } close(F); } +exit $found; diff --git a/scripts/maint/display_callgraph.py b/scripts/maint/display_callgraph.py deleted file mode 100755 index c9001c6d96..0000000000 --- a/scripts/maint/display_callgraph.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/python - -import cPickle - -data = cPickle.load(open("callgraph.pkl")) - -# data = data['modItems'] - -callgraph = data['callgraph'] -closure = data['closure'] -sccs = data['sccs'] -fn_bottle, call_bottle = data['bottlenecks'] - -for n_reachable, fn in sorted(list((len(r), fn) for fn, r in closure.iteritems())): - print "%s can reach %s other functions." %(fn, n_reachable) - - -c = [ (len(component), component) for component in sccs ] -c.sort() - -print "\n================================" - -for n, component in c: - if n < 2: - continue - print "Strongly connected component of size %d:"%n - print component - - -print "\n================================" - -print "====== Number of functions pulled into blob, by function in blob." -fn_bottle.sort() -for n, fn in fn_bottle[-30:]: - print "%3d: %s"%(n, fn) - -print "====== Number of functions pulled into blob, by call in blob." -call_bottle.sort() -for n, fn1, _, fn2 in call_bottle[-30:]: - print "%3d: %s -> %s "%(n, fn2, fn1) - diff --git a/scripts/maint/fallback.blacklist b/scripts/maint/fallback.blacklist index c9fd8a9236..a118cb5919 100644 --- a/scripts/maint/fallback.blacklist +++ b/scripts/maint/fallback.blacklist @@ -3,6 +3,8 @@ # Format: # [ IPv4[:DirPort] ] [ orport=<ORPort> ] [ id=<ID> ] ... # [ ipv6=<IPv6>[:<IPv6 ORPort>] ] +# or use: +# scripts/maint/generateFallbackDirLine.py fingerprint ... # # If a sufficiently specific group of attributes matches, the directory mirror # will be excluded: (each group is listed on its own line) @@ -27,11 +29,6 @@ # https://lists.torproject.org/pipermail/tor-relays/2015-December/008384.html 80.82.215.199:80 orport=443 id=3BEFAB76461B6B99DCF34C285E933562F5712AE4 ipv6=[2001:4ba0:cafe:a18::1]:443 -# https://lists.torproject.org/pipermail/tor-relays/2016-January/008515.html -# later opt-out in -# https://lists.torproject.org/pipermail/tor-relays/2016-January/008521.html -5.9.158.75:80 orport=443 id=F1BE15429B3CE696D6807F4D4A58B1BFEC45C822 ipv6=[2a01:4f8:190:514a::2]:443 - # Email sent directly to teor, verified using relay contact info 5.34.183.168:80 orport=443 id=601C92108A568742A7A6D9473FE3A414F7149070 217.12.199.208:8080 orport=22 id=BCFB0933367D626715DA32A147F417194A5D48D6 @@ -40,14 +37,6 @@ 62.210.207.124:9030 orport=9001 id=58938B1A5C4029B4415D38A4F36B7724273F4755 ipv6=[2001:bc8:31eb:100::1]:9001 62.210.207.124:9130 orport=9101 id=338D0AB6DBAB7B529B9C91B2FD770658000693C4 ipv6=[2001:bc8:31eb:100::1]:9101 -# these fallback candidates fail the consensus download test in a way that -# causes stem to hang (and not respond to ^C, at least on OS X) -# (Is something sending weird responses to DirPort traffic?) -#217.23.14.190:1194 -#151.80.164.147:80 -#148.251.255.92:80 -#78.142.19.59:80 - # Email sent directly to teor, verified using relay contact info 216.17.99.183:80 orport=443 id=D52CD431CEF28E01B11F545A84347EE45524BCA7 216.17.99.183:8080 orport=9001 id=EE21F83AB6F76E3B3FFCBA5C2496F789CB84E7C6 @@ -80,9 +69,6 @@ 185.21.216.140:9030 orport=9001 id=921DA852C95141F8964B359F774B35502E489869 # Email sent directly to teor, verified using relay contact info -62.210.82.44:143 orport=21 id=1C90D3AEADFF3BCD079810632C8B85637924A58E ipv6=[2001:bc8:3d7c::]:21 - -# Email sent directly to teor, verified using relay contact info 46.101.220.161:80 orport=443 id=7DDFE5B2C306B19A79832FBE581EAA245BAE90C6 ipv6=[2a03:b0c0:3:d0::8b:3001]:443 # Email sent directly to teor, verified using relay contact info @@ -132,7 +118,6 @@ 85.114.135.20:9030 orport=9001 id=ED8A9291A3139E34BBD35037B082081EC6C26C80 ipv6=[2001:4ba0:fff5:2d::8]:9001 148.251.128.156:9030 orport=9001 id=E382042E06A0A68AFC533E5AD5FB6867A12DF9FF ipv6=[2a01:4f8:210:238a::8]:9001 62.210.115.147:9030 orport=9001 id=7F1D94E2C36F8CC595C2AB00022A5AE38171D50B ipv6=[2001:bc8:3182:101::8]:9001 -212.47.250.24:9030 orport=9001 id=33DA0CAB7C27812EFF2E22C9705630A54D101FEB # Email sent directly to teor, verified using relay contact info 74.208.220.222:60000 orport=59999 id=4AA22235F0E9B3795A33930343CBB3EDAC60C5B0 @@ -206,24 +191,42 @@ # Email sent directly to teor, verified using relay contact info 88.190.208.4:30555 orport=30556 id=030A6EB24725C05D8E0FCE21923CBA5223E75E0E -# Fallback was on 0.2.8.2-alpha list, but changed fingerprint before 0.2.8.5 -46.101.102.71:80 orport=443 id=9504CB22EEB25D344DE63CB7A6F2C46F895C3686 ipv6=[2a03:b0c0:3:d0::2ed:7001]:9050 -# Also blacklist anything with the new fingerprint -id=9C8A123081EFBE022EF795630F447839DDFDDDEC +# Fallback was on 0.2.8.2-alpha list, but opted-out before 0.2.8.6 +37.187.1.149:9030 orport=9001 id=08DC0F3C6E3D9C527C1FC8745D35DD1B0DE1875D ipv6=[2001:41d0:a:195::1]:9001 -# Fallbacks were on 0.2.8.2-alpha list, but downloads were slow before 0.2.8.5 -185.96.88.29:80 orport=443 id=86C281AD135058238D7A337D546C902BE8505DDE -178.62.36.64:9030 orport=9001 id=B87C84E38DAECFFFFDE98E5AEE5786AFDC748F2C +# Email sent directly to teor, verified using relay contact info +195.154.15.227:9030 orport=9001 id=6C3E3AB2F5F03CD71B637D433BAD924A1ECC5796 -# Fallback was on 0.2.8.2-alpha list, but changed address before 0.2.8.5 -84.219.173.60:9030 orport=443 id=855BC2DABE24C861CD887DB9B2E950424B49FC34 -# Also blacklist anything with the new address -84.216.235.55:9030 orport=443 +# Fallback was on 0.2.8.6 list, but opted-out before 0.2.9 +144.76.73.140:9030 orport=9001 id=6A640018EABF3DA9BAD9321AA37C2C87BBE1F907 -# Fallbacks were on 0.2.8.2-alpha list, but disappeared before 0.2.8.5 -81.7.17.171:80 orport=443 id=CFECDDCA990E3EF7B7EC958B22441386B6B8D820 ipv6=[2a02:180:1:1::517:11ab]:443 -51.254.215.121:80 orport=443 id=262B66AD25C79588AD1FC8ED0E966395B47E5C1D -185.100.85.138:80 orport=46356 id=5C4DF16A0029CC4F67D3E127356E68F219269859 +# https://lists.torproject.org/pipermail/tor-relays/2016-December/011114.html +# no dirport +86.107.110.34:0 orport=9001 id=A0E3D30A660DB70CA0B6D081BA54D094DED6F28D +94.242.59.147:80 orport=9001 id=674DCBB0D9C1C4C4DBFB4A9AE024AF59FE4E7F46 ipv6=[2a00:1838:35:42::b648]:9001 -# Fallback was on 0.2.8.2-alpha list, but opted-out before 0.2.8.6 -37.187.1.149:9030 orport=9001 id=08DC0F3C6E3D9C527C1FC8745D35DD1B0DE1875D ipv6=[2001:41d0:a:195::1]:9001 +# Email sent directly to teor, verified using relay contact info +167.114.152.100:9030 orport=443 id=0EF5E5FFC5D1EABCBDA1AFF6F6D6325C5756B0B2 ipv6=[2607:5300:100:200::1608]:443 + +# Email sent directly to teor, verified using relay contact info +163.172.35.245:80 orport=443 id=B771AA877687F88E6F1CA5354756DF6C8A7B6B24 + +# Email sent directly to teor, verified using relay contact info +104.243.35.196:9030 orport=9001 id=FA3415659444AE006E7E9E5375E82F29700CFDFD + +# Emails sent directly to teor, verified using relay contact info +217.12.199.208:80 orport=443 id=DF3AED4322B1824BF5539AE54B2D1B38E080FF05 ipv6=[2a02:27a8:0:2::7e]:443 + +# Emails sent directly to teor, verified using relay contact info +195.154.75.84:9030 orport=9001 id=F80FDE27EFCB3F6A7B4E2CC517133DBFFA78BA2D +195.154.127.246:9030 orport=9001 id=4FEE77AFFD157BBCF2D896AE417FBF647860466C + +# Email sent directly to teor, verified using relay contact info +5.35.251.247:9030 orport=9001 id=9B1F5187DFBA89DC24B37EA7BF896C12B43A27AE + +#https://lists.torproject.org/pipermail/tor-relays/2017-May/012281.html +62.210.124.124:9030 orport=9001 id=86E78DD3720C78DA8673182EF96C54B162CD660C ipv6=[2001:bc8:3f23:100::1]:9001 +62.210.124.124:9130 orport=9101 id=2EBD117806EE43C3CC885A8F1E4DC60F207E7D3E ipv6=[2001:bc8:3f23:100::1]:9101 + +# Email sent directly to teor +212.51.156.193:995 orport=110 id=32E7AAF1F602814D699BEF6761AD03E387758D49 ipv6=[2a02:168:4a01::49]:110 diff --git a/scripts/maint/fallback.whitelist b/scripts/maint/fallback.whitelist index c801e46b15..e9158e1280 100644 --- a/scripts/maint/fallback.whitelist +++ b/scripts/maint/fallback.whitelist @@ -2,6 +2,8 @@ # # Format: # IPv4:DirPort orport=<ORPort> id=<ID> [ ipv6=<IPv6>:<IPv6 ORPort> ] +# or use: +# scripts/maint/generateFallbackDirLine.py fingerprint ... # # All attributes must match for the directory mirror to be included. # If the fallback has an ipv6 key, the whitelist line must also have @@ -28,8 +30,9 @@ # <IPv4>:<DirPort> orport=<ORPort> id=<ID> [ ipv6=<IPv6>:<IPv6 ORPort> ] # https://lists.torproject.org/pipermail/tor-relays/2015-December/008362.html -78.47.18.110:443 orport=80 id=F8D27B163B9247B232A2EEE68DD8B698695C28DE -131.188.40.188:443 orport=80 id=EBE718E1A49EE229071702964F8DB1F318075FF8 +# https://trac.torproject.org/projects/tor/ticket/22321#comment:22 +78.47.18.110:443 orport=80 id=F8D27B163B9247B232A2EEE68DD8B698695C28DE ipv6=[2a01:4f8:120:4023::110]:80 # fluxe3 +131.188.40.188:1443 orport=80 id=EBE718E1A49EE229071702964F8DB1F318075FF8 ipv6=[2001:638:a000:4140::ffff:188]:80 # fluxe4 # https://lists.torproject.org/pipermail/tor-relays/2015-December/008366.html 5.39.88.19:9030 orport=9001 id=7CB8C31432A796731EA7B6BF4025548DFEB25E0C ipv6=[2001:41d0:8:9a13::1]:9050 @@ -37,8 +40,6 @@ # https://lists.torproject.org/pipermail/tor-relays/2015-December/008370.html # https://lists.torproject.org/pipermail/tor-relays/2016-January/008517.html # https://lists.torproject.org/pipermail/tor-relays/2016-January/008555.html -62.210.124.124:9030 orport=9001 id=86E78DD3720C78DA8673182EF96C54B162CD660C ipv6=[2001:bc8:3f23:100::1]:9001 -62.210.124.124:9130 orport=9101 id=2EBD117806EE43C3CC885A8F1E4DC60F207E7D3E ipv6=[2001:bc8:3f23:100::1]:9101 212.47.237.95:9030 orport=9001 id=3F5D8A879C58961BB45A3D26AC41B543B40236D6 212.47.237.95:9130 orport=9101 id=6FB38EB22E57EF7ED5EF00238F6A48E553735D88 @@ -49,27 +50,26 @@ # https://lists.torproject.org/pipermail/tor-relays/2015-December/008373.html 167.114.35.28:9030 orport=9001 id=E65D300F11E1DB12C534B0146BDAB6972F1A8A48 -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008374.html -170.130.1.7:9030 orport=9001 id=FA3415659444AE006E7E9E5375E82F29700CFDFD - # https://lists.torproject.org/pipermail/tor-relays/2015-December/008378.html 144.76.14.145:110 orport=143 id=14419131033443AE6E21DA82B0D307F7CAE42BDB ipv6=[2a01:4f8:190:9490::dead]:443 # https://lists.torproject.org/pipermail/tor-relays/2015-December/008379.html # Email sent directly to teor, verified using relay contact info 91.121.84.137:4951 orport=4051 id=6DE61A6F72C1E5418A66BFED80DFB63E4C77668F - -# https://lists.torproject.org/pipermail/tor-relays/2015-December/008380.html -5.175.233.86:80 orport=443 id=5525D0429BFE5DC4F1B0E9DE47A4CFA169661E33 +91.121.84.137:4952 orport=4052 id=9FBEB75E8BC142565F12CBBE078D63310236A334 # https://lists.torproject.org/pipermail/tor-relays/2015-December/008381.html -# Sent additional email to teor with more relays -178.254.44.135:9030 orport=9001 id=8FA37B93397015B2BC5A525C908485260BE9F422 -178.254.20.134:80 orport=443 id=9F5068310818ED7C70B0BC4087AB55CB12CB4377 -178.254.20.134:9030 orport=9001 id=2CE96A8A1DA032664C90F574AFFBECE18A6E8DFC -178.254.44.135:80 orport=443 id=AE6A8C18E7499B586CD36246AC4BCAFFBBF93AB2 -178.254.13.126:80 orport=443 id=F9246DEF2B653807236DA134F2AEAB103D58ABFE -178.254.13.126:9030 orport=9001 id=0C475BA4D3AA3C289B716F95954CAD616E50C4E5 +# Sent additional emails to teor with updated relays +81.7.11.96:9030 orport=9001 id=8FA37B93397015B2BC5A525C908485260BE9F422 # Doedel22 +# 9F5068310818ED7C70B0BC4087AB55CB12CB4377 not found in current consensus +178.254.19.101:80 orport=443 id=F9246DEF2B653807236DA134F2AEAB103D58ABFE # Freebird31 +178.254.19.101:9030 orport=9001 id=0C475BA4D3AA3C289B716F95954CAD616E50C4E5 # Freebird32 +81.7.14.253:9001 orport=443 id=1AE039EE0B11DB79E4B4B29CBA9F752864A0259E # Ichotolot60 +81.7.11.186:1080 orport=443 id=B86137AE9681701901C6720E55C16805B46BD8E3 # BeastieJoy60 +85.25.213.211:465 orport=80 id=CE47F0356D86CF0A1A2008D97623216D560FB0A8 # BeastieJoy61 +85.25.159.65:995 orport=80 id=52BFADA8BEAA01BA46C8F767F83C18E2FE50C1B9 # BeastieJoy63 +81.7.3.67:993 orport=443 id=A2E6BB5C391CD46B38C55B4329C35304540771F1 # BeastieJoy62 +81.7.14.31:9001 orport=443 id=7600680249A22080ECC6173FBBF64D6FCF330A61 # Ichotolot62 # https://lists.torproject.org/pipermail/tor-relays/2015-December/008382.html 51.255.33.237:9091 orport=9001 id=A360C21FA87FFA2046D92C17086A6B47E5C68109 @@ -98,33 +98,28 @@ # https://lists.torproject.org/pipermail/tor-relays/2016-January/008542.html 178.62.199.226:80 orport=443 id=CBEFF7BA4A4062045133C053F2D70524D8BBE5BE ipv6=[2a03:b0c0:2:d0::b7:5001]:443 -# Emails sent directly to teor, verified using relay contact info -217.12.199.208:80 orport=443 id=DF3AED4322B1824BF5539AE54B2D1B38E080FF05 - # Email sent directly to teor, verified using relay contact info 94.23.204.175:9030 orport=9001 id=5665A3904C89E22E971305EE8C1997BCA4123C69 -# https://twitter.com/binarytenshi/status/717952514327453697 -94.126.23.174:9030 orport=9001 id=6FC6F08270D565BE89B7C819DD8E2D487397C073 - # Email sent directly to teor, verified using relay contact info -171.25.193.78:80 orport=443 id=A478E421F83194C114F41E94F95999672AED51FE ipv6=[2001:67c:289c:3::78]:443 171.25.193.77:80 orport=443 id=A10C4F666D27364036B562823E5830BC448E046A ipv6=[2001:67c:289c:3::77]:443 -171.25.193.131:80 orport=443 id=79861CF8522FC637EF046F7688F5289E49D94576 +171.25.193.78:80 orport=443 id=A478E421F83194C114F41E94F95999672AED51FE ipv6=[2001:67c:289c:3::78]:443 171.25.193.20:80 orport=443 id=DD8BD7307017407FCC36F8D04A688F74A0774C02 ipv6=[2001:67c:289c::20]:443 -# OK, but same machine as 79861CF8522FC637EF046F7688F5289E49D94576 -#171.25.193.132:80 orport=443 id=01C67E0CA8F97111E652C7564CB3204361FFFAB8 -# OK, but same machine as DD8BD7307017407FCC36F8D04A688F74A0774C02 -#171.25.193.25:80 orport=443 id=185663B7C12777F052B2C2D23D7A239D8DA88A0F ipv6=[2001:67c:289c::25]:443 +# same machine as DD8BD7307017407FCC36F8D04A688F74A0774C02 +171.25.193.25:80 orport=443 id=185663B7C12777F052B2C2D23D7A239D8DA88A0F ipv6=[2001:67c:289c::25]:443 # Email sent directly to teor, verified using relay contact info -212.47.229.2:9030 orport=9001 id=20462CBA5DA4C2D963567D17D0B7249718114A68 +212.47.229.2:9030 orport=9001 id=20462CBA5DA4C2D963567D17D0B7249718114A68 ipv6=[2001:bc8:4400:2100::f03]:9001 93.115.97.242:9030 orport=9001 id=B5212DB685A2A0FCFBAE425738E478D12361710D -46.28.109.231:9030 orport=9001 id=F70B7C5CD72D74C7F9F2DC84FA9D20D51BA13610 ipv6=[2a02:2b88:2:1::4205:42]:9001 +46.28.109.231:9030 orport=9001 id=F70B7C5CD72D74C7F9F2DC84FA9D20D51BA13610 ipv6=[2a02:2b88:2:1::4205:1]:9001 # Email sent directly to teor, verified using relay contact info -85.235.250.88:80 orport=443 id=72B2B12A3F60408BDBC98C6DF53988D3A0B3F0EE -185.96.180.29:80 orport=443 id=F93D8F37E35C390BCAD9F9069E13085B745EC216 +85.235.250.88:80 orport=443 id=72B2B12A3F60408BDBC98C6DF53988D3A0B3F0EE # TykRelay01 +185.96.88.29:80 orport=443 id=86C281AD135058238D7A337D546C902BE8505DDE # TykRelay051 +# This fallback opted-in in previous releases, then changed its details, +# and so we blacklisted it. Now we want to whitelist changes. +# Assume details update is permanent +185.96.180.29:80 orport=443 id=F93D8F37E35C390BCAD9F9069E13085B745EC216 # TykRelay06 # Email sent directly to teor, verified using relay contact info 185.11.180.67:80 orport=9001 id=794D8EA8343A4E820320265D05D4FA83AB6D1778 @@ -154,31 +149,20 @@ 178.16.208.59:80 orport=443 id=136F9299A5009A4E0E96494E723BDB556FB0A26B ipv6=[2a00:1c20:4089:1234:bff6:e1bb:1ce3:8dc6]:443 # Email sent directly to teor, verified using relay contact info -195.154.8.111:80 orport=443 id=FCB6695F8F2DC240E974510A4B3A0F2B12AB5B64 -51.255.235.246:80 orport=443 id=9B99C72B02AF8E3E5BE3596964F9CACD0090D132 5.39.76.158:80 orport=443 id=C41F60F8B00E7FEF5CCC5BC6BB514CA1B8AAB651 # Email sent directly to teor, verified using relay contact info -109.163.234.5:80 orport=443 id=5C84C35936B7100B949AC75764EEF1352550550B -109.163.234.7:80 orport=443 id=C46524E586E1B997329703D356C07EE12B28C722 -109.163.234.9:80 orport=443 id=5714542DCBEE1DD9864824723638FD44B2122CEA -77.247.181.162:80 orport=443 id=7BB160A8F54BD74F3DA5F2CE701E8772B841859D -109.163.234.4:80 orport=443 id=6B1E001929AF4DDBB747D02EC28340792B7724A6 -77.247.181.164:80 orport=443 id=10E13E340651D0EF66B4DEBF610B3C0981168107 -109.163.234.8:80 orport=443 id=20B0038D7A2FD73C696922551B8344CB0893D1F8 -77.247.181.166:80 orport=443 id=06E123865C590189B3181114F23F0F13A7BC0E69 -109.163.234.2:80 orport=443 id=B4F883DB3D478C7AE569C9F6CB766FD58650DC6A -62.102.148.67:80 orport=443 id=4A0C3E177AF684581EF780981AEAF51A98A6B5CF -109.163.234.5:80 orport=443 id=5C84C35936B7100B949AC75764EEF1352550550B -109.163.234.7:80 orport=443 id=C46524E586E1B997329703D356C07EE12B28C722 -109.163.234.9:80 orport=443 id=5714542DCBEE1DD9864824723638FD44B2122CEA -77.247.181.162:80 orport=443 id=7BB160A8F54BD74F3DA5F2CE701E8772B841859D -109.163.234.4:80 orport=443 id=6B1E001929AF4DDBB747D02EC28340792B7724A6 -77.247.181.164:80 orport=443 id=10E13E340651D0EF66B4DEBF610B3C0981168107 -109.163.234.8:80 orport=443 id=20B0038D7A2FD73C696922551B8344CB0893D1F8 -77.247.181.166:80 orport=443 id=06E123865C590189B3181114F23F0F13A7BC0E69 -109.163.234.2:80 orport=443 id=B4F883DB3D478C7AE569C9F6CB766FD58650DC6A +109.163.234.2:80 orport=443 id=14F92FF956105932E9DEC5B82A7778A0B1BD9A52 +109.163.234.4:80 orport=443 id=4888770464F0E900EFEF1BA181EA873D13F7713C +109.163.234.5:80 orport=443 id=5EB8D862E70981B8690DEDEF546789E26AB2BD24 +109.163.234.7:80 orport=443 id=23038A7F2845EBA2234ECD6651BD4A7762F51B18 +109.163.234.8:80 orport=443 id=0818DAE0E2DDF795AEDEAC60B15E71901084F281 +109.163.234.9:80 orport=443 id=ABF7FBF389C9A747938B639B20E80620B460B2A9 62.102.148.67:80 orport=443 id=4A0C3E177AF684581EF780981AEAF51A98A6B5CF +# Assume details update is permanent +77.247.181.166:80 orport=443 id=77131D7E2EC1CA9B8D737502256DA9103599CE51 # CriticalMass +77.247.181.164:80 orport=443 id=204DFD2A2C6A0DC1FA0EACB495218E0B661704FD # HaveHeart +77.247.181.162:80 orport=443 id=7BFB908A3AA5B491DA4CA72CCBEE0E1F2A939B55 # sofia # https://twitter.com/biotimylated/status/718994247500718080 212.47.252.149:9030 orport=9001 id=2CAC39BAA996791CEFAADC9D4754D65AF5EB77C0 @@ -215,9 +199,7 @@ # Email sent directly to teor, verified using relay contact info 86.59.119.88:80 orport=443 id=ACD889D86E02EDDAB1AFD81F598C0936238DC6D0 - -# Email sent directly to teor, verified using relay contact info -144.76.73.140:9030 orport=9001 id=6A640018EABF3DA9BAD9321AA37C2C87BBE1F907 +86.59.119.83:80 orport=443 id=FC9AC8EA0160D88BCCFDE066940D7DD9FA45495B # Email sent directly to teor, verified using relay contact info 193.11.164.243:9030 orport=9001 id=FFA72BD683BC2FCF988356E6BEC1E490F313FB07 ipv6=[2001:6b0:7:125::243]:9001 @@ -232,20 +214,19 @@ # Email sent directly to teor, verified using relay contact info 89.187.142.208:80 orport=443 id=64186650FFE4469EBBE52B644AE543864D32F43C -# Email sent directly to teor, verified using relay contact info -212.51.134.123:9030 orport=9001 id=50586E25BE067FD1F739998550EDDCB1A14CA5B2 ipv6=[2a02:168:6e00:0:3a60:77ff:fe9c:8bd1]:9001 +# Email sent directly to teor +# Assume details update is permanent +212.51.134.123:9030 orport=9001 id=50586E25BE067FD1F739998550EDDCB1A14CA5B2 # Jans # Email sent directly to teor, verified using relay contact info 46.101.143.173:80 orport=443 id=F960DF50F0FD4075AC9B505C1D4FFC8384C490FB # Email sent directly to teor, verified using relay contact info -217.79.190.25:9030 orport=9090 id=361D33C96D0F161275EE67E2C91EE10B276E778B - -# Email sent directly to teor, verified using relay contact info 193.171.202.146:9030 orport=9001 id=01A9258A46E97FF8B2CAC7910577862C14F2C524 # Email sent directly to teor, verified using relay contact info -197.231.221.211:9030 orport=9001 id=BC630CBBB518BE7E9F4E09712AB0269E9DC7D626 +# Assume details update is permanent +197.231.221.211:9030 orport=443 id=BC630CBBB518BE7E9F4E09712AB0269E9DC7D626 # IPredator # Email sent directly to teor, verified using relay contact info 185.61.138.18:8080 orport=4443 id=2541759BEC04D37811C2209A88E863320271EC9C @@ -256,7 +237,7 @@ 193.11.114.46:9032 orport=9003 id=B83DC1558F0D34353BB992EF93AFEAFDB226A73E # Email sent directly to teor, verified using relay contact info -144.76.26.175:9012 orport=9011 id=2BA2C8E96B2590E1072AECE2BDB5C48921BF8510 +138.201.250.33:9012 orport=9011 id=2BA2C8E96B2590E1072AECE2BDB5C48921BF8510 # Email sent directly to teor, verified using relay contact info 37.221.162.226:9030 orport=9001 id=D64366987CB39F61AD21DBCF8142FA0577B92811 @@ -274,12 +255,12 @@ 134.119.3.164:9030 orport=9001 id=D1B8AAA98C65F3DF7D8BB3AF881CAEB84A33D8EE # Email sent directly to teor, verified using relay contact info -81.7.10.93:31336 orport=31337 id=99E246DB480B313A3012BC3363093CC26CD209C7 +173.212.254.192:31336 orport=31337 id=99E246DB480B313A3012BC3363093CC26CD209C7 # Email sent directly to teor, verified using relay contact info 178.62.22.36:80 orport=443 id=A0766C0D3A667A3232C7D569DE94A28F9922FCB1 ipv6=[2a03:b0c0:1:d0::174:1]:9050 -188.166.23.127:80 orport=443 id=3771A8154DEA98D551607806C80A209CDAA74535 ipv6=[2a03:b0c0:2:d0::27b:7001]:9050 -198.199.64.217:80 orport=443 id=FAD306BAA59F6A02783F8606BDAA431F5FF7D1EA ipv6=[2604:a880:400:d0::1a9:b001]:9050 +188.166.23.127:80 orport=443 id=8672E8A01B4D3FA4C0BBE21C740D4506302EA487 ipv6=[2a03:b0c0:2:d0::27b:7001]:9050 +198.199.64.217:80 orport=443 id=B1D81825CFD7209BD1B4520B040EF5653C204A23 ipv6=[2604:a880:400:d0::1a9:b001]:9050 159.203.32.149:80 orport=443 id=55C7554AFCEC1062DCBAC93E67B2E03C6F330EFC ipv6=[2604:a880:cad:d0::105:f001]:9050 # Email sent directly to teor, verified using relay contact info @@ -301,9 +282,6 @@ 212.47.230.49:9030 orport=9001 id=3D6D0771E54056AEFC28BB1DE816951F11826E97 # Email sent directly to teor, verified using relay contact info -176.31.180.157:143 orport=22 id=E781F4EC69671B3F1864AE2753E0890351506329 ipv6=[2001:41d0:8:eb9d::1]:22 - -# Email sent directly to teor, verified using relay contact info 192.99.55.69:80 orport=443 id=0682DE15222A4A4A0D67DBA72A8132161992C023 192.99.59.140:80 orport=443 id=3C9148DA49F20654730FAC83FFF693A4D49D0244 51.254.215.13:80 orport=443 id=73C30C8ABDD6D9346C822966DE73B9F82CB6178A @@ -318,7 +296,7 @@ 151.80.42.103:9030 orport=9001 id=9007C1D8E4F03D506A4A011B907A9E8D04E3C605 ipv6=[2001:41d0:e:f67::114]:9001 # Email sent directly to teor, verified using relay contact info -5.39.92.199:80 orport=443 id=0BEA4A88D069753218EAAAD6D22EA87B9A1319D6 +5.39.92.199:80 orport=443 id=0BEA4A88D069753218EAAAD6D22EA87B9A1319D6 ipv6=[2001:41d0:8:b1c7::1]:443 # Email sent directly to teor, verified using relay contact info 176.31.159.231:80 orport=443 id=D5DBCC0B4F029F80C7B8D33F20CF7D97F0423BB1 @@ -328,17 +306,15 @@ 46.148.18.74:8080 orport=443 id=6CACF0B5F03C779672F3C5C295F37C8D234CA3F7 # Email sent directly to teor, verified using relay contact info -37.187.102.108:9090 orport=5550 id=F4263275CF54A6836EE7BD527B1328836A6F06E1 -212.47.241.21:80 orport=443 id=892F941915F6A0C6E0958E52E0A9685C190CF45C +37.187.102.108:80 orport=443 id=F4263275CF54A6836EE7BD527B1328836A6F06E1 ipv6=[2001:41d0:a:266c::1]:443 # EvilMoe +212.47.241.21:80 orport=443 id=892F941915F6A0C6E0958E52E0A9685C190CF45C # EvilMoe # Email sent directly to teor, verified using relay contact info -195.191.233.221:80 orport=443 id=DE134FC8E5CC4EC8A5DE66934E70AC9D70267197 +212.129.38.254:9030 orport=9001 id=FDF845FC159C0020E2BDDA120C30C5C5038F74B4 -# Email sent directly to teor, verified using relay contact info -62.210.238.33:9030 orport=9001 id=FDF845FC159C0020E2BDDA120C30C5C5038F74B4 - -# Email sent directly to teor, verified using relay contact info -37.157.195.87:8030 orport=443 id=12FD624EE73CEF37137C90D38B2406A66F68FAA2 +# Email sent directly to teor +37.157.195.87:8030 orport=443 id=12FD624EE73CEF37137C90D38B2406A66F68FAA2 # thanatosCZ +5.189.169.190:8030 orport=8080 id=8D79F73DCD91FC4F5017422FAC70074D6DB8DD81 # thanatosDE # Email sent directly to teor, verified using relay contact info 37.187.7.74:80 orport=443 id=AEA43CB1E47BE5F8051711B2BF01683DB1568E05 ipv6=[2001:41d0:a:74a::1]:443 @@ -356,9 +332,6 @@ 37.187.102.186:9030 orport=9001 id=489D94333DF66D57FFE34D9D59CC2D97E2CB0053 ipv6=[2001:41d0:a:26ba::1]:9001 # Email sent directly to teor, verified using relay contact info -5.35.251.247:9030 orport=9001 id=9B1F5187DFBA89DC24B37EA7BF896C12B43A27AE - -# Email sent directly to teor, verified using relay contact info 198.96.155.3:8080 orport=5001 id=BCEDF6C193AA687AE471B8A22EBF6BC57C2D285E # Email sent directly to teor, verified using relay contact info @@ -405,14 +378,6 @@ 91.219.237.229:80 orport=443 id=1ECD73B936CB6E6B3CD647CC204F108D9DF2C9F7 # Email sent directly to teor, verified using relay contact info -# Suitable, check with operator before adding -#212.47.240.10:82 orport=443 id=2A4C448784F5A83AFE6C78DA357D5E31F7989DEB -212.47.240.10:81 orport=993 id=72527E3242CB15AADE28374AE0D35833FC083F60 -163.172.131.88:80 orport=443 id=AD253B49E303C6AB1E048B014392AC569E8A7DAE ipv6=[2001:bc8:4400:2100::2:1009]:443 -# Suitable, check with operator before adding -#163.172.131.88:81 orport=993 id=D5F3FB17504744FB7ECEF46F4B1D155258A6D942 ipv6=D5F3FB17504744FB7ECEF46F4B1D155258A6D942 - -# Email sent directly to teor, verified using relay contact info 46.101.151.222:80 orport=443 id=1DBAED235E3957DE1ABD25B4206BE71406FB61F8 178.62.60.37:80 orport=443 id=175921396C7C426309AB03775A9930B6F611F794 @@ -440,11 +405,8 @@ # Email sent directly to teor, verified using relay contact info 5.199.142.236:9030 orport=9001 id=F4C0EDAA0BF0F7EC138746F8FEF1CE26C7860265 -# Email sent directly to teor, verified using relay contact info -188.166.133.133:9030 orport=9001 id=774555642FDC1E1D4FDF2E0C31B7CA9501C5C9C7 ipv6=[2a03:b0c0:2:d0::5:f001]:9001 - -# Email sent directly to teor, verified using relay contact info -5.196.88.122:9030 orport=9001 id=0C2C599AFCB26F5CFC2C7592435924C1D63D9484 +# Email sent directly to teor +188.166.133.133:9030 orport=9001 id=774555642FDC1E1D4FDF2E0C31B7CA9501C5C9C7 ipv6=[2a03:b0c0:2:d0::26c0:1]:9001 # dropsy # Email sent directly to teor, verified using relay contact info 46.8.249.10:80 orport=443 id=31670150090A7C3513CB7914B9610E786391A95D @@ -456,12 +418,10 @@ 46.4.24.161:9030 orport=9001 id=DB4C76A3AD7E234DA0F00D6F1405D8AFDF4D8DED 46.4.24.161:9031 orport=9002 id=7460F3D12EBE861E4EE073F6233047AACFE46AB4 46.38.51.132:9030 orport=9001 id=810DEFA7E90B6C6C383C063028EC397A71D7214A -163.172.194.53:9030 orport=9001 id=8C00FA7369A7A308F6A137600F0FA07990D9D451 +163.172.194.53:9030 orport=9001 id=8C00FA7369A7A308F6A137600F0FA07990D9D451 ipv6=[2001:bc8:225f:142:6c69:7461:7669:73]:9001 # Email sent directly to teor, verified using relay contact info 176.10.107.180:9030 orport=9001 id=3D7E274A87D9A89AF064C13D1EE4CA1F184F2600 -195.154.75.84:9030 orport=9001 id=F80FDE27EFCB3F6A7B4E2CC517133DBFFA78BA2D -195.154.127.246:9030 orport=9001 id=4FEE77AFFD157BBCF2D896AE417FBF647860466C # Email sent directly to teor, verified using relay contact info 46.28.207.19:80 orport=443 id=5B92FA5C8A49D46D235735504C72DBB3472BA321 @@ -485,11 +445,10 @@ 5.9.146.203:80 orport=443 id=1F45542A24A61BF9408F1C05E0DCE4E29F2CBA11 # Email sent directly to teor, verified using relay contact info -167.114.152.100:9030 orport=443 id=0EF5E5FFC5D1EABCBDA1AFF6F6D6325C5756B0B2 ipv6=[2607:5300:100:200::1608]:443 - -# Email sent directly to teor, verified using relay contact info -192.99.168.102:80 orport=443 id=230A8B2A8BA861210D9B4BA97745AEC217A94207 -167.114.153.21:80 orport=443 id=0B85617241252517E8ECF2CFC7F4C1A32DCD153F +# Updated details from atlas based on ticket #20010 +163.172.176.167:80 orport=443 id=230A8B2A8BA861210D9B4BA97745AEC217A94207 +163.172.149.155:80 orport=443 id=0B85617241252517E8ECF2CFC7F4C1A32DCD153F +163.172.149.122:80 orport=443 id=A9406A006D6E7B5DA30F2C6D4E42A338B5E340B2 # Email sent directly to teor, verified using relay contact info 204.11.50.131:9030 orport=9001 id=185F2A57B0C4620582602761097D17DB81654F70 @@ -498,13 +457,10 @@ 151.236.222.217:44607 orport=9001 id=94D58704C2589C130C9C39ED148BD8EA468DBA54 # Email sent directly to teor, verified using relay contact info -194.150.168.79:11112 orport=11111 id=29F1020B94BE25E6BE1AD13E93CE19D2131B487C - -# Email sent directly to teor, verified using relay contact info 185.35.202.221:9030 orport=9001 id=C13B91384CDD52A871E3ECECE4EF74A7AC7DCB08 ipv6=[2a02:ed06::221]:9001 # Email sent directly to teor, verified using relay contact info -5.9.151.241:9030 orport=4223 id=9BF04559224F0F1C3C953D641F1744AF0192543A +5.9.151.241:9030 orport=4223 id=9BF04559224F0F1C3C953D641F1744AF0192543A ipv6=[2a01:4f8:190:34f0::2]:4223 # Email sent directly to teor, verified using relay contact info 89.40.71.149:8081 orport=8080 id=EC639EDAA5121B47DBDF3D6B01A22E48A8CB6CC7 @@ -513,7 +469,7 @@ 92.222.20.130:80 orport=443 id=0639612FF149AA19DF3BCEA147E5B8FED6F3C87C # Email sent directly to teor, verified using relay contact info -80.112.155.100:9030 orport=9001 id=1163378F239C36CA1BDC730AC50BF4F2976141F5 ipv6=[2001:470:7b02::38]:9001 +80.112.155.100:9030 orport=9001 id=53B000310984CD86AF47E5F3CD0BFF184E34B383 ipv6=[2001:470:7b02::38]:9001 # Email sent directly to teor, verified using relay contact info 83.212.99.68:80 orport=443 id=DDBB2A38252ADDA53E4492DDF982CA6CC6E10EC0 ipv6=[2001:648:2ffc:1225:a800:bff:fe3d:67b5]:443 @@ -522,9 +478,6 @@ 95.130.11.147:9030 orport=443 id=6B697F3FF04C26123466A5C0E5D1F8D91925967A # Email sent directly to teor, verified using relay contact info -176.31.191.26:9030 orport=9001 id=7350AB9ED7568F22745198359373C04AC783C37C - -# Email sent directly to teor, verified using relay contact info 128.199.55.207:9030 orport=9001 id=BCEF908195805E03E92CCFE669C48738E556B9C5 ipv6=[2a03:b0c0:2:d0::158:3001]:9001 # Email sent directly to teor, verified using relay contact info @@ -540,16 +493,17 @@ 80.240.139.111:80 orport=443 id=DD3BE7382C221F31723C7B294310EF9282B9111B # Email sent directly to teor, verified using relay contact info -185.97.32.18:9030 orport=9001 id=3BAB316CAAEC47E71905EB6C65584636D5689A8A +185.97.32.18:9030 orport=9001 id=04250C3835019B26AA6764E85D836088BE441088 -# Email sent directly to teor, verified using relay contact info -149.56.45.200:9030 orport=9001 id=FE296180018833AF03A8EACD5894A614623D3F76 +# Email sent directly to teor +149.56.45.200:9030 orport=9001 id=FE296180018833AF03A8EACD5894A614623D3F76 ipv6=[2607:5300:201:3000::17d3]:9002 # PiotrTorpotkinOne # Email sent directly to teor, verified using relay contact info -81.2.209.10:443 orport=80 id=B6904ADD4C0D10CDA7179E051962350A69A63243 +81.2.209.10:443 orport=80 id=B6904ADD4C0D10CDA7179E051962350A69A63243 ipv6=[2001:15e8:201:1::d10a]:80 # Email sent directly to teor, verified using relay contact info -195.154.164.243:80 orport=443 id=AC66FFA4AB35A59EBBF5BF4C70008BF24D8A7A5C ipv6=[2001:bc8:399f:f000::1]:993 +# IPv6 address unreliable +195.154.164.243:80 orport=443 id=AC66FFA4AB35A59EBBF5BF4C70008BF24D8A7A5C #ipv6=[2001:bc8:399f:f000::1]:993 138.201.26.2:80 orport=443 id=6D3A3ED5671E4E3F58D4951438B10AE552A5FA0F 81.7.16.182:80 orport=443 id=51E1CF613FD6F9F11FE24743C91D6F9981807D82 ipv6=[2a02:180:1:1::517:10b6]:993 134.119.36.135:80 orport=443 id=763C9556602BD6207771A7A3D958091D44C43228 ipv6=[2a00:1158:3::2a8]:993 @@ -563,7 +517,7 @@ 217.12.208.117:80 orport=443 id=E6E18151300F90C235D3809F90B31330737CEB43 ipv6=[2a00:1ca8:a7::1bb]:993 81.7.10.251:80 orport=443 id=8073670F8F852971298F8AF2C5B23AE012645901 ipv6=[2a02:180:1:1::517:afb]:993 46.36.39.50:80 orport=443 id=ED4B0DBA79AEF5521564FA0231455DCFDDE73BB6 ipv6=[2a02:25b0:aaaa:aaaa:8d49:b692:4852:0]:995 -91.194.90.103:80 orport=443 id=75C4495F4D80522CA6F6A3FB349F1B009563F4B7 ipv6=[2a02:c200:0:10:3:0:5449:1]:993 +91.194.90.103:80 orport=443 id=75C4495F4D80522CA6F6A3FB349F1B009563F4B7 ipv6=[2a02:c205:3000:5449::1]:993 163.172.25.118:80 orport=22 id=0CF8F3E6590F45D50B70F2F7DA6605ECA6CD408F 188.138.88.42:80 orport=443 id=70C55A114C0EF3DC5784A4FAEE64388434A3398F 81.7.13.84:80 orport=443 id=0C1E7DD9ED0676C788933F68A9985ED853CA5812 ipv6=[2a02:180:1:1::5b8f:538c]:993 @@ -580,18 +534,17 @@ # Email sent directly to teor, verified using relay contact info 212.238.208.48:9030 orport=9001 id=F406219CDD339026D160E53FCA0EF6857C70F109 ipv6=[2001:984:a8fb:1:ba27:ebff:feac:c109]:9001 -# Email sent directly to teor, verified using relay contact info -176.158.132.12:9030 orport=9001 id=DC163DDEF4B6F0C6BC226F9F6656A5A30C5C5686 +# Email sent directly to teor +176.158.236.102:9030 orport=9001 id=DC163DDEF4B6F0C6BC226F9F6656A5A30C5C5686 # Underworld # Email sent directly to teor, verified using relay contact info 91.229.20.27:9030 orport=9001 id=9A0D54D3A6D2E0767596BF1515E6162A75B3293F # Email sent directly to teor, verified using relay contact info -# Awaiting confirmation of new ORPort from relay operator 80.127.137.19:80 orport=443 id=6EF897645B79B6CB35E853B32506375014DE3621 ipv6=[2001:981:47c1:1::6]:443 -# Email sent directly to teor, verified using relay contact info -163.172.138.22:80 orport=443 id=8664DC892540F3C789DB37008236C096C871734D +# Email sent directly to teor +163.172.138.22:80 orport=443 id=16102E458460349EE45C0901DAA6C30094A9BBEA ipv6=[2001:bc8:4400:2100::1:3]:443 # mkultra # Email sent directly to teor, verified using relay contact info 97.74.237.196:9030 orport=9001 id=2F0F32AB1E5B943CA7D062C03F18960C86E70D94 @@ -603,10 +556,11 @@ 178.62.98.160:9030 orport=9001 id=8B92044763E880996A988831B15B2B0E5AD1544A # Email sent directly to teor, verified using relay contact info -195.154.15.227:9030 orport=9001 id=6C3E3AB2F5F03CD71B637D433BAD924A1ECC5796 +163.172.217.50:9030 orport=9001 id=02ECD99ECD596013A8134D46531560816ECC4BE6 # Email sent directly to teor, verified using relay contact info 185.100.86.100:80 orport=443 id=0E8C0C8315B66DB5F703804B3889A1DD66C67CE0 +185.100.84.82:80 orport=443 id=7D05A38E39FC5D29AFE6BE487B9B4DC9E635D09E # Email sent directly to teor, verified using relay contact info 164.132.77.175:9030 orport=9001 id=3B33F6FCA645AD4E91428A3AF7DC736AD9FB727B @@ -617,13 +571,15 @@ 178.62.86.96:9030 orport=9001 id=439D0447772CB107B886F7782DBC201FA26B92D1 ipv6=[2a03:b0c0:1:d0::3cf:7001]:9050 # Email sent directly to teor, verified using relay contact info -91.233.106.121:80 orport=443 id=896364B7996F5DFBA0E15D1A2E06D0B98B555DD6 +# Very low bandwidth, stale consensues, excluded to cut down on warnings +#91.233.106.121:80 orport=443 id=896364B7996F5DFBA0E15D1A2E06D0B98B555DD6 # Email sent directly to teor, verified using relay contact info -167.114.113.48:9030 orport=443 id=2EC0C66EA700C44670444280AABAB1EC78B722A0 +167.114.113.48:9030 orport=403 id=2EC0C66EA700C44670444280AABAB1EC78B722A0 # Email sent directly to teor, verified using relay contact info -79.120.16.42:9030 orport=9001 id=BD552C165E2ED2887D3F1CCE9CFF155DDA2D86E6 +# Assume details update is permanent +213.141.138.174:9030 orport=9001 id=BD552C165E2ED2887D3F1CCE9CFF155DDA2D86E6 # Schakalium # Email sent directly to teor, verified using relay contact info 95.128.43.164:80 orport=443 id=616081EC829593AF4232550DE6FFAA1D75B37A90 ipv6=[2a02:ec0:209:10::4]:443 @@ -652,10 +608,13 @@ # Email sent directly to teor, verified using relay contact info 31.31.78.49:80 orport=443 id=46791D156C9B6C255C2665D4D8393EC7DBAA7798 -# Email sent directly to teor, verified using relay contact info -96.47.231.214:9030 orport=8080 id=F843CB5729575D76FF1FFBB2179BDCF52C0C6387 -192.99.246.48:9030 orport=9001 id=CD6B149BED1BB254EF6DFF9D75DDB11E7F8A38A4 ipv6=[2607:5300:100:200::de3]:9002 -192.160.102.164:80 orport=9001 id=823AA81E277F366505545522CEDC2F529CE4DC3F ipv6=[2605:e200:d00c:c01d::1111]:9002 +# Email sent directly to teor +192.160.102.169:80 orport=9001 id=C0192FF43E777250084175F4E59AC1BA2290CE38 ipv6=[2620:132:300c:c01d::9]:9002 # manipogo +192.160.102.166:80 orport=9001 id=547DA56F6B88B6C596B3E3086803CDA4F0EF8F21 ipv6=[2620:132:300c:c01d::6]:9002 # chaucer +192.160.102.170:80 orport=9001 id=557ACEC850F54EEE65839F83CACE2B0825BE811E ipv6=[2620:132:300c:c01d::a]:9002 # ogopogo +192.160.102.164:80 orport=9001 id=823AA81E277F366505545522CEDC2F529CE4DC3F ipv6=[2620:132:300c:c01d::4]:9002 # snowfall +192.160.102.165:80 orport=9001 id=C90CA3B7FE01A146B8268D56977DC4A2C024B9EA ipv6=[2620:132:300c:c01d::5]:9002 # cowcat +192.160.102.168:80 orport=9001 id=F6A358DD367B3282D6EF5824C9D45E1A19C7E815 ipv6=[2620:132:300c:c01d::8]:9002 # prawksi # Email sent directly to teor, verified using relay contact info 136.243.214.137:80 orport=443 id=B291D30517D23299AD7CEE3E60DFE60D0E3A4664 @@ -666,8 +625,8 @@ # Email sent directly to teor, verified using relay contact info 192.87.28.28:9030 orport=9001 id=ED2338CAC2711B3E331392E1ED2831219B794024 -# OK, but same machine as ED2338CAC2711B3E331392E1ED2831219B794024 -#192.87.28.82:9030 orport=9001 id=844AE9CAD04325E955E2BE1521563B79FE7094B7 +# same machine as ED2338CAC2711B3E331392E1ED2831219B794024 +192.87.28.82:9030 orport=9001 id=844AE9CAD04325E955E2BE1521563B79FE7094B7 # https://twitter.com/kosjoli/status/719507270904758272 85.10.202.87:9030 orport=9001 id=971AFB23C168DCD8EDA17473C1C452B359DE3A5A @@ -675,20 +634,18 @@ 46.4.111.124:9030 orport=9001 id=D9065F9E57899B3D272AA212317AF61A9B14D204 # Email sent directly to teor, verified using relay contact info -78.46.164.129:9030 orport=9001 id=52AEA31188331F421B2EDB494DB65CD181E5B257 - -# Email sent directly to teor, verified using relay contact info 185.100.85.61:80 orport=443 id=025B66CEBC070FCB0519D206CF0CF4965C20C96E # Email sent directly to teor, verified using relay contact info 108.166.168.158:80 orport=443 id=CDAB3AE06A8C9C6BF817B3B0F1877A4B91465699 # Email sent directly to teor, verified using relay contact info -91.219.236.222:80 orport=443 id=EC413181CEB1C8EDC17608BBB177CD5FD8535E99 +91.219.236.222:80 orport=443 id=20704E7DD51501DC303FA51B738D7B7E61397CF6 # Email sent directly to teor, verified using relay contact info 185.14.185.240:9030 orport=443 id=D62FB817B0288085FAC38A6DC8B36DCD85B70260 192.34.63.137:9030 orport=443 id=ABCB4965F1FEE193602B50A365425105C889D3F8 +128.199.197.16:9030 orport=443 id=DEE5298B3BA18CDE651421CD2DCB34A4A69F224D # Email sent directly to teor, verified using relay contact info 185.13.38.75:9030 orport=9001 id=D2A1703758A0FBBA026988B92C2F88BAB59F9361 @@ -719,13 +676,14 @@ 166.70.207.2:9030 orport=9001 id=E3DB2E354B883B59E8DC56B3E7A353DDFD457812 # Emails sent directly to teor, verified using relay contact info -#69.162.139.9:9030 orport=9001 id=4791FC0692EAB60DF2BCCAFF940B95B74E7654F6 ipv6=[2607:f128:40:1212::45a2:8b09]:9001 +69.162.139.9:9030 orport=9001 id=4791FC0692EAB60DF2BCCAFF940B95B74E7654F6 ipv6=[2607:f128:40:1212::45a2:8b09]:9001 # Email sent directly to teor, verified using relay contact info 213.239.217.18:1338 orport=1337 id=C37BC191AC389179674578C3E6944E925FE186C2 ipv6=[2a01:4f8:a0:746a:101:1:1:1]:1337 # Email sent directly to teor, verified using relay contact info -188.40.128.246:9030 orport=9001 id=AD19490C7DBB26D3A68EFC824F67E69B0A96E601 +# Assume details update is permanent +188.40.128.246:9030 orport=9001 id=AD19490C7DBB26D3A68EFC824F67E69B0A96E601 ipv6=[2a01:4f8:221:1ac1:dead:beef:7005:9001]:9001 # sputnik # Email sent directly to teor, verified using relay contact info 88.198.253.13:9030 orport=9001 id=DF924196D69AAE3C00C115A9CCDF7BB62A175310 ipv6=[2a01:4f8:11a:b1f::2]:9001 @@ -743,20 +701,44 @@ # Email sent directly to teor, verified using relay contact info 107.170.101.39:9030 orport=443 id=30973217E70AF00EBE51797FF6D9AA720A902EAA -# Email sent directly to teor, verified using relay contact info -192.99.212.139:80 orport=443 id=F10BDE279AE71515DDCCCC61DC19AC8765F8A3CC - -# Email sent directly to teor, verified using relay contact info -163.172.35.249:80 orport=443 id=C08DE49658E5B3CFC6F2A952B453C4B608C9A16A -163.172.35.247:80 orport=443 id=71AB4726D830FAE776D74AEF790CF04D8E0151B4 -163.172.13.124:80 orport=443 id=B771AA877687F88E6F1CA5354756DF6C8A7B6B24 +# Email sent directly to teor +193.70.112.165:80 orport=443 id=F10BDE279AE71515DDCCCC61DC19AC8765F8A3CC # ParkBenchInd001 + +# Email sent directly to teor +185.220.101.6:10006 orport=20006 id=C08DE49658E5B3CFC6F2A952B453C4B608C9A16A # niftyvolcanorabbit +185.220.101.13:10013 orport=20013 id=71AB4726D830FAE776D74AEF790CF04D8E0151B4 # niftycottontail +185.220.101.5:10005 orport=20005 id=1084200B44021D308EA4253F256794671B1D099A # niftyhedgehog +185.220.101.9:10009 orport=20009 id=14877C6384A9E793F422C8D1DDA447CACA4F7C4B # niftywoodmouse +185.220.101.8:10008 orport=20008 id=24E91955D969AEA1D80413C64FE106FAE7FD2EA9 # niftymouse +185.220.101.1:10001 orport=20001 id=28F4F392F8F19E3FBDE09616D9DB8143A1E2DDD3 # niftycottonmouse +185.220.101.21:10021 orport=20021 id=348B89013EDDD99E4755951D1EC284D9FED71226 # niftysquirrel +185.220.101.10:10010 orport=20010 id=4031460683AE9E0512D3620C2758D98758AC6C93 # niftyeuropeanrabbit +185.220.101.34:10034 orport=20034 id=47C42E2094EE482E7C9B586B10BABFB67557030B # niftyquokka +185.220.101.18:10018 orport=20018 id=5D5006E4992F2F97DF4F8B926C3688870EB52BD8 # niftyplagiodontia +185.220.101.28:10028 orport=20028 id=609E598FB6A00BCF7872906B602B705B64541C50 # niftychipmunk +185.220.101.20:10020 orport=20020 id=619349D82424C601CAEB94161A4CF778993DAEE7 # niftytucotuco +185.220.101.17:10017 orport=20017 id=644DECC5A1879C0FE23DE927DD7049F58BBDF349 # niftyhutia +185.220.101.0:10000 orport=20000 id=6E94866ED8CA098BACDFD36D4E8E2B459B8A734E # niftybeaver +185.220.101.30:10030 orport=20030 id=71CFDEB4D9E00CCC3E31EC4E8A29E109BBC1FB36 # niftypedetidae +185.220.101.29:10029 orport=20029 id=7DC52AE6667A30536BA2383CD102CFC24F20AD71 # niftyllipika +185.220.101.41:10041 orport=20041 id=7E281CD2C315C4F7A84BC7C8721C3BC974DDBFA3 # niftyporcupine +185.220.101.25:10025 orport=20025 id=8EE0534532EA31AA5172B1892F53B2F25C76EB02 # niftyjerboa +185.220.101.33:10033 orport=20033 id=906DCB390F2BA987AE258D745E60BAAABAD31DE8 # niftyquokka +185.220.101.26:10026 orport=20026 id=92A6085EABAADD928B6F8E871540A1A41CBC08BA # niftypedetes +185.220.101.40:10040 orport=20040 id=9A857254F379194D1CD76F4A79A20D2051BEDA3F # niftynutria +185.220.101.42:10042 orport=20042 id=9B816A5B3EB20B8E4E9B9D1FBA299BD3F40F0320 # niftypygmyjerboa +185.220.101.2:10002 orport=20002 id=B740BCECC4A9569232CDD45C0E1330BA0D030D33 # niftybunny +185.220.101.32:10032 orport=20032 id=B771AA877687F88E6F1CA5354756DF6C8A7B6B24 # niftypika +185.220.101.12:10012 orport=20012 id=BC82F2190DE2E97DE65F49B4A95572374BDC0789 # niftycapybara +185.220.101.22:10022 orport=20022 id=CA37CD46799449D83B6B98B8C22C649906307888 # niftyjackrabbit +185.220.101.4:10004 orport=20004 id=CDA2EA326E2272C57ACB26773D7252C211795B78 # niftygerbil +185.220.101.14:10014 orport=20014 id=E7EBA5D8A4E09684D11A1DF24F75362817333768 # niftyhare +185.220.101.16:10016 orport=20016 id=EC1997D51892E4607C68E800549A1E7E4694005A # niftyguineapig +185.220.101.24:10024 orport=20024 id=FDA70EC93DB01E3CB418CB6943B0C68464B18B4C # niftyrat # Email sent directly to teor, verified using relay contact info 64.113.32.29:9030 orport=9001 id=30C19B81981F450C402306E2E7CFB6C3F79CB6B2 -# Email sent directly to teor, verified using relay contact info -212.51.156.193:995 orport=110 id=32E7AAF1F602814D699BEF6761AD03E387758D49 ipv6=[2a02:168:4a01::49]:110 - # Emails sent directly to teor, verified using relay contact info 51.254.101.242:9002 orport=9001 id=4CC9CC9195EC38645B699A33307058624F660CCF @@ -768,3 +750,247 @@ # Email sent directly to teor, verified using relay contact info 62.216.5.120:9030 orport=9001 id=D032D4D617140D6B828FC7C4334860E45E414FBE + +# Email sent directly to teor, verified using relay contact info +51.254.136.195:80 orport=443 id=7BB70F8585DFC27E75D692970C0EEB0F22983A63 + +# Email sent directly to teor, verified using relay contact info +163.172.13.165:9030 orport=9001 id=33DA0CAB7C27812EFF2E22C9705630A54D101FEB ipv6=[2001:bc8:38cb:201::8]:9001 + +# Email sent directly to teor, verified using relay contact info +5.196.88.122:9030 orport=9001 id=0C2C599AFCB26F5CFC2C7592435924C1D63D9484 ipv6=[2001:41d0:a:fb7a::1]:9001 + +# Email sent directly to teor, verified using relay contact info +5.9.158.75:80 orport=443 id=1AF72E8906E6C49481A791A6F8F84F8DFEBBB2BA ipv6=[2a01:4f8:190:514a::2]:443 + +# Email sent directly to teor, verified using relay contact info +46.101.169.151:9030 orport=9001 id=D760C5B436E42F93D77EF2D969157EEA14F9B39C ipv6=[2a03:b0c0:3:d0::74f:a001]:9001 + +# Email sent directly to teor, verified using relay contact info +199.249.223.81:80 orport=443 id=F7447E99EB5CBD4D5EB913EE0E35AC642B5C1EF3 +199.249.223.79:80 orport=443 id=D33292FEDE24DD40F2385283E55C87F85C0943B6 +199.249.223.78:80 orport=443 id=EC15DB62D9101481F364DE52EB8313C838BDDC29 +199.249.223.77:80 orport=443 id=CC4A3AE960E3617F49BF9887B79186C14CBA6813 +199.249.223.76:80 orport=443 id=43209F6D50C657A56FE79AF01CA69F9EF19BD338 +199.249.223.75:80 orport=443 id=60D3667F56AEC5C69CF7E8F557DB21DDF6C36060 +199.249.223.74:80 orport=443 id=5F4CD12099AF20FAF9ADFDCEC65316A376D0201C +199.249.223.73:80 orport=443 id=5649CB2158DA94FB747415F26628BEC07FA57616 +199.249.223.72:80 orport=443 id=B028707969D8ED84E6DEA597A884F78AAD471971 +199.249.223.71:80 orport=443 id=B6320E44A230302C7BF9319E67597A9B87882241 +199.249.223.60:80 orport=443 id=B7047FBDE9C53C39011CA84E5CB2A8E3543066D0 +199.249.223.61:80 orport=443 id=40E7D6CE5085E4CDDA31D51A29D1457EB53F12AD +199.249.223.62:80 orport=443 id=0077BCBA7244DB3E6A5ED2746E86170066684887 +199.249.223.63:80 orport=443 id=1DB25DF59DAA01B5BE3D3CEB8AFED115940EBE8B +199.249.223.64:80 orport=443 id=9F2856F6D2B89AD4EF6D5723FAB167DB5A53519A +199.249.223.65:80 orport=443 id=9D21F034C3BFF4E7737D08CF775DC1745706801F +199.249.223.66:80 orport=443 id=C5A53BCC174EF8FD0DCB223E4AA929FA557DEDB2 +199.249.223.67:80 orport=443 id=155D6F57425F16C0624D77777641E4EB1B47C6F0 +199.249.223.68:80 orport=443 id=DF20497E487A979995D851A5BCEC313DF7E5BC51 +199.249.223.69:80 orport=443 id=7FA8E7E44F1392A4E40FFC3B69DB3B00091B7FD3 + +# https://lists.torproject.org/pipermail/tor-relays/2016-December/011114.html +86.105.212.130:9030 orport=443 id=9C900A7F6F5DD034CFFD192DAEC9CCAA813DB022 + +# Email sent directly to teor, verified using relay contact info +178.33.183.251:80 orport=443 id=DD823AFB415380A802DCAEB9461AE637604107FB ipv6=[2001:41d0:2:a683::251]:443 + +# Email sent directly to teor, verified using relay contact info +31.185.104.19:80 orport=443 id=9EAD5B2D3DBD96DBC80DCE423B0C345E920A758D +# same machine as 9EAD5B2D3DBD96DBC80DCE423B0C345E920A758D +31.185.104.20:80 orport=443 id=ADB2C26629643DBB9F8FE0096E7D16F9414B4F8D +31.185.104.21:80 orport=443 id=C2AAB088555850FC434E68943F551072042B85F1 +31.185.104.22:80 orport=443 id=5BA3A52760A0EABF7E7C3ED3048A77328FF0F148 + +# Email sent directly to teor, verified using relay contact info +185.34.60.114:80 orport=443 id=7F7A695DF6F2B8640A70B6ADD01105BC2EBC5135 + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013939.html +94.142.242.84:80 orport=443 id=AA0D167E03E298F9A8CD50F448B81FBD7FA80D56 ipv6=[2a02:898:24:84::1]:443 # rejozenger + +# Email sent directly to teor, verified using relay contact info +185.129.62.62:9030 orport=9001 id=ACDD9E85A05B127BA010466C13C8C47212E8A38F ipv6=[2a06:d380:0:3700::62]:9001 + +# Email sent directly to teor, verified using relay contact info +# The e84 part of the IPv6 address does not have a leading 0 in the consensus +81.30.158.213:9030 orport=9001 id=789EA6C9AE9ADDD8760903171CFA9AC5741B0C70 ipv6=[2001:4ba0:cafe:e84::1]:9001 + +# https://lists.torproject.org/pipermail/tor-relays/2016-December/011209.html +5.9.159.14:9030 orport=9001 id=0F100F60C7A63BED90216052324D29B08CFCF797 + +# Email sent directly to teor, verified using relay contact info +45.62.255.25:80 orport=443 id=3473ED788D9E63361D1572B7E82EC54338953D2A + +# Email sent directly to teor, verified using relay contact info +217.79.179.177:9030 orport=9001 id=3E53D3979DB07EFD736661C934A1DED14127B684 ipv6=[2001:4ba0:fff9:131:6c4f::90d3]:9001 + +# Email sent directly to teor, verified using relay contact info +212.47.244.38:8080 orport=443 id=E81EF60A73B3809F8964F73766B01BAA0A171E20 +163.172.157.213:8080 orport=443 id=4623A9EC53BFD83155929E56D6F7B55B5E718C24 +163.172.139.104:8080 orport=443 id=68F175CCABE727AA2D2309BCD8789499CEE36ED7 + +# Email sent directly to teor, verified using relay contact info +163.172.223.200:80 orport=443 id=998BF3ED7F70E33D1C307247B9626D9E7573C438 +195.154.122.54:80 orport=443 id=64E99CB34C595A02A3165484BD1215E7389322C6 + +# Email sent directly to teor, verified using relay contact info +185.100.86.128:9030 orport=9001 id=9B31F1F1C1554F9FFB3455911F82E818EF7C7883 +185.100.85.101:9030 orport=9001 id=4061C553CA88021B8302F0814365070AAE617270 +31.171.155.108:9030 orport=9001 id=D3E5EDDBE5159388704D6785BE51930AAFACEC6F + +# Email sent directly to teor, verified using relay contact info +89.163.247.43:9030 orport=9001 id=BC7ACFAC04854C77167C7D66B7E471314ED8C410 ipv6=[2001:4ba0:fff7:25::5]:9001 + +# Email sent directly to teor, verified using relay contact info +95.85.8.226:80 orport=443 id=1211AC1BBB8A1AF7CBA86BCE8689AA3146B86423 + +# Email sent directly to teor, verified using relay contact info +85.214.151.72:9030 orport=9001 id=722D365140C8C52DBB3C9FF6986E3CEFFE2BA812 + +# email sent directly to teor +72.52.75.27:9030 orport=9001 id=8567AD0A6369ED08527A8A8533A5162AC00F7678 # piecoopdotnet + +# Email sent directly to teor, verified using relay contact info +5.9.146.203:80 orport=443 id=1F45542A24A61BF9408F1C05E0DCE4E29F2CBA11 +5.9.159.14:9030 orport=9001 id=0F100F60C7A63BED90216052324D29B08CFCF797 + +# Email sent directly to teor, verified using relay contact info +# Assume details update is permanent +5.9.147.226:9030 orport=9001 id=B0553175AADB0501E5A61FC61CEA3970BE130FF2 ipv6=[2a01:4f8:190:30e1::2]:9001 # zwiubel + +# https://trac.torproject.org/projects/tor/ticket/22527#comment:1 +199.184.246.250:80 orport=443 id=1F6ABD086F40B890A33C93CC4606EE68B31C9556 ipv6=[2620:124:1009:1::171]:443 + +# https://trac.torproject.org/projects/tor/ticket/24695 +163.172.53.84:143 orport=21 id=1C90D3AEADFF3BCD079810632C8B85637924A58E ipv6=[2001:bc8:24f8::]:21 # Multivac + +# Email sent directly to teor +54.36.237.163:80 orport=443 id=DB2682153AC0CCAECD2BD1E9EBE99C6815807A1E # GermanCraft2 + +# Email sent directly to teor +62.138.7.171:9030 orport=9001 id=9844B981A80B3E4B50897098E2D65167E6AEF127 # 0x3d004 +62.138.7.171:8030 orport=8001 id=9285B22F7953D7874604EEE2B470609AD81C74E9 # 0x3d005 +91.121.23.100:9030 orport=9001 id=3711E80B5B04494C971FB0459D4209AB7F2EA799 # 0x3d002 +91.121.23.100:8030 orport=8001 id=CFBBA0D858F02E40B1432A65F6D13C9BDFE7A46B # 0x3d001 +51.15.13.245:9030 orport=9001 id=CED527EAC230E7B56E5B363F839671829C3BA01B # 0x3d006 +51.15.13.245:8030 orport=8001 id=8EBB8D1CF48FE2AB95C451DA8F10DB6235F40F8A # 0x3d007 + +# Email sent directly to teor +104.192.5.248:9030 orport=9001 id=BF735F669481EE1CCC348F0731551C933D1E2278 # Freeway11 + +# Email sent directly to teor +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013961.html +178.17.174.14:9030 orport=9001 id=B06F093A3D4DFAD3E923F4F28A74901BD4F74EB1 # TorExitMoldova +178.17.170.156:9030 orport=9001 id=41C59606AFE1D1AA6EC6EF6719690B856F0B6587 # TorExitMoldova2 + +# Email sent directly to teor +163.172.221.44:59030 orport=59001 id=164604F5C86FC8CC9C0288BD9C02311958427597 # altego + +# Email sent directly to teor +46.38.237.221:9030 orport=9001 id=D30E9D4D639068611D6D96861C95C2099140B805 # mine + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013911.html +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013912.html +199.249.223.62:80 orport=443 id=0077BCBA7244DB3E6A5ED2746E86170066684887 # Quintex13 +199.249.224.45:80 orport=443 id=041646640AB306EA74B001966E86169B04CC88D2 # QuintexAirVPN26 +199.249.223.67:80 orport=443 id=155D6F57425F16C0624D77777641E4EB1B47C6F0 # Quintex18 +199.249.223.45:80 orport=443 id=1AE949967F82BBE7534A3D6BA77A7EBE1CED4369 # Quintex36 +199.249.223.63:80 orport=443 id=1DB25DF59DAA01B5BE3D3CEB8AFED115940EBE8B # Quintex14 +199.249.224.63:80 orport=443 id=1E5136DDC52FAE1219208F0A6BADB0BA62587EE6 # Quintex43 +199.249.224.46:80 orport=443 id=2ED4D25766973713EB8C56A290BF07E06B85BF12 # QuintexAirVPN27 +199.249.223.42:80 orport=443 id=3687FEC7E73F61AC66F7AE251E7DEE6BBD8C0252 # Quintex33 +199.249.223.49:80 orport=443 id=36D68478366CB8627866757EBCE7FB3C17FC1CB8 # Quintex40 +199.249.224.49:80 orport=443 id=3CA0D15567024D2E0B557DC0CF3E962B37999A79 # QuintexAirVPN30 +199.249.223.61:80 orport=443 id=40E7D6CE5085E4CDDA31D51A29D1457EB53F12AD # Quintex12 +199.249.223.76:80 orport=443 id=43209F6D50C657A56FE79AF01CA69F9EF19BD338 # QuintexAirVPN5 +199.249.224.41:80 orport=443 id=54A4820B46E65509BF3E2B892E66930A41759DE9 # QuintexAirVPN22 +199.249.223.73:80 orport=443 id=5649CB2158DA94FB747415F26628BEC07FA57616 # QuintexAirVPN8 +199.249.223.74:80 orport=443 id=5F4CD12099AF20FAF9ADFDCEC65316A376D0201C # QuintexAirVPN7 +199.249.223.75:80 orport=443 id=60D3667F56AEC5C69CF7E8F557DB21DDF6C36060 # QuintexAirVPN6 +199.249.223.46:80 orport=443 id=66E19E8C4773086F669A1E06A3F8C23B6C079129 # Quintex37 +199.249.224.65:80 orport=443 id=764BF8A03868F84C8F323C1A676AA254B80DC3BF # Quintex45 +199.249.223.48:80 orport=443 id=7A3DD280EA4CD4DD16EF8C67B93D9BDE184D1A81 # Quintex39 +199.249.224.68:80 orport=443 id=7E6E9A6FDDB8DC7C92F0CFCC3CBE76C29F061799 # Quintex48 +199.249.223.69:80 orport=443 id=7FA8E7E44F1392A4E40FFC3B69DB3B00091B7FD3 # Quintex20 +199.249.223.44:80 orport=443 id=8B80169BEF71450FC4069A190853523B7AEA45E1 # Quintex35 +199.249.224.60:80 orport=443 id=9314BD9503B9014261A65C221D77E57389DBCCC1 # Quintex50 +199.249.224.40:80 orport=443 id=9C1E7D92115D431385B8CAEA6A7C15FB89CE236B # QuintexAirVPN21 +199.249.223.65:80 orport=443 id=9D21F034C3BFF4E7737D08CF775DC1745706801F # Quintex16 +199.249.224.67:80 orport=443 id=9E2D7C6981269404AA1970B53891701A20424EF8 # Quintex47 +199.249.223.64:80 orport=443 id=9F2856F6D2B89AD4EF6D5723FAB167DB5A53519A # Quintex15 +199.249.224.48:80 orport=443 id=A0DB820FEC87C0405F7BF05DEE5E4ADED2BB9904 # QuintexAirVPN29 +199.249.224.64:80 orport=443 id=A4A393FEF48640961AACE92D041934B55348CEF9 # Quintex44 +199.249.223.72:80 orport=443 id=B028707969D8ED84E6DEA597A884F78AAD471971 # QuintexAirVPN9 +199.249.223.40:80 orport=443 id=B0CD9F9B5B60651ADC5919C0F1EAA87DBA1D9249 # Quintex31 +199.249.224.61:80 orport=443 id=B2197C23A4FF5D1C49EE45BA7688BA8BCCD89A0B # Quintex41 +199.249.223.71:80 orport=443 id=B6320E44A230302C7BF9319E67597A9B87882241 # QuintexAirVPN10 +199.249.223.60:80 orport=443 id=B7047FBDE9C53C39011CA84E5CB2A8E3543066D0 # Quintex11 +199.249.224.66:80 orport=443 id=C78AFFEEE320EA0F860961763E613FD2FAC855F5 # Quintex46 +199.249.224.44:80 orport=443 id=CB7C0D841FE376EF43F7845FF201B0290C0A239E # QuintexAirVPN25 +199.249.223.47:80 orport=443 id=CC14C97F1D23EE97766828FC8ED8582E21E11665 # Quintex38 +199.249.223.77:80 orport=443 id=CC4A3AE960E3617F49BF9887B79186C14CBA6813 # QuintexAirVPN4 +199.249.223.41:80 orport=443 id=D25210CE07C49F2A4F2BC7A506EB0F5EA7F5E2C2 # Quintex32 +199.249.223.79:80 orport=443 id=D33292FEDE24DD40F2385283E55C87F85C0943B6 # QuintexAirVPN2 +199.249.224.47:80 orport=443 id=D6FF2697CEA5C0C7DA84797C2E71163814FC2466 # QuintexAirVPN28 +199.249.223.68:80 orport=443 id=DF20497E487A979995D851A5BCEC313DF7E5BC51 # Quintex19 +199.249.223.43:80 orport=443 id=E480D577F58E782A5BC4FA6F49A6650E9389302F # Quintex34 +199.249.224.69:80 orport=443 id=EABC2DD0D47B5DB11F2D37EB3C60C2A4D91C10F2 # Quintex49 +199.249.223.78:80 orport=443 id=EC15DB62D9101481F364DE52EB8313C838BDDC29 # QuintexAirVPN3 +199.249.224.42:80 orport=443 id=F21DE9C7DE31601D9716781E17E24380887883D1 # QuintexAirVPN23 +199.249.223.81:80 orport=443 id=F7447E99EB5CBD4D5EB913EE0E35AC642B5C1EF3 # QuintexAirVPN1 +199.249.224.43:80 orport=443 id=FDD700C791CC6BB0AC1C2099A82CBC367AD4B764 # QuintexAirVPN24 +199.249.224.62:80 orport=443 id=FE00A3A835680E67FBBC895A724E2657BB253E97 # Quintex42 +199.249.223.66:80 orport=443 id=C5A53BCC174EF8FD0DCB223E4AA929FA557DEDB2 # Quintex17 + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013914.html +5.196.23.64:9030 orport=9001 id=775B0FAFDE71AADC23FFC8782B7BEB1D5A92733E # Aerodynamik01 +217.182.75.181:9030 orport=9001 id=EFEACD781604EB80FBC025EDEDEA2D523AEAAA2F # Aerodynamik02 +193.70.43.76:9030 orport=9001 id=484A10BA2B8D48A5F0216674C8DD50EF27BC32F3 # Aerodynamik03 +149.56.141.138:9030 orport=9001 id=1938EBACBB1A7BFA888D9623C90061130E63BB3F # Aerodynamik04 + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013917.html +104.200.20.46:80 orport=9001 id=78E2BE744A53631B4AAB781468E94C52AB73968B # bynumlawtor + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013929.html +139.99.130.178:80 orport=443 id=867B95CACD64653FEEC4D2CEFC5C49B4620307A7 # coffswifi2 + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013946.html +172.98.193.43:80 orport=443 id=5E56738E7F97AA81DEEF59AF28494293DFBFCCDF # Backplane + +# Email sent directly to teor +62.210.254.132:80 orport=443 id=8456DFA94161CDD99E480C2A2992C366C6564410 # turingmachine + +# Email sent directly to teor +80.127.117.180:80 orport=443 id=328E54981C6DDD7D89B89E418724A4A7881E3192 ipv6=[2001:985:e77:10::4]:443 # sjc01 + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/013960.html +51.15.205.214:9030 orport=9001 id=8B6556601612F1E2AFCE2A12FFFAF8482A76DD1F ipv6=[2001:bc8:4400:2500::5:b07]:9001 # titania1 +51.15.205.214:9031 orport=9002 id=5E363D72488276160D062DDD2DFA25CFEBAF5EA9 ipv6=[2001:bc8:4400:2500::5:b07]:9002 # titania2 + +# Email sent directly to teor +185.129.249.124:9030 orport=9001 id=1FA8F638298645BE58AC905276680889CB795A94 # treadstone + +# https://lists.torproject.org/pipermail/tor-relays/2017-December/014000.html +24.117.231.229:34175 orport=45117 id=CE24412AD69444954B4015E293AE53DDDAFEA3D6 # Anosognosia + +# https://lists.torproject.org/pipermail/tor-relays/2018-January/014012.html +128.31.0.13:80 orport=443 id=A53C46F5B157DD83366D45A8E99A244934A14C46 # csailmitexit + +# Email sent directly to teor +82.247.103.117:110 orport=995 id=C9B3C1661A9577BA24C1C2C6123918921A495509 # Casper01 +109.238.2.79:110 orport=995 id=7520892E3DD133D0B0464D01A158B54B8E2A8B75 # Casper02 +51.15.179.153:110 orport=995 id=BB60F5BA113A0B8B44B7B37DE3567FE561E92F78 # Casper04 + +# Email sent directly to teor +80.127.107.179:80 orport=443 id=BC6B2E2F62ACC5EDECBABE64DA1E48F84DD98B78 ipv6=[2001:981:4a22:c::6]:443 # TVISION02 + +# https://lists.torproject.org/pipermail/tor-relays/2018-January/014020.html +37.120.174.249:80 orport=443 id=11DF0017A43AF1F08825CD5D973297F81AB00FF3 ipv6=[2a03:4000:6:724c:df98:15f9:b34d:443]:443 # gGDHjdcC6zAlM8k08lX + +# These fallbacks opted-in in previous releases, then changed their details, +# and so we blacklisted them. Now we want to whitelist changes. +# Assume details update is permanent +85.230.184.93:9030 orport=443 id=855BC2DABE24C861CD887DB9B2E950424B49FC34 # Logforme +176.31.180.157:143 orport=22 id=E781F4EC69671B3F1864AE2753E0890351506329 ipv6=[2001:41d0:8:eb9d::1]:22 # armbrust + +# https://lists.torproject.org/pipermail/tor-relays/2018-January/014024.html +82.161.212.209:9030 orport=9001 id=4E8CE6F5651E7342C1E7E5ED031E82078134FB0D ipv6=[2001:980:d7ed:1:ff:b0ff:fe00:d0b]:9001 # ymkeo diff --git a/scripts/maint/format_changelog.py b/scripts/maint/format_changelog.py index e909fc550a..c5a0cfc81b 100755 --- a/scripts/maint/format_changelog.py +++ b/scripts/maint/format_changelog.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (c) 2014-2015, The Tor Project, Inc. +# Copyright (c) 2014-2017, The Tor Project, Inc. # See LICENSE for licensing information # # This script reformats a section of the changelog to wrap everything to @@ -205,6 +205,8 @@ def head_score(s): score = -300 elif lw.startswith("deprecated version"): score = -200 + elif lw.startswith("directory auth"): + score = -150 elif (('new' in lw and 'requirement' in lw) or ('new' in lw and 'dependenc' in lw) or ('build' in lw and 'requirement' in lw) or diff --git a/scripts/maint/generateFallbackDirLine.py b/scripts/maint/generateFallbackDirLine.py new file mode 100755 index 0000000000..b856c938bf --- /dev/null +++ b/scripts/maint/generateFallbackDirLine.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Generate a fallback directory whitelist/blacklist line for every fingerprint +# passed as an argument. +# +# Usage: +# generateFallbackDirLine.py fingerprint ... + +import sys +import urllib2 + +import stem.descriptor.remote +import stem.util.tor_tools + +if len(sys.argv) <= 1: + print('Usage: %s fingerprint ...' % sys.argv[0]) + sys.exit(1) + +for fingerprint in sys.argv[1:]: + if not stem.util.tor_tools.is_valid_fingerprint(fingerprint): + print("'%s' isn't a valid relay fingerprint" % fingerprint) + sys.exit(1) + + try: + desc = stem.descriptor.remote.get_server_descriptors(fingerprint).run()[0] + except urllib2.HTTPError as exc: + if exc.code == 404: + print('# %s not found in recent descriptors' % fingerprint) + continue + else: + raise + + if not desc.dir_port: + print("# %s needs a DirPort" % fingerprint) + else: + ipv6_addresses = [(address, port) for address, port, is_ipv6 in desc.or_addresses if is_ipv6] + ipv6_field = ' ipv6=[%s]:%s' % ipv6_addresses[0] if ipv6_addresses else '' + print('%s:%s orport=%s id=%s%s # %s' % (desc.address, desc.dir_port, desc.or_port, fingerprint, ipv6_field, desc.nickname)) diff --git a/scripts/maint/generate_callgraph.sh b/scripts/maint/generate_callgraph.sh deleted file mode 100755 index c6b33c0aea..0000000000 --- a/scripts/maint/generate_callgraph.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -C_FILES=`echo src/common/*.c src/or/*.c src/tools/*.c` -CFLAGS="-Isrc/ext/trunnel -Isrc/trunnel -I. -Isrc/ext -Isrc/common -DLOCALSTATEDIR=\"\" -DSHARE_DATADIR=\"\" -Dinline=" - -mkdir -p callgraph/src/common -mkdir -p callgraph/src/or -mkdir -p callgraph/src/tools - -for fn in $C_FILES; do - echo $fn - clang $CFLAGS -S -emit-llvm -fno-inline -o - $fn | \ - opt -analyze -print-callgraph >/dev/null 2> "callgraph/${fn}allgraph" -done diff --git a/scripts/maint/lintChanges.py b/scripts/maint/lintChanges.py index b63a4eb3a1..d5b8fcae5c 100755 --- a/scripts/maint/lintChanges.py +++ b/scripts/maint/lintChanges.py @@ -7,7 +7,7 @@ import re import os -KNOWN_GROUPS=set([ +KNOWN_GROUPS = set([ "Minor bugfix", "Minor bugfixes", "Major bugfix", @@ -20,7 +20,20 @@ KNOWN_GROUPS=set([ "Testing", "Documentation", "Code simplification and refactoring", - "Removed features"]) + "Removed features", + "Deprecated features", + "Directory authority changes"]) + +NEEDS_SUBCATEGORIES = set([ + "Minor bugfix", + "Minor bugfixes", + "Major bugfix", + "Major bugfixes", + "Minor feature", + "Minor features", + "Major feature", + "Major features", + ]) def lintfile(fname): have_warned = [] @@ -43,17 +56,13 @@ def lintfile(fname): if bugnum and bugnum not in contents: warn("bug number {} does not appear".format(bugnum)) - lines = contents.split("\n") - m = re.match(r'^[ ]{2}o ([^\(:]*)([^:]*):', contents) if not m: - warn("header not in format expected") + warn("Header not in format expected. (' o Foo:' or ' o Foo (Bar):')") elif m.group(1).strip() not in KNOWN_GROUPS: - warn("Weird header: %r"%m.group(1)) - elif ( ("bugfix" in m.group(1) or "feature" in m.group(1)) and - ("Removed" not in m.group(1)) and - '(' not in m.group(2)): - warn("Missing subcategory on %s"%m.group(1)) + warn("Unrecognized header: %r" % m.group(1)) + elif (m.group(1) in NEEDS_SUBCATEGORIES and '(' not in m.group(2)): + warn("Missing subcategory on %r" % m.group(1)) if m: isBug = ("bug" in m.group(1).lower() or "fix" in m.group(1).lower()) @@ -63,23 +72,46 @@ def lintfile(fname): contents = " ".join(contents.split()) if re.search(r'\#\d{2,}', contents): - warn("don't use a # before ticket numbers") + warn("Don't use a # before ticket numbers. ('bug 1234' not '#1234')") if isBug and not re.search(r'(\d+)', contents): - warn("bugfix does not mention a number") - elif isBug and not re.search(r'Fixes ([a-z ]*)bug (\d+)', contents): - warn("bugfix does not say 'Fixes bug XXX'") + warn("Ticket marked as bugfix, but does not mention a number.") + elif isBug and not re.search(r'Fixes ([a-z ]*)bugs? (\d+)', contents): + warn("Ticket marked as bugfix, but does not say 'Fixes bug XXX'") if re.search(r'[bB]ug (\d+)', contents): if not re.search(r'[Bb]ugfix on ', contents): - warn("bugfix does not say 'bugfix on X.Y.Z'") - elif not re.search('[fF]ixes ([a-z ]*)bug (\d+); bugfix on ', + warn("Bugfix does not say 'bugfix on X.Y.Z'") + elif not re.search('[fF]ixes ([a-z ]*)bugs? (\d+)((, \d+)* and \d+)?; bugfix on ', contents): - warn("bugfix incant is not semicoloned") - + warn("Bugfix does not say 'Fixes bug X; bugfix on Y'") + elif re.search('tor-([0-9]+)', contents): + warn("Do not prefix versions with 'tor-'. ('0.1.2', not 'tor-0.1.2'.)") + + return have_warned != [] + +def files(args): + """Walk through the arguments: for directories, yield their contents; + for files, just yield the files. Only search one level deep, because + that's how the changes directory is laid out.""" + for f in args: + if os.path.isdir(f): + for item in os.listdir(f): + if item.startswith("."): #ignore dotfiles + continue + yield os.path.join(f, item) + else: + yield f if __name__ == '__main__': - for fname in sys.argv[1:]: + problems = 0 + for fname in files(sys.argv[1:]): if fname.endswith("~"): continue - lintfile(fname) + if lintfile(fname): + problems += 1 + + if problems: + sys.exit(1) + else: + sys.exit(0) diff --git a/scripts/maint/lookupFallbackDirContact.py b/scripts/maint/lookupFallbackDirContact.py new file mode 100755 index 0000000000..14c53d1282 --- /dev/null +++ b/scripts/maint/lookupFallbackDirContact.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +# Lookup fallback directory contact lines for every fingerprint passed as an +# argument. +# +# Usage: +# lookupFallbackDirContact.py fingerprint ... + +import sys + +import stem.descriptor.remote as remote + +if len(sys.argv) <= 1: + print "Usage: {} fingerprint ...".format(sys.argv[0]) + sys.exit(-1) + +# we need descriptors, because the consensus does not have contact infos +descriptor_list = remote.get_server_descriptors(fingerprints=sys.argv[1:]).run() + +descriptor_list_fingerprints = [] +for d in descriptor_list: + assert d.fingerprint in sys.argv[1:] + descriptor_list_fingerprints.append(d.fingerprint) + print "{} {}".format(d.fingerprint, d.contact) + +for fingerprint in sys.argv[1:]: + if fingerprint not in descriptor_list_fingerprints: + print "{} not found in current descriptors".format(fingerprint) diff --git a/scripts/maint/redox.py b/scripts/maint/redox.py index 43f5b6eb16..53d3d902eb 100755 --- a/scripts/maint/redox.py +++ b/scripts/maint/redox.py @@ -1,6 +1,6 @@ #!/usr/bin/python # -# Copyright (c) 2008-2015, The Tor Project, Inc. +# Copyright (c) 2008-2017, The Tor Project, Inc. # See LICENSE for licensing information. # # Hi! @@ -101,7 +101,7 @@ def read(): def findline(lines, lineno, ident): """Given a list of all the lines in the file (adjusted so 1-indexing works), - a line number that ident is alledgedly on, and ident, I figure out + a line number that ident is allegedly on, and ident, I figure out the line where ident was really declared.""" lno = lineno for lineno in xrange(lineno, 0, -1): diff --git a/scripts/maint/run_calltool.sh b/scripts/maint/run_calltool.sh new file mode 100755 index 0000000000..efb8706fea --- /dev/null +++ b/scripts/maint/run_calltool.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# You can find calltool at https://gitweb.torproject.org/user/nickm/calltool.git + +set -e + +if test "x$CALLTOOL_PATH" != "x"; then + PYTHONPATH="${CALLTOOL_PATH}:${PYTHONPATH}" + export PYTHONPATH +fi + +mkdir -p callgraph + +SUBITEMS="fn_graph fn_invgraph fn_scc fn_scc_weaklinks module_graph module_invgraph module_scc module_scc_weaklinks" + +for calculation in $SUBITEMS; do + echo "======== $calculation" + python -m calltool $calculation > callgraph/$calculation +done + +echo <<EOF > callgraph/README +This directory holds output from calltool, as run on Tor. For more +information about each of these files, see the NOTES and README files in +the calltool distribution. + +You can find calltool at + https://gitweb.torproject.org/user/nickm/calltool.git +EOF + diff --git a/scripts/maint/sortChanges.py b/scripts/maint/sortChanges.py index d6ec0e269d..22e40fd369 100755 --- a/scripts/maint/sortChanges.py +++ b/scripts/maint/sortChanges.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (c) 2014-2015, The Tor Project, Inc. +# Copyright (c) 2014-2017, The Tor Project, Inc. # See LICENSE for licensing information """This script sorts a bunch of changes files listed on its command diff --git a/scripts/maint/updateCopyright.pl b/scripts/maint/updateCopyright.pl index 8bd6a18210..beb0b8f26e 100755 --- a/scripts/maint/updateCopyright.pl +++ b/scripts/maint/updateCopyright.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -i -w -p -$NEWYEAR=2016; +$NEWYEAR=2017; -s/Copyright(.*) (201[^6]), The Tor Project/Copyright$1 $2-${NEWYEAR}, The Tor Project/; +s/Copyright(.*) (201[^7]), The Tor Project/Copyright$1 $2-${NEWYEAR}, The Tor Project/; s/Copyright(.*)-(20..), The Tor Project/Copyright$1-${NEWYEAR}, The Tor Project/; diff --git a/scripts/maint/updateFallbackDirs.py b/scripts/maint/updateFallbackDirs.py index 110ecda64c..b093463e08 100755 --- a/scripts/maint/updateFallbackDirs.py +++ b/scripts/maint/updateFallbackDirs.py @@ -1,20 +1,25 @@ -#!/usr/bin/python +#!/usr/bin/env python -# Usage: scripts/maint/updateFallbackDirs.py > src/or/fallback_dirs.inc +# Usage: +# +# Regenerate the list: +# scripts/maint/updateFallbackDirs.py > src/or/fallback_dirs.inc 2> fallback_dirs.log +# +# Check the existing list: +# scripts/maint/updateFallbackDirs.py check_existing > fallback_dirs.inc.ok 2> fallback_dirs.log +# mv fallback_dirs.inc.ok src/or/fallback_dirs.inc # # This script should be run from a stable, reliable network connection, # with no other network activity (and not over tor). # If this is not possible, please disable: # PERFORM_IPV4_DIRPORT_CHECKS and PERFORM_IPV6_DIRPORT_CHECKS # -# Needs dateutil (and potentially other python packages) -# Needs stem available in your PYTHONPATH, or just ln -s ../stem/stem . +# Needs dateutil, stem, and potentially other python packages. # Optionally uses ipaddress (python 3 builtin) or py2-ipaddress (package) -# for netblock analysis, in PYTHONPATH, or just -# ln -s ../py2-ipaddress-3.4.1/ipaddress.py . +# for netblock analysis. # # Then read the logs to make sure the fallbacks aren't dominated by a single -# netblock or port +# netblock or port. # Script by weasel, April 2015 # Portions by gsathya & karsten, 2013 @@ -37,16 +42,13 @@ import dateutil.parser # bson_lazy provides bson #from bson import json_util import copy +import re -from stem.descriptor.remote import DescriptorDownloader +from stem.descriptor import DocumentHandler +from stem.descriptor.remote import get_consensus, get_server_descriptors, MAX_FINGERPRINTS import logging -# INFO tells you why each relay was included or excluded -# WARN tells you about potential misconfigurations and relay detail changes -logging.basicConfig(level=logging.WARNING) logging.root.name = '' -# INFO tells you about each consensus download attempt -logging.getLogger('stem').setLevel(logging.WARNING) HAVE_IPADDRESS = False try: @@ -64,6 +66,17 @@ except ImportError: ## Top-Level Configuration +# We use semantic versioning: https://semver.org +# In particular: +# * major changes include removing a mandatory field, or anything else that +# would break an appropriately tolerant parser, +# * minor changes include adding a field, +# * patch changes include changing header comments or other unstructured +# content +FALLBACK_FORMAT_VERSION = '2.0.0' +SECTION_SEPARATOR_BASE = '=====' +SECTION_SEPARATOR_COMMENT = '/* ' + SECTION_SEPARATOR_BASE + ' */' + # Output all candidate fallbacks, or only output selected fallbacks? OUTPUT_CANDIDATES = False @@ -80,7 +93,28 @@ PERFORM_IPV4_DIRPORT_CHECKS = False if OUTPUT_CANDIDATES else True # Don't check ~1000 candidates when OUTPUT_CANDIDATES is True PERFORM_IPV6_DIRPORT_CHECKS = False if OUTPUT_CANDIDATES else False -# Output fallback name, flags, and ContactInfo in a C comment? +# Must relays be running now? +MUST_BE_RUNNING_NOW = (PERFORM_IPV4_DIRPORT_CHECKS + or PERFORM_IPV6_DIRPORT_CHECKS) + +# Clients have been using microdesc consensuses by default for a while now +DOWNLOAD_MICRODESC_CONSENSUS = True + +# If a relay delivers an expired consensus, if it expired less than this many +# seconds ago, we still allow the relay. This should never be less than -90, +# as all directory mirrors should have downloaded a consensus 90 minutes +# before it expires. It should never be more than 24 hours, because clients +# reject consensuses that are older than REASONABLY_LIVE_TIME. +# For the consensus expiry check to be accurate, the machine running this +# script needs an accurate clock. +# +# Relays on 0.3.0 and later return a 404 when they are about to serve an +# expired consensus. This makes them fail the download check. +# We use a tolerance of 0, so that 0.2.x series relays also fail the download +# check if they serve an expired consensus. +CONSENSUS_EXPIRY_TOLERANCE = 0 + +# Output fallback name, flags, bandwidth, and ContactInfo in a C comment? OUTPUT_COMMENTS = True if OUTPUT_CANDIDATES else False # Output matching ContactInfo in fallbacks list or the blacklist? @@ -88,6 +122,12 @@ OUTPUT_COMMENTS = True if OUTPUT_CANDIDATES else False CONTACT_COUNT = True if OUTPUT_CANDIDATES else False CONTACT_BLACKLIST_COUNT = True if OUTPUT_CANDIDATES else False +# How the list should be sorted: +# fingerprint: is useful for stable diffs of fallback lists +# measured_bandwidth: is useful when pruning the list based on bandwidth +# contact: is useful for contacting operators once the list has been pruned +OUTPUT_SORT_FIELD = 'contact' if OUTPUT_CANDIDATES else 'fingerprint' + ## OnionOO Settings ONIONOO = 'https://onionoo.torproject.org/' @@ -121,24 +161,33 @@ BLACKLIST_EXCLUDES_WHITELIST_ENTRIES = True WHITELIST_FILE_NAME = 'scripts/maint/fallback.whitelist' BLACKLIST_FILE_NAME = 'scripts/maint/fallback.blacklist' +FALLBACK_FILE_NAME = 'src/or/fallback_dirs.inc' # The number of bytes we'll read from a filter file before giving up MAX_LIST_FILE_SIZE = 1024 * 1024 ## Eligibility Settings -# Reduced due to a bug in tor where a relay submits a 0 DirPort when restarted -# This causes OnionOO to (correctly) reset its stability timer -# This issue will be fixed in 0.2.7.7 and 0.2.8.2 -# Until then, the CUTOFFs below ensure a decent level of stability. -ADDRESS_AND_PORT_STABLE_DAYS = 7 -# What time-weighted-fraction of these flags must FallbackDirs -# Equal or Exceed? -CUTOFF_RUNNING = .95 -CUTOFF_V2DIR = .95 -CUTOFF_GUARD = .95 -# What time-weighted-fraction of these flags must FallbackDirs -# Equal or Fall Under? +# Require fallbacks to have the same address and port for a set amount of time +# We used to have this at 1 week, but that caused many fallback failures, which +# meant that we had to rebuild the list more often. We want fallbacks to be +# stable for 2 years, so we set it to a few months. +# +# If a relay changes address or port, that's it, it's not useful any more, +# because clients can't find it +ADDRESS_AND_PORT_STABLE_DAYS = 90 +# We ignore relays that have been down for more than this period +MAX_DOWNTIME_DAYS = 0 if MUST_BE_RUNNING_NOW else 7 +# FallbackDirs must have a time-weighted-fraction that is greater than or +# equal to: +# Mirrors that are down half the time are still useful half the time +CUTOFF_RUNNING = .50 +CUTOFF_V2DIR = .50 +# Guard flags are removed for some time after a relay restarts, so we ignore +# the guard flag. +CUTOFF_GUARD = .00 +# FallbackDirs must have a time-weighted-fraction that is less than or equal +# to: # .00 means no bad exits PERMITTED_BADEXIT = .00 @@ -155,28 +204,41 @@ ONIONOO_SCALE_ONE = 999. _FB_POG = 0.2 FALLBACK_PROPORTION_OF_GUARDS = None if OUTPUT_CANDIDATES else _FB_POG -# We want exactly 100 fallbacks for the initial release -# This gives us scope to add extra fallbacks to the list as needed # Limit the number of fallbacks (eliminating lowest by advertised bandwidth) -MAX_FALLBACK_COUNT = None if OUTPUT_CANDIDATES else 100 -# Emit a C #error if the number of fallbacks is below -MIN_FALLBACK_COUNT = 100 +MAX_FALLBACK_COUNT = None if OUTPUT_CANDIDATES else 200 +# Emit a C #error if the number of fallbacks is less than expected +MIN_FALLBACK_COUNT = 0 if OUTPUT_CANDIDATES else MAX_FALLBACK_COUNT*0.5 + +# The maximum number of fallbacks on the same address, contact, or family +# +# With 150 fallbacks, this means each operator sees 5% of client bootstraps. +# For comparison: +# - We try to limit guard and exit operators to 5% of the network +# - The directory authorities used to see 11% of client bootstraps each +# +# We also don't want too much of the list to go down if a single operator +# has to move all their relays. +MAX_FALLBACKS_PER_IP = 1 +MAX_FALLBACKS_PER_IPV4 = MAX_FALLBACKS_PER_IP +MAX_FALLBACKS_PER_IPV6 = MAX_FALLBACKS_PER_IP +MAX_FALLBACKS_PER_CONTACT = 7 +MAX_FALLBACKS_PER_FAMILY = 7 ## Fallback Bandwidth Requirements -# Any fallback with the Exit flag has its bandwidth multipled by this fraction +# Any fallback with the Exit flag has its bandwidth multiplied by this fraction # to make sure we aren't further overloading exits # (Set to 1.0, because we asked that only lightly loaded exits opt-in, # and the extra load really isn't that much for large relays.) EXIT_BANDWIDTH_FRACTION = 1.0 # If a single fallback's bandwidth is too low, it's pointless adding it -# We expect fallbacks to handle an extra 30 kilobytes per second of traffic -# Make sure they can support a hundred times the expected extra load -# (Use 102.4 to make it come out nicely in MB/s) +# We expect fallbacks to handle an extra 10 kilobytes per second of traffic +# Make sure they can support fifty times the expected extra load +# # We convert this to a consensus weight before applying the filter, # because all the bandwidth amounts are specified by the relay -MIN_BANDWIDTH = 102.4 * 30.0 * 1024.0 +MIN_BANDWIDTH = 50.0 * 10.0 * 1024.0 # Clients will time out after 30 seconds trying to download a consensus # So allow fallback directories half that to deliver a consensus @@ -188,21 +250,6 @@ CONSENSUS_DOWNLOAD_SPEED_MAX = 15.0 # This avoids delisting a relay due to transient network conditions CONSENSUS_DOWNLOAD_RETRY = True -## Fallback Weights for Client Selection - -# All fallback weights are equal, and set to the value below -# Authorities are weighted 1.0 by default -# Clients use these weights to select fallbacks and authorities at random -# If there are 100 fallbacks and 9 authorities: -# - each fallback is chosen with probability 10.0/(10.0*100 + 1.0*9) ~= 0.99% -# - each authority is chosen with probability 1.0/(10.0*100 + 1.0*9) ~= 0.09% -# A client choosing a bootstrap directory server will choose a fallback for -# 10.0/(10.0*100 + 1.0*9) * 100 = 99.1% of attempts, and an authority for -# 1.0/(10.0*100 + 1.0*9) * 9 = 0.9% of attempts. -# (This disregards the bootstrap schedules, where clients start by choosing -# from fallbacks & authoritites, then later choose from only authorities.) -FALLBACK_OUTPUT_WEIGHT = 10.0 - ## Parsing Functions def parse_ts(t): @@ -242,6 +289,10 @@ def cleanse_c_multiline_comment(raw_string): bad_char_list = '*/' # Prevent a malicious string from using C nulls bad_char_list += '\0' + # Avoid confusing parsers by making sure there is only one comma per fallback + bad_char_list += ',' + # Avoid confusing parsers by making sure there is only one equals per field + bad_char_list += '=' # Be safer by removing bad characters entirely cleansed_string = remove_bad_chars(cleansed_string, bad_char_list) # Some compilers may further process the content of comments @@ -262,6 +313,10 @@ def cleanse_c_string(raw_string): bad_char_list += '\\' # Prevent a malicious string from using C nulls bad_char_list += '\0' + # Avoid confusing parsers by making sure there is only one comma per fallback + bad_char_list += ',' + # Avoid confusing parsers by making sure there is only one equals per field + bad_char_list += '=' # Be safer by removing bad characters entirely cleansed_string = remove_bad_chars(cleansed_string, bad_char_list) # Some compilers may further process the content of strings @@ -329,6 +384,15 @@ def read_from_file(file_name, max_len): ) return None +def parse_fallback_file(file_name): + file_data = read_from_file(file_name, MAX_LIST_FILE_SIZE) + file_data = cleanse_unprintable(file_data) + file_data = remove_bad_chars(file_data, '\n"\0') + file_data = re.sub('/\*.*?\*/', '', file_data) + file_data = file_data.replace(',', '\n') + file_data = file_data.replace(' weight=10', '') + return file_data + def load_possibly_compressed_response_json(response): if response.info().get('Content-Encoding') == 'gzip': buf = StringIO.StringIO( response.read() ) @@ -367,8 +431,8 @@ def onionoo_fetch(what, **kwargs): params = kwargs params['type'] = 'relay' #params['limit'] = 10 - params['first_seen_days'] = '%d-'%(ADDRESS_AND_PORT_STABLE_DAYS,) - params['last_seen_days'] = '-7' + params['first_seen_days'] = '%d-'%(ADDRESS_AND_PORT_STABLE_DAYS) + params['last_seen_days'] = '-%d'%(MAX_DOWNTIME_DAYS) params['flag'] = 'V2Dir' url = ONIONOO + what + '?' + urllib.urlencode(params) @@ -491,12 +555,14 @@ class Candidate(object): details['flags'] = [] if (not 'advertised_bandwidth' in details or details['advertised_bandwidth'] is None): - # relays without advertised bandwdith have it calculated from their + # relays without advertised bandwidth have it calculated from their # consensus weight details['advertised_bandwidth'] = 0 if (not 'effective_family' in details or details['effective_family'] is None): details['effective_family'] = [] + if not 'platform' in details: + details['platform'] = None details['last_changed_address_or_port'] = parse_ts( details['last_changed_address_or_port']) self._data = details @@ -511,6 +577,8 @@ class Candidate(object): self._compute_ipv6addr() if not self.has_ipv6(): logging.debug("Failed to get an ipv6 address for %s."%(self._fpr,)) + self._compute_version() + self._extra_info_cache = None def _stable_sort_or_addresses(self): # replace self._data['or_addresses'] with a stable ordering, @@ -623,6 +691,59 @@ class Candidate(object): self.ipv6orport = int(port) return + def _compute_version(self): + # parse the version out of the platform string + # The platform looks like: "Tor 0.2.7.6 on Linux" + self._data['version'] = None + if self._data['platform'] is None: + return + # be tolerant of weird whitespacing, use a whitespace split + tokens = self._data['platform'].split() + for token in tokens: + vnums = token.split('.') + # if it's at least a.b.c.d, with potentially an -alpha-dev, -alpha, -rc + if (len(vnums) >= 4 and vnums[0].isdigit() and vnums[1].isdigit() and + vnums[2].isdigit()): + self._data['version'] = token + return + + # From #20509 + # bug #20499 affects versions from 0.2.9.1-alpha-dev to 0.2.9.4-alpha-dev + # and version 0.3.0.0-alpha-dev + # Exhaustive lists are hard to get wrong + STALE_CONSENSUS_VERSIONS = ['0.2.9.1-alpha-dev', + '0.2.9.2-alpha', + '0.2.9.2-alpha-dev', + '0.2.9.3-alpha', + '0.2.9.3-alpha-dev', + '0.2.9.4-alpha', + '0.2.9.4-alpha-dev', + '0.3.0.0-alpha-dev' + ] + + def is_valid_version(self): + # call _compute_version before calling this + # is the version of the relay a version we want as a fallback? + # checks both recommended versions and bug #20499 / #20509 + # + # if the relay doesn't have a recommended version field, exclude the relay + if not self._data.has_key('recommended_version'): + log_excluded('%s not a candidate: no recommended_version field', + self._fpr) + return False + if not self._data['recommended_version']: + log_excluded('%s not a candidate: version not recommended', self._fpr) + return False + # if the relay doesn't have version field, exclude the relay + if not self._data.has_key('version'): + log_excluded('%s not a candidate: no version field', self._fpr) + return False + if self._data['version'] in Candidate.STALE_CONSENSUS_VERSIONS: + logging.warning('%s not a candidate: version delivers stale consensuses', + self._fpr) + return False + return True + @staticmethod def _extract_generic_history(history, which='unknown'): # given a tree like this: @@ -767,41 +888,42 @@ class Candidate(object): self._badexit = self._avg_generic_history(badexit) / ONIONOO_SCALE_ONE def is_candidate(self): - must_be_running_now = (PERFORM_IPV4_DIRPORT_CHECKS - or PERFORM_IPV6_DIRPORT_CHECKS) - if (must_be_running_now and not self.is_running()): - logging.info('%s not a candidate: not running now, unable to check ' + - 'DirPort consensus download', self._fpr) - return False - if (self._data['last_changed_address_or_port'] > - self.CUTOFF_ADDRESS_AND_PORT_STABLE): - logging.info('%s not a candidate: changed address/port recently (%s)', - self._fpr, self._data['last_changed_address_or_port']) - return False - if self._running < CUTOFF_RUNNING: - logging.info('%s not a candidate: running avg too low (%lf)', - self._fpr, self._running) - return False - if self._v2dir < CUTOFF_V2DIR: - logging.info('%s not a candidate: v2dir avg too low (%lf)', - self._fpr, self._v2dir) - return False - if self._badexit is not None and self._badexit > PERMITTED_BADEXIT: - logging.info('%s not a candidate: badexit avg too high (%lf)', - self._fpr, self._badexit) - return False - # if the relay doesn't report a version, also exclude the relay - if (not self._data.has_key('recommended_version') - or not self._data['recommended_version']): - logging.info('%s not a candidate: version not recommended', self._fpr) - return False - if self._guard < CUTOFF_GUARD: - logging.info('%s not a candidate: guard avg too low (%lf)', - self._fpr, self._guard) - return False - if (not self._data.has_key('consensus_weight') - or self._data['consensus_weight'] < 1): - logging.info('%s not a candidate: consensus weight invalid', self._fpr) + try: + if (MUST_BE_RUNNING_NOW and not self.is_running()): + log_excluded('%s not a candidate: not running now, unable to check ' + + 'DirPort consensus download', self._fpr) + return False + if (self._data['last_changed_address_or_port'] > + self.CUTOFF_ADDRESS_AND_PORT_STABLE): + log_excluded('%s not a candidate: changed address/port recently (%s)', + self._fpr, self._data['last_changed_address_or_port']) + return False + if self._running < CUTOFF_RUNNING: + log_excluded('%s not a candidate: running avg too low (%lf)', + self._fpr, self._running) + return False + if self._v2dir < CUTOFF_V2DIR: + log_excluded('%s not a candidate: v2dir avg too low (%lf)', + self._fpr, self._v2dir) + return False + if self._badexit is not None and self._badexit > PERMITTED_BADEXIT: + log_excluded('%s not a candidate: badexit avg too high (%lf)', + self._fpr, self._badexit) + return False + # this function logs a message depending on which check fails + if not self.is_valid_version(): + return False + if self._guard < CUTOFF_GUARD: + log_excluded('%s not a candidate: guard avg too low (%lf)', + self._fpr, self._guard) + return False + if (not self._data.has_key('consensus_weight') + or self._data['consensus_weight'] < 1): + log_excluded('%s not a candidate: consensus weight invalid', self._fpr) + return False + except BaseException as e: + logging.warning("Exception %s when checking if fallback is a candidate", + str(e)) return False return True @@ -878,26 +1000,26 @@ class Candidate(object): for key in entry: value = entry[key] if key == 'id' and value == self._fpr: - logging.info('%s is in the blacklist: fingerprint matches', + log_excluded('%s is in the blacklist: fingerprint matches', self._fpr) return True if key == 'ipv4' and value == self.dirip: # if the dirport is present, check it too if entry.has_key('dirport'): if int(entry['dirport']) == self.dirport: - logging.info('%s is in the blacklist: IPv4 (%s) and ' + + log_excluded('%s is in the blacklist: IPv4 (%s) and ' + 'DirPort (%d) match', self._fpr, self.dirip, self.dirport) return True # if the orport is present, check it too elif entry.has_key('orport'): if int(entry['orport']) == self.orport: - logging.info('%s is in the blacklist: IPv4 (%s) and ' + + log_excluded('%s is in the blacklist: IPv4 (%s) and ' + 'ORPort (%d) match', self._fpr, self.dirip, self.orport) return True else: - logging.info('%s is in the blacklist: IPv4 (%s) matches, and ' + + log_excluded('%s is in the blacklist: IPv4 (%s) matches, and ' + 'entry has no DirPort or ORPort', self._fpr, self.dirip) return True @@ -911,19 +1033,19 @@ class Candidate(object): # if the dirport is present, check it too if entry.has_key('dirport'): if int(entry['dirport']) == self.dirport: - logging.info('%s is in the blacklist: IPv6 (%s) and ' + + log_excluded('%s is in the blacklist: IPv6 (%s) and ' + 'DirPort (%d) match', self._fpr, ipv6, self.dirport) return True # we've already checked the ORPort, it's part of entry['ipv6'] else: - logging.info('%s is in the blacklist: IPv6 (%s) matches, and' + + log_excluded('%s is in the blacklist: IPv6 (%s) matches, and' + 'entry has no DirPort', self._fpr, ipv6) return True elif (key == 'ipv6' or self.has_ipv6()): # only log if the fingerprint matches but the IPv6 doesn't if entry.has_key('id') and entry['id'] == self._fpr: - logging.info('%s skipping IPv6 blacklist comparison: relay ' + + log_excluded('%s skipping IPv6 blacklist comparison: relay ' + 'has%s IPv6%s, but entry has%s IPv6%s', self._fpr, '' if self.has_ipv6() else ' no', (' (' + ipv6 + ')') if self.has_ipv6() else '', @@ -1062,42 +1184,63 @@ class Candidate(object): return True return False - # report how long it takes to download a consensus from dirip:dirport + # log how long it takes to download a consensus from dirip:dirport + # returns True if the download failed, False if it succeeded within max_time @staticmethod - def fallback_consensus_download_speed(dirip, dirport, nickname, max_time): + def fallback_consensus_download_speed(dirip, dirport, nickname, fingerprint, + max_time): download_failed = False - downloader = DescriptorDownloader() - start = datetime.datetime.utcnow() # some directory mirrors respond to requests in ways that hang python # sockets, which is why we log this line here - logging.info('Initiating consensus download from %s (%s:%d).', nickname, - dirip, dirport) + logging.info('Initiating %sconsensus download from %s (%s:%d) %s.', + 'microdesc ' if DOWNLOAD_MICRODESC_CONSENSUS else '', + nickname, dirip, dirport, fingerprint) # there appears to be about 1 second of overhead when comparing stem's # internal trace time and the elapsed time calculated here TIMEOUT_SLOP = 1.0 + start = datetime.datetime.utcnow() try: - downloader.get_consensus(endpoints = [(dirip, dirport)], - timeout = (max_time + TIMEOUT_SLOP), - validate = True, - retries = 0, - fall_back_to_authority = False).run() + consensus = get_consensus( + endpoints = [(dirip, dirport)], + timeout = (max_time + TIMEOUT_SLOP), + validate = True, + retries = 0, + fall_back_to_authority = False, + document_handler = DocumentHandler.BARE_DOCUMENT, + microdescriptor = DOWNLOAD_MICRODESC_CONSENSUS + ).run()[0] + end = datetime.datetime.utcnow() + time_since_expiry = (end - consensus.valid_until).total_seconds() except Exception, stem_error: - logging.info('Unable to retrieve a consensus from %s: %s', nickname, + end = datetime.datetime.utcnow() + log_excluded('Unable to retrieve a consensus from %s: %s', nickname, stem_error) status = 'error: "%s"' % (stem_error) level = logging.WARNING download_failed = True - elapsed = (datetime.datetime.utcnow() - start).total_seconds() - if elapsed > max_time: + elapsed = (end - start).total_seconds() + if download_failed: + # keep the error failure status, and avoid using the variables + pass + elif elapsed > max_time: status = 'too slow' level = logging.WARNING download_failed = True + elif (time_since_expiry > 0): + status = 'outdated consensus, expired %ds ago'%(int(time_since_expiry)) + if time_since_expiry <= CONSENSUS_EXPIRY_TOLERANCE: + status += ', tolerating up to %ds'%(CONSENSUS_EXPIRY_TOLERANCE) + level = logging.INFO + else: + status += ', invalid' + level = logging.WARNING + download_failed = True else: status = 'ok' level = logging.DEBUG - logging.log(level, 'Consensus download: %0.1fs %s from %s (%s:%d), ' + + logging.log(level, 'Consensus download: %0.1fs %s from %s (%s:%d) %s, ' + 'max download time %0.1fs.', elapsed, status, nickname, - dirip, dirport, max_time) + dirip, dirport, fingerprint, max_time) return download_failed # does this fallback download the consensus fast enough? @@ -1109,12 +1252,14 @@ class Candidate(object): ipv4_failed = Candidate.fallback_consensus_download_speed(self.dirip, self.dirport, self._data['nickname'], + self._fpr, CONSENSUS_DOWNLOAD_SPEED_MAX) if self.has_ipv6() and PERFORM_IPV6_DIRPORT_CHECKS: # Clients assume the IPv6 DirPort is the same as the IPv4 DirPort ipv6_failed = Candidate.fallback_consensus_download_speed(self.ipv6addr, self.dirport, self._data['nickname'], + self._fpr, CONSENSUS_DOWNLOAD_SPEED_MAX) return ((not ipv4_failed) and (not ipv6_failed)) @@ -1151,6 +1296,7 @@ class Candidate(object): # /* # nickname # flags + # adjusted bandwidth, consensus weight # [contact] # [identical contact counts] # */ @@ -1162,6 +1308,13 @@ class Candidate(object): s += 'Flags: ' s += cleanse_c_multiline_comment(' '.join(sorted(self._data['flags']))) s += '\n' + # this is an adjusted bandwidth, see calculate_measured_bandwidth() + bandwidth = self._data['measured_bandwidth'] + weight = self._data['consensus_weight'] + s += 'Bandwidth: %.1f MByte/s, Consensus Weight: %d'%( + bandwidth/(1024.0*1024.0), + weight) + s += '\n' if self._data['contact'] is not None: s += cleanse_c_multiline_comment(self._data['contact']) if CONTACT_COUNT or CONTACT_BLACKLIST_COUNT: @@ -1183,6 +1336,7 @@ class Candidate(object): s += '\n' s += '*/' s += '\n' + return s # output the fallback info C string for this fallback # this is the text that would go after FallbackDir in a torrc @@ -1190,8 +1344,14 @@ class Candidate(object): # comment-out the returned string def fallbackdir_info(self, dl_speed_ok): # "address:dirport orport=port id=fingerprint" + # (insert additional madatory fields here) # "[ipv6=addr:orport]" - # "weight=FALLBACK_OUTPUT_WEIGHT", + # (insert additional optional fields here) + # /* nickname=name */ + # /* extrainfo={0,1} */ + # (insert additional comment fields here) + # /* ===== */ + # , # # Do we want a C string, or a commented-out string? c_string = dl_speed_ok @@ -1212,10 +1372,34 @@ class Candidate(object): self.orport, cleanse_c_string(self._fpr)) s += '\n' + # (insert additional madatory fields here) if self.has_ipv6(): s += '" ipv6=%s:%d"'%(cleanse_c_string(self.ipv6addr), self.ipv6orport) s += '\n' - s += '" weight=%d",'%(FALLBACK_OUTPUT_WEIGHT) + # (insert additional optional fields here) + if not comment_string: + s += '/* ' + s += 'nickname=%s'%(cleanse_c_string(self._data['nickname'])) + if not comment_string: + s += ' */' + s += '\n' + # if we know that the fallback is an extrainfo cache, flag it + # and if we don't know, assume it is not + if not comment_string: + s += '/* ' + s += 'extrainfo=%d'%(1 if self._extra_info_cache else 0) + if not comment_string: + s += ' */' + s += '\n' + # (insert additional comment fields here) + # The terminator and comma must be the last line in each fallback entry + if not comment_string: + s += '/* ' + s += SECTION_SEPARATOR_BASE + if not comment_string: + s += ' */' + s += '\n' + s += ',' if comment_string: s += '\n' s += '*/' @@ -1251,7 +1435,8 @@ class CandidateList(dict): d = fetch('details', fields=('fingerprint,nickname,contact,last_changed_address_or_port,' + 'consensus_weight,advertised_bandwidth,or_addresses,' + - 'dir_address,recommended_version,flags,effective_family')) + 'dir_address,recommended_version,flags,effective_family,' + + 'platform')) logging.debug('Loading details document done.') if not 'relays' in d: raise Exception("No relays found in document.") @@ -1297,13 +1482,12 @@ class CandidateList(dict): self.fallbacks.sort(key=lambda f: f._data['measured_bandwidth'], reverse=True) - # sort fallbacks by their fingerprint, lowest to highest - # this is useful for stable diffs of fallback lists - def sort_fallbacks_by_fingerprint(self): - self.fallbacks.sort(key=lambda f: f._fpr) + # sort fallbacks by the data field data_field, lowest to highest + def sort_fallbacks_by(self, data_field): + self.fallbacks.sort(key=lambda f: f._data[data_field]) @staticmethod - def load_relaylist(file_name): + def load_relaylist(file_obj): """ Read each line in the file, and parse it like a FallbackDir line: an IPv4 address and optional port: <IPv4 address>:<port> @@ -1318,8 +1502,9 @@ class CandidateList(dict): (of string -> string key/value pairs), and these dictionaries are placed in an array. comments start with # and are ignored """ + file_data = file_obj['data'] + file_name = file_obj['name'] relaylist = [] - file_data = read_from_file(file_name, MAX_LIST_FILE_SIZE) if file_data is None: return relaylist for line in file_data.split('\n'): @@ -1360,12 +1545,12 @@ class CandidateList(dict): return relaylist # apply the fallback whitelist and blacklist - def apply_filter_lists(self): + def apply_filter_lists(self, whitelist_obj, blacklist_obj): excluded_count = 0 logging.debug('Applying whitelist and blacklist.') # parse the whitelist and blacklist - whitelist = self.load_relaylist(WHITELIST_FILE_NAME) - blacklist = self.load_relaylist(BLACKLIST_FILE_NAME) + whitelist = self.load_relaylist(whitelist_obj) + blacklist = self.load_relaylist(blacklist_obj) filtered_fallbacks = [] for f in self.fallbacks: in_whitelist = f.is_in_whitelist(whitelist) @@ -1385,7 +1570,7 @@ class CandidateList(dict): elif in_blacklist: # exclude excluded_count += 1 - logging.info('Excluding %s: in blacklist.', f._fpr) + log_excluded('Excluding %s: in blacklist.', f._fpr) else: if INCLUDE_UNLISTED_ENTRIES: # include @@ -1393,7 +1578,7 @@ class CandidateList(dict): else: # exclude excluded_count += 1 - logging.info('Excluding %s: in neither blacklist nor whitelist.', + log_excluded('Excluding %s: in neither blacklist nor whitelist.', f._fpr) self.fallbacks = filtered_fallbacks return excluded_count @@ -1404,7 +1589,7 @@ class CandidateList(dict): excluded_count, initial_count) # calculate each fallback's measured bandwidth based on the median - # consensus weight to advertised bandwdith ratio + # consensus weight to advertised bandwidth ratio def calculate_measured_bandwidth(self): self.sort_fallbacks_by_cw_to_bw_factor() median_fallback = self.fallback_median(True) @@ -1429,8 +1614,8 @@ class CandidateList(dict): # the bandwidth we log here is limited by the relay's consensus weight # as well as its adverttised bandwidth. See set_measured_bandwidth # for details - logging.info('%s not a candidate: bandwidth %.1fMB/s too low, must ' + - 'be at least %.1fMB/s', f._fpr, + log_excluded('%s not a candidate: bandwidth %.1fMByte/s too low, ' + + 'must be at least %.1fMByte/s', f._fpr, f._data['measured_bandwidth']/(1024.0*1024.0), MIN_BANDWIDTH/(1024.0*1024.0)) self.fallbacks = above_min_bw_fallbacks @@ -1470,49 +1655,85 @@ class CandidateList(dict): else: return None - # does exclusion_list contain attribute? + # return a new bag suitable for storing attributes + @staticmethod + def attribute_new(): + return dict() + + # get the count of attribute in attribute_bag + # if attribute is None or the empty string, return 0 + @staticmethod + def attribute_count(attribute, attribute_bag): + if attribute is None or attribute == '': + return 0 + if attribute not in attribute_bag: + return 0 + return attribute_bag[attribute] + + # does attribute_bag contain more than max_count instances of attribute? # if so, return False # if not, return True - # if attribute is None or the empty string, always return True + # if attribute is None or the empty string, or max_count is invalid, + # always return True @staticmethod - def allow(attribute, exclusion_list): - if attribute is None or attribute == '': + def attribute_allow(attribute, attribute_bag, max_count=1): + if attribute is None or attribute == '' or max_count <= 0: return True - elif attribute in exclusion_list: + elif CandidateList.attribute_count(attribute, attribute_bag) >= max_count: return False else: return True - # make sure there is only one fallback per IPv4 address, and per IPv6 address + # add attribute to attribute_bag, incrementing the count if it is already + # present + # if attribute is None or the empty string, or count is invalid, + # do nothing + @staticmethod + def attribute_add(attribute, attribute_bag, count=1): + if attribute is None or attribute == '' or count <= 0: + pass + attribute_bag.setdefault(attribute, 0) + attribute_bag[attribute] += count + + # make sure there are only MAX_FALLBACKS_PER_IP fallbacks per IPv4 address, + # and per IPv6 address # there is only one IPv4 address on each fallback: the IPv4 DirPort address # (we choose the IPv4 ORPort which is on the same IPv4 as the DirPort) # there is at most one IPv6 address on each fallback: the IPv6 ORPort address # we try to match the IPv4 ORPort, but will use any IPv6 address if needed - # (clients assume the IPv6 DirPort is the same as the IPv4 DirPort, but - # typically only use the IPv6 ORPort) + # (clients only use the IPv6 ORPort) # if there is no IPv6 address, only the IPv4 address is checked # return the number of candidates we excluded def limit_fallbacks_same_ip(self): ip_limit_fallbacks = [] - ip_list = [] + ip_list = CandidateList.attribute_new() for f in self.fallbacks: - if (CandidateList.allow(f.dirip, ip_list) - and CandidateList.allow(f.ipv6addr, ip_list)): + if (CandidateList.attribute_allow(f.dirip, ip_list, + MAX_FALLBACKS_PER_IPV4) + and CandidateList.attribute_allow(f.ipv6addr, ip_list, + MAX_FALLBACKS_PER_IPV6)): ip_limit_fallbacks.append(f) - ip_list.append(f.dirip) + CandidateList.attribute_add(f.dirip, ip_list) if f.has_ipv6(): - ip_list.append(f.ipv6addr) - elif not CandidateList.allow(f.dirip, ip_list): - logging.info('Eliminated %s: already have fallback on IPv4 %s'%( - f._fpr, f.dirip)) - elif f.has_ipv6() and not CandidateList.allow(f.ipv6addr, ip_list): - logging.info('Eliminated %s: already have fallback on IPv6 %s'%( - f._fpr, f.ipv6addr)) + CandidateList.attribute_add(f.ipv6addr, ip_list) + elif not CandidateList.attribute_allow(f.dirip, ip_list, + MAX_FALLBACKS_PER_IPV4): + log_excluded('Eliminated %s: already have %d fallback(s) on IPv4 %s' + %(f._fpr, CandidateList.attribute_count(f.dirip, ip_list), + f.dirip)) + elif (f.has_ipv6() and + not CandidateList.attribute_allow(f.ipv6addr, ip_list, + MAX_FALLBACKS_PER_IPV6)): + log_excluded('Eliminated %s: already have %d fallback(s) on IPv6 %s' + %(f._fpr, CandidateList.attribute_count(f.ipv6addr, + ip_list), + f.ipv6addr)) original_count = len(self.fallbacks) self.fallbacks = ip_limit_fallbacks return original_count - len(self.fallbacks) - # make sure there is only one fallback per ContactInfo + # make sure there are only MAX_FALLBACKS_PER_CONTACT fallbacks for each + # ContactInfo # if there is no ContactInfo, allow the fallback # this check can be gamed by providing no ContactInfo, or by setting the # ContactInfo to match another fallback @@ -1520,41 +1741,96 @@ class CandidateList(dict): # go down at similar times, its usefulness outweighs the risk def limit_fallbacks_same_contact(self): contact_limit_fallbacks = [] - contact_list = [] + contact_list = CandidateList.attribute_new() for f in self.fallbacks: - if CandidateList.allow(f._data['contact'], contact_list): + if CandidateList.attribute_allow(f._data['contact'], contact_list, + MAX_FALLBACKS_PER_CONTACT): contact_limit_fallbacks.append(f) - contact_list.append(f._data['contact']) + CandidateList.attribute_add(f._data['contact'], contact_list) else: - logging.info(('Eliminated %s: already have fallback on ' + - 'ContactInfo %s')%(f._fpr, f._data['contact'])) + log_excluded( + 'Eliminated %s: already have %d fallback(s) on ContactInfo %s' + %(f._fpr, CandidateList.attribute_count(f._data['contact'], + contact_list), + f._data['contact'])) original_count = len(self.fallbacks) self.fallbacks = contact_limit_fallbacks return original_count - len(self.fallbacks) - # make sure there is only one fallback per effective family + # make sure there are only MAX_FALLBACKS_PER_FAMILY fallbacks per effective + # family # if there is no family, allow the fallback - # this check can't be gamed, because we use effective family, which ensures - # mutual family declarations + # we use effective family, which ensures mutual family declarations + # but the check can be gamed by not declaring a family at all # if any indirect families exist, the result depends on the order in which # fallbacks are sorted in the list def limit_fallbacks_same_family(self): family_limit_fallbacks = [] - fingerprint_list = [] + fingerprint_list = CandidateList.attribute_new() for f in self.fallbacks: - if CandidateList.allow(f._fpr, fingerprint_list): + if CandidateList.attribute_allow(f._fpr, fingerprint_list, + MAX_FALLBACKS_PER_FAMILY): family_limit_fallbacks.append(f) - fingerprint_list.append(f._fpr) - fingerprint_list.extend(f._data['effective_family']) + CandidateList.attribute_add(f._fpr, fingerprint_list) + for family_fingerprint in f._data['effective_family']: + CandidateList.attribute_add(family_fingerprint, fingerprint_list) else: - # technically, we already have a fallback with this fallback in its - # effective family - logging.info('Eliminated %s: already have fallback in effective ' + - 'family'%(f._fpr)) + # we already have a fallback with this fallback in its effective + # family + log_excluded( + 'Eliminated %s: already have %d fallback(s) in effective family' + %(f._fpr, CandidateList.attribute_count(f._fpr, fingerprint_list))) original_count = len(self.fallbacks) self.fallbacks = family_limit_fallbacks return original_count - len(self.fallbacks) + # try once to get the descriptors for fingerprint_list using stem + # returns an empty list on exception + @staticmethod + def get_fallback_descriptors_once(fingerprint_list): + desc_list = get_server_descriptors(fingerprints=fingerprint_list).run(suppress=True) + return desc_list + + # try up to max_retries times to get the descriptors for fingerprint_list + # using stem. Stops retrying when all descriptors have been retrieved. + # returns a list containing the descriptors that were retrieved + @staticmethod + def get_fallback_descriptors(fingerprint_list, max_retries=5): + # we can't use stem's retries=, because we want to support more than 96 + # descriptors + # + # add an attempt for every MAX_FINGERPRINTS (or part thereof) in the list + max_retries += (len(fingerprint_list) + MAX_FINGERPRINTS - 1) / MAX_FINGERPRINTS + remaining_list = fingerprint_list + desc_list = [] + for _ in xrange(max_retries): + if len(remaining_list) == 0: + break + new_desc_list = CandidateList.get_fallback_descriptors_once(remaining_list[0:MAX_FINGERPRINTS]) + for d in new_desc_list: + try: + remaining_list.remove(d.fingerprint) + except ValueError: + # warn and ignore if a directory mirror returned a bad descriptor + logging.warning("Directory mirror returned unwanted descriptor %s, ignoring", + d.fingerprint) + continue + desc_list.append(d) + return desc_list + + # find the fallbacks that cache extra-info documents + # Onionoo doesn't know this, so we have to use stem + def mark_extra_info_caches(self): + fingerprint_list = [ f._fpr for f in self.fallbacks ] + logging.info("Downloading fallback descriptors to find extra-info caches") + desc_list = CandidateList.get_fallback_descriptors(fingerprint_list) + for d in desc_list: + self[d.fingerprint]._extra_info_cache = d.extra_info_cache + missing_descriptor_list = [ f._fpr for f in self.fallbacks + if f._extra_info_cache is None ] + for f in missing_descriptor_list: + logging.warning("No descriptor for {}. Assuming extrainfo=0.".format(f)) + # try a download check on each fallback candidate in order # stop after max_count successful downloads # but don't remove any candidates from the array @@ -1714,7 +1990,7 @@ class CandidateList(dict): # this doesn't actually tell us anything useful #self.describe_fallback_ipv4_netblock_mask(8) self.describe_fallback_ipv4_netblock_mask(16) - self.describe_fallback_ipv4_netblock_mask(24) + #self.describe_fallback_ipv4_netblock_mask(24) # log a message about the proportion of fallbacks in each IPv6 /12 (RIR), # /23 (smaller RIR blocks), /32 (LIR), /48 (Customer), and /64 (Host) @@ -1724,7 +2000,7 @@ class CandidateList(dict): #self.describe_fallback_ipv6_netblock_mask(12) #self.describe_fallback_ipv6_netblock_mask(23) self.describe_fallback_ipv6_netblock_mask(32) - self.describe_fallback_ipv6_netblock_mask(48) + #self.describe_fallback_ipv6_netblock_mask(48) self.describe_fallback_ipv6_netblock_mask(64) # log a message about the proportion of fallbacks in each IPv4 and IPv6 @@ -1802,6 +2078,18 @@ class CandidateList(dict): CandidateList.describe_percentage(dir_count, fallback_count))) + # return a list of fallbacks which cache extra-info documents + def fallbacks_with_extra_info_cache(self): + return filter(lambda x: x._extra_info_cache, self.fallbacks) + + # log a message about the proportion of fallbacks that cache extra-info docs + def describe_fallback_extra_info_caches(self): + extra_info_falback_count = len(self.fallbacks_with_extra_info_cache()) + fallback_count = len(self.fallbacks) + logging.warning('%s of fallbacks cache extra-info documents'%( + CandidateList.describe_percentage(extra_info_falback_count, + fallback_count))) + # return a list of fallbacks which have the Exit flag def fallbacks_with_exit(self): return filter(lambda x: x.is_exit(), self.fallbacks) @@ -1829,10 +2117,6 @@ class CandidateList(dict): def summarise_fallbacks(self, eligible_count, operator_count, failed_count, guard_count, target_count): s = '' - s += '/* To comment-out entries in this file, use C comments, and add *' - s += ' to the start of each line. (stem finds fallback entries using "' - s += ' at the start of a line.) */' - s += '\n' # Report: # whether we checked consensus download times # the number of fallback directories (and limits/exclusions, if relevant) @@ -1878,8 +2162,8 @@ class CandidateList(dict): min_bw = min_fb._data['measured_bandwidth'] max_fb = self.fallback_max() max_bw = max_fb._data['measured_bandwidth'] - s += 'Bandwidth Range: %.1f - %.1f MB/s'%(min_bw/(1024.0*1024.0), - max_bw/(1024.0*1024.0)) + s += 'Bandwidth Range: %.1f - %.1f MByte/s'%(min_bw/(1024.0*1024.0), + max_bw/(1024.0*1024.0)) s += '\n' s += '*/' if fallback_count < MIN_FALLBACK_COUNT: @@ -1892,12 +2176,57 @@ class CandidateList(dict): s += 'or setting INCLUDE_UNLISTED_ENTRIES = True.' return s +def process_existing(): + logging.basicConfig(level=logging.INFO) + logging.getLogger('stem').setLevel(logging.INFO) + whitelist = {'data': parse_fallback_file(FALLBACK_FILE_NAME), + 'name': FALLBACK_FILE_NAME} + blacklist = {'data': read_from_file(BLACKLIST_FILE_NAME, MAX_LIST_FILE_SIZE), + 'name': BLACKLIST_FILE_NAME} + list_fallbacks(whitelist, blacklist) + +def process_default(): + logging.basicConfig(level=logging.WARNING) + logging.getLogger('stem').setLevel(logging.WARNING) + whitelist = {'data': read_from_file(WHITELIST_FILE_NAME, MAX_LIST_FILE_SIZE), + 'name': WHITELIST_FILE_NAME} + blacklist = {'data': read_from_file(BLACKLIST_FILE_NAME, MAX_LIST_FILE_SIZE), + 'name': BLACKLIST_FILE_NAME} + list_fallbacks(whitelist, blacklist) + ## Main Function +def main(): + if get_command() == 'check_existing': + process_existing() + else: + process_default() + +def get_command(): + if len(sys.argv) == 2: + return sys.argv[1] + else: + return None + +def log_excluded(msg, *args): + if get_command() == 'check_existing': + logging.warning(msg, *args) + else: + logging.info(msg, *args) -def list_fallbacks(): +def list_fallbacks(whitelist, blacklist): """ Fetches required onionoo documents and evaluates the fallback directory criteria for each of the relays """ + print "/* type=fallback */" + print ("/* version={} */" + .format(cleanse_c_multiline_comment(FALLBACK_FORMAT_VERSION))) + now = datetime.datetime.utcnow() + timestamp = now.strftime('%Y%m%d%H%M%S') + print ("/* timestamp={} */" + .format(cleanse_c_multiline_comment(timestamp))) + # end the header with a separator, to make it easier for parsers + print SECTION_SEPARATOR_COMMENT + logging.warning('Downloading and parsing Onionoo data. ' + 'This may take some time.') # find relays that could be fallbacks @@ -1927,7 +2256,7 @@ def list_fallbacks(): # warning that the details have changed from those in the whitelist. # instead, there will be an info-level log during the eligibility check. initial_count = len(candidates.fallbacks) - excluded_count = candidates.apply_filter_lists() + excluded_count = candidates.apply_filter_lists(whitelist, blacklist) print candidates.summarise_filters(initial_count, excluded_count) eligible_count = len(candidates.fallbacks) @@ -1963,6 +2292,9 @@ def list_fallbacks(): 'This may take some time.') failed_count = candidates.perform_download_consensus_checks(max_count) + # work out which fallbacks cache extra-infos + candidates.mark_extra_info_caches() + # analyse and log interesting diversity metrics # like netblock, ports, exit, IPv4-only # (we can't easily analyse AS, and it's hard to accurately analyse country) @@ -1971,6 +2303,7 @@ def list_fallbacks(): if HAVE_IPADDRESS: candidates.describe_fallback_netblocks() candidates.describe_fallback_ports() + candidates.describe_fallback_extra_info_caches() candidates.describe_fallback_exit_flag() # output C comments summarising the fallback selection process @@ -1985,15 +2318,20 @@ def list_fallbacks(): for s in fetch_source_list(): print describe_fetch_source(s) + # start the list with a separator, to make it easy for parsers + print SECTION_SEPARATOR_COMMENT + + # sort the list differently depending on why we've created it: # if we're outputting the final fallback list, sort by fingerprint # this makes diffs much more stable - # otherwise, leave sorted by bandwidth, which allows operators to be - # contacted in priority order - if not OUTPUT_CANDIDATES: - candidates.sort_fallbacks_by_fingerprint() + # otherwise, if we're trying to find a bandwidth cutoff, or we want to + # contact operators in priority order, sort by bandwidth (not yet + # implemented) + # otherwise, if we're contacting operators, sort by contact + candidates.sort_fallbacks_by(OUTPUT_SORT_FIELD) for x in candidates.fallbacks: print x.fallbackdir_line(candidates.fallbacks, prefilter_fallbacks) if __name__ == "__main__": - list_fallbacks() + main() diff --git a/scripts/maint/updateRustDependencies.sh b/scripts/maint/updateRustDependencies.sh new file mode 100755 index 0000000000..a5a92579d3 --- /dev/null +++ b/scripts/maint/updateRustDependencies.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Tor Project, Inc. +# Copyright (c) 2018 isis agora lovecruft +# See LICENSE for license information +# +# updateRustDependencies.sh +# ------------------------- +# Update our vendored Rust dependencies, either adding/removing +# dependencies and/or upgrading current dependencies to newer +# versions. +# +# To use this script, first add your dependencies, exactly specifying +# their versions, into the appropriate *crate-level* Cargo.toml in +# src/rust/ (i.e. *not* /src/rust/Cargo.toml, but instead the one for +# your crate). +# +# Next, run this script. Then, go into src/ext/rust and commit the +# changes to the tor-rust-dependencies repo. + +set -e + +HERE=`dirname $(realpath $0)` +TOPLEVEL=`dirname $(dirname $HERE)` +TOML="$TOPLEVEL/src/rust/Cargo.toml" +VENDORED="$TOPLEVEL/src/ext/rust/crates" +CARGO=`which cargo` + +if ! test -f "$TOML" ; then + printf "Error: Couldn't find workspace Cargo.toml in expected location: %s\n" "$TOML" +fi + +if ! test -d "$VENDORED" ; then + printf "Error: Couldn't find directory for Rust dependencies! Expected location: %s\n" "$VENDORED" +fi + +if test -z "$CARGO" ; then + printf "Error: cargo must be installed and in your \$PATH\n" +fi + +if test -z `cargo --list | grep vendor` ; then + printf "Error: cargo-vendor not installed\n" +fi + +$CARGO vendor -v --locked --explicit-version --no-delete --sync $TOML $VENDORED diff --git a/scripts/test/cov-diff b/scripts/test/cov-diff index 7da7f0be9d..6179dff63e 100755 --- a/scripts/test/cov-diff +++ b/scripts/test/cov-diff @@ -7,11 +7,15 @@ DIRA="$1" DIRB="$2" -for A in $DIRA/*; do - B=$DIRB/`basename $A` - perl -pe 's/^\s*\!*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$A" > "$A.tmp" - perl -pe 's/^\s*\!*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$B" > "$B.tmp" - diff -u "$A.tmp" "$B.tmp" +for B in $DIRB/*; do + A=$DIRA/`basename $B` + if [ -f $A ]; then + perl -pe 's/^\s*\!*\d+(\*?):/ 1$1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$A" > "$A.tmp" + else + cat /dev/null > "$A.tmp" + fi + perl -pe 's/^\s*\!*\d+(\*?):/ 1$1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$B" > "$B.tmp" + diff -u "$A.tmp" "$B.tmp" |perl -pe 's/^((?:\+\+\+|---)(?:.*tmp))\s+.*/$1/;' rm "$A.tmp" "$B.tmp" done diff --git a/scripts/test/cov-exclude b/scripts/test/cov-exclude index 5117f11ec4..5cb9b1282d 100755 --- a/scripts/test/cov-exclude +++ b/scripts/test/cov-exclude @@ -26,3 +26,9 @@ if ($excluding or $exclude_this) { s{^\s*\#\#+:}{ x:}; s{^ (\s*)(\d+):}{$1!!!$2:}; } + +if (eof and $excluding) { + warn "Runaway LCOV_EXCL_START in $ARGV"; + $excluding = 0; +} + diff --git a/scripts/test/coverage b/scripts/test/coverage index f4ae475828..f10c5afaae 100755 --- a/scripts/test/coverage +++ b/scripts/test/coverage @@ -29,7 +29,7 @@ for fn in src/or/*.c src/common/*.c; do gcov -o $on $fn if [ -e $GC ] then - if [ -n $dst ] + if [ -d "$dst" ] then mv $GC $dst/$GC fi diff --git a/scripts/test/scan-build.sh b/scripts/test/scan-build.sh index 36e69e6d00..8d126cbcee 100644..100755 --- a/scripts/test/scan-build.sh +++ b/scripts/test/scan-build.sh @@ -5,37 +5,76 @@ # This script is used for running a bunch of clang scan-build checkers # on Tor. +# These don't seem to cause false positives in our code, so let's turn +# them on. CHECKERS="\ - -disable-checker deadcode.DeadStores \ - -enable-checker alpha.core.CastSize \ + -enable-checker alpha.core.CallAndMessageUnInitRefArg \ -enable-checker alpha.core.CastToStruct \ + -enable-checker alpha.core.Conversion \ + -enable-checker alpha.core.FixedAddr \ -enable-checker alpha.core.IdenticalExpr \ + -enable-checker alpha.core.PointerArithm \ -enable-checker alpha.core.SizeofPtr \ - -enable-checker alpha.security.ArrayBoundV2 \ + -enable-checker alpha.core.TestAfterDivZero \ -enable-checker alpha.security.MallocOverflow \ -enable-checker alpha.security.ReturnPtrRange \ - -enable-checker alpha.unix.SimpleStream + -enable-checker alpha.unix.BlockInCriticalSection \ + -enable-checker alpha.unix.Chroot \ + -enable-checker alpha.unix.PthreadLock \ + -enable-checker alpha.unix.PthreadLock \ + -enable-checker alpha.unix.SimpleStream \ + -enable-checker alpha.unix.Stream \ -enable-checker alpha.unix.cstring.BufferOverlap \ -enable-checker alpha.unix.cstring.NotNullTerminated \ - -enable-checker alpha.unix.cstring.OutOfBounds \ - -enable-checker alpha.core.FixedAddr \ + -enable-checker valist.CopyToSelf \ + -enable-checker valist.Uninitialized \ + -enable-checker valist.Unterminated \ + -enable-checker security.FloatLoopCounter \ -enable-checker security.insecureAPI.strcpy \ - -enable-checker alpha.unix.PthreadLock \ - -enable-checker alpha.core.PointerArithm \ - -enable-checker alpha.core.TestAfterDivZero \ " +# These have high false-positive rates. +EXTRA_CHECKERS="\ + -enable-checker alpha.security.ArrayBoundV2 \ + -enable-checker alpha.unix.cstring.OutOfBounds \ + -enable-checker alpha.core.CastSize \ +" + +# These don't seem to generate anything useful +NOISY_CHECKERS="\ + -enable-checker alpha.clone.CloneChecker \ + -enable-checker alpha.deadcode.UnreachableCode \ +" + +if test "x$SCAN_BUILD_OUTPUT" != "x"; then + OUTPUTARG="-o $SCAN_BUILD_OUTPUT" +else + OUTPUTARG="" +fi + scan-build \ $CHECKERS \ ./configure scan-build \ + make clean + +# Make this not get scanned for dead assignments, since it has lots of +# dead assignments we don't care about. +scan-build \ $CHECKERS \ - make -j2 -k + -disable-checker deadcode.DeadStores \ + make -j5 -k ./src/ext/ed25519/ref10/libed25519_ref10.a +scan-build \ + $CHECKERS $OUTPUTARG \ + make -j5 -k + +CHECKERS="\ +" # This one gives a false positive on every strcmp. # -enable-checker alpha.core.PointerSub # Needs work -# alpha.unix.MallocWithAnnotations ?? +# -enable-checker alpha.unix.MallocWithAnnotations |