summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/codegen/fuzzing_include_am.py5
-rwxr-xr-xscripts/maint/checkIncludes.py66
-rw-r--r--scripts/maint/fallback.whitelist175
-rwxr-xr-xscripts/maint/pre-push.git-hook61
-rwxr-xr-xscripts/maint/updateFallbackDirs.py302
-rwxr-xr-xscripts/maint/updateRustDependencies.sh18
-rwxr-xr-xscripts/maint/updateVersions.pl.in59
-rwxr-xr-xscripts/maint/update_versions.py133
-rwxr-xr-xscripts/test/scan-build.sh5
9 files changed, 623 insertions, 201 deletions
diff --git a/scripts/codegen/fuzzing_include_am.py b/scripts/codegen/fuzzing_include_am.py
index 3c948d87cf..a944584453 100755
--- a/scripts/codegen/fuzzing_include_am.py
+++ b/scripts/codegen/fuzzing_include_am.py
@@ -13,6 +13,7 @@ FUZZERS = """
iptsv2
microdesc
socks
+ strops
vrs
"""
@@ -23,12 +24,12 @@ FUZZING_CPPFLAGS = \
FUZZING_CFLAGS = \
$(AM_CFLAGS) $(TEST_CFLAGS)
FUZZING_LDFLAG = \
- @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
+ @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) @TOR_LDFLAGS_libevent@
FUZZING_LIBS = \
$(TOR_INTERNAL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ \
diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py
index 46a3f39638..3afd9bbebe 100755
--- a/scripts/maint/checkIncludes.py
+++ b/scripts/maint/checkIncludes.py
@@ -33,6 +33,9 @@ else:
def open_file(fname):
return open(fname, 'r', encoding='utf-8')
+def warn(msg):
+ print(msg, file=sys.stderr)
+
def err(msg):
""" Declare that an error has happened, and remember that there has
been an error. """
@@ -48,14 +51,34 @@ def fname_is_c(fname):
INCLUDE_PATTERN = re.compile(r'\s*#\s*include\s+"([^"]*)"')
RULES_FNAME = ".may_include"
+ALLOWED_PATTERNS = [
+ re.compile(r'^.*\*\.(h|inc)$'),
+ re.compile(r'^.*/.*\.h$'),
+ re.compile(r'^ext/.*\.c$'),
+ re.compile(r'^orconfig.h$'),
+ re.compile(r'^micro-revision.i$'),
+]
+
+def pattern_is_normal(s):
+ for p in ALLOWED_PATTERNS:
+ if p.match(s):
+ return True
+ return False
+
class Rules(object):
""" A 'Rules' object is the parsed version of a .may_include file. """
def __init__(self, dirpath):
self.dirpath = dirpath
+ if dirpath.startswith("src/"):
+ self.incpath = dirpath[4:]
+ else:
+ self.incpath = dirpath
self.patterns = []
self.usedPatterns = set()
def addPattern(self, pattern):
+ if not pattern_is_normal(pattern):
+ warn("Unusual pattern {} in {}".format(pattern, self.dirpath))
self.patterns.append(pattern)
def includeOk(self, path):
@@ -86,6 +109,20 @@ class Rules(object):
if p not in self.usedPatterns:
print("Pattern {} in {} was never used.".format(p, self.dirpath))
+ def getAllowedDirectories(self):
+ allowed = []
+ for p in self.patterns:
+ m = re.match(r'^(.*)/\*\.(h|inc)$', p)
+ if m:
+ allowed.append(m.group(1))
+ continue
+ m = re.match(r'^(.*)/[^/]*$', p)
+ if m:
+ allowed.append(m.group(1))
+ continue
+
+ return allowed
+
def load_include_rules(fname):
""" Read a rules file from 'fname', and return it as a Rules object. """
result = Rules(os.path.split(fname)[0])
@@ -98,6 +135,9 @@ def load_include_rules(fname):
return result
list_unused = False
+log_sorted_levels = False
+
+uses_dirs = { }
for dirpath, dirnames, fnames in os.walk("src"):
if ".may_include" in fnames:
@@ -108,8 +148,34 @@ for dirpath, dirnames, fnames in os.walk("src"):
if list_unused:
rules.noteUnusedRules()
+ uses_dirs[rules.incpath] = rules.getAllowedDirectories()
+
if trouble:
err(
"""To change which includes are allowed in a C file, edit the {}
files in its enclosing directory.""".format(RULES_FNAME))
sys.exit(1)
+
+all_levels = []
+
+n = 0
+while uses_dirs:
+ n += 0
+ cur_level = []
+ for k in list(uses_dirs):
+ uses_dirs[k] = [ d for d in uses_dirs[k]
+ if (d in uses_dirs and d != k)]
+ if uses_dirs[k] == []:
+ cur_level.append(k)
+ for k in cur_level:
+ del uses_dirs[k]
+ n += 1
+ if cur_level and log_sorted_levels:
+ print(n, cur_level)
+ if n > 100:
+ break
+
+if uses_dirs:
+ print("There are circular .may_include dependencies in here somewhere:",
+ uses_dirs)
+ sys.exit(1)
diff --git a/scripts/maint/fallback.whitelist b/scripts/maint/fallback.whitelist
index 79551948c6..60d3e7bb85 100644
--- a/scripts/maint/fallback.whitelist
+++ b/scripts/maint/fallback.whitelist
@@ -1,34 +1,23 @@
# updateFallbackDirs.py directory mirror whitelist
#
-# Format:
-# IPv4:DirPort orport=<ORPort> id=<ID> [ ipv6=<IPv6>:<IPv6 ORPort> ]
-# or use:
-# scripts/maint/generateFallbackDirLine.py fingerprint ...
+# At least one of these keys must match for a directory mirror to be included
+# in the fallback list:
+# id
+# ipv4
+# ipv6
+# The ports and nickname are ignored. Missing or extra ipv6 addresses
+# are ignored.
#
-# All attributes must match for the directory mirror to be included.
-# If the fallback has an ipv6 key, the whitelist line must also have
-# it, and vice versa, otherwise they don't match.
-# (The blacklist overrides the whitelist.)
-
-# To replace this list with the hard-coded fallback list (for testing), use
-# a command similar to:
-# cat src/app/config/fallback_dirs.inc | grep \" | grep -v weight | \
-# tr -d '\n' | \
-# sed 's/"" / /g' | sed 's/""/"/g' | tr \" '\n' | grep -v '^$' \
-# > scripts/maint/fallback.whitelist
+# The latest relay details from Onionoo are included in the generated list.
#
-# When testing before a release, exclusions due to changed details will result
-# in a warning, unless the IPv4 address or port change happened recently.
-# Then it is only logged at info level, as part of the eligibility check.
-# Exclusions due to stability also are only shown at info level.
+# To check the hard-coded fallback list (for testing), use:
+# $ updateFallbackDirs.py check_existing
#
-# Add the number of selected, slow, and excluded relays, and compare that to
-# the number of hard-coded relays. If it's less, use info-level logs to find
-# out why each of the missing relays was excluded.
-
# If a relay operator wants their relay to be a FallbackDir,
# enter the following information here:
-# <IPv4>:<DirPort> orport=<ORPort> id=<ID> [ ipv6=<IPv6>:<IPv6 ORPort> ]
+# <IPv4>:<DirPort> orport=<ORPort> id=<ID> ( ipv6=[<IPv6>]:<IPv6 ORPort> )?
+# or use:
+# scripts/maint/generateFallbackDirLine.py fingerprint ...
# https://lists.torproject.org/pipermail/tor-relays/2015-December/008362.html
# https://trac.torproject.org/projects/tor/ticket/22321#comment:22
@@ -57,7 +46,6 @@
# 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
-91.121.84.137:4952 orport=4052 id=9FBEB75E8BC142565F12CBBE078D63310236A334
# https://lists.torproject.org/pipermail/tor-relays/2015-December/008381.html
# Sent additional emails to teor with updated relays
@@ -173,8 +161,6 @@
# Email sent directly to teor, verified using relay contact info
94.242.246.24:23 orport=8080 id=EC116BCB80565A408CE67F8EC3FE3B0B02C3A065 ipv6=[2a01:608:ffff:ff07::1:24]:9004
-176.126.252.11:443 orport=9001 id=B0279A521375F3CB2AE210BDBFC645FDD2E1973A ipv6=[2a02:59e0:0:7::11]:9003
-176.126.252.12:21 orport=8080 id=379FB450010D17078B3766C2273303C358C3A442 ipv6=[2a02:59e0:0:7::12]:81
94.242.246.23:443 orport=9001 id=F65E0196C94DFFF48AFBF2F5F9E3E19AAE583FD0 ipv6=[2a01:608:ffff:ff07::1:23]:9003
85.248.227.164:444 orport=9002 id=B84F248233FEA90CAD439F292556A3139F6E1B82 ipv6=[2a00:1298:8011:212::164]:9004
85.248.227.163:443 orport=9001 id=C793AB88565DDD3C9E4C6F15CCB9D8C7EF964CE9 ipv6=[2a00:1298:8011:212::163]:9003
@@ -297,9 +283,6 @@
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 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
176.31.159.230:80 orport=443 id=631748AFB41104D77ADBB7E5CD4F8E8AE876E683
195.154.79.128:80 orport=443 id=C697612CA5AED06B8D829FCC6065B9287212CB2F
@@ -324,10 +307,14 @@
185.66.250.141:9030 orport=9001 id=B1726B94885CE3AC3910CA8B60622B97B98E2529
# Email sent directly to teor, verified using relay contact info
+# Email sent directly to Phoul
185.104.120.7:9030 orport=443 id=445F1C853966624FB3CF1E12442570DC553CC2EC ipv6=[2a06:3000::120:7]:443
-185.104.120.2:9030 orport=21 id=518FF8708698E1DA09C823C36D35DF89A2CAD956
-185.104.120.4:9030 orport=9001 id=F92B3CB9BBE0CB22409843FB1AE4DBCD5EFAC835
-185.104.120.3:9030 orport=21 id=707C1B61AC72227B34487B56D04BAA3BA1179CE8 ipv6=[2a06:3000::120:3]:21
+185.104.120.2:9030 orport=21 id=518FF8708698E1DA09C823C36D35DF89A2CAD956 ipv6=[2a06:3000::120:2]:443
+185.104.120.4:9030 orport=9001 id=F92B3CB9BBE0CB22409843FB1AE4DBCD5EFAC835 ipv6=[2a06:3000::120:4]:443
+185.104.120.3:9030 orport=21 id=707C1B61AC72227B34487B56D04BAA3BA1179CE8 ipv6=[2a06:3000::120:3]:443
+185.104.120.5:80 orport=443 id=3EBDF84DE3B16F0EBF7D51450F07913A02EFDA6C ipv6=[2a06:3000::120:5]:443
+185.104.120.60:80 orport=443 id=D05C9C7068EB5A45F670D5E38A14907EE6223141 ipv6=[2a06:3000::120:60]:443
+
# Email sent directly to teor, verified using relay contact info
37.187.102.186:9030 orport=9001 id=489D94333DF66D57FFE34D9D59CC2D97E2CB0053 ipv6=[2001:41d0:a:26ba::1]:9001
@@ -379,10 +366,6 @@
91.219.237.229:80 orport=443 id=1ECD73B936CB6E6B3CD647CC204F108D9DF2C9F7
# 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
-
-# Email sent directly to teor, verified using relay contact info
178.62.197.82:80 orport=443 id=0D3EBA17E1C78F1E9900BABDB23861D46FCAF163
# Email sent directly to teor, verified using relay contact info
@@ -406,9 +389,6 @@
# Email sent directly to teor, verified using relay contact info
5.199.142.236:9030 orport=9001 id=F4C0EDAA0BF0F7EC138746F8FEF1CE26C7860265
-# 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
@@ -564,7 +544,6 @@
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
78.24.75.53:9030 orport=9001 id=DEB73705B2929AE9BE87091607388939332EF123
# Email sent directly to teor, verified using relay contact info
@@ -685,6 +664,7 @@
# Email sent directly to teor, verified using relay contact info
# 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
+129.13.131.140:80 orport=443 id=F2DFE5FA1E4CF54F8E761A6D304B9B4EC69BDAE8 ipv6=[2a00:1398:5:f604:cafe:cafe:cafe:9001]:443 # AlleKochenKaffee
# 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
@@ -696,8 +676,8 @@
# Email sent directly to teor, verified using relay contact info
176.10.104.240:80 orport=443 id=0111BA9B604669E636FFD5B503F382A4B7AD6E80
176.10.104.240:8080 orport=8443 id=AD86CD1A49573D52A7B6F4A35750F161AAD89C88
-176.10.104.243:80 orport=443 id=88487BDD980BF6E72092EE690E8C51C0AA4A538C
176.10.104.243:8080 orport=8443 id=95DA61AEF23A6C851028C1AA88AD8593F659E60F
+94.230.208.147:80 orport=443 id=9AA3FF35E7A549D2337E962333D366E102FE4D50 ipv6=[2a02:418:6017::147]:443
# Email sent directly to teor, verified using relay contact info
107.170.101.39:9030 orport=443 id=30973217E70AF00EBE51797FF6D9AA720A902EAA
@@ -738,13 +718,14 @@
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
+198.232.165.2:9030 orport=9001 id=30C19B81981F450C402306E2E7CFB6C3F79CB6B2
# Emails sent directly to teor, verified using relay contact info
51.254.101.242:9002 orport=9001 id=4CC9CC9195EC38645B699A33307058624F660CCF
# Emails sent directly to teor, verified using relay contact info
-85.214.62.48:80 orport=443 id=6A7551EEE18F78A9813096E82BF84F740D32B911
+# Updated IP https://trac.torproject.org/projects/tor/ticket/24805#comment:16
+94.130.186.5:80 orport=443 id=6A7551EEE18F78A9813096E82BF84F740D32B911
# Email sent directly to teor, verified using relay contact info
173.255.245.116:9030 orport=9001 id=91E4015E1F82DAF0121D62267E54A1F661AB6DC7
@@ -756,13 +737,11 @@
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
+5.9.158.75:9030 orport=9001 id=D11D11877769B9E617537B4B46BFB92B443DE33D ipv6=[2a01:4f8:190:514a::2]:9001
# 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
@@ -834,9 +813,9 @@
195.154.122.54:80 orport=443 id=64E99CB34C595A02A3165484BD1215E7389322C6
# Email sent directly to teor, verified using relay contact info
+# Email sent directly to Phoul
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
@@ -943,10 +922,13 @@
199.249.223.66:80 orport=443 id=C5A53BCC174EF8FD0DCB223E4AA929FA557DEDB2 # Quintex17
# https://lists.torproject.org/pipermail/tor-relays/2017-December/013914.html
+# https://lists.torproject.org/pipermail/tor-relays/2018-January/014063.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
+54.37.73.111:9030 orport=9001 id=92412EA1B9AA887D462B51D816777002F4D58907 # Aerodynamik05
+54.37.17.235:9030 orport=9001 id=360CBA08D1E24F513162047BDB54A1015E531534 # Aerodynamik06
# https://lists.torproject.org/pipermail/tor-relays/2017-December/013917.html
104.200.20.46:80 orport=9001 id=78E2BE744A53631B4AAB781468E94C52AB73968B # bynumlawtor
@@ -960,16 +942,10 @@
# 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
@@ -995,3 +971,94 @@
# 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
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-January/014055.html
+37.157.255.35:9030 orport=9090 id=361D33C96D0F161275EE67E2C91EE10B276E778B # cxx4freedom
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-January/014064.html
+87.118.122.120:80 orport=443 id=A2A6616723B511D8E068BB71705191763191F6B2 # otheontelth
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-January/014069.html
+185.100.86.182:9030 orport=8080 id=E51620B90DCB310138ED89EDEDD0A5C361AAE24E # NormalCitizen
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-January/014267.html
+51.15.72.211:80 orport=9001 id=D122094E396DF8BA560843E7B983B0EA649B7DF9 ipv6=[2001:bc8:4700:2300::1b:f09]:9001 # gjtorrelay
+
+# Email sent directly to Phoul
+185.34.33.2:9265 orport=31415 id=D71B1CA1C9DC7E8CA64158E106AD770A21160FEE # lqdn
+
+# Email sent directly to Phoul
+78.156.110.135:9091 orport=9090 id=F48FD1AED068496D51D1384BC7497C04E4985DA6 # SkynetC2
+
+# Email sent directly to Phoul
+5.200.21.144:80 orport=443 id=0C039F35C2E40DCB71CD8A07E97C7FD7787D42D6 # libel
+64.79.152.132:80 orport=443 id=375DCBB2DBD94E5263BC0C015F0C9E756669617E # ebola
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-June/015524.html
+132.248.241.5:9030 orport=9001 id=4661DE96D3F8E923994B05218F23760C8D7935A4
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-June/015522.html
+96.253.78.108:80 orport=442 id=924B24AFA7F075D059E8EEB284CC400B33D3D036
+
+# Email sent directly to Phoul
+163.172.218.10:9030 orport=9001 id=78809B6C50CB6491DB3A72C60EC39DC85BF72D1F ipv6=[2001:bc8:3f23:1100::1]:9001
+163.172.218.10:9130 orport=9101 id=B247BA9E0AEA93E6D7BF4080CFBB964034AF2B28 ipv6=[2001:bc8:3f23:1100::1]:9101
+
+# Email sent directly to Phoul
+158.255.212.178:8080 orport=8443 id=D941D380E5228E7B4D372AF4D484629A96DC48B9 ipv6=[2a03:f80:ed15:158:255:212:178:2]:8443
+
+# Email sent directly to Phoul
+45.79.108.130:9030 orport=9001 id=AEDAC7081AE14B8D241ECF0FF17A2858AB4383D0 ipv6=[2600:3c01:e000:131::8000:0]:9001
+
+# Email sent directly to Phoul
+51.254.147.57:80 orport=443 id=EB80A8D52F07238B576C42CEAB98ADD084EE075E
+217.182.51.248:80 orport=443 id=D6BA940D3255AB40DC5EE5B0B285FA143E1F9865
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-June/015541.html
+195.191.81.7:9030 orport=9001 id=41A3C16269C7B63DB6EB741DBDDB4E1F586B1592 ipv6=[2a00:1908:fffc:ffff:c0a6:ccff:fe62:e1a1]:9001
+51.254.96.208:9030 orport=9001 id=8101421BEFCCF4C271D5483C5AABCAAD245BBB9D ipv6=[2001:41d0:401:3100::30dc]:9001
+163.172.154.162:9030 orport=9001 id=F741E5124CB12700DA946B78C9B2DD175D6CD2A1 ipv6=[2001:bc8:4400:2100::17:419]:9001
+51.15.78.0:9030 orport=9001 id=15BE17C99FACE24470D40AF782D6A9C692AB36D6 ipv6=[2001:bc8:4700:2300::16:c0b]:9001
+54.37.139.118:9030 orport=9001 id=90A5D1355C4B5840E950EB61E673863A6AE3ACA1 ipv6=[2001:41d0:601:1100::1b8]:9001
+51.38.65.160:9030 orport=9001 id=3CB4193EF4E239FCEDC4DC43468E0B0D6B67ACC3 ipv6=[2001:41d0:801:2000::f6e]:9001
+
+# Email sent directly to Phoul
+54.37.138.138:8080 orport=993 id=1576BE143D8727745BB2BCDDF183291B3C3EFEFC
+
+# Email sent directly to Phoul
+67.215.255.140:9030 orport=9001 id=23917BB3F3994BC61F0C9D7AD19B069F9E150D26
+
+# Email sent directly to Phoul
+195.154.105.170:9030 orport=9001 id=E947C029087FA1C3499BEF5D4372947C51223D8F
+
+# Email sent directly to Phoul
+23.129.64.101:80 orport=443 id=2EB20285FE55927B7AECC47BB94F22534FBC3941 ipv6=[2620:18c:0:1001::101]:443
+23.129.64.102:80 orport=443 id=CA9739E2805A3CD73CF75BBCB6785C32394240E3 ipv6=[2620:18c:0:1001::102]:443
+23.129.64.103:80 orport=443 id=8ED84B53BD9556CCBB036073A1AD508EC27CBE52 ipv6=[2620:18c:0:1001::103]:443
+
+# Email sent directly to Phoul
+37.139.8.104:9030 orport=9001 id=7088D485934E8A403B81531F8C90BDC75FA43C98 ipv6=[2a03:b0c0:0:1010::24c:1001]:9001
+
+# Email sent directly to Phoul
+178.254.7.88:9030 orpport=9001 id=85A885433E50B1874F11CEC9BE98451E24660976
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-August/015869.html
+5.45.111.149:80 orport=443 id=D405FCCF06ADEDF898DF2F29C9348DCB623031BA ipv6=[2a03:4000:6:2388:df98:15f9:b34d:443]:443
+
+# https://trac.torproject.org/projects/tor/ticket/27297
+37.252.185.182:9030 orport=8080 id=113143469021882C3A4B82F084F8125B08EE471E ipv6=[2a00:63c1:a:182::2]:8080
+
+# Email sent directly to Phoul
+139.99.130.178:80 orport=443 id=867B95CACD64653FEEC4D2CEFC5C49B4620307A7
+
+# Email sent directly to Phoul
+104.131.11.214:9030 orport=8080 id=32828476F4F84E15C42B4C360A5CD8DE4C3C2BE7
+
+# Email sent directly to Phoul / Teor
+178.175.139.122:80 orport=443 id=490FB3FAAF8837407D94CA7E1DEF025DEF0F3516 ipv6=[2a00:1dc0:3002::3]:443
+
+# Email sent directly to Phoul
+192.42.116.16:80 orport=443 id=81B75D534F91BFB7C57AB67DA10BCEF622582AE8
+
+# https://lists.torproject.org/pipermail/tor-relays/2018-November/016610.html
+24.117.194.80:80 orport=443 id=B6C4C9A43658F686F8892CA5666717532F72979C
diff --git a/scripts/maint/pre-push.git-hook b/scripts/maint/pre-push.git-hook
new file mode 100755
index 0000000000..26296023fb
--- /dev/null
+++ b/scripts/maint/pre-push.git-hook
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# To install this script, copy it into .git/hooks/pre-push path in your
+# local copy of git repository. Make sure it has permission to execute.
+#
+# This is git pre-push hook script to prevent "fixup!" and "squash!" commits
+# from ending up in upstream branches (master, release-* or maint-*).
+#
+# The following sample script was used as starting point:
+# https://github.com/git/git/blob/master/templates/hooks--pre-push.sample
+
+z40=0000000000000000000000000000000000000000
+
+CUR_BRANCH=$(git rev-parse --abbrev-ref HEAD)
+if [ "$CUR_BRANCH" != "master" ] && [[ $CUR_BRANCH != release-* ]] &&
+ [[ $CUR_BRANCH != maint-* ]]
+then
+ exit 0
+fi
+
+echo "Running pre-push hook"
+
+# shellcheck disable=SC2034
+while read -r local_ref local_sha remote_ref remote_sha
+do
+ if [ "$local_sha" = $z40 ]
+ then
+ # Handle delete
+ :
+ else
+ if [ "$remote_sha" = $z40 ]
+ then
+ # New branch, examine all commits
+ range="$local_sha"
+ else
+ # Update to existing branch, examine new commits
+ range="$remote_sha..$local_sha"
+ fi
+
+ # Check for fixup! commit
+ commit=$(git rev-list -n 1 --grep '^fixup!' "$range")
+ if [ -n "$commit" ]
+ then
+ echo >&2 "Found fixup! commit in $local_ref, not pushing"
+ echo >&2 "If you really want to push this, use --no-verify."
+ exit 1
+ fi
+
+ # Check for squash! commit
+ commit=$(git rev-list -n 1 --grep '^squash!' "$range")
+ if [ -n "$commit" ]
+ then
+ echo >&2 "Found squash! commit in $local_ref, not pushing"
+ echo >&2 "If you really want to push this, use --no-verify."
+ exit 1
+ fi
+ fi
+done
+
+exit 0
+
diff --git a/scripts/maint/updateFallbackDirs.py b/scripts/maint/updateFallbackDirs.py
index 0ea3992d8f..14372d0e83 100755
--- a/scripts/maint/updateFallbackDirs.py
+++ b/scripts/maint/updateFallbackDirs.py
@@ -18,8 +18,8 @@
# Optionally uses ipaddress (python 3 builtin) or py2-ipaddress (package)
# for netblock analysis.
#
-# Then read the logs to make sure the fallbacks aren't dominated by a single
-# netblock or port.
+# After running this script, read the logs to make sure the fallbacks aren't
+# dominated by a single netblock or port.
# Script by weasel, April 2015
# Portions by gsathya & karsten, 2013
@@ -39,8 +39,6 @@ import urllib
import urllib2
import hashlib
import dateutil.parser
-# bson_lazy provides bson
-#from bson import json_util
import copy
import re
@@ -100,19 +98,29 @@ MUST_BE_RUNNING_NOW = (PERFORM_IPV4_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.
+# If a relay delivers an invalid consensus, if it will become valid less than
+# this many seconds in the future, or expired less than this many seconds ago,
+# accept the relay as a fallback. 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
+# Relays on 0.3.0 and later return a 404 when they are about to serve a
+# consensus that expired more than 24 hours ago. 0.2.9 and earlier relays
+# will serve consensuses that are very old.
+#
+# Relays on 0.3.5.6-rc? and later return a 404 when they are about to serve a
+# consensus that will become valid more than 24 hours in the future. Older
+# relays don't serve future consensuses.
+#
+# A 404 makes relays fail the download check. We use a tolerance of 24 hours,
+# so that 0.2.9 relays also fail the download check if they serve a consensus
+# that is not reasonably live.
+#
+# REASONABLY_LIVE_TIME should never be more than Tor's REASONABLY_LIVE_TIME,
+# (24 hours), because clients reject consensuses that are older than that.
+# Clients on 0.3.5.5-alpha? and earlier also won't select guards from
+# consensuses that have expired, but can bootstrap if they already have guards
+# in their state file.
+REASONABLY_LIVE_TIME = 24*60*60
# Output fallback name, flags, bandwidth, and ContactInfo in a C comment?
OUTPUT_COMMENTS = True if OUTPUT_CANDIDATES else False
@@ -912,61 +920,181 @@ class Candidate(object):
return False
return True
- def is_in_whitelist(self, relaylist):
- """ A fallback matches if each key in the whitelist line matches:
+ def id_matches(self, id, exact=False):
+ """ Does this fallback's id match id?
+ exact is ignored. """
+ return self._fpr == id
+
+ def ipv4_addr_matches(self, ipv4_addr, exact=False):
+ """ Does this fallback's IPv4 address match ipv4_addr?
+ exact is ignored. """
+ return self.dirip == ipv4_addr
+
+ def ipv4_dirport_matches(self, ipv4_dirport, exact=False):
+ """ Does this fallback's IPv4 dirport match ipv4_dirport?
+ If exact is False, always return True. """
+ if exact:
+ return self.dirport == int(ipv4_dirport)
+ else:
+ return True
+
+ def ipv4_and_dirport_matches(self, ipv4_addr, ipv4_dirport, exact=False):
+ """ Does this fallback's IPv4 address match ipv4_addr?
+ If exact is True, also check ipv4_dirport. """
+ ipv4_match = self.ipv4_addr_matches(ipv4_addr, exact=exact)
+ if exact:
+ return ipv4_match and self.ipv4_dirport_matches(ipv4_dirport,
+ exact=exact)
+ else:
+ return ipv4_match
+
+ def ipv4_orport_matches(self, ipv4_orport, exact=False):
+ """ Does this fallback's IPv4 orport match ipv4_orport?
+ If exact is False, always return True. """
+ if exact:
+ return self.orport == int(ipv4_orport)
+ else:
+ return True
+
+ def ipv4_and_orport_matches(self, ipv4_addr, ipv4_orport, exact=False):
+ """ Does this fallback's IPv4 address match ipv4_addr?
+ If exact is True, also check ipv4_orport. """
+ ipv4_match = self.ipv4_addr_matches(ipv4_addr, exact=exact)
+ if exact:
+ return ipv4_match and self.ipv4_orport_matches(ipv4_orport,
+ exact=exact)
+ else:
+ return ipv4_match
+
+ def ipv6_addr_matches(self, ipv6_addr, exact=False):
+ """ Does this fallback's IPv6 address match ipv6_addr?
+ Both addresses must be present to match.
+ exact is ignored. """
+ if self.has_ipv6() and ipv6_addr is not None:
+ # Check that we have a bracketed IPv6 address without a port
+ assert(ipv6_addr.startswith('[') and ipv6_addr.endswith(']'))
+ return self.ipv6addr == ipv6_addr
+ else:
+ return False
+
+ def ipv6_orport_matches(self, ipv6_orport, exact=False):
+ """ Does this fallback's IPv6 orport match ipv6_orport?
+ Both ports must be present to match.
+ If exact is False, always return True. """
+ if exact:
+ return (self.has_ipv6() and ipv6_orport is not None and
+ self.ipv6orport == int(ipv6_orport))
+ else:
+ return True
+
+ def ipv6_and_orport_matches(self, ipv6_addr, ipv6_orport, exact=False):
+ """ Does this fallback's IPv6 address match ipv6_addr?
+ If exact is True, also check ipv6_orport. """
+ ipv6_match = self.ipv6_addr_matches(ipv6_addr, exact=exact)
+ if exact:
+ return ipv6_match and self.ipv6_orport_matches(ipv6_orport,
+ exact=exact)
+ else:
+ return ipv6_match
+
+ def entry_matches_exact(self, entry):
+ """ Is entry an exact match for this fallback?
+ A fallback is an exact match for entry if each key in entry matches:
ipv4
dirport
orport
id
- ipv6 address and port (if present)
+ ipv6 address and port (if present in the fallback or the whitelist)
If the fallback has an ipv6 key, the whitelist line must also have
- it, and vice versa, otherwise they don't match. """
- ipv6 = None
- if self.has_ipv6():
- ipv6 = '%s:%d'%(self.ipv6addr, self.ipv6orport)
- for entry in relaylist:
- if entry['id'] != self._fpr:
- # can't log here unless we match an IP and port, because every relay's
- # fingerprint is compared to every entry's fingerprint
- if entry['ipv4'] == self.dirip and int(entry['orport']) == self.orport:
- logging.warning('%s excluded: has OR %s:%d changed fingerprint to ' +
- '%s?', entry['id'], self.dirip, self.orport,
- self._fpr)
- if self.has_ipv6() and entry.has_key('ipv6') and entry['ipv6'] == ipv6:
- logging.warning('%s excluded: has OR %s changed fingerprint to ' +
- '%s?', entry['id'], ipv6, self._fpr)
- continue
- if entry['ipv4'] != self.dirip:
- logging.warning('%s excluded: has it changed IPv4 from %s to %s?',
- self._fpr, entry['ipv4'], self.dirip)
- continue
- if int(entry['dirport']) != self.dirport:
- logging.warning('%s excluded: has it changed DirPort from %s:%d to ' +
- '%s:%d?', self._fpr, self.dirip, int(entry['dirport']),
- self.dirip, self.dirport)
- continue
- if int(entry['orport']) != self.orport:
- logging.warning('%s excluded: has it changed ORPort from %s:%d to ' +
- '%s:%d?', self._fpr, self.dirip, int(entry['orport']),
- self.dirip, self.orport)
- continue
- if entry.has_key('ipv6') and self.has_ipv6():
- # if both entry and fallback have an ipv6 address, compare them
- if entry['ipv6'] != ipv6:
- logging.warning('%s excluded: has it changed IPv6 ORPort from %s ' +
- 'to %s?', self._fpr, entry['ipv6'], ipv6)
- continue
- # if the fallback has an IPv6 address but the whitelist entry
- # doesn't, or vice versa, the whitelist entry doesn't match
- elif entry.has_key('ipv6') and not self.has_ipv6():
- logging.warning('%s excluded: has it lost its former IPv6 address %s?',
- self._fpr, entry['ipv6'])
- continue
- elif not entry.has_key('ipv6') and self.has_ipv6():
- logging.warning('%s excluded: has it gained an IPv6 address %s?',
- self._fpr, ipv6)
- continue
+ it, otherwise they don't match.
+
+ Logs a warning-level message if the fallback would be an exact match,
+ but one of the id, ipv4, ipv4 orport, ipv4 dirport, or ipv6 orport
+ have changed. """
+ if not self.id_matches(entry['id'], exact=True):
+ # can't log here unless we match an IP and port, because every relay's
+ # fingerprint is compared to every entry's fingerprint
+ if self.ipv4_and_orport_matches(entry['ipv4'],
+ entry['orport'],
+ exact=True):
+ logging.warning('%s excluded: has OR %s:%d changed fingerprint to ' +
+ '%s?', entry['id'], self.dirip, self.orport,
+ self._fpr)
+ if self.ipv6_and_orport_matches(entry.get('ipv6_addr'),
+ entry.get('ipv6_orport'),
+ exact=True):
+ logging.warning('%s excluded: has OR %s changed fingerprint to ' +
+ '%s?', entry['id'], entry['ipv6'], self._fpr)
+ return False
+ if not self.ipv4_addr_matches(entry['ipv4'], exact=True):
+ logging.warning('%s excluded: has it changed IPv4 from %s to %s?',
+ self._fpr, entry['ipv4'], self.dirip)
+ return False
+ if not self.ipv4_dirport_matches(entry['dirport'], exact=True):
+ logging.warning('%s excluded: has it changed DirPort from %s:%d to ' +
+ '%s:%d?', self._fpr, self.dirip, int(entry['dirport']),
+ self.dirip, self.dirport)
+ return False
+ if not self.ipv4_orport_matches(entry['orport'], exact=True):
+ logging.warning('%s excluded: has it changed ORPort from %s:%d to ' +
+ '%s:%d?', self._fpr, self.dirip, int(entry['orport']),
+ self.dirip, self.orport)
+ return False
+ if entry.has_key('ipv6') and self.has_ipv6():
+ # if both entry and fallback have an ipv6 address, compare them
+ if not self.ipv6_and_orport_matches(entry['ipv6_addr'],
+ entry['ipv6_orport'],
+ exact=True):
+ logging.warning('%s excluded: has it changed IPv6 ORPort from %s ' +
+ 'to %s:%d?', self._fpr, entry['ipv6'],
+ self.ipv6addr, self.ipv6orport)
+ return False
+ # if the fallback has an IPv6 address but the whitelist entry
+ # doesn't, or vice versa, the whitelist entry doesn't match
+ elif entry.has_key('ipv6') and not self.has_ipv6():
+ logging.warning('%s excluded: has it lost its former IPv6 address %s?',
+ self._fpr, entry['ipv6'])
+ return False
+ elif not entry.has_key('ipv6') and self.has_ipv6():
+ logging.warning('%s excluded: has it gained an IPv6 address %s:%d?',
+ self._fpr, self.ipv6addr, self.ipv6orport)
+ return False
+ return True
+
+ def entry_matches_fuzzy(self, entry):
+ """ Is entry a fuzzy match for this fallback?
+ A fallback is a fuzzy match for entry if at least one of these keys
+ in entry matches:
+ id
+ ipv4
+ ipv6 (if present in both the fallback and whitelist)
+ The ports and nickname are ignored. Missing or extra ipv6 addresses
+ are ignored.
+
+ Doesn't log any warning messages. """
+ if self.id_matches(entry['id'], exact=False):
return True
+ if self.ipv4_addr_matches(entry['ipv4'], exact=False):
+ return True
+ if entry.has_key('ipv6') and self.has_ipv6():
+ # if both entry and fallback have an ipv6 address, compare them
+ if self.ipv6_addr_matches(entry['ipv6_addr'], exact=False):
+ return True
+ return False
+
+ def is_in_whitelist(self, relaylist, exact=False):
+ """ If exact is True (existing fallback list), check if this fallback is
+ an exact match for any whitelist entry, using entry_matches_exact().
+
+ If exact is False (new fallback whitelist), check if this fallback is
+ a fuzzy match for any whitelist entry, using entry_matches_fuzzy(). """
+ for entry in relaylist:
+ if exact:
+ if self.entry_matches_exact(entry):
+ return True
+ else:
+ if self.entry_matches_fuzzy(entry):
+ return True
return False
def cw_to_bw_factor(self):
@@ -1124,6 +1252,7 @@ class Candidate(object):
).run()[0]
end = datetime.datetime.utcnow()
time_since_expiry = (end - consensus.valid_until).total_seconds()
+ time_until_valid = (consensus.valid_after - end).total_seconds()
except Exception, stem_error:
end = datetime.datetime.utcnow()
log_excluded('Unable to retrieve a consensus from %s: %s', nickname,
@@ -1141,8 +1270,17 @@ class Candidate(object):
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)
+ if time_since_expiry <= REASONABLY_LIVE_TIME:
+ status += ', tolerating up to %ds'%(REASONABLY_LIVE_TIME)
+ level = logging.INFO
+ else:
+ status += ', invalid'
+ level = logging.WARNING
+ download_failed = True
+ elif (time_until_valid > 0):
+ status = 'future consensus, valid in %ds'%(int(time_until_valid))
+ if time_until_valid <= REASONABLY_LIVE_TIME:
+ status += ', tolerating up to %ds'%(REASONABLY_LIVE_TIME)
level = logging.INFO
else:
status += ', invalid'
@@ -1400,7 +1538,7 @@ class CandidateList(dict):
each line's key/value pairs are placed in a dictonary,
(of string -> string key/value pairs),
and these dictionaries are placed in an array.
- comments start with # and are ignored """
+ comments start with # and are ignored. """
file_data = file_obj['data']
file_name = file_obj['name']
relaylist = []
@@ -1440,18 +1578,28 @@ class CandidateList(dict):
relay_entry['dirport'] = ipv4_maybe_dirport_split[1]
elif kvl == 2:
relay_entry[key_value_split[0]] = key_value_split[1]
+ # split ipv6 addresses and orports
+ if key_value_split[0] == 'ipv6':
+ ipv6_orport_split = key_value_split[1].rsplit(':', 1)
+ ipv6l = len(ipv6_orport_split)
+ if ipv6l != 2:
+ print '#error Bad %s IPv6 item: %s, format is [ipv6]:orport.'%(
+ file_name, item)
+ relay_entry['ipv6_addr'] = ipv6_orport_split[0]
+ relay_entry['ipv6_orport'] = ipv6_orport_split[1]
relaylist.append(relay_entry)
return relaylist
- # apply the fallback whitelist
- def apply_filter_lists(self, whitelist_obj):
+ def apply_filter_lists(self, whitelist_obj, exact=False):
+ """ Apply the fallback whitelist_obj to this fallback list,
+ passing exact to is_in_whitelist(). """
excluded_count = 0
logging.debug('Applying whitelist')
# parse the whitelist
whitelist = self.load_relaylist(whitelist_obj)
filtered_fallbacks = []
for f in self.fallbacks:
- in_whitelist = f.is_in_whitelist(whitelist)
+ in_whitelist = f.is_in_whitelist(whitelist, exact=exact)
if in_whitelist:
# include
filtered_fallbacks.append(f)
@@ -2064,14 +2212,14 @@ def process_existing():
logging.getLogger('stem').setLevel(logging.INFO)
whitelist = {'data': parse_fallback_file(FALLBACK_FILE_NAME),
'name': FALLBACK_FILE_NAME}
- list_fallbacks(whitelist)
+ list_fallbacks(whitelist, exact=True)
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}
- list_fallbacks(whitelist)
+ list_fallbacks(whitelist, exact=False)
## Main Function
def main():
@@ -2092,10 +2240,10 @@ def log_excluded(msg, *args):
else:
logging.info(msg, *args)
-def list_fallbacks(whitelist):
+def list_fallbacks(whitelist, exact=False):
""" Fetches required onionoo documents and evaluates the
- fallback directory criteria for each of the relays """
-
+ fallback directory criteria for each of the relays,
+ passing exact to apply_filter_lists(). """
print "/* type=fallback */"
print ("/* version={} */"
.format(cleanse_c_multiline_comment(FALLBACK_FORMAT_VERSION)))
@@ -2135,7 +2283,7 @@ def list_fallbacks(whitelist):
# 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(whitelist)
+ excluded_count = candidates.apply_filter_lists(whitelist, exact=exact)
print candidates.summarise_filters(initial_count, excluded_count)
eligible_count = len(candidates.fallbacks)
diff --git a/scripts/maint/updateRustDependencies.sh b/scripts/maint/updateRustDependencies.sh
index a5a92579d3..6d0587351f 100755
--- a/scripts/maint/updateRustDependencies.sh
+++ b/scripts/maint/updateRustDependencies.sh
@@ -20,26 +20,26 @@
set -e
-HERE=`dirname $(realpath $0)`
-TOPLEVEL=`dirname $(dirname $HERE)`
+HERE=$(dirname "$(realpath "$0")")
+TOPLEVEL=$(dirname "$(dirname "$HERE")")
TOML="$TOPLEVEL/src/rust/Cargo.toml"
VENDORED="$TOPLEVEL/src/ext/rust/crates"
-CARGO=`which cargo`
+CARGO=$(command -v cargo)
if ! test -f "$TOML" ; then
- printf "Error: Couldn't find workspace Cargo.toml in expected location: %s\n" "$TOML"
+ 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"
+ 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"
+ 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"
+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
+$CARGO vendor -v --locked --explicit-version --no-delete --sync "$TOML" "$VENDORED"
diff --git a/scripts/maint/updateVersions.pl.in b/scripts/maint/updateVersions.pl.in
deleted file mode 100755
index 65c51a1f2d..0000000000
--- a/scripts/maint/updateVersions.pl.in
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/perl -w
-
-$CONFIGURE_IN = '@abs_top_srcdir@/configure.ac';
-$ORCONFIG_H = '@abs_top_srcdir@/src/win32/orconfig.h';
-$TOR_NSI = '@abs_top_srcdir@/contrib/win32build/tor-mingw.nsi.in';
-
-$quiet = 1;
-
-sub demand {
- my $fn = shift;
- die "Missing file $fn" unless (-f $fn);
-}
-
-demand($CONFIGURE_IN);
-demand($ORCONFIG_H);
-demand($TOR_NSI);
-
-# extract version from configure.ac
-
-open(F, $CONFIGURE_IN) or die "$!";
-$version = undef;
-while (<F>) {
- if (/AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)/) {
- $version = $1;
- last;
- }
-}
-die "No version found" unless $version;
-print "Tor version is $version\n" unless $quiet;
-close F;
-
-sub correctversion {
- my ($fn, $defchar) = @_;
- undef $/;
- open(F, $fn) or die "$!";
- my $s = <F>;
- close F;
- if ($s =~ /^$defchar(?:)define\s+VERSION\s+\"([^\"]+)\"/m) {
- $oldver = $1;
- if ($oldver ne $version) {
- print "Version mismatch in $fn: It thinks that the version is $oldver. I think it's $version. Fixing.\n";
- $line = $defchar . "define VERSION \"$version\"";
- open(F, ">$fn.bak");
- print F $s;
- close F;
- $s =~ s/^$defchar(?:)define\s+VERSION.*?$/$line/m;
- open(F, ">$fn");
- print F $s;
- close F;
- } else {
- print "$fn has the correct version. Good.\n" unless $quiet;
- }
- } else {
- print "Didn't find a version line in $fn -- uh oh.\n";
- }
-}
-
-correctversion($TOR_NSI, "!");
-correctversion($ORCONFIG_H, "#");
diff --git a/scripts/maint/update_versions.py b/scripts/maint/update_versions.py
new file mode 100755
index 0000000000..8067f2c6c8
--- /dev/null
+++ b/scripts/maint/update_versions.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import io
+import os
+import re
+import sys
+import time
+
+def P(path):
+ """
+ Give 'path' as a path relative to the abs_top_srcdir environment
+ variable.
+ """
+ return os.path.join(
+ os.environ.get('abs_top_srcdir', "."),
+ path)
+
+def warn(msg):
+ """
+ Print an warning message.
+ """
+ print("WARNING: {}".format(msg), file=sys.stderr)
+
+def find_version(infile):
+ """
+ Given an open file (or some other iterator of lines) holding a
+ configure.ac file, find the current version line.
+ """
+ for line in infile:
+ m = re.search(r'AC_INIT\(\[tor\],\s*\[([^\]]*)\]\)', line)
+ if m:
+ return m.group(1)
+
+ return None
+
+def update_version_in(infile, outfile, regex, versionline):
+ """
+ Copy every line from infile to outfile. If any line matches 'regex',
+ replace it with 'versionline'. Return True if any line was changed;
+ false otherwise.
+
+ 'versionline' is either a string -- in which case it is used literally,
+ or a function that receives the output of 'regex.match'.
+ """
+ found = False
+ have_changed = False
+ for line in infile:
+ m = regex.match(line)
+ if m:
+ found = True
+ oldline = line
+ if type(versionline) == type(u""):
+ line = versionline
+ else:
+ line = versionline(m)
+ if not line.endswith("\n"):
+ line += "\n"
+ if oldline != line:
+ have_changed = True
+ outfile.write(line)
+
+ if not found:
+ warn("didn't find any version line to replace in {}".format(infile.name))
+
+ return have_changed
+
+def replace_on_change(fname, change):
+ """
+ If "change" is true, replace fname with fname.tmp. Otherwise,
+ delete fname.tmp. Log what we're doing to stderr.
+ """
+ if not change:
+ print("No change in {}".format(fname))
+ os.unlink(fname+".tmp")
+ else:
+ print("Updating {}".format(fname))
+ os.rename(fname+".tmp", fname)
+
+
+def update_file(fname,
+ regex,
+ versionline,
+ encoding="utf-8"):
+ """
+ Replace any line matching 'regex' in 'fname' with 'versionline'.
+ Do not modify 'fname' if there are no changes made. Use the
+ provided encoding to read and write.
+ """
+ with io.open(fname, "r", encoding=encoding) as f, \
+ io.open(fname+".tmp", "w", encoding=encoding) as outf:
+ have_changed = update_version_in(f, outf, regex, versionline)
+
+ replace_on_change(fname, have_changed)
+
+# Find out our version
+with open("configure.ac") as f:
+ version = find_version(f)
+
+# If we have no version, we can't proceed.
+if version == None:
+ print("No version found in configure.ac", file=sys.stderr())
+ sys.exit(1)
+
+print("The version is {}".format(version))
+
+today = time.strftime("%Y-%m-%d", time.gmtime())
+
+# In configure.ac, we replace the definition of APPROX_RELEASE_DATE
+# with "{today} for {version}", but only if the version does not match
+# what is already there.
+def replace_fn(m):
+ if m.group(1) != version:
+ # The version changed -- we change the date.
+ return u'AC_DEFINE(APPROX_RELEASE_DATE, ["{}"], # for {}'.format(today, version)
+ else:
+ # No changes.
+ return m.group(0)
+update_file(P("configure.ac"),
+ re.compile(r'AC_DEFINE\(APPROX_RELEASE_DATE.* for (.*)'),
+ replace_fn)
+
+# In tor-mingw.nsi.in, we replace the definition of VERSION.
+update_file(P("contrib/win32build/tor-mingw.nsi.in"),
+ re.compile(r'!define VERSION .*'),
+ u'!define VERSION "{}"'.format(version),
+ encoding="iso-8859-1")
+
+# In src/win32/orconfig.h, we replace the definition of VERSION.
+update_file(P("src/win32/orconfig.h"),
+ re.compile(r'#define VERSION .*'),
+ u'#define VERSION "{}"'.format(version))
diff --git a/scripts/test/scan-build.sh b/scripts/test/scan-build.sh
index 8d126cbcee..26e05ff101 100755
--- a/scripts/test/scan-build.sh
+++ b/scripts/test/scan-build.sh
@@ -33,6 +33,7 @@ CHECKERS="\
-enable-checker security.insecureAPI.strcpy \
"
+# shellcheck disable=SC2034
# These have high false-positive rates.
EXTRA_CHECKERS="\
-enable-checker alpha.security.ArrayBoundV2 \
@@ -40,6 +41,7 @@ EXTRA_CHECKERS="\
-enable-checker alpha.core.CastSize \
"
+# shellcheck disable=SC2034
# These don't seem to generate anything useful
NOISY_CHECKERS="\
-enable-checker alpha.clone.CloneChecker \
@@ -52,6 +54,7 @@ else
OUTPUTARG=""
fi
+# shellcheck disable=SC2086
scan-build \
$CHECKERS \
./configure
@@ -61,11 +64,13 @@ scan-build \
# Make this not get scanned for dead assignments, since it has lots of
# dead assignments we don't care about.
+# shellcheck disable=SC2086
scan-build \
$CHECKERS \
-disable-checker deadcode.DeadStores \
make -j5 -k ./src/ext/ed25519/ref10/libed25519_ref10.a
+# shellcheck disable=SC2086
scan-build \
$CHECKERS $OUTPUTARG \
make -j5 -k