|
@@ -26,6 +26,7 @@ import hashlib
|
|
|
import dateutil.parser
|
|
|
|
|
|
|
|
|
+import copy
|
|
|
|
|
|
from stem.descriptor.remote import DescriptorDownloader
|
|
|
|
|
@@ -52,6 +53,11 @@ PERFORM_IPV4_DIRPORT_CHECKS = False if OUTPUT_CANDIDATES else True
|
|
|
|
|
|
PERFORM_IPV6_DIRPORT_CHECKS = False if OUTPUT_CANDIDATES else False
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+CONTACT_COUNT = True if OUTPUT_CANDIDATES else False
|
|
|
+CONTACT_BLACKLIST_COUNT = True if OUTPUT_CANDIDATES else False
|
|
|
+
|
|
|
|
|
|
|
|
|
ONIONOO = 'https://onionoo.torproject.org/'
|
|
@@ -123,8 +129,9 @@ CONSENSUS_DOWNLOAD_RETRY = True
|
|
|
_FB_POG = 0.2
|
|
|
FALLBACK_PROPORTION_OF_GUARDS = None if OUTPUT_CANDIDATES else _FB_POG
|
|
|
|
|
|
+
|
|
|
|
|
|
-MAX_FALLBACK_COUNT = None if OUTPUT_CANDIDATES else 500
|
|
|
+MAX_FALLBACK_COUNT = None if OUTPUT_CANDIDATES else 100
|
|
|
|
|
|
MIN_FALLBACK_COUNT = 100
|
|
|
|
|
@@ -958,11 +965,12 @@ class Candidate(object):
|
|
|
CONSENSUS_DOWNLOAD_SPEED_MAX)
|
|
|
return ((not ipv4_failed) and (not ipv6_failed))
|
|
|
|
|
|
- def fallbackdir_line(self, dl_speed_ok):
|
|
|
+ def fallbackdir_line(self, dl_speed_ok, fallbacks, prefilter_fallbacks):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
@@ -978,6 +986,22 @@ class Candidate(object):
|
|
|
s += '\n'
|
|
|
if self._data['contact'] is not None:
|
|
|
s += cleanse_c_multiline_comment(self._data['contact'])
|
|
|
+ if CONTACT_COUNT or CONTACT_BLACKLIST_COUNT:
|
|
|
+ fallback_count = len([f for f in fallbacks
|
|
|
+ if f._data['contact'] == self._data['contact']])
|
|
|
+ if fallback_count > 1:
|
|
|
+ s += '\n'
|
|
|
+ s += '%d identical contacts listed' % (fallback_count)
|
|
|
+ if CONTACT_BLACKLIST_COUNT:
|
|
|
+ prefilter_count = len([f for f in prefilter_fallbacks
|
|
|
+ if f._data['contact'] == self._data['contact']])
|
|
|
+ filter_count = prefilter_count - fallback_count
|
|
|
+ if filter_count > 0:
|
|
|
+ if fallback_count > 1:
|
|
|
+ s += ' '
|
|
|
+ else:
|
|
|
+ s += '\n'
|
|
|
+ s += '%d blacklisted' % (filter_count)
|
|
|
s += '\n'
|
|
|
s += '*/'
|
|
|
s += '\n'
|
|
@@ -1170,13 +1194,6 @@ class CandidateList(dict):
|
|
|
return '/* Whitelist & blacklist excluded %d of %d candidates. */'%(
|
|
|
excluded_count, initial_count)
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- def exclude_excess_fallbacks(self):
|
|
|
- if MAX_FALLBACK_COUNT is not None:
|
|
|
- self.fallbacks = self.fallbacks[:MAX_FALLBACK_COUNT]
|
|
|
-
|
|
|
def fallback_min_weight(self):
|
|
|
if len(self.fallbacks) > 0:
|
|
|
return self.fallbacks[-1]
|
|
@@ -1192,63 +1209,55 @@ class CandidateList(dict):
|
|
|
def summarise_fallbacks(self, eligible_count, guard_count, target_count,
|
|
|
max_count):
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
|
|
|
-
|
|
|
- s = '/*'
|
|
|
+
|
|
|
+ if PERFORM_IPV4_DIRPORT_CHECKS or PERFORM_IPV6_DIRPORT_CHECKS:
|
|
|
+ s = '/* Checked %s%s%s DirPorts served a consensus within %.1fs. */'%(
|
|
|
+ 'IPv4' if PERFORM_IPV4_DIRPORT_CHECKS else '',
|
|
|
+ ' and ' if (PERFORM_IPV4_DIRPORT_CHECKS
|
|
|
+ and PERFORM_IPV6_DIRPORT_CHECKS) else '',
|
|
|
+ 'IPv6' if PERFORM_IPV6_DIRPORT_CHECKS else '',
|
|
|
+ CONSENSUS_DOWNLOAD_SPEED_MAX)
|
|
|
+ else:
|
|
|
+ s = '/* Did not check IPv4 or IPv6 DirPort consensus downloads. */'
|
|
|
s += '\n'
|
|
|
- s += 'Fallback Directory Summary'
|
|
|
+
|
|
|
+ s += '/*'
|
|
|
s += '\n'
|
|
|
|
|
|
fallback_count = len(self.fallbacks)
|
|
|
if FALLBACK_PROPORTION_OF_GUARDS is None:
|
|
|
- fallback_proportion = ' (none)'
|
|
|
+ fallback_proportion = ''
|
|
|
else:
|
|
|
- fallback_proportion = '%d (%d * %f)'%(target_count, guard_count,
|
|
|
- FALLBACK_PROPORTION_OF_GUARDS)
|
|
|
- s += 'Final Count: %d (Eligible %d, Target %d%s'%(
|
|
|
- min(max_count, fallback_count),
|
|
|
- eligible_count,
|
|
|
- fallback_count,
|
|
|
- fallback_proportion)
|
|
|
+ fallback_proportion = ', Target %d (%d * %f)'%(target_count, guard_count,
|
|
|
+ FALLBACK_PROPORTION_OF_GUARDS)
|
|
|
+ s += 'Final Count: %d (Eligible %d%s'%(fallback_count,
|
|
|
+ eligible_count,
|
|
|
+ fallback_proportion)
|
|
|
if MAX_FALLBACK_COUNT is not None:
|
|
|
s += ', Clamped to %d'%(MAX_FALLBACK_COUNT)
|
|
|
s += ')\n'
|
|
|
- if fallback_count < MIN_FALLBACK_COUNT:
|
|
|
- s += '*/'
|
|
|
- s += '\n'
|
|
|
-
|
|
|
-
|
|
|
- s += '#error Fallback Count %d is too low. '%(fallback_count)
|
|
|
- s += 'Must be at least %d for diversity. '%(MIN_FALLBACK_COUNT)
|
|
|
- s += 'Try adding entries to the whitelist, '
|
|
|
- s += 'or setting INCLUDE_UNLISTED_ENTRIES = True.'
|
|
|
- s += '\n'
|
|
|
- s += '/*'
|
|
|
+ if eligible_count != fallback_count:
|
|
|
+ s += 'Excluded: %d (Eligible Count Exceeded Target Count)'%(
|
|
|
+ eligible_count - fallback_count)
|
|
|
s += '\n'
|
|
|
min_fb = self.fallback_min_weight()
|
|
|
min_weight = min_fb._data['consensus_weight']
|
|
|
max_fb = self.fallback_max_weight()
|
|
|
max_weight = max_fb._data['consensus_weight']
|
|
|
- s += 'Max Weight: %d'%(max_weight)
|
|
|
+ s += 'Consensus Weight Range: %d - %d'%(min_weight, max_weight)
|
|
|
s += '\n'
|
|
|
- s += 'Min Weight: %d'%(min_weight)
|
|
|
- s += '\n'
|
|
|
- if eligible_count != fallback_count:
|
|
|
- s += 'Excluded: %d (Eligible Count Exceeded Target Count)'%(
|
|
|
- eligible_count - fallback_count)
|
|
|
- s += '\n'
|
|
|
s += '*/'
|
|
|
- if PERFORM_IPV4_DIRPORT_CHECKS or PERFORM_IPV6_DIRPORT_CHECKS:
|
|
|
- s += '/* Checked %s%s%s DirPorts served a consensus within %.1fs. */'%(
|
|
|
- 'IPv4' if PERFORM_IPV4_DIRPORT_CHECKS else '',
|
|
|
- ' and ' if (PERFORM_IPV4_DIRPORT_CHECKS
|
|
|
- and PERFORM_IPV6_DIRPORT_CHECKS) else '',
|
|
|
- 'IPv6' if PERFORM_IPV6_DIRPORT_CHECKS else '',
|
|
|
- CONSENSUS_DOWNLOAD_SPEED_MAX)
|
|
|
- else:
|
|
|
- s += '/* Did not check IPv4 or IPv6 DirPort consensus downloads. */'
|
|
|
+ if fallback_count < MIN_FALLBACK_COUNT:
|
|
|
+
|
|
|
+
|
|
|
+ s += '\n'
|
|
|
+ s += '#error Fallback Count %d is too low. '%(fallback_count)
|
|
|
+ s += 'Must be at least %d for diversity. '%(MIN_FALLBACK_COUNT)
|
|
|
+ s += 'Try adding entries to the whitelist, '
|
|
|
+ s += 'or setting INCLUDE_UNLISTED_ENTRIES = True.'
|
|
|
return s
|
|
|
|
|
|
|
|
@@ -1271,11 +1280,12 @@ def list_fallbacks():
|
|
|
|
|
|
|
|
|
if MAX_FALLBACK_COUNT is None:
|
|
|
- max_count = guard_count
|
|
|
+ max_count = target_count
|
|
|
else:
|
|
|
max_count = min(target_count, MAX_FALLBACK_COUNT)
|
|
|
|
|
|
candidates.compute_fallbacks()
|
|
|
+ prefilter_fallbacks = copy.copy(candidates.fallbacks)
|
|
|
|
|
|
|
|
|
initial_count = len(candidates.fallbacks)
|
|
@@ -1286,9 +1296,8 @@ def list_fallbacks():
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
- candidates.exclude_excess_fallbacks()
|
|
|
+
|
|
|
+
|
|
|
|
|
|
if len(candidates.fallbacks) > 0:
|
|
|
print candidates.summarise_fallbacks(eligible_count, guard_count,
|
|
@@ -1299,11 +1308,17 @@ def list_fallbacks():
|
|
|
for s in fetch_source_list():
|
|
|
print describe_fetch_source(s)
|
|
|
|
|
|
- for x in candidates.fallbacks[:max_count]:
|
|
|
+ active_count = 0
|
|
|
+ for x in candidates.fallbacks:
|
|
|
dl_speed_ok = x.fallback_consensus_dl_check()
|
|
|
- print x.fallbackdir_line(dl_speed_ok)
|
|
|
-
|
|
|
-
|
|
|
+ print x.fallbackdir_line(dl_speed_ok, candidates.fallbacks,
|
|
|
+ prefilter_fallbacks)
|
|
|
+ if dl_speed_ok:
|
|
|
+
|
|
|
+ active_count += 1
|
|
|
+ if active_count >= max_count:
|
|
|
+
|
|
|
+ break
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
list_fallbacks()
|