aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/config/auth_dirs.inc2
-rw-r--r--src/app/config/fallback_dirs.inc567
-rw-r--r--src/app/main/main.c5
-rw-r--r--src/config/torrc.minimal.in-staging3
-rw-r--r--src/config/torrc.sample.in3
-rw-r--r--src/core/include.am2
-rw-r--r--src/core/or/channeltls.c20
-rw-r--r--src/core/or/circuitpadding.c222
-rw-r--r--src/core/or/circuitpadding.h25
-rw-r--r--src/core/or/circuitpadding_machines.c4
-rw-r--r--src/core/or/connection_edge.c1
-rw-r--r--src/core/or/or.h4
-rw-r--r--src/core/or/or_circuit_st.h7
-rw-r--r--src/core/or/protover.c2
-rw-r--r--src/core/or/protover.h2
-rw-r--r--src/core/or/relay.c242
-rw-r--r--src/core/or/relay.h5
-rw-r--r--src/core/or/versions.c5
-rw-r--r--src/ext/csiphash.c8
-rw-r--r--src/feature/client/entrynodes.c4
-rw-r--r--src/feature/control/control_auth.c8
-rw-r--r--src/feature/control/control_cmd.c86
-rw-r--r--src/feature/control/control_cmd.h5
-rw-r--r--src/feature/control/control_events.c2
-rw-r--r--src/feature/control/control_events.h3
-rw-r--r--src/feature/control/control_proto.c5
-rw-r--r--src/feature/control/control_proto.h4
-rw-r--r--src/feature/dirauth/keypin.c2
-rw-r--r--src/feature/dircache/dircache.c13
-rw-r--r--src/feature/dircommon/directory.c69
-rw-r--r--src/feature/dircommon/directory.h1
-rw-r--r--src/feature/hs/hs_cache.c5
-rw-r--r--src/feature/hs/hs_circuitmap.c27
-rw-r--r--src/feature/hs/hs_circuitmap.h2
-rw-r--r--src/feature/hs/hs_common.c2
-rw-r--r--src/feature/hs/hs_dos.c188
-rw-r--r--src/feature/hs/hs_dos.h37
-rw-r--r--src/feature/hs/hs_intropoint.c29
-rw-r--r--src/feature/nodelist/networkstatus.c2
-rw-r--r--src/feature/nodelist/routerlist.c18
-rw-r--r--src/feature/relay/router.c22
-rw-r--r--src/feature/rend/rendmid.c11
-rw-r--r--src/lib/confmgt/var_type_def_st.h2
-rw-r--r--src/lib/defs/include.am1
-rw-r--r--src/lib/defs/logging_types.h23
-rw-r--r--src/lib/encoding/confline.c13
-rw-r--r--src/lib/encoding/confline.h1
-rw-r--r--src/lib/err/.may_include3
-rw-r--r--src/lib/err/backtrace.c4
-rw-r--r--src/lib/err/backtrace.h7
-rw-r--r--src/lib/log/.may_include1
-rw-r--r--src/lib/log/log.c6
-rw-r--r--src/lib/log/log.h83
-rw-r--r--src/lib/net/address.c110
-rw-r--r--src/lib/net/resolve.c339
-rw-r--r--src/lib/string/printf.c8
-rw-r--r--src/lib/time/compat_time.c2
-rw-r--r--src/rust/protover/protover.rs4
-rw-r--r--src/rust/tor_log/tor_log.rs8
-rw-r--r--src/test/include.am7
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_addr.c675
-rw-r--r--src/test/test_btrack.c4
-rw-r--r--src/test/test_circuitbuild.c47
-rw-r--r--src/test/test_circuitpadding.c30
-rw-r--r--src/test/test_controller.c106
-rw-r--r--src/test/test_controller_events.c3
-rw-r--r--src/test/test_hs_cache.c23
-rw-r--r--src/test/test_hs_client.c89
-rw-r--r--src/test/test_hs_common.c1
-rw-r--r--src/test/test_hs_dos.c134
-rw-r--r--src/test/test_hs_intropoint.c61
-rw-r--r--src/test/test_hs_service.c1
-rw-r--r--src/test/test_introduce.c3
-rw-r--r--src/test/test_logging.c2
-rw-r--r--src/test/test_options.c4
-rwxr-xr-xsrc/test/test_rebind.sh2
-rw-r--r--src/test/test_routerlist.c2
-rw-r--r--src/test/test_status.c24
-rw-r--r--src/test/test_token_bucket.c2
-rw-r--r--src/test/test_util.c2
-rw-r--r--src/test/testing_common.c2
-rw-r--r--src/tools/tor-print-ed-signing-cert.c7
84 files changed, 2510 insertions, 1012 deletions
diff --git a/src/app/config/auth_dirs.inc b/src/app/config/auth_dirs.inc
index 08a919b053..278f08bfcf 100644
--- a/src/app/config/auth_dirs.inc
+++ b/src/app/config/auth_dirs.inc
@@ -7,7 +7,7 @@
"86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
"dizum orport=443 "
"v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
- "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
+ "45.66.33.45:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
"Serge orport=9001 bridge "
"66.111.2.131:9030 BA44 A889 E64B 93FA A2B1 14E0 2C2A 279A 8555 C533",
"gabelmoo orport=443 "
diff --git a/src/app/config/fallback_dirs.inc b/src/app/config/fallback_dirs.inc
index 9f60f309f8..793f65ce88 100644
--- a/src/app/config/fallback_dirs.inc
+++ b/src/app/config/fallback_dirs.inc
@@ -1,55 +1,62 @@
/* type=fallback */
/* version=2.0.0 */
-/* timestamp=20181207055710 */
-/* timestamp0=20181207055710 */
-/* timestamp1=20181207193756 */
-/* timestamp2=20181207195255 */
-/* ===== */
-/* 0: Whitelist excluded 1275 of 1462 candidates. */
-/* 1: Whitelist excluded 1279 of 1470 candidates. */
-/* 2: Whitelist excluded 1278 of 1469 candidates. */
+/* timestamp=20190625114911 */
+/* timestamp0=20190625114911 */
+/* timestamp1=20190628085927 */
+/* source=whitelist */
+/* ===== */
+/* 0: Whitelist excluded 1550 of 1711 candidates. */
+/* 1: Whitelist excluded 1601 of 1765 candidates. */
/* Checked IPv4 DirPorts served a consensus within 15.0s. */
/*
0:
-Final Count: 148 (Eligible 187, Target 351 (1757 * 0.20), Max 200)
-Excluded: 39 (Same Operator 28, Failed/Skipped Download 7, Excess 4)
-Bandwidth Range: 0.8 - 43.8 MByte/s
+Final Count: 140 (Eligible 161, Target 414 (2072 * 0.20), Max 200)
+Excluded: 21 (Same Operator 16, Failed/Skipped Download 3, Excess 2)
+Bandwidth Range: 0.5 - 54.5 MByte/s
MERGED WITH:
1:
-Final Count: 138 (Eligible 191, Target 353 (1768 * 0.20), Max 200)
-Excluded: 53 (Same Operator 29, Failed/Skipped Download 20, Excess 4)
-Bandwidth Range: 1.0 - 46.9 MByte/s
-
-MERGED WITH:
-
-2:
-Final Count: 145 (Eligible 191, Target 353 (1768 * 0.20), Max 200)
-Excluded: 46 (Same Operator 29, Failed/Skipped Download 13, Excess 4)
-Bandwidth Range: 1.0 - 46.9 MByte/s
+Final Count: 140 (Eligible 164, Target 414 (2073 * 0.20), Max 200)
+Excluded: 24 (Same Operator 16, Failed/Skipped Download 4, Excess 4)
+Bandwidth Range: 0.8 - 54.5 MByte/s
*/
/*
-0: Onionoo Source: details Date: 2018-12-07 05:00:00 Version: 7.0
-1: Onionoo Source: details Date: 2018-12-07 18:00:00 Version: 7.0
-2: Onionoo Source: details Date: 2018-12-07 18:00:00 Version: 7.0
+):
+Onionoo Source: details Date: 2019-06-25 10:00:00 Version: 7.0
URL: https:onionoo.torproject.orgdetails?fieldsfingerprint%2Cnickname%2Ccontact%2Clast_changed_address_or_port%2Cconsensus_weight%2Cadvertised_bandwidth%2Cor_addresses%2Cdir_address%2Crecommended_version%2Cflags%2Ceffective_family%2Cplatform&flagV2Dir&typerelay&last_seen_days-0&first_seen_days90-
+
+MERGED WITH:
+
+1:
+Onionoo Source: details Date: 2019-06-28 07:00:00 Version: 7.0
+URL: https:onionoo.torproject.orgdetails?fieldsfingerprint%2Cnickname%2Ccontact%2Clast_changed_address_or_port%2Cconsensus_weight%2Cadvertised_bandwidth%2Cor_addresses%2Cdir_address%2Crecommended_version%2Cflags%2Ceffective_family%2Cplatform&last_seen_days-0&flagV2Dir&first_seen_days90-&typerelay&order-consensus_weight%2Cfirst_seen
*/
/*
-0: Onionoo Source: uptime Date: 2018-12-07 05:00:00 Version: 7.0
-1: Onionoo Source: uptime Date: 2018-12-07 18:00:00 Version: 7.0
-2: Onionoo Source: uptime Date: 2018-12-07 18:00:00 Version: 7.0
+0:
+Onionoo Source: uptime Date: 2019-06-25 10:00:00 Version: 7.0
URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&last_seen_days-0
+
+MERGED WITH:
+
+1:
+Onionoo Source: uptime Date: 2019-06-28 07:00:00 Version: 7.0
+URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&order-consensus_weight%2Cfirst_seen&last_seen_days-0
*/
/* ===== */
-"176.10.104.240:80 orport=443 id=0111BA9B604669E636FFD5B503F382A4B7AD6E80"
-/* nickname=DigiGesTor1e1 */
+"185.13.39.197:80 orport=443 id=001524DD403D729F08F7E5D77813EF12756CFA8D"
+/* nickname=Neldoreth */
/* extrainfo=0 */
/* ===== */
,
-"193.171.202.146:9030 orport=9001 id=01A9258A46E97FF8B2CAC7910577862C14F2C524"
-" ipv6=[2001:628:200a:f001:20::146]:9001"
-/* nickname=ins0 */
+"185.100.85.61:80 orport=443 id=025B66CEBC070FCB0519D206CF0CF4965C20C96E"
+/* nickname=nibbana */
+/* extrainfo=0 */
+/* ===== */
+,
+"185.225.17.3:80 orport=443 id=0338F9F55111FE8E3570E7DE117EF3AF999CC1D7"
+" ipv6=[2a0a:c800:1:5::3]:443"
+/* nickname=Nebuchadnezzar */
/* extrainfo=0 */
/* ===== */
,
@@ -63,17 +70,6 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"5.196.88.122:9030 orport=9001 id=0C2C599AFCB26F5CFC2C7592435924C1D63D9484"
-" ipv6=[2001:41d0:a:fb7a::1]:9001"
-/* nickname=ATo */
-/* extrainfo=0 */
-/* ===== */
-,
-"185.100.86.100:80 orport=443 id=0E8C0C8315B66DB5F703804B3889A1DD66C67CE0"
-/* nickname=saveyourprivacyex1 */
-/* extrainfo=0 */
-/* ===== */
-,
"37.252.185.182:9030 orport=8080 id=113143469021882C3A4B82F084F8125B08EE471E"
" ipv6=[2a00:63c1:a:182::2]:8080"
/* nickname=parasol */
@@ -86,42 +82,30 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"193.11.114.43:9030 orport=9001 id=12AD30E5D25AA67F519780E2111E611A455FDC89"
-" ipv6=[2001:6b0:30:1000::99]:9050"
-/* nickname=mdfnet1 */
+"95.85.8.226:80 orport=443 id=1211AC1BBB8A1AF7CBA86BCE8689AA3146B86423"
+/* nickname=ccrelaycc */
/* extrainfo=0 */
/* ===== */
,
-"193.234.15.59:80 orport=443 id=136F9299A5009A4E0E96494E723BDB556FB0A26B"
-" ipv6=[2a00:1c20:4089:1234:bff6:e1bb:1ce3:8dc6]:443"
-/* nickname=bakunin2 */
-/* extrainfo=0 */
-/* ===== */
-,
-"144.76.14.145:110 orport=143 id=14419131033443AE6E21DA82B0D307F7CAE42BDB"
-" ipv6=[2a01:4f8:190:9490::dead]:443"
-/* nickname=PedicaboMundi */
-/* extrainfo=0 */
-/* ===== */
-,
-"185.220.101.9:10009 orport=20009 id=14877C6384A9E793F422C8D1DDA447CACA4F7C4B"
-/* nickname=niftywoodmouse */
+"193.11.114.43:9030 orport=9001 id=12AD30E5D25AA67F519780E2111E611A455FDC89"
+" ipv6=[2001:6b0:30:1000::99]:9050"
+/* nickname=mdfnet1 */
/* extrainfo=0 */
/* ===== */
,
-"54.37.138.138:8080 orport=993 id=1576BE143D8727745BB2BCDDF183291B3C3EFEFC"
-/* nickname=anotherone */
+"37.157.195.87:8030 orport=443 id=12FD624EE73CEF37137C90D38B2406A66F68FAA2"
+/* nickname=thanatosCZ */
/* extrainfo=0 */
/* ===== */
,
-"51.15.78.0:9030 orport=9001 id=15BE17C99FACE24470D40AF782D6A9C692AB36D6"
-" ipv6=[2001:bc8:4700:2300::16:c0b]:9001"
-/* nickname=rofltor07 */
+"217.182.51.248:80 orport=443 id=183005F78229D94EE51CE7795A42280070A48D0D"
+/* nickname=Cosworth02 */
/* extrainfo=0 */
/* ===== */
,
-"204.11.50.131:9030 orport=9001 id=185F2A57B0C4620582602761097D17DB81654F70"
-/* nickname=BoingBoing */
+"171.25.193.25:80 orport=443 id=185663B7C12777F052B2C2D23D7A239D8DA88A0F"
+" ipv6=[2001:67c:289c::25]:443"
+/* nickname=DFRI5 */
/* extrainfo=0 */
/* ===== */
,
@@ -135,9 +119,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=1 */
/* ===== */
,
-"163.172.53.84:143 orport=21 id=1C90D3AEADFF3BCD079810632C8B85637924A58E"
-" ipv6=[2001:bc8:24f8::]:21"
-/* nickname=Multivac */
+"50.7.74.171:9030 orport=9001 id=1CD17CB202063C51C7DAD3BACEF87ECE81C2350F"
+" ipv6=[2001:49f0:d002:2::51]:443"
+/* nickname=theia1 */
/* extrainfo=0 */
/* ===== */
,
@@ -153,24 +137,13 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"163.172.176.167:80 orport=443 id=230A8B2A8BA861210D9B4BA97745AEC217A94207"
-/* nickname=niij01 */
-/* extrainfo=0 */
-/* ===== */
-,
-"185.220.101.8:10008 orport=20008 id=24E91955D969AEA1D80413C64FE106FAE7FD2EA9"
-/* nickname=niftymouse */
+"77.247.181.164:80 orport=443 id=204DFD2A2C6A0DC1FA0EACB495218E0B661704FD"
+/* nickname=HaveHeart */
/* extrainfo=0 */
/* ===== */
,
-"138.201.250.33:9012 orport=9011 id=2BA2C8E96B2590E1072AECE2BDB5C48921BF8510"
-/* nickname=storm */
-/* extrainfo=0 */
-/* ===== */
-,
-"193.234.15.56:80 orport=443 id=2CDCFED0142B28B002E89D305CBA2E26063FADE2"
-" ipv6=[2a00:1c20:4089:1234:cd49:b58a:9ebe:67ec]:443"
-/* nickname=jaures */
+"163.172.176.167:80 orport=443 id=230A8B2A8BA861210D9B4BA97745AEC217A94207"
+/* nickname=niij01 */
/* extrainfo=0 */
/* ===== */
,
@@ -179,14 +152,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"94.230.208.147:8080 orport=8443 id=311A4533F7A2415F42346A6C8FA77E6FD279594C"
-" ipv6=[2a02:418:6017::147]:8443"
-/* nickname=DigiGesTor3e2 */
+"212.83.154.33:8080 orport=8443 id=322C6E3A973BC10FC36DE3037AD27BC89F14723B"
+/* nickname=bauruine204 */
/* extrainfo=0 */
/* ===== */
,
-"212.83.154.33:8080 orport=8443 id=322C6E3A973BC10FC36DE3037AD27BC89F14723B"
-/* nickname=bauruine204 */
+"109.105.109.162:52860 orport=60784 id=32EE911D968BE3E016ECA572BB1ED0A9EE43FC2F"
+" ipv6=[2001:948:7:2::163]:5001"
+/* nickname=ndnr1 */
/* extrainfo=0 */
/* ===== */
,
@@ -196,64 +169,53 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"54.37.17.235:9030 orport=9001 id=360CBA08D1E24F513162047BDB54A1015E531534"
-/* nickname=Aerodynamik06 */
-/* extrainfo=0 */
-/* ===== */
-,
"37.157.255.35:9030 orport=9090 id=361D33C96D0F161275EE67E2C91EE10B276E778B"
/* nickname=cxx4freedom */
/* extrainfo=0 */
/* ===== */
,
-"37.187.22.87:9030 orport=9001 id=36B9E7AC1E36B62A9D6F330ABEB6012BA7F0D400"
-" ipv6=[2001:41d0:a:1657::1]:9001"
-/* nickname=kimsufi321 */
-/* extrainfo=0 */
-/* ===== */
-,
"64.79.152.132:80 orport=443 id=375DCBB2DBD94E5263BC0C015F0C9E756669617E"
/* nickname=ebola */
/* extrainfo=0 */
/* ===== */
,
-"62.210.92.11:9130 orport=9101 id=387B065A38E4DAA16D9D41C2964ECBC4B31D30FF"
-" ipv6=[2001:bc8:338c::1]:9101"
-/* nickname=redjohn1 */
+"213.183.60.21:9030 orport=443 id=39F91959416763AFD34DBEEC05474411B964B2DC"
+/* nickname=angeltest11 */
/* extrainfo=0 */
/* ===== */
,
-"198.50.191.95:80 orport=443 id=39F096961ED2576975C866D450373A9913AFDC92"
-/* nickname=thomas */
+"50.7.74.174:9030 orport=9001 id=3AFDAAD91A15B4C6A7686A53AA8627CA871FF491"
+" ipv6=[2001:49f0:d002:2::57]:443"
+/* nickname=theia7 */
/* extrainfo=0 */
/* ===== */
,
-"66.111.2.16:9030 orport=9001 id=3F092986E9B87D3FDA09B71FA3A602378285C77A"
-" ipv6=[2610:1c0:0:5::16]:9001"
-/* nickname=NYCBUG1 */
+"199.249.230.83:80 orport=443 id=3CA0D15567024D2E0B557DC0CF3E962B37999A79"
+" ipv6=[2620:7:6001::ffff:c759:e653]:80"
+/* nickname=QuintexAirVPN30 */
/* extrainfo=0 */
/* ===== */
,
-"185.100.85.101:9030 orport=9001 id=4061C553CA88021B8302F0814365070AAE617270"
-/* nickname=TorExitRomania */
+"51.38.65.160:9030 orport=9001 id=3CB4193EF4E239FCEDC4DC43468E0B0D6B67ACC3"
+" ipv6=[2001:41d0:801:2000::f6e]:9001"
+/* nickname=rofltor10 */
/* extrainfo=0 */
/* ===== */
,
-"195.191.81.7:9030 orport=9001 id=41A3C16269C7B63DB6EB741DBDDB4E1F586B1592"
-" ipv6=[2a00:1908:fffc:ffff:c0a6:ccff:fe62:e1a1]:9001"
-/* nickname=rofltor02 */
+"217.79.179.177:9030 orport=9001 id=3E53D3979DB07EFD736661C934A1DED14127B684"
+" ipv6=[2001:4ba0:fff9:131:6c4f::90d3]:9001"
+/* nickname=Unnamed */
/* extrainfo=0 */
/* ===== */
,
-"178.17.170.156:9030 orport=9001 id=41C59606AFE1D1AA6EC6EF6719690B856F0B6587"
-" ipv6=[2a00:1dc0:caff:48::9257]:9001"
-/* nickname=TorExitMoldova2 */
+"66.111.2.16:9030 orport=9001 id=3F092986E9B87D3FDA09B71FA3A602378285C77A"
+" ipv6=[2610:1c0:0:5::16]:9001"
+/* nickname=NYCBUG1 */
/* extrainfo=0 */
/* ===== */
,
-"81.7.10.251:80 orport=443 id=45362E8ECD651CCAC521156FFBD2FF7F27FA8E88"
-" ipv6=[2a02:180:1:1::517:afb]:443"
-/* nickname=torpidsDEisppro2 */
+"185.100.85.101:9030 orport=9001 id=4061C553CA88021B8302F0814365070AAE617270"
+/* nickname=TorExitRomania */
/* extrainfo=0 */
/* ===== */
,
@@ -262,8 +224,8 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"132.248.241.5:9030 orport=9001 id=4661DE96D3F8E923994B05218F23760C8D7935A4"
-/* nickname=toritounam */
+"195.123.245.141:9030 orport=443 id=465D17C6FC297E3857B5C6F152006A1E212944EA"
+/* nickname=angeltest14 */
/* extrainfo=0 */
/* ===== */
,
@@ -272,18 +234,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.34:10034 orport=20034 id=47C42E2094EE482E7C9B586B10BABFB67557030B"
-/* nickname=niftysugarglider */
-/* extrainfo=0 */
-/* ===== */
-,
"193.70.43.76:9030 orport=9001 id=484A10BA2B8D48A5F0216674C8DD50EF27BC32F3"
/* nickname=Aerodynamik03 */
/* extrainfo=0 */
/* ===== */
,
-"51.254.101.242:9002 orport=9001 id=4CC9CC9195EC38645B699A33307058624F660CCF"
-/* nickname=devsum */
+"37.187.102.186:9030 orport=9001 id=489D94333DF66D57FFE34D9D59CC2D97E2CB0053"
+" ipv6=[2001:41d0:a:26ba::1]:9001"
+/* nickname=txtfileTorNode65536 */
/* extrainfo=0 */
/* ===== */
,
@@ -293,9 +251,15 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"212.51.134.123:9030 orport=9001 id=50586E25BE067FD1F739998550EDDCB1A14CA5B2"
-/* nickname=Jans */
-/* extrainfo=0 */
+"108.53.208.157:80 orport=443 id=4F0DB7E687FC7C0AE55C8F243DA8B0EB27FBF1F2"
+/* nickname=Binnacle */
+/* extrainfo=1 */
+/* ===== */
+,
+"5.9.158.75:9030 orport=9001 id=509EAB4C5D10C9A9A24B4EA0CE402C047A2D64E6"
+" ipv6=[2a01:4f8:190:514a::2]:9001"
+/* nickname=zwiebeltoralf2 */
+/* extrainfo=1 */
/* ===== */
,
"81.7.16.182:80 orport=443 id=51E1CF613FD6F9F11FE24743C91D6F9981807D82"
@@ -304,11 +268,6 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"85.25.159.65:995 orport=80 id=52BFADA8BEAA01BA46C8F767F83C18E2FE50C1B9"
-/* nickname=BeastieJoy63 */
-/* extrainfo=0 */
-/* ===== */
-,
"192.160.102.166:80 orport=9001 id=547DA56F6B88B6C596B3E3086803CDA4F0EF8F21"
" ipv6=[2620:132:300c:c01d::6]:9002"
/* nickname=chaucer */
@@ -321,20 +280,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"95.130.12.119:80 orport=443 id=587E0A9552E4274B251F29B5B2673D38442EE4BF"
-/* nickname=Nuath */
-/* extrainfo=0 */
-/* ===== */
-,
-"185.21.100.50:9030 orport=9001 id=58ED9C9C35E433EE58764D62892B4FFD518A3CD0"
-" ipv6=[2a00:1158:2:cd00:0:74:6f:72]:443"
-/* nickname=SamAAdams2 */
-/* extrainfo=0 */
-/* ===== */
-,
-"193.234.15.62:80 orport=443 id=5CF8AFA5E4B0BB88942A44A3F3AAE08C3BDFD60B"
-" ipv6=[2a00:1c20:4089:1234:a6a4:2926:d0af:dfee]:443"
-/* nickname=jaures4 */
+"50.7.74.170:80 orport=443 id=5BF17163CBE73D8CD9FDBE030C944EA05707DA93"
+" ipv6=[2001:49f0:d002:2::58]:443"
+/* nickname=theia8 */
/* extrainfo=0 */
/* ===== */
,
@@ -343,8 +291,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.28:10028 orport=20028 id=609E598FB6A00BCF7872906B602B705B64541C50"
-/* nickname=niftychipmunk */
+"95.128.43.164:80 orport=443 id=616081EC829593AF4232550DE6FFAA1D75B37A90"
+" ipv6=[2a02:ec0:209:10::4]:443"
+/* nickname=AquaRayTerminus */
/* extrainfo=0 */
/* ===== */
,
@@ -353,6 +302,12 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
+"94.130.186.5:80 orport=443 id=6A7551EEE18F78A9813096E82BF84F740D32B911"
+" ipv6=[2a01:4f8:1c0c:45f7::1]:443"
+/* nickname=TorMachine */
+/* extrainfo=0 */
+/* ===== */
+,
"80.127.137.19:80 orport=443 id=6EF897645B79B6CB35E853B32506375014DE3621"
" ipv6=[2001:981:47c1:1::6]:443"
/* nickname=d6relay */
@@ -370,19 +325,27 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.30:10030 orport=20030 id=71CFDEB4D9E00CCC3E31EC4E8A29E109BBC1FB36"
-/* nickname=niftypedetidae */
+"85.235.250.88:80 orport=443 id=72B2B12A3F60408BDBC98C6DF53988D3A0B3F0EE"
+" ipv6=[2a01:3a0:1:1900:85:235:250:88]:443"
+/* nickname=TykRelay01 */
/* extrainfo=0 */
/* ===== */
,
-"85.235.250.88:80 orport=443 id=72B2B12A3F60408BDBC98C6DF53988D3A0B3F0EE"
-/* nickname=TykRelay01 */
+"178.17.170.23:9030 orport=9001 id=742C45F2D9004AADE0077E528A4418A6A81BC2BA"
+" ipv6=[2a00:1dc0:caff:7d::8254]:9001"
+/* nickname=TorExitMoldova2 */
/* extrainfo=0 */
/* ===== */
,
-"81.7.14.31:9001 orport=443 id=7600680249A22080ECC6173FBBF64D6FCF330A61"
-/* nickname=Ichotolot62 */
-/* extrainfo=1 */
+"50.7.74.173:9030 orport=9001 id=745369332749021C6FAF100D327BC3BF1DF4707B"
+" ipv6=[2001:49f0:d002:2::55]:443"
+/* nickname=theia5 */
+/* extrainfo=0 */
+/* ===== */
+,
+"77.247.181.166:80 orport=443 id=77131D7E2EC1CA9B8D737502256DA9103599CE51"
+/* nickname=CriticalMass */
+/* extrainfo=0 */
/* ===== */
,
"5.196.23.64:9030 orport=9001 id=775B0FAFDE71AADC23FFC8782B7BEB1D5A92733E"
@@ -390,13 +353,24 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
+"185.244.193.141:9030 orport=9001 id=79509683AB4C8DDAF90A120C69A4179C6CD5A387"
+" ipv6=[2a03:4000:27:192:24:12:1984:4]:9001"
+/* nickname=DerDickeReloaded */
+/* extrainfo=0 */
+/* ===== */
+,
"51.254.136.195:80 orport=443 id=7BB70F8585DFC27E75D692970C0EEB0F22983A63"
/* nickname=torproxy02 */
/* extrainfo=0 */
/* ===== */
,
-"185.100.84.82:80 orport=443 id=7D05A38E39FC5D29AFE6BE487B9B4DC9E635D09E"
-/* nickname=saveyourprivacyexit */
+"77.247.181.162:80 orport=443 id=7BFB908A3AA5B491DA4CA72CCBEE0E1F2A939B55"
+/* nickname=sofia */
+/* extrainfo=0 */
+/* ===== */
+,
+"185.220.101.48:10048 orport=20048 id=7E281CD2C315C4F7A84BC7C8721C3BC974DDBFA3"
+/* nickname=niftyporcupine */
/* extrainfo=0 */
/* ===== */
,
@@ -411,12 +385,6 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"217.12.199.190:80 orport=443 id=81AFA888F8F8F4A024AB58ECA0ADDEBB93FF01DA"
-" ipv6=[2a02:27a8:0:2::486]:993"
-/* nickname=torpidsUAitlas */
-/* extrainfo=0 */
-/* ===== */
-,
"192.42.116.16:80 orport=443 id=81B75D534F91BFB7C57AB67DA10BCEF622582AE8"
/* nickname=hviv104 */
/* extrainfo=0 */
@@ -439,19 +407,19 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"185.96.88.29:80 orport=443 id=86C281AD135058238D7A337D546C902BE8505DDE"
-/* nickname=TykRelay05 */
+"85.230.178.139:9030 orport=443 id=855BC2DABE24C861CD887DB9B2E950424B49FC34"
+/* nickname=Logforme */
/* extrainfo=0 */
/* ===== */
,
-"93.180.156.84:9030 orport=9001 id=8844D87E9B038BE3270938F05AF797E1D3C74C0F"
-/* nickname=BARACUDA */
+"178.254.7.88:8080 orport=8443 id=85A885433E50B1874F11CEC9BE98451E24660976"
+/* nickname=wr3ck3d0ni0n01 */
/* extrainfo=0 */
/* ===== */
,
-"51.15.205.214:9030 orport=9001 id=8B6556601612F1E2AFCE2A12FFFAF8482A76DD1F"
-" ipv6=[2001:bc8:4400:2500::5:b07]:9001"
-/* nickname=titania1 */
+"185.96.88.29:80 orport=443 id=86C281AD135058238D7A337D546C902BE8505DDE"
+" ipv6=[2a00:4020::185:96:88:29]:443"
+/* nickname=TykRelay05 */
/* extrainfo=0 */
/* ===== */
,
@@ -461,35 +429,46 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
+"5.189.169.190:8030 orport=8080 id=8D79F73DCD91FC4F5017422FAC70074D6DB8DD81"
+/* nickname=thanatosDE */
+/* extrainfo=0 */
+/* ===== */
+,
"81.7.11.96:9030 orport=9001 id=8FA37B93397015B2BC5A525C908485260BE9F422"
/* nickname=Doedel22 */
/* extrainfo=0 */
/* ===== */
,
+"54.37.139.118:9030 orport=9001 id=90A5D1355C4B5840E950EB61E673863A6AE3ACA1"
+" ipv6=[2001:41d0:601:1100::1b8]:9001"
+/* nickname=rofltor09 */
+/* extrainfo=0 */
+/* ===== */
+,
"37.187.20.59:80 orport=443 id=91D23D8A539B83D2FB56AA67ECD4D75CC093AC55"
" ipv6=[2001:41d0:a:143b::1]:993"
/* nickname=torpidsFRovh */
/* extrainfo=0 */
/* ===== */
,
-"51.255.41.65:9030 orport=9001 id=9231DF741915AA1630031A93026D88726877E93A"
-/* nickname=PrisnCellRelayFR1 */
+"173.255.245.116:9030 orport=9001 id=91E4015E1F82DAF0121D62267E54A1F661AB6DC7"
+/* nickname=IWorshipHisShadow */
/* extrainfo=0 */
/* ===== */
,
-"54.37.73.111:9030 orport=9001 id=92412EA1B9AA887D462B51D816777002F4D58907"
-/* nickname=Aerodynamik05 */
+"96.253.78.108:80 orport=443 id=924B24AFA7F075D059E8EEB284CC400B33D3D036"
+/* nickname=NSDFreedom */
/* extrainfo=0 */
/* ===== */
,
-"96.253.78.108:80 orport=443 id=924B24AFA7F075D059E8EEB284CC400B33D3D036"
-/* nickname=NSDFreedom */
+"92.38.163.21:9030 orport=443 id=9288B75B5FF8861EFF32A6BE8825CC38A4F9F8C2"
+/* nickname=angeltest9 */
/* extrainfo=0 */
/* ===== */
,
-"193.234.15.57:80 orport=443 id=92CFD9565B24646CAC2D172D3DB503D69E777B8A"
-" ipv6=[2a00:1c20:4089:1234:7825:2c5d:1ecd:c66f]:443"
-/* nickname=bakunin */
+"163.172.53.84:80 orport=443 id=935F589545B8A271A722E330445BB99F67DBB058"
+" ipv6=[2001:bc8:24f8::]:443"
+/* nickname=Multivac0 */
/* extrainfo=0 */
/* ===== */
,
@@ -508,23 +487,17 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"91.229.20.27:9030 orport=9001 id=9A0D54D3A6D2E0767596BF1515E6162A75B3293F"
-/* nickname=gordonkeybag */
-/* extrainfo=0 */
-/* ===== */
-,
-"66.111.2.20:9030 orport=9001 id=9A68B85A02318F4E7E87F2828039FBD5D75B0142"
-" ipv6=[2610:1c0:0:5::20]:9001"
-/* nickname=NYCBUG0 */
-/* extrainfo=0 */
-/* ===== */
-,
"185.100.86.128:9030 orport=9001 id=9B31F1F1C1554F9FFB3455911F82E818EF7C7883"
" ipv6=[2a06:1700:1::11]:9001"
/* nickname=TorExitFinland */
/* extrainfo=0 */
/* ===== */
,
+"185.220.101.49:10049 orport=20049 id=9B816A5B3EB20B8E4E9B9D1FBA299BD3F40F0320"
+/* nickname=niftypygmyjerboa */
+/* extrainfo=0 */
+/* ===== */
+,
"86.105.212.130:9030 orport=443 id=9C900A7F6F5DD034CFFD192DAEC9CCAA813DB022"
/* nickname=firstor2 */
/* extrainfo=0 */
@@ -545,54 +518,28 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=1 */
/* ===== */
,
-"171.25.193.77:80 orport=443 id=A10C4F666D27364036B562823E5830BC448E046A"
-" ipv6=[2001:67c:289c:3::77]:443"
-/* nickname=DFRI1 */
-/* extrainfo=0 */
-/* ===== */
-,
-"87.118.122.120:80 orport=443 id=A2A6616723B511D8E068BB71705191763191F6B2"
-/* nickname=otheontelth */
-/* extrainfo=0 */
-/* ===== */
-,
"81.7.3.67:993 orport=443 id=A2E6BB5C391CD46B38C55B4329C35304540771F1"
/* nickname=BeastieJoy62 */
/* extrainfo=1 */
/* ===== */
,
-"171.25.193.78:80 orport=443 id=A478E421F83194C114F41E94F95999672AED51FE"
-" ipv6=[2001:67c:289c:3::78]:443"
-/* nickname=DFRI4 */
-/* extrainfo=0 */
-/* ===== */
-,
-"193.234.15.58:80 orport=443 id=A4C98CEA3F34E05299417E9F885A642C88EF6029"
-" ipv6=[2a00:1c20:4089:1234:cdae:1b3e:cc38:3d45]:443"
-/* nickname=jaures2 */
-/* extrainfo=0 */
-/* ===== */
-,
"128.31.0.13:80 orport=443 id=A53C46F5B157DD83366D45A8E99A244934A14C46"
/* nickname=csailmitexit */
/* extrainfo=0 */
/* ===== */
,
-"94.142.242.84:80 orport=443 id=AA0D167E03E298F9A8CD50F448B81FBD7FA80D56"
-" ipv6=[2a02:898:24:84::1]:443"
-/* nickname=rejozenger */
+"185.246.152.22:9030 orport=443 id=A86EC24F5B8B964F67AC7C27CE92842025983274"
+/* nickname=angeltest19 */
/* extrainfo=0 */
/* ===== */
,
-"195.154.164.243:80 orport=443 id=AC66FFA4AB35A59EBBF5BF4C70008BF24D8A7A5C"
-" ipv6=[2001:bc8:399f:f000::1]:993"
-/* nickname=torpidsFRonline3 */
+"163.172.149.122:80 orport=443 id=A9406A006D6E7B5DA30F2C6D4E42A338B5E340B2"
+/* nickname=niij03 */
/* extrainfo=0 */
/* ===== */
,
-"86.59.119.88:80 orport=443 id=ACD889D86E02EDDAB1AFD81F598C0936238DC6D0"
-" ipv6=[2001:858:2:30:86:59:119:88]:443"
-/* nickname=ph3x */
+"176.10.107.180:9030 orport=9001 id=AC2BEDD0BAC72838EA7E6F113F856C4E8018ACDB"
+/* nickname=schokomilch */
/* extrainfo=0 */
/* ===== */
,
@@ -602,12 +549,6 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"188.40.128.246:9030 orport=9001 id=AD19490C7DBB26D3A68EFC824F67E69B0A96E601"
-" ipv6=[2a01:4f8:221:1ac1:dead:beef:7005:9001]:9001"
-/* nickname=sputnik */
-/* extrainfo=0 */
-/* ===== */
-,
"31.185.104.20:80 orport=443 id=ADB2C26629643DBB9F8FE0096E7D16F9414B4F8D"
/* nickname=Digitalcourage3ip2 */
/* extrainfo=0 */
@@ -636,14 +577,19 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
+"199.249.230.64:80 orport=443 id=B2197C23A4FF5D1C49EE45BA7688BA8BCCD89A0B"
+" ipv6=[2620:7:6001::ffff:c759:e640]:80"
+/* nickname=Quintex41 */
+/* extrainfo=0 */
+/* ===== */
+,
"136.243.214.137:80 orport=443 id=B291D30517D23299AD7CEE3E60DFE60D0E3A4664"
/* nickname=TorKIT */
/* extrainfo=0 */
/* ===== */
,
-"193.234.15.60:80 orport=443 id=B44FBE5366AD98B46D829754FA4AC599BAE41A6A"
-" ipv6=[2a00:1c20:4089:1234:67bc:79f3:61c0:6e49]:443"
-/* nickname=jaures3 */
+"212.47.233.86:9030 orport=9001 id=B4CAFD9CBFB34EC5DAAC146920DC7DFAFE91EA20"
+/* nickname=netimanmu */
/* extrainfo=0 */
/* ===== */
,
@@ -652,14 +598,8 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"81.2.209.10:443 orport=80 id=B6904ADD4C0D10CDA7179E051962350A69A63243"
-" ipv6=[2001:15e8:201:1::d10a]:80"
-/* nickname=torzabehlice */
-/* extrainfo=0 */
-/* ===== */
-,
-"185.220.101.32:10032 orport=20032 id=B771AA877687F88E6F1CA5354756DF6C8A7B6B24"
-/* nickname=niftypika */
+"51.38.134.104:9030 orport=443 id=B57A87009FA838471FB2227DDE68165AB2A2FCC4"
+/* nickname=angeltest5 */
/* extrainfo=0 */
/* ===== */
,
@@ -679,6 +619,22 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=1 */
/* ===== */
,
+"51.15.179.153:110 orport=995 id=BB60F5BA113A0B8B44B7B37DE3567FE561E92F78"
+/* nickname=Casper04 */
+/* extrainfo=0 */
+/* ===== */
+,
+"198.96.155.3:8080 orport=5001 id=BCEDF6C193AA687AE471B8A22EBF6BC57C2D285E"
+/* nickname=gurgle */
+/* extrainfo=0 */
+/* ===== */
+,
+"128.199.55.207:9030 orport=9001 id=BCEF908195805E03E92CCFE669C48738E556B9C5"
+" ipv6=[2a03:b0c0:2:d0::158:3001]:9001"
+/* nickname=EldritchReaper */
+/* extrainfo=0 */
+/* ===== */
+,
"213.141.138.174:9030 orport=9001 id=BD552C165E2ED2887D3F1CCE9CFF155DDA2D86E6"
/* nickname=Schakalium */
/* extrainfo=0 */
@@ -690,8 +646,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"104.192.5.248:9030 orport=443 id=BF735F669481EE1CCC348F0731551C933D1E2278"
-/* nickname=Freeway1a1 */
+"212.47.233.250:9030 orport=9001 id=BF735F669481EE1CCC348F0731551C933D1E2278"
+" ipv6=[2001:bc8:4400:2b00::1c:629]:9001"
+/* nickname=FreewaySca */
/* extrainfo=0 */
/* ===== */
,
@@ -701,8 +658,8 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"185.220.101.6:10006 orport=20006 id=C08DE49658E5B3CFC6F2A952B453C4B608C9A16A"
-/* nickname=niftyvolcanorabbit */
+"132.248.241.5:9130 orport=9101 id=C0C4F339046EB824999F711D178472FDF53BE7F5"
+/* nickname=toritounam2 */
/* extrainfo=0 */
/* ===== */
,
@@ -711,20 +668,9 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"213.239.217.18:1338 orport=1337 id=C37BC191AC389179674578C3E6944E925FE186C2"
-" ipv6=[2a01:4f8:a0:746a:101:1:1:1]:1337"
-/* nickname=xzdsb */
-/* extrainfo=0 */
-/* ===== */
-,
-"188.138.112.60:1433 orport=1521 id=C414F28FD2BEC1553024299B31D4E726BEB8E788"
-/* nickname=zebra620 */
-/* extrainfo=0 */
-/* ===== */
-,
-"193.234.15.55:80 orport=443 id=C4AEA05CF380BAD2230F193E083B8869B4A29937"
-" ipv6=[2a00:1c20:4089:1234:7b2c:11c5:5221:903e]:443"
-/* nickname=bakunin4 */
+"50.7.74.170:9030 orport=9001 id=C36A434DB54C66E1A97A5653858CE36024352C4D"
+" ipv6=[2001:49f0:d002:2::59]:443"
+/* nickname=theia9 */
/* extrainfo=0 */
/* ===== */
,
@@ -745,34 +691,37 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"85.25.213.211:465 orport=80 id=CE47F0356D86CF0A1A2008D97623216D560FB0A8"
-/* nickname=BeastieJoy61 */
+"51.254.147.57:80 orport=443 id=D15AFF44BE641368B958A32FB6B071AC2136B8B1"
+/* nickname=Cosworth01 */
/* extrainfo=0 */
/* ===== */
,
-"46.38.237.221:9030 orport=9001 id=D30E9D4D639068611D6D96861C95C2099140B805"
-/* nickname=mine */
+"50.7.74.172:80 orport=443 id=D1AFBF3117B308B6D1A7AA762B1315FD86A6B8AF"
+" ipv6=[2001:49f0:d002:2::52]:443"
+/* nickname=theia2 */
/* extrainfo=0 */
/* ===== */
,
-"5.45.111.149:80 orport=443 id=D405FCCF06ADEDF898DF2F29C9348DCB623031BA"
-" ipv6=[2a03:4000:6:2388:df98:15f9:b34d:443]:443"
-/* nickname=gGDHjdcC6zAlM8k08lY */
+"62.141.38.69:9030 orport=443 id=D379A1CB8285748FFF64AE94296CA89878F25B22"
+" ipv6=[2001:4ba0:cafe:ac5::1]:443"
+/* nickname=angeltest3 */
/* extrainfo=0 */
/* ===== */
,
-"37.187.115.157:9030 orport=9001 id=D5039E1EBFD96D9A3F9846BF99EC9F75EDDE902A"
-/* nickname=Janky328891 */
+"5.45.111.149:80 orport=443 id=D405FCCF06ADEDF898DF2F29C9348DCB623031BA"
+" ipv6=[2a03:4000:6:2388:df98:15f9:b34d:443]:443"
+/* nickname=gGDHjdcC6zAlM8k08lY */
/* extrainfo=0 */
/* ===== */
,
-"217.182.51.248:80 orport=443 id=D6BA940D3255AB40DC5EE5B0B285FA143E1F9865"
-/* nickname=Cosworth02 */
+"50.7.74.174:80 orport=443 id=D50101A2ABD09DC245F7E96C0818D003CDD62351"
+" ipv6=[2001:49f0:d002:2::56]:443"
+/* nickname=theia6 */
/* extrainfo=0 */
/* ===== */
,
-"185.34.33.2:9265 orport=31415 id=D71B1CA1C9DC7E8CA64158E106AD770A21160FEE"
-/* nickname=lqdn */
+"37.187.115.157:9030 orport=9001 id=D5039E1EBFD96D9A3F9846BF99EC9F75EDDE902A"
+/* nickname=Janky328891 */
/* extrainfo=0 */
/* ===== */
,
@@ -792,6 +741,11 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
+"176.158.236.102:9030 orport=9001 id=DC163DDEF4B6F0C6BC226F9F6656A5A30C5C5686"
+/* nickname=Underworld */
+/* extrainfo=0 */
+/* ===== */
+,
"178.33.183.251:80 orport=443 id=DD823AFB415380A802DCAEB9461AE637604107FB"
" ipv6=[2001:41d0:2:a683::251]:443"
/* nickname=grenouille */
@@ -804,18 +758,17 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"83.212.99.68:80 orport=443 id=DDBB2A38252ADDA53E4492DDF982CA6CC6E10EC0"
-" ipv6=[2001:648:2ffc:1225:a800:bff:fe3d:67b5]:443"
-/* nickname=zouzounella */
-/* extrainfo=0 */
-/* ===== */
-,
"92.222.38.67:80 orport=443 id=DED6892FF89DBD737BA689698A171B2392EB3E82"
" ipv6=[2001:41d0:52:100::112a]:443"
/* nickname=ThorExit */
/* extrainfo=0 */
/* ===== */
,
+"166.70.207.2:9130 orport=9101 id=E41B16F7DDF52EBB1DB4268AB2FE340B37AD8904"
+/* nickname=xmission1 */
+/* extrainfo=0 */
+/* ===== */
+,
"185.100.86.182:9030 orport=8080 id=E51620B90DCB310138ED89EDEDD0A5C361AAE24E"
/* nickname=NormalCitizen */
/* extrainfo=0 */
@@ -826,17 +779,30 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"51.254.147.57:80 orport=443 id=EB80A8D52F07238B576C42CEAB98ADD084EE075E"
-/* nickname=Cosworth01 */
+"185.4.132.148:80 orport=443 id=E8D114B3C78D8E6E7FEB1004650DD632C2143C9E"
+" ipv6=[2a02:c500:2:f0::5492]:443"
+/* nickname=libreonion1 */
/* extrainfo=0 */
/* ===== */
,
+"131.188.40.188:1443 orport=80 id=EBE718E1A49EE229071702964F8DB1F318075FF8"
+" ipv6=[2001:638:a000:4140::ffff:188]:80"
+/* nickname=fluxe4 */
+/* extrainfo=1 */
+/* ===== */
+,
"192.87.28.28:9030 orport=9001 id=ED2338CAC2711B3E331392E1ED2831219B794024"
" ipv6=[2001:678:230:3028:192:87:28:28]:9001"
/* nickname=SEC6xFreeBSD64 */
/* extrainfo=0 */
/* ===== */
,
+"37.252.187.111:9030 orport=443 id=EE4AF632058F0734C1426B1AD689F47445CA2056"
+" ipv6=[2a00:63c1:c:111::2]:443"
+/* nickname=angeltest7 */
+/* extrainfo=0 */
+/* ===== */
+,
"217.182.75.181:9030 orport=9001 id=EFEACD781604EB80FBC025EDEDEA2D523AEAAA2F"
/* nickname=Aerodynamik02 */
/* extrainfo=0 */
@@ -847,27 +813,20 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=0 */
/* ===== */
,
-"129.13.131.140:80 orport=443 id=F2DFE5FA1E4CF54F8E761A6D304B9B4EC69BDAE8"
-" ipv6=[2a00:1398:5:f604:cafe:cafe:cafe:9001]:443"
-/* nickname=AlleKochenKaffee */
-/* extrainfo=0 */
-/* ===== */
-,
"37.187.102.108:80 orport=443 id=F4263275CF54A6836EE7BD527B1328836A6F06E1"
" ipv6=[2001:41d0:a:266c::1]:443"
/* nickname=EvilMoe */
/* extrainfo=0 */
/* ===== */
,
-"192.160.102.168:80 orport=9001 id=F6A358DD367B3282D6EF5824C9D45E1A19C7E815"
-" ipv6=[2620:132:300c:c01d::8]:9002"
-/* nickname=prawksi */
+"5.199.142.236:9030 orport=9001 id=F4C0EDAA0BF0F7EC138746F8FEF1CE26C7860265"
+/* nickname=tornodenumber9004 */
/* extrainfo=0 */
/* ===== */
,
-"163.172.154.162:9030 orport=9001 id=F741E5124CB12700DA946B78C9B2DD175D6CD2A1"
-" ipv6=[2001:bc8:4400:2100::17:419]:9001"
-/* nickname=rofltor06 */
+"192.160.102.168:80 orport=9001 id=F6A358DD367B3282D6EF5824C9D45E1A19C7E815"
+" ipv6=[2620:132:300c:c01d::8]:9002"
+/* nickname=prawksi */
/* extrainfo=0 */
/* ===== */
,
@@ -877,25 +836,21 @@ URL: https:onionoo.torproject.orguptime?first_seen_days90-&flagV2Dir&typerelay&l
/* extrainfo=1 */
/* ===== */
,
-"178.254.19.101:80 orport=443 id=F9246DEF2B653807236DA134F2AEAB103D58ABFE"
-/* nickname=Freebird31 */
-/* extrainfo=1 */
-/* ===== */
-,
"185.96.180.29:80 orport=443 id=F93D8F37E35C390BCAD9F9069E13085B745EC216"
+" ipv6=[2a00:4820::185:96:180:29]:443"
/* nickname=TykRelay06 */
/* extrainfo=0 */
/* ===== */
,
-"86.59.119.83:80 orport=443 id=FC9AC8EA0160D88BCCFDE066940D7DD9FA45495B"
-" ipv6=[2001:858:2:30:86:59:119:83]:443"
-/* nickname=ph3x */
-/* extrainfo=0 */
-/* ===== */
-,
"149.56.45.200:9030 orport=9001 id=FE296180018833AF03A8EACD5894A614623D3F76"
" ipv6=[2607:5300:201:3000::17d3]:9002"
/* nickname=PyotrTorpotkinOne */
/* extrainfo=0 */
/* ===== */
,
+"193.11.164.243:9030 orport=9001 id=FFA72BD683BC2FCF988356E6BEC1E490F313FB07"
+" ipv6=[2001:6b0:7:125::243]:9001"
+/* nickname=Lule */
+/* extrainfo=0 */
+/* ===== */
+,
diff --git a/src/app/main/main.c b/src/app/main/main.c
index 31cee37637..3bdf8f146b 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -41,6 +41,7 @@
#include "feature/dircache/consdiffmgr.h"
#include "feature/dirparse/routerparse.h"
#include "feature/hibernate/hibernate.h"
+#include "feature/hs/hs_dos.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/routerlist.h"
@@ -637,6 +638,10 @@ tor_init(int argc, char *argv[])
/* Initialize circuit padding to defaults+torrc until we get a consensus */
circpad_machines_init();
+ /* Initialize hidden service DoS subsystem. We need to do this once the
+ * configuration object has been set because it can be accessed. */
+ hs_dos_init();
+
/* Initialize predicted ports list after loading options */
predicted_ports_init();
diff --git a/src/config/torrc.minimal.in-staging b/src/config/torrc.minimal.in-staging
index cb3adca35c..90bad7f7cc 100644
--- a/src/config/torrc.minimal.in-staging
+++ b/src/config/torrc.minimal.in-staging
@@ -88,6 +88,9 @@
## yourself to make this work.
#ORPort 443 NoListen
#ORPort 127.0.0.1:9090 NoAdvertise
+## If you want to listen on IPv6 your numeric address must be explictly
+## between square brackets as follows. You must also listen on IPv4.
+#ORPort [2001:DB8::1]:9050
## The IP address or full DNS name for incoming connections to your
## relay. Leave commented out and Tor will guess.
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index 9d514e6bda..51e1c3af4b 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -88,6 +88,9 @@
## yourself to make this work.
#ORPort 443 NoListen
#ORPort 127.0.0.1:9090 NoAdvertise
+## If you want to listen on IPv6 your numeric address must be explictly
+## between square brackets as follows. You must also listen on IPv4.
+#ORPort [2001:DB8::1]:9050
## The IP address or full DNS name for incoming connections to your
## relay. Leave commented out and Tor will guess.
diff --git a/src/core/include.am b/src/core/include.am
index 1a4b9fb8ab..ee275f172c 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -117,6 +117,7 @@ LIBTOR_APP_A_SOURCES = \
src/feature/hs/hs_config.c \
src/feature/hs/hs_control.c \
src/feature/hs/hs_descriptor.c \
+ src/feature/hs/hs_dos.c \
src/feature/hs/hs_ident.c \
src/feature/hs/hs_intropoint.c \
src/feature/hs/hs_service.c \
@@ -374,6 +375,7 @@ noinst_HEADERS += \
src/feature/hs/hs_config.h \
src/feature/hs/hs_control.h \
src/feature/hs/hs_descriptor.h \
+ src/feature/hs/hs_dos.h \
src/feature/hs/hs_ident.h \
src/feature/hs/hs_intropoint.h \
src/feature/hs/hs_service.h \
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index 5442cae938..2a6edc951c 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -1664,7 +1664,19 @@ tor_addr_from_netinfo_addr(tor_addr_t *tor_addr,
}
/**
- * Process a 'netinfo' cell.
+ * Helper: compute the absolute value of a time_t.
+ *
+ * (we need this because labs() doesn't always work for time_t, since
+ * long can be shorter than time_t.)
+ */
+static inline time_t
+time_abs(time_t val)
+{
+ return (val < 0) ? -val : val;
+}
+
+/**
+ * Process a 'netinfo' cell
*
* This function is called to handle an incoming NETINFO cell; read and act
* on its contents, and set the connection state to "open".
@@ -1679,7 +1691,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
time_t now = time(NULL);
const routerinfo_t *me = router_get_my_routerinfo();
- long apparent_skew = 0;
+ time_t apparent_skew = 0;
tor_addr_t my_apparent_addr = TOR_ADDR_NULL;
int started_here = 0;
const char *identity_digest = NULL;
@@ -1765,7 +1777,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
my_addr_type = netinfo_addr_get_addr_type(my_addr);
my_addr_len = netinfo_addr_get_len(my_addr);
- if (labs(now - chan->conn->handshake_state->sent_versions_at) < 180) {
+ if ((now - chan->conn->handshake_state->sent_versions_at) < 180) {
apparent_skew = now - timestamp;
}
/* We used to check:
@@ -1842,7 +1854,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
/* Act on apparent skew. */
/** Warn when we get a netinfo skew with at least this value. */
#define NETINFO_NOTICE_SKEW 3600
- if (labs(apparent_skew) > NETINFO_NOTICE_SKEW &&
+ if (time_abs(apparent_skew) > NETINFO_NOTICE_SKEW &&
(started_here ||
connection_or_digest_is_known_relay(chan->conn->identity_digest))) {
int trusted = router_digest_is_trusted_dir(chan->conn->identity_digest);
diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c
index 9210fa4e37..99c68d5f6b 100644
--- a/src/core/or/circuitpadding.c
+++ b/src/core/or/circuitpadding.c
@@ -17,7 +17,7 @@
* Each padding type is described by a state machine (circpad_machine_spec_t),
* which is also referred as a "padding machine" in this file. Currently,
* these state machines are hardcoded in the source code (e.g. see
- * circpad_circ_client_machine_init()), but in the future we will be able to
+ * circpad_machines_init()), but in the future we will be able to
* serialize them in the torrc or the consensus.
*
* As specified by prop#254, clients can negotiate padding with relays by using
@@ -138,6 +138,11 @@ static void
circpad_circuit_machineinfo_free_idx(circuit_t *circ, int idx)
{
if (circ->padding_info[idx]) {
+ log_fn(LOG_INFO,LD_CIRC, "Freeing padding info idx %d on circuit %u (%d)",
+ idx, CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0,
+ circ->purpose);
+
tor_free(circ->padding_info[idx]->histogram);
timer_free(circ->padding_info[idx]->padding_timer);
tor_free(circ->padding_info[idx]);
@@ -210,8 +215,9 @@ circpad_marked_circuit_for_padding(circuit_t *circ, int reason)
}
log_info(LD_CIRC, "Circuit %d is not marked for close because of a "
- " pending padding machine.", CIRCUIT_IS_ORIGIN(circ) ?
- TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0);
+ "pending padding machine in index %d.",
+ CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0, i);
/* If the machine has had no network events at all within the
* last circpad_delay_t timespan, it's in some deadlock state.
@@ -222,10 +228,11 @@ circpad_marked_circuit_for_padding(circuit_t *circ, int reason)
if (circ->padding_info[i]->last_cell_time_sec +
(time_t)CIRCPAD_DELAY_MAX_SECS < approx_time()) {
log_notice(LD_BUG, "Circuit %d was not marked for close because of a "
- " pending padding machine for over an hour. Circuit is a %s",
+ "pending padding machine in index %d for over an hour. "
+ "Circuit is a %s",
CIRCUIT_IS_ORIGIN(circ) ?
TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0,
- circuit_purpose_to_string(circ->purpose));
+ i, circuit_purpose_to_string(circ->purpose));
return 0; // abort timer reached; mark the circuit for close now
}
@@ -254,17 +261,25 @@ circpad_marked_circuit_for_padding(circuit_t *circ, int reason)
return 0; // No machine wanted to keep the circuit open; mark for close
}
-/** Free all the machineinfos in <b>circ</b> that match <b>machine_num</b>. */
-static void
+/**
+ * Free all the machineinfos in <b>circ</b> that match <b>machine_num</b>.
+ *
+ * Returns true if any machineinfos with that number were freed.
+ * False otherwise. */
+static int
free_circ_machineinfos_with_machine_num(circuit_t *circ, int machine_num)
{
+ int found = 0;
FOR_EACH_CIRCUIT_MACHINE_BEGIN(i) {
if (circ->padding_machine[i] &&
circ->padding_machine[i]->machine_num == machine_num) {
circpad_circuit_machineinfo_free_idx(circ, i);
circ->padding_machine[i] = NULL;
+ found = 1;
}
} FOR_EACH_CIRCUIT_MACHINE_END;
+
+ return found;
}
/**
@@ -442,6 +457,9 @@ circpad_is_token_removal_supported(circpad_machine_runtime_t *mi)
/* Machines that do want token removal are less sensitive to performance.
* Let's spend some time to check that our state is consistent and sane */
const circpad_state_t *state = circpad_machine_current_state(mi);
+ if (BUG(!state)) {
+ return 1;
+ }
tor_assert_nonfatal(state->token_removal != CIRCPAD_TOKEN_REMOVAL_NONE);
tor_assert_nonfatal(state->histogram_len == mi->histogram_len);
tor_assert_nonfatal(mi->histogram_len != 0);
@@ -513,7 +531,9 @@ circpad_choose_state_length(circpad_machine_runtime_t *mi)
mi->state_length = clamp_double_to_int64(length);
- log_info(LD_CIRC, "State length sampled to %"PRIu64".", mi->state_length);
+ log_info(LD_CIRC, "State length sampled to %"PRIu64" for circuit %u",
+ mi->state_length, CIRCUIT_IS_ORIGIN(mi->on_circ) ?
+ TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0);
}
/**
@@ -544,11 +564,12 @@ circpad_distribution_sample_iat_delay(const circpad_state_t *state,
}
/**
- * Sample an expected time-until-next-packet delay from the histogram.
+ * Sample an expected time-until-next-packet delay from the histogram or
+ * probability distribution.
*
- * The bin is chosen with probability proportional to the number
- * of tokens in each bin, and then a time value is chosen uniformly from
- * that bin's [start,end) time range.
+ * A bin of the histogram is chosen with probability proportional to the number
+ * of tokens in each bin, and then a time value is chosen uniformly from that
+ * bin's [start,end) time range.
*/
STATIC circpad_delay_t
circpad_machine_sample_delay(circpad_machine_runtime_t *mi)
@@ -647,12 +668,7 @@ circpad_machine_sample_delay(circpad_machine_runtime_t *mi)
/**
* Sample a value from the specified probability distribution.
*
- * This performs inverse transform sampling
- * (https://en.wikipedia.org/wiki/Inverse_transform_sampling).
- *
- * XXX: These formulas were taken verbatim. Need a floating wizard
- * to check them for catastropic cancellation and other issues (teor?).
- * Also: is 32bits of double from [0.0,1.0) enough?
+ * Uses functions from src/lib/math/prob_distr.c .
*/
static double
circpad_distribution_sample(circpad_distribution_t dist)
@@ -736,6 +752,8 @@ circpad_distribution_sample(circpad_distribution_t dist)
/**
* Find the index of the first bin whose upper bound is
* greater than the target, and that has tokens remaining.
+ *
+ * Used for histograms with token removal.
*/
static circpad_hist_index_t
circpad_machine_first_higher_index(const circpad_machine_runtime_t *mi,
@@ -758,6 +776,8 @@ circpad_machine_first_higher_index(const circpad_machine_runtime_t *mi,
/**
* Find the index of the first bin whose lower bound is lower or equal to
* <b>target_bin_usec</b>, and that still has tokens remaining.
+ *
+ * Used for histograms with token removal.
*/
static circpad_hist_index_t
circpad_machine_first_lower_index(const circpad_machine_runtime_t *mi,
@@ -779,6 +799,8 @@ circpad_machine_first_lower_index(const circpad_machine_runtime_t *mi,
/**
* Remove a token from the first non-empty bin whose upper bound is
* greater than the target.
+ *
+ * Used for histograms with token removal.
*/
STATIC void
circpad_machine_remove_higher_token(circpad_machine_runtime_t *mi,
@@ -800,6 +822,8 @@ circpad_machine_remove_higher_token(circpad_machine_runtime_t *mi,
/**
* Remove a token from the first non-empty bin whose upper bound is
* lower than the target.
+ *
+ * Used for histograms with token removal.
*/
STATIC void
circpad_machine_remove_lower_token(circpad_machine_runtime_t *mi,
@@ -829,6 +853,8 @@ circpad_machine_remove_lower_token(circpad_machine_runtime_t *mi,
* midpoint.
*
* If it is false, use bin index distance only.
+ *
+ * Used for histograms with token removal.
*/
STATIC void
circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi,
@@ -911,6 +937,8 @@ circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi,
* Remove a token from the exact bin corresponding to the target.
*
* If it is empty, do nothing.
+ *
+ * Used for histograms with token removal.
*/
static void
circpad_machine_remove_exact(circpad_machine_runtime_t *mi,
@@ -1075,8 +1103,11 @@ circpad_machine_remove_token(circpad_machine_runtime_t *mi)
state = circpad_machine_current_state(mi);
+ /* If we are not in a padding state (like start or end), we're done */
+ if (!state)
+ return;
/* Don't remove any tokens if we're not doing token removal */
- if (!state || state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE)
+ if (state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE)
return;
current_time = monotime_absolute_usec();
@@ -1095,10 +1126,6 @@ circpad_machine_remove_token(circpad_machine_runtime_t *mi)
timer_disable(mi->padding_timer);
}
- /* If we are not in a padding state (like start or end), we're done */
- if (!state)
- return;
-
/* Perform the specified token removal strategy */
switch (state->token_removal) {
case CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC:
@@ -1188,7 +1215,9 @@ circpad_send_padding_cell_for_callback(circpad_machine_runtime_t *mi)
/* Make sure circuit didn't close on us */
if (mi->on_circ->marked_for_close) {
log_fn(LOG_INFO,LD_CIRC,
- "Padding callback on a circuit marked for close. Ignoring.");
+ "Padding callback on circuit marked for close (%u). Ignoring.",
+ CIRCUIT_IS_ORIGIN(mi->on_circ) ?
+ TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0);
return CIRCPAD_STATE_CHANGED;
}
@@ -1344,7 +1373,7 @@ circpad_machine_reached_padding_limit(circpad_machine_runtime_t *mi)
/* If circpad_max_global_padding_pct is non-zero, and we've
* sent more than the global padding cell limit, then check our
- * gloabl tor process percentage limit on padding. */
+ * global tor process percentage limit on padding. */
if (circpad_global_max_padding_percent &&
circpad_global_padding_sent >= circpad_global_allowed_cells) {
uint64_t total_cells = circpad_global_padding_sent +
@@ -1399,7 +1428,9 @@ circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi))
// Don't pad in end (but also don't cancel any previously
// scheduled padding either).
if (mi->current_state == CIRCPAD_STATE_END) {
- log_fn(LOG_INFO, LD_CIRC, "Padding end state");
+ log_fn(LOG_INFO, LD_CIRC, "Padding end state on circuit %u",
+ CIRCUIT_IS_ORIGIN(mi->on_circ) ?
+ TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0);
return CIRCPAD_STATE_UNCHANGED;
}
@@ -1439,7 +1470,9 @@ circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi))
} else {
mi->padding_scheduled_at_usec = 1;
}
- log_fn(LOG_INFO,LD_CIRC,"\tPadding in %u usec", in_usec);
+ log_fn(LOG_INFO,LD_CIRC,"\tPadding in %u usec on circuit %u", in_usec,
+ CIRCUIT_IS_ORIGIN(mi->on_circ) ?
+ TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0);
// Don't schedule if we have infinite delay.
if (in_usec == CIRCPAD_DELAY_INFINITE) {
@@ -1463,7 +1496,9 @@ circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi))
timeout.tv_sec = in_usec/TOR_USEC_PER_SEC;
timeout.tv_usec = (in_usec%TOR_USEC_PER_SEC);
- log_fn(LOG_INFO, LD_CIRC, "\tPadding in %u sec, %u usec",
+ log_fn(LOG_INFO, LD_CIRC, "\tPadding circuit %u in %u sec, %u usec",
+ CIRCUIT_IS_ORIGIN(mi->on_circ) ?
+ TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0,
(unsigned)timeout.tv_sec, (unsigned)timeout.tv_usec);
if (mi->padding_timer) {
@@ -1484,7 +1519,7 @@ circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi))
/**
* If the machine transitioned to the END state, we need
* to check to see if it wants us to shut it down immediately.
- * If it does, then we need to send the appropate negotation commands
+ * If it does, then we need to send the appropiate negotiation commands
* depending on which side it is.
*
* After this function is called, mi may point to freed memory. Do
@@ -1494,6 +1529,12 @@ static void
circpad_machine_spec_transitioned_to_end(circpad_machine_runtime_t *mi)
{
const circpad_machine_spec_t *machine = CIRCPAD_GET_MACHINE(mi);
+ circuit_t *on_circ = mi->on_circ;
+
+ log_fn(LOG_INFO,LD_CIRC, "Padding machine in end state on circuit %u (%d)",
+ CIRCUIT_IS_ORIGIN(on_circ) ?
+ TO_ORIGIN_CIRCUIT(on_circ)->global_identifier : 0,
+ on_circ->purpose);
/*
* We allow machines to shut down and delete themselves as opposed
@@ -1501,7 +1542,7 @@ circpad_machine_spec_transitioned_to_end(circpad_machine_runtime_t *mi)
* we can handle the case where this machine started while it was
* the only machine that matched conditions, but *since* then more
* "higher ranking" machines now match the conditions, and would
- * be given a chance to take precidence over this one in
+ * be given a chance to take precedence over this one in
* circpad_add_matching_machines().
*
* Returning to START or waiting forever in END would not give those
@@ -1509,7 +1550,6 @@ circpad_machine_spec_transitioned_to_end(circpad_machine_runtime_t *mi)
* here does.
*/
if (machine->should_negotiate_end) {
- circuit_t *on_circ = mi->on_circ;
if (machine->is_origin_side) {
/* We free the machine info here so that we can be replaced
* by a different machine. But we must leave the padding_machine
@@ -1575,7 +1615,9 @@ circpad_machine_spec_transition,(circpad_machine_runtime_t *mi,
* a transition to itself. All non-specified events are ignored.
*/
log_fn(LOG_INFO, LD_CIRC,
- "Circpad machine %d transitioning from %u to %u",
+ "Circuit %u circpad machine %d transitioning from %u to %u",
+ CIRCUIT_IS_ORIGIN(mi->on_circ) ?
+ TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier : 0,
mi->machine_index, mi->current_state, s);
/* If this is not the same state, switch and init tokens,
@@ -1628,7 +1670,7 @@ circpad_estimate_circ_rtt_on_received(circuit_t *circ,
if (CIRCUIT_IS_ORIGIN(circ) || mi->stop_rtt_update)
return;
- /* If we already have a last receieved packet time, that means we
+ /* If we already have a last received packet time, that means we
* did not get a response before this packet. The RTT estimate
* only makes sense if we do not have multiple packets on the
* wire, so stop estimating if this is the second packet
@@ -1660,6 +1702,9 @@ circpad_estimate_circ_rtt_on_received(circuit_t *circ,
}
} else {
const circpad_state_t *state = circpad_machine_current_state(mi);
+ if (BUG(!state)) {
+ return;
+ }
/* Since monotime is unpredictably expensive, only update this field
* if rtt estimates are needed. Otherwise, stop the rtt update. */
@@ -1770,6 +1815,61 @@ circpad_cell_event_nonpadding_sent(circuit_t *on_circ)
} FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END;
}
+/** Check if this cell or circuit are related to circuit padding and handle
+ * them if so. Return 0 if the cell was handled in this subsystem and does
+ * not need any other consideration, otherwise return 1.
+ */
+int
+circpad_check_received_cell(cell_t *cell, circuit_t *circ,
+ crypt_path_t *layer_hint,
+ const relay_header_t *rh)
+{
+ /* First handle the padding commands, since we want to ignore any other
+ * commands if this circuit is padding-specific. */
+ switch (rh->command) {
+ case RELAY_COMMAND_DROP:
+ /* Already examined in circpad_deliver_recognized_relay_cell_events */
+ return 0;
+ case RELAY_COMMAND_PADDING_NEGOTIATE:
+ circpad_handle_padding_negotiate(circ, cell);
+ return 0;
+ case RELAY_COMMAND_PADDING_NEGOTIATED:
+ if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0)
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length);
+ return 0;
+ }
+
+ /* If this is a padding circuit we don't need to parse any other commands
+ * than the padding ones. Just drop them to the floor.
+ *
+ * Note: we deliberately do not call circuit_read_valid_data() here. The
+ * vanguards addon (specifically the 'bandguards' component's dropped cell
+ * detection) will thus close this circuit, as it would for any other
+ * unexpected cell. However, default tor will *not* close the circuit.
+ *
+ * This is intentional. We are not yet certain that is it optimal to keep
+ * padding circuits open in cases like these, rather than closing them.
+ * We suspect that continuing to pad is optimal against a passive classifier,
+ * but as soon as the adversary is active (even as a client adversary) this
+ * might change.
+ *
+ * So as a way forward, we log the cell command and circuit number, to
+ * help us enumerate the most common instances of this in testing with
+ * vanguards, to see which are common enough to verify and handle
+ * properly.
+ * - Mike
+ */
+ if (circ->purpose == CIRCUIT_PURPOSE_C_CIRCUIT_PADDING) {
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Ignored cell (%d) that arrived in padding circuit "
+ " %u.", rh->command, CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0);
+ return 0;
+ }
+
+ return 1;
+}
+
/**
* A "non-padding" cell has been received by this endpoint. React
* according to any padding state machines on the circuit.
@@ -2071,7 +2171,10 @@ circpad_add_matching_machines(origin_circuit_t *on_circ,
if (circpad_negotiate_padding(on_circ, machine->machine_num,
machine->target_hopnum,
CIRCPAD_COMMAND_START) < 0) {
- log_info(LD_CIRC, "Padding not negotiated. Cleaning machine");
+ log_info(LD_CIRC,
+ "Padding not negotiated. Cleaning machine from circuit %u",
+ CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0);
circpad_circuit_machineinfo_free_idx(circ, i);
circ->padding_machine[i] = NULL;
on_circ->padding_negotiation_failed = 1;
@@ -2292,7 +2395,7 @@ circpad_deliver_sent_relay_cell_events(circuit_t *circ,
/* Optimization: The event for RELAY_COMMAND_DROP is sent directly
* from circpad_send_padding_cell_for_callback(). This is to avoid
* putting a cell_t and a relay_header_t on the stack repeatedly
- * if we decide to send a long train of padidng cells back-to-back
+ * if we decide to send a long train of padding cells back-to-back
* with 0 delay. So we do nothing here. */
return;
} else {
@@ -2656,8 +2759,9 @@ circpad_node_supports_padding(const node_t *node)
{
if (node->rs) {
log_fn(LOG_INFO, LD_CIRC, "Checking padding: %s",
- node->rs->pv.supports_padding ? "supported" : "unsupported");
- return node->rs->pv.supports_padding;
+ node->rs->pv.supports_hs_setup_padding ?
+ "supported" : "unsupported");
+ return node->rs->pv.supports_hs_setup_padding;
}
log_fn(LOG_INFO, LD_CIRC, "Empty routerstatus in padding check");
@@ -2734,8 +2838,9 @@ circpad_negotiate_padding(origin_circuit_t *circ,
&type)) < 0)
return -1;
- log_fn(LOG_INFO,LD_CIRC, "Negotiating padding on circuit %u (%d)",
- circ->global_identifier, TO_CIRCUIT(circ)->purpose);
+ log_fn(LOG_INFO,LD_CIRC,
+ "Negotiating padding on circuit %u (%d), command %d",
+ circ->global_identifier, TO_CIRCUIT(circ)->purpose, command);
return circpad_send_command_to_hop(circ, target_hopnum,
RELAY_COMMAND_PADDING_NEGOTIATE,
@@ -2797,22 +2902,28 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
circpad_negotiate_t *negotiate;
if (CIRCUIT_IS_ORIGIN(circ)) {
- log_fn(LOG_WARN, LD_PROTOCOL,
- "Padding negotiate cell unsupported at origin.");
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Padding negotiate cell unsupported at origin (circuit %u)",
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier);
return -1;
}
if (circpad_negotiate_parse(&negotiate, cell->payload+RELAY_HEADER_SIZE,
CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) {
- log_fn(LOG_WARN, LD_CIRC,
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
"Received malformed PADDING_NEGOTIATE cell; dropping.");
return -1;
}
if (negotiate->command == CIRCPAD_COMMAND_STOP) {
/* Free the machine corresponding to this machine type */
- free_circ_machineinfos_with_machine_num(circ, negotiate->machine_type);
- log_fn(LOG_WARN, LD_CIRC,
+ if (free_circ_machineinfos_with_machine_num(circ,
+ negotiate->machine_type)) {
+ log_info(LD_CIRC, "Received STOP command for machine %u",
+ negotiate->machine_type);
+ goto done;
+ }
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
"Received circuit padding stop command for unknown machine.");
goto err;
} else if (negotiate->command == CIRCPAD_COMMAND_START) {
@@ -2853,28 +2964,31 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell,
circpad_negotiated_t *negotiated;
if (!CIRCUIT_IS_ORIGIN(circ)) {
- log_fn(LOG_WARN, LD_PROTOCOL,
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
"Padding negotiated cell unsupported at non-origin.");
return -1;
}
/* Verify this came from the expected hop */
if (!circpad_padding_is_from_expected_hop(circ, layer_hint)) {
- log_fn(LOG_WARN, LD_PROTOCOL,
- "Padding negotiated cell from wrong hop!");
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Padding negotiated cell from wrong hop on circuit %u",
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier);
return -1;
}
if (circpad_negotiated_parse(&negotiated, cell->payload+RELAY_HEADER_SIZE,
CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) < 0) {
- log_fn(LOG_WARN, LD_CIRC,
- "Received malformed PADDING_NEGOTIATED cell; "
- "dropping.");
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Received malformed PADDING_NEGOTIATED cell on circuit %u; "
+ "dropping.", TO_ORIGIN_CIRCUIT(circ)->global_identifier);
return -1;
}
if (negotiated->command == CIRCPAD_COMMAND_STOP) {
- log_info(LD_CIRC, "Received STOP command on PADDING_NEGOTIATED");
+ log_info(LD_CIRC,
+ "Received STOP command on PADDING_NEGOTIATED for circuit %u",
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier);
/* There may not be a padding_info here if we shut down the
* machine in circpad_shutdown_old_machines(). Or, if
* circpad_add_matching_matchines() added a new machine,
@@ -2887,8 +3001,10 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell,
// and be sad
free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type);
TO_ORIGIN_CIRCUIT(circ)->padding_negotiation_failed = 1;
- log_fn(LOG_INFO, LD_CIRC,
- "Middle node did not accept our padding request.");
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Middle node did not accept our padding request on circuit %u (%d)",
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier,
+ circ->purpose);
}
circpad_negotiated_free(negotiated);
diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h
index 3cf40e11db..e9eb32c618 100644
--- a/src/core/or/circuitpadding.h
+++ b/src/core/or/circuitpadding.h
@@ -51,7 +51,7 @@ typedef enum {
CIRCPAD_EVENT_INFINITY = 4,
/* All histogram bins are empty (we are out of tokens) */
CIRCPAD_EVENT_BINS_EMPTY = 5,
- /* just a counter of the events above */
+ /* This state has used up its cell count */
CIRCPAD_EVENT_LENGTH_COUNT = 6
} circpad_event_t;
#define CIRCPAD_NUM_EVENTS ((int)CIRCPAD_EVENT_LENGTH_COUNT+1)
@@ -79,7 +79,7 @@ typedef uint32_t circpad_delay_t;
* An infinite padding cell delay means don't schedule any padding --
* simply wait until a different event triggers a transition.
*
- * This means that the maximum delay we can scedule is UINT32_MAX-1
+ * This means that the maximum delay we can schedule is UINT32_MAX-1
* microseconds, or about 4300 seconds (1.25 hours).
* XXX: Is this enough if we want to simulate light, intermittent
* activity on an onion service?
@@ -106,8 +106,8 @@ typedef uint32_t circpad_delay_t;
*
* If any of these elements is set, then the circuit will be tested against
* that specific condition. If an element is unset, then we don't test it.
- * (E.g. If neither NO_STREAMS or STREAMS are set, then we will not care
- * whether a circuit has streams attached when we apply a state machine)
+ * (E.g., if neither NO_STREAMS or STREAMS are set, then we will not care
+ * whether a circuit has streams attached when we apply a state machine.)
*
* The helper function circpad_circuit_state() converts circuit state
* flags into this more compact representation.
@@ -255,8 +255,9 @@ typedef struct circpad_distribution_t {
typedef uint16_t circpad_statenum_t;
#define CIRCPAD_STATENUM_MAX (UINT16_MAX)
-/** A histogram is used to sample padding delays given a machine state. This
- * constant defines the maximum histogram width (i.e. the max number of bins).
+/** A histogram can be used to sample padding delays given a machine state.
+ * This constant defines the maximum histogram width (i.e. the max number of
+ * bins).
*
* The current limit is arbitrary and could be raised if there is a need,
* however too many bins will be hard to serialize in the future.
@@ -275,10 +276,10 @@ typedef uint16_t circpad_statenum_t;
* happen. The mutable information that gets updated in runtime are carried in
* a circpad_machine_runtime_t.
*
- * This struct describes the histograms and parameters of a single
- * state in the adaptive padding machine. Instances of this struct
- * exist in global circpad machine definitions that come from torrc
- * or the consensus.
+ * This struct describes the histograms and/or probability distributions, as
+ * well as parameters of a single state in the adaptive padding machine.
+ * Instances of this struct exist in global circpad machine definitions that
+ * come from torrc or the consensus.
*/
typedef struct circpad_state_t {
/**
@@ -733,6 +734,10 @@ bool circpad_padding_negotiated(struct circuit_t *circ,
circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose);
+int circpad_check_received_cell(cell_t *cell, circuit_t *circ,
+ crypt_path_t *layer_hint,
+ const relay_header_t *rh);
+
MOCK_DECL(circpad_decision_t,
circpad_machine_schedule_padding,(circpad_machine_runtime_t *));
diff --git a/src/core/or/circuitpadding_machines.c b/src/core/or/circuitpadding_machines.c
index 75d2614aca..7220d657fc 100644
--- a/src/core/or/circuitpadding_machines.c
+++ b/src/core/or/circuitpadding_machines.c
@@ -155,7 +155,6 @@ circpad_machine_relay_hide_intro_circuits(smartlist_t *machines_sl)
relay_machine->name = "relay_ip_circ";
relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
- relay_machine->target_hopnum = 2;
/* This is a relay-side machine */
relay_machine->is_origin_side = 0;
@@ -387,7 +386,6 @@ circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl)
/* Only pad after the circuit has been built and pad to the middle */
relay_machine->conditions.min_hops = 2;
relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
- relay_machine->target_hopnum = 2;
/* This is a relay-side machine */
relay_machine->is_origin_side = 0;
@@ -408,7 +406,7 @@ circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl)
/* OBFUSCATE_CIRC_SETUP -> END transition when we send our first
* padding packet and/or hit the state length (the state length is 1). */
relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
- next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_END;
+ next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_END;
relay_machine->states[CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP].
next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index c08d2a9ff5..091d9c9b09 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -3833,6 +3833,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
if (! bcell.is_begindir) {
/* Steal reference */
+ tor_assert(bcell.address);
address = bcell.address;
port = bcell.port;
diff --git a/src/core/or/or.h b/src/core/or/or.h
index db6d089582..ab258629a6 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -841,8 +841,8 @@ typedef struct protover_summary_flags_t {
unsigned int supports_v3_rendezvous_point: 1;
/** True iff this router has a protocol list that allows clients to
- * negotiate link-level padding. Requires Padding>=1. */
- unsigned int supports_padding : 1;
+ * negotiate hs circuit setup padding. Requires Padding>=2. */
+ unsigned int supports_hs_setup_padding : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h
index 6789668224..8f319585a6 100644
--- a/src/core/or/or_circuit_st.h
+++ b/src/core/or/or_circuit_st.h
@@ -12,6 +12,8 @@
#include "core/or/circuit_st.h"
#include "core/or/crypt_path_st.h"
+#include "lib/evloop/token_bucket.h"
+
struct onion_queue_t;
/** An or_circuit_t holds information needed to implement a circuit at an
@@ -69,6 +71,11 @@ struct or_circuit_t {
* exit-ward queues of this circuit; reset every time when writing
* buffer stats to disk. */
uint64_t total_cell_waiting_time;
+
+ /** INTRODUCE2 cell bucket controlling how much can go on this circuit. Only
+ * used if this is a service introduction circuit at the intro point
+ * (purpose = CIRCUIT_PURPOSE_INTRO_POINT). */
+ token_bucket_ctr_t introduce2_bucket;
};
#endif /* !defined(OR_CIRCUIT_ST_H) */
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index e12919f0a8..ccd33fabf7 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -402,7 +402,7 @@ protover_get_supported_protocols(void)
#endif
"Microdesc=1-2 "
"Relay=1-2 "
- "Padding=1 "
+ "Padding=2 "
"FlowCtrl=1";
}
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index d8e541735f..af45a31aeb 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -28,6 +28,8 @@ struct smartlist_t;
#define PROTOVER_HS_INTRO_V3 4
/** The protover version number that signifies HSv3 rendezvous point support */
#define PROTOVER_HS_RENDEZVOUS_POINT_V3 2
+/** The protover that signals support for HS circuit setup padding machines */
+#define PROTOVER_HS_SETUP_PADDING 2
/** List of recognized subprotocols. */
/// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust`
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 9f90a09699..a437b54792 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -265,8 +265,8 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
if (cell_direction == CELL_DIRECTION_OUT) {
++stats_n_relay_cells_delivered;
log_debug(LD_OR,"Sending away from origin.");
- if ((reason=connection_edge_process_relay_cell(cell, circ, conn, NULL))
- < 0) {
+ reason = connection_edge_process_relay_cell(cell, circ, conn, NULL);
+ if (reason < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"connection_edge_process_relay_cell (away from origin) "
"failed.");
@@ -276,8 +276,9 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
if (cell_direction == CELL_DIRECTION_IN) {
++stats_n_relay_cells_delivered;
log_debug(LD_OR,"Sending to origin.");
- if ((reason = connection_edge_process_relay_cell(cell, circ, conn,
- layer_hint)) < 0) {
+ reason = connection_edge_process_relay_cell(cell, circ, conn,
+ layer_hint);
+ if (reason < 0) {
/* If a client is trying to connect to unknown hidden service port,
* END_CIRC_AT_ORIGIN is sent back so we can then close the circuit.
* Do not log warn as this is an expected behavior for a service. */
@@ -1576,93 +1577,33 @@ process_sendme_cell(const relay_header_t *rh, const cell_t *cell,
return 0;
}
-/** An incoming relay cell has arrived on circuit <b>circ</b>. If
- * <b>conn</b> is NULL this is a control cell, else <b>cell</b> is
- * destined for <b>conn</b>.
- *
- * If <b>layer_hint</b> is defined, then we're the origin of the
- * circuit, and it specifies the hop that packaged <b>cell</b>.
+/** A helper for connection_edge_process_relay_cell(): Actually handles the
+ * cell that we received on the connection.
*
- * Return -reason if you want to warn and tear down the circuit, else 0.
+ * The arguments are the same as in the parent function
+ * connection_edge_process_relay_cell(), plus the relay header <b>rh</b> as
+ * unpacked by the parent function, and <b>optimistic_data</b> as set by the
+ * parent function.
*/
STATIC int
-connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
- edge_connection_t *conn,
- crypt_path_t *layer_hint)
+handle_relay_cell_command(cell_t *cell, circuit_t *circ,
+ edge_connection_t *conn, crypt_path_t *layer_hint,
+ relay_header_t *rh, int optimistic_data)
{
- static int num_seen=0;
- relay_header_t rh;
unsigned domain = layer_hint?LD_APP:LD_EXIT;
int reason;
- int optimistic_data = 0; /* Set to 1 if we receive data on a stream
- * that's in the EXIT_CONN_STATE_RESOLVING
- * or EXIT_CONN_STATE_CONNECTING states. */
-
- tor_assert(cell);
- tor_assert(circ);
-
- relay_header_unpack(&rh, cell->payload);
-// log_fn(LOG_DEBUG,"command %d stream %d", rh.command, rh.stream_id);
- num_seen++;
- log_debug(domain, "Now seen %d relay cells here (command %d, stream %d).",
- num_seen, rh.command, rh.stream_id);
-
- if (rh.length > RELAY_PAYLOAD_SIZE) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Relay cell length field too long. Closing circuit.");
- return - END_CIRC_REASON_TORPROTOCOL;
- }
-
- if (rh.stream_id == 0) {
- switch (rh.command) {
- case RELAY_COMMAND_BEGIN:
- case RELAY_COMMAND_CONNECTED:
- case RELAY_COMMAND_END:
- case RELAY_COMMAND_RESOLVE:
- case RELAY_COMMAND_RESOLVED:
- case RELAY_COMMAND_BEGIN_DIR:
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay command %d with zero "
- "stream_id. Dropping.", (int)rh.command);
- return 0;
- default:
- ;
- }
- }
- /* Tell circpad that we've received a recognized cell */
- circpad_deliver_recognized_relay_cell_events(circ, rh.command, layer_hint);
+ tor_assert(rh);
- /* either conn is NULL, in which case we've got a control cell, or else
- * conn points to the recognized stream. */
- if (conn && !connection_state_is_open(TO_CONN(conn))) {
- if (conn->base_.type == CONN_TYPE_EXIT &&
- (conn->base_.state == EXIT_CONN_STATE_CONNECTING ||
- conn->base_.state == EXIT_CONN_STATE_RESOLVING) &&
- rh.command == RELAY_COMMAND_DATA) {
- /* Allow DATA cells to be delivered to an exit node in state
- * EXIT_CONN_STATE_CONNECTING or EXIT_CONN_STATE_RESOLVING.
- * This speeds up HTTP, for example. */
- optimistic_data = 1;
- } else if (rh.stream_id == 0 && rh.command == RELAY_COMMAND_DATA) {
- log_warn(LD_BUG, "Somehow I had a connection that matched a "
- "data cell with stream ID 0.");
- } else {
- return connection_edge_process_relay_cell_not_open(
- &rh, cell, circ, conn, layer_hint);
- }
+ /* First pass the cell to the circuit padding subsystem, in case it's a
+ * padding cell or circuit that should be handled there. */
+ if (circpad_check_received_cell(cell, circ, layer_hint, rh) == 0) {
+ log_debug(domain, "Cell handled as circuit padding");
+ return 0;
}
- switch (rh.command) {
- case RELAY_COMMAND_DROP:
- /* Already examined in circpad_deliver_recognized_relay_cell_events */
- return 0;
- case RELAY_COMMAND_PADDING_NEGOTIATE:
- circpad_handle_padding_negotiate(circ, cell);
- return 0;
- case RELAY_COMMAND_PADDING_NEGOTIATED:
- if (circpad_handle_padding_negotiated(circ, cell, layer_hint) == 0)
- circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
- return 0;
+ /* Now handle all the other commands */
+ switch (rh->command) {
case RELAY_COMMAND_BEGIN:
case RELAY_COMMAND_BEGIN_DIR:
if (layer_hint &&
@@ -1683,7 +1624,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
"Begin cell for known stream. Dropping.");
return 0;
}
- if (rh.command == RELAY_COMMAND_BEGIN_DIR &&
+ if (rh->command == RELAY_COMMAND_BEGIN_DIR &&
circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) {
/* Assign this circuit and its app-ward OR connection a unique ID,
* so that we can measure download times. The local edge and dir
@@ -1710,7 +1651,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
/* Consider sending a circuit-level SENDME cell. */
sendme_circuit_consider_sending(circ, layer_hint);
- if (rh.stream_id == 0) {
+ if (rh->stream_id == 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay data cell with zero "
"stream_id. Dropping.");
return 0;
@@ -1718,16 +1659,16 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (connection_half_edge_is_valid_data(ocirc->half_streams,
- rh.stream_id)) {
- circuit_read_valid_data(ocirc, rh.length);
+ rh->stream_id)) {
+ circuit_read_valid_data(ocirc, rh->length);
log_info(domain,
"data cell on circ %u valid on half-closed "
- "stream id %d", ocirc->global_identifier, rh.stream_id);
+ "stream id %d", ocirc->global_identifier, rh->stream_id);
}
}
log_info(domain,"data cell dropped, unknown stream (streamid %d).",
- rh.stream_id);
+ rh->stream_id);
return 0;
}
@@ -1742,13 +1683,13 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
return -END_CIRC_REASON_TORPROTOCOL;
}
/* Total all valid application bytes delivered */
- if (CIRCUIT_IS_ORIGIN(circ) && rh.length > 0) {
- circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
+ if (CIRCUIT_IS_ORIGIN(circ) && rh->length > 0) {
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length);
}
- stats_n_data_bytes_received += rh.length;
+ stats_n_data_bytes_received += rh->length;
connection_buf_add((char*)(cell->payload + RELAY_HEADER_SIZE),
- rh.length, TO_CONN(conn));
+ rh->length, TO_CONN(conn));
#ifdef MEASUREMENTS_21206
/* Count number of RELAY_DATA cells received on a linked directory
@@ -1769,20 +1710,20 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
return 0;
case RELAY_COMMAND_END:
- reason = rh.length > 0 ?
+ reason = rh->length > 0 ?
get_uint8(cell->payload+RELAY_HEADER_SIZE) : END_STREAM_REASON_MISC;
if (!conn) {
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (connection_half_edge_is_valid_end(ocirc->half_streams,
- rh.stream_id)) {
+ rh->stream_id)) {
- circuit_read_valid_data(ocirc, rh.length);
+ circuit_read_valid_data(ocirc, rh->length);
log_info(domain,
"end cell (%s) on circ %u valid on half-closed "
"stream id %d",
stream_end_reason_to_string(reason),
- ocirc->global_identifier, rh.stream_id);
+ ocirc->global_identifier, rh->stream_id);
return 0;
}
}
@@ -1814,7 +1755,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
/* Total all valid application bytes delivered */
if (CIRCUIT_IS_ORIGIN(circ)) {
- circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length);
}
}
return 0;
@@ -1822,7 +1763,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
case RELAY_COMMAND_EXTEND2: {
static uint64_t total_n_extend=0, total_nonearly=0;
total_n_extend++;
- if (rh.stream_id) {
+ if (rh->stream_id) {
log_fn(LOG_PROTOCOL_WARN, domain,
"'extend' cell received for non-zero stream. Dropping.");
return 0;
@@ -1863,9 +1804,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
log_debug(domain,"Got an extended cell! Yay.");
{
extended_cell_t extended_cell;
- if (extended_cell_parse(&extended_cell, rh.command,
+ if (extended_cell_parse(&extended_cell, rh->command,
(const uint8_t*)cell->payload+RELAY_HEADER_SIZE,
- rh.length)<0) {
+ rh->length)<0) {
log_warn(LD_PROTOCOL,
"Can't parse EXTENDED cell; killing circuit.");
return -END_CIRC_REASON_TORPROTOCOL;
@@ -1883,7 +1824,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
}
/* Total all valid bytes delivered. */
if (CIRCUIT_IS_ORIGIN(circ)) {
- circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh.length);
+ circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ), rh->length);
}
return 0;
case RELAY_COMMAND_TRUNCATE:
@@ -1927,7 +1868,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
* circuit is being torn down anyway, though. */
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_read_valid_data(TO_ORIGIN_CIRCUIT(circ),
- rh.length);
+ rh->length);
}
circuit_truncated(TO_ORIGIN_CIRCUIT(circ),
get_uint8(cell->payload + RELAY_HEADER_SIZE));
@@ -1942,11 +1883,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (connection_half_edge_is_valid_connected(ocirc->half_streams,
- rh.stream_id)) {
- circuit_read_valid_data(ocirc, rh.length);
+ rh->stream_id)) {
+ circuit_read_valid_data(ocirc, rh->length);
log_info(domain,
"connected cell on circ %u valid on half-closed "
- "stream id %d", ocirc->global_identifier, rh.stream_id);
+ "stream id %d", ocirc->global_identifier, rh->stream_id);
return 0;
}
}
@@ -1954,10 +1895,10 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
log_info(domain,
"'connected' received on circid %u for streamid %d, "
"no conn attached anymore. Ignoring.",
- (unsigned)circ->n_circ_id, rh.stream_id);
+ (unsigned)circ->n_circ_id, rh->stream_id);
return 0;
case RELAY_COMMAND_SENDME:
- return process_sendme_cell(&rh, cell, circ, conn, layer_hint, domain);
+ return process_sendme_cell(rh, cell, circ, conn, layer_hint, domain);
case RELAY_COMMAND_RESOLVE:
if (layer_hint) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
@@ -1985,11 +1926,11 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (CIRCUIT_IS_ORIGIN(circ)) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (connection_half_edge_is_valid_resolved(ocirc->half_streams,
- rh.stream_id)) {
- circuit_read_valid_data(ocirc, rh.length);
+ rh->stream_id)) {
+ circuit_read_valid_data(ocirc, rh->length);
log_info(domain,
"resolved cell on circ %u valid on half-closed "
- "stream id %d", ocirc->global_identifier, rh.stream_id);
+ "stream id %d", ocirc->global_identifier, rh->stream_id);
return 0;
}
}
@@ -2007,17 +1948,96 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
case RELAY_COMMAND_INTRO_ESTABLISHED:
case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
rend_process_relay_cell(circ, layer_hint,
- rh.command, rh.length,
+ rh->command, rh->length,
cell->payload+RELAY_HEADER_SIZE);
return 0;
}
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received unknown relay command %d. Perhaps the other side is using "
"a newer version of Tor? Dropping.",
- rh.command);
+ rh->command);
return 0; /* for forward compatibility, don't kill the circuit */
}
+/** An incoming relay cell has arrived on circuit <b>circ</b>. If
+ * <b>conn</b> is NULL this is a control cell, else <b>cell</b> is
+ * destined for <b>conn</b>.
+ *
+ * If <b>layer_hint</b> is defined, then we're the origin of the
+ * circuit, and it specifies the hop that packaged <b>cell</b>.
+ *
+ * Return -reason if you want to warn and tear down the circuit, else 0.
+ */
+STATIC int
+connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
+ edge_connection_t *conn,
+ crypt_path_t *layer_hint)
+{
+ static int num_seen=0;
+ relay_header_t rh;
+ unsigned domain = layer_hint?LD_APP:LD_EXIT;
+ int optimistic_data = 0; /* Set to 1 if we receive data on a stream
+ * that's in the EXIT_CONN_STATE_RESOLVING
+ * or EXIT_CONN_STATE_CONNECTING states. */
+
+ tor_assert(cell);
+ tor_assert(circ);
+
+ relay_header_unpack(&rh, cell->payload);
+// log_fn(LOG_DEBUG,"command %d stream %d", rh.command, rh.stream_id);
+ num_seen++;
+ log_debug(domain, "Now seen %d relay cells here (command %d, stream %d).",
+ num_seen, rh.command, rh.stream_id);
+
+ if (rh.length > RELAY_PAYLOAD_SIZE) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Relay cell length field too long. Closing circuit.");
+ return - END_CIRC_REASON_TORPROTOCOL;
+ }
+
+ if (rh.stream_id == 0) {
+ switch (rh.command) {
+ case RELAY_COMMAND_BEGIN:
+ case RELAY_COMMAND_CONNECTED:
+ case RELAY_COMMAND_END:
+ case RELAY_COMMAND_RESOLVE:
+ case RELAY_COMMAND_RESOLVED:
+ case RELAY_COMMAND_BEGIN_DIR:
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay command %d with zero "
+ "stream_id. Dropping.", (int)rh.command);
+ return 0;
+ default:
+ ;
+ }
+ }
+
+ /* Tell circpad that we've received a recognized cell */
+ circpad_deliver_recognized_relay_cell_events(circ, rh.command, layer_hint);
+
+ /* either conn is NULL, in which case we've got a control cell, or else
+ * conn points to the recognized stream. */
+ if (conn && !connection_state_is_open(TO_CONN(conn))) {
+ if (conn->base_.type == CONN_TYPE_EXIT &&
+ (conn->base_.state == EXIT_CONN_STATE_CONNECTING ||
+ conn->base_.state == EXIT_CONN_STATE_RESOLVING) &&
+ rh.command == RELAY_COMMAND_DATA) {
+ /* Allow DATA cells to be delivered to an exit node in state
+ * EXIT_CONN_STATE_CONNECTING or EXIT_CONN_STATE_RESOLVING.
+ * This speeds up HTTP, for example. */
+ optimistic_data = 1;
+ } else if (rh.stream_id == 0 && rh.command == RELAY_COMMAND_DATA) {
+ log_warn(LD_BUG, "Somehow I had a connection that matched a "
+ "data cell with stream ID 0.");
+ } else {
+ return connection_edge_process_relay_cell_not_open(
+ &rh, cell, circ, conn, layer_hint);
+ }
+ }
+
+ return handle_relay_cell_command(cell, circ, conn, layer_hint,
+ &rh, optimistic_data);
+}
+
/** How many relay_data cells have we built, ever? */
uint64_t stats_n_data_cells_packaged = 0;
/** How many bytes of data have we put in relay_data cells have we built,
diff --git a/src/core/or/relay.h b/src/core/or/relay.h
index 79036f97bd..99f7553013 100644
--- a/src/core/or/relay.h
+++ b/src/core/or/relay.h
@@ -99,6 +99,11 @@ circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids);
uint8_t packed_cell_get_command(const packed_cell_t *cell, int wide_circ_ids);
#ifdef RELAY_PRIVATE
+STATIC int
+handle_relay_cell_command(cell_t *cell, circuit_t *circ,
+ edge_connection_t *conn, crypt_path_t *layer_hint,
+ relay_header_t *rh, int optimistic_data);
+
STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
tor_addr_t *addr_out, int *ttl_out);
/** An address-and-ttl tuple as yielded by resolved_cell_parse */
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 2a572d4704..06417bb4eb 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -448,8 +448,9 @@ memoize_protover_summary(protover_summary_flags_t *out,
out->supports_v3_rendezvous_point =
protocol_list_supports_protocol(protocols, PRT_HSREND,
PROTOVER_HS_RENDEZVOUS_POINT_V3);
- out->supports_padding =
- protocol_list_supports_protocol(protocols, PRT_PADDING, 1);
+ out->supports_hs_setup_padding =
+ protocol_list_supports_protocol(protocols, PRT_PADDING,
+ PROTOVER_HS_SETUP_PADDING);
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
cached = strmap_set(protover_summary_map, protocols, new_cached);
diff --git a/src/ext/csiphash.c b/src/ext/csiphash.c
index af8559a476..faa52ae4e1 100644
--- a/src/ext/csiphash.c
+++ b/src/ext/csiphash.c
@@ -87,6 +87,13 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *k
v0 ^= mi;
}
+#ifdef __COVERITY__
+ {
+ uint64_t mi = 0;
+ memcpy(&mi, m+i, (src_sz-blocks));
+ last7 = _le64toh(mi) | (uint64_t)(src_sz & 0xff) << 56;
+ }
+#else
switch (src_sz - blocks) {
case 7: last7 |= (uint64_t)m[i + 6] << 48; /* Falls through. */
case 6: last7 |= (uint64_t)m[i + 5] << 40; /* Falls through. */
@@ -98,6 +105,7 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *k
case 0:
default:;
}
+#endif
v3 ^= last7;
DOUBLE_ROUND(v0,v1,v2,v3);
v0 ^= last7;
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 4afcee2021..54a9238d8f 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -2611,6 +2611,10 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs,
entry_guard_t *guard = entry_guard_handle_get(state->guard);
if (!guard || guard->in_selection != gs)
continue;
+ if (TO_CIRCUIT(circ)->marked_for_close) {
+ /* Don't consider any marked for close circuits. */
+ continue;
+ }
smartlist_add(all_circuits, circ);
} SMARTLIST_FOREACH_END(circ);
diff --git a/src/feature/control/control_auth.c b/src/feature/control/control_auth.c
index 49d4d415c6..a574d07b33 100644
--- a/src/feature/control/control_auth.c
+++ b/src/feature/control/control_auth.c
@@ -151,12 +151,8 @@ handle_control_authchallenge(control_connection_t *conn,
goto fail;
}
if (args->kwargs == NULL || args->kwargs->next != NULL) {
- /* connection_write_str_to_buf("512 AUTHCHALLENGE requires exactly "
- "2 arguments.\r\n", conn);
- */
- control_printf_endreply(conn, 512,
- "AUTHCHALLENGE dislikes argument list %s",
- escaped(args->raw_body));
+ control_write_endreply(conn, 512,
+ "Wrong number of arguments for AUTHCHALLENGE");
goto fail;
}
if (strcmp(args->kwargs->key, "")) {
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index abb579bd43..ad4a4ef0af 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -703,9 +703,8 @@ handle_control_mapaddress(control_connection_t *conn,
connection_buf_add(r, sz, TO_CONN(conn));
tor_free(r);
} else {
- const char *response =
- "512 syntax error: not enough arguments to mapaddress.\r\n";
- connection_buf_add(response, strlen(response), TO_CONN(conn));
+ control_write_endreply(conn, 512, "syntax error: "
+ "not enough arguments to mapaddress.");
}
SMARTLIST_FOREACH(reply, char *, cp, tor_free(cp));
@@ -845,7 +844,7 @@ handle_control_extendcircuit(control_connection_t *conn,
"addresses that are allowed by the firewall configuration; "
"circuit marked for closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), -END_CIRC_REASON_CONNECTFAILED);
- connection_write_str_to_buf("551 Couldn't start circuit\r\n", conn);
+ control_write_endreply(conn, 551, "Couldn't start circuit");
goto done;
}
circuit_append_new_exit(circ, info);
@@ -1744,16 +1743,10 @@ handle_control_add_onion(control_connection_t *conn,
goto out;
} else if (!strcasecmp(arg->key, "ClientAuth")) {
- char *err_msg = NULL;
int created = 0;
rend_authorized_client_t *client =
- add_onion_helper_clientauth(arg->value,
- &created, &err_msg);
+ add_onion_helper_clientauth(arg->value, &created, conn);
if (!client) {
- if (err_msg) {
- connection_write_str_to_buf(err_msg, conn);
- tor_free(err_msg);
- }
goto out;
}
@@ -1818,19 +1811,13 @@ handle_control_add_onion(control_connection_t *conn,
add_onion_secret_key_t pk = { NULL };
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
- char *err_msg = NULL;
const char *onionkey = smartlist_get(args->args, 0);
if (add_onion_helper_keyarg(onionkey, discard_pk,
&key_new_alg, &key_new_blob, &pk, &hs_version,
- &err_msg) < 0) {
- if (err_msg) {
- connection_write_str_to_buf(err_msg, conn);
- tor_free(err_msg);
- }
+ conn) < 0) {
goto out;
}
- tor_assert(!err_msg);
/* Hidden service version 3 don't have client authentication support so if
* ClientAuth was given, send back an error. */
@@ -1876,8 +1863,8 @@ handle_control_add_onion(control_connection_t *conn,
char *encoded = rend_auth_encode_cookie(ac->descriptor_cookie,
auth_type);
tor_assert(encoded);
- connection_printf_to_buf(conn, "250-ClientAuth=%s:%s\r\n",
- ac->client_name, encoded);
+ control_printf_midreply(conn, 250, "ClientAuth=%s:%s",
+ ac->client_name, encoded);
memwipe(encoded, 0, strlen(encoded));
tor_free(encoded);
});
@@ -1930,27 +1917,30 @@ handle_control_add_onion(control_connection_t *conn,
* ADD_ONION command. Return a new crypto_pk_t and if a new key was generated
* and the private key not discarded, the algorithm and serialized private key,
* or NULL and an optional control protocol error message on failure. The
- * caller is responsible for freeing the returned key_new_blob and err_msg.
+ * caller is responsible for freeing the returned key_new_blob.
*
* Note: The error messages returned are deliberately vague to avoid echoing
* key material.
+ *
+ * Note: conn is only used for writing control replies. For testing
+ * purposes, it can be NULL if control_write_reply() is appropriately
+ * mocked.
*/
STATIC int
add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out, char **key_new_blob_out,
add_onion_secret_key_t *decoded_key, int *hs_version,
- char **err_msg_out)
+ control_connection_t *conn)
{
smartlist_t *key_args = smartlist_new();
crypto_pk_t *pk = NULL;
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
- char *err_msg = NULL;
int ret = -1;
smartlist_split_string(key_args, arg, ":", SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(key_args) != 2) {
- err_msg = tor_strdup("512 Invalid key type/blob\r\n");
+ control_write_endreply(conn, 512, "Invalid key type/blob");
goto err;
}
@@ -1967,12 +1957,12 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
/* "RSA:<Base64 Blob>" - Loading a pre-existing RSA1024 key. */
pk = crypto_pk_base64_decode_private(key_blob, strlen(key_blob));
if (!pk) {
- err_msg = tor_strdup("512 Failed to decode RSA key\r\n");
+ control_write_endreply(conn, 512, "Failed to decode RSA key");
goto err;
}
if (crypto_pk_num_bits(pk) != PK_BYTES*8) {
crypto_pk_free(pk);
- err_msg = tor_strdup("512 Invalid RSA key size\r\n");
+ control_write_endreply(conn, 512, "Invalid RSA key size");
goto err;
}
decoded_key->v2 = pk;
@@ -1983,7 +1973,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob,
strlen(key_blob)) != sizeof(sk->seckey)) {
tor_free(sk);
- err_msg = tor_strdup("512 Failed to decode ED25519-V3 key\r\n");
+ control_write_endreply(conn, 512, "Failed to decode ED25519-V3 key");
goto err;
}
decoded_key->v3 = sk;
@@ -1995,15 +1985,15 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
/* "RSA1024", RSA 1024 bit, also currently "BEST" by default. */
pk = crypto_pk_new();
if (crypto_pk_generate_key(pk)) {
- tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n",
- key_type_rsa1024);
+ control_printf_endreply(conn, 551, "Failed to generate %s key",
+ key_type_rsa1024);
goto err;
}
if (!discard_pk) {
if (crypto_pk_base64_encode_private(pk, &key_new_blob)) {
crypto_pk_free(pk);
- tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
- key_type_rsa1024);
+ control_printf_endreply(conn, 551, "Failed to encode %s key",
+ key_type_rsa1024);
goto err;
}
key_new_alg = key_type_rsa1024;
@@ -2014,8 +2004,8 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
if (ed25519_secret_key_generate(sk, 1) < 0) {
tor_free(sk);
- tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n",
- key_type_ed25519_v3);
+ control_printf_endreply(conn, 551, "Failed to generate %s key",
+ key_type_ed25519_v3);
goto err;
}
if (!discard_pk) {
@@ -2025,8 +2015,8 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
sizeof(sk->seckey), 0) != (len - 1)) {
tor_free(sk);
tor_free(key_new_blob);
- tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
- key_type_ed25519_v3);
+ control_printf_endreply(conn, 551, "Failed to encode %s key",
+ key_type_ed25519_v3);
goto err;
}
key_new_alg = key_type_ed25519_v3;
@@ -2034,11 +2024,11 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
decoded_key->v3 = sk;
*hs_version = HS_VERSION_THREE;
} else {
- err_msg = tor_strdup("513 Invalid key type\r\n");
+ control_write_endreply(conn, 513, "Invalid key type");
goto err;
}
} else {
- err_msg = tor_strdup("513 Invalid key type\r\n");
+ control_write_endreply(conn, 513, "Invalid key type");
goto err;
}
@@ -2052,11 +2042,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
});
smartlist_free(key_args);
- if (err_msg_out) {
- *err_msg_out = err_msg;
- } else {
- tor_free(err_msg);
- }
*key_new_alg_out = key_new_alg;
*key_new_blob_out = key_new_blob;
@@ -2066,27 +2051,30 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
/** Helper function to handle parsing a ClientAuth argument to the
* ADD_ONION command. Return a new rend_authorized_client_t, or NULL
* and an optional control protocol error message on failure. The
- * caller is responsible for freeing the returned auth_client and err_msg.
+ * caller is responsible for freeing the returned auth_client.
*
* If 'created' is specified, it will be set to 1 when a new cookie has
* been generated.
+ *
+ * Note: conn is only used for writing control replies. For testing
+ * purposes, it can be NULL if control_write_reply() is appropriately
+ * mocked.
*/
STATIC rend_authorized_client_t *
-add_onion_helper_clientauth(const char *arg, int *created, char **err_msg)
+add_onion_helper_clientauth(const char *arg, int *created,
+ control_connection_t *conn)
{
int ok = 0;
tor_assert(arg);
tor_assert(created);
- tor_assert(err_msg);
- *err_msg = NULL;
smartlist_t *auth_args = smartlist_new();
rend_authorized_client_t *client =
tor_malloc_zero(sizeof(rend_authorized_client_t));
smartlist_split_string(auth_args, arg, ":", 0, 0);
if (smartlist_len(auth_args) < 1 || smartlist_len(auth_args) > 2) {
- *err_msg = tor_strdup("512 Invalid ClientAuth syntax\r\n");
+ control_write_endreply(conn, 512, "Invalid ClientAuth syntax");
goto err;
}
client->client_name = tor_strdup(smartlist_get(auth_args, 0));
@@ -2096,7 +2084,7 @@ add_onion_helper_clientauth(const char *arg, int *created, char **err_msg)
client->descriptor_cookie,
NULL, &decode_err_msg) < 0) {
tor_assert(decode_err_msg);
- tor_asprintf(err_msg, "512 %s\r\n", decode_err_msg);
+ control_write_endreply(conn, 512, decode_err_msg);
tor_free(decode_err_msg);
goto err;
}
@@ -2107,7 +2095,7 @@ add_onion_helper_clientauth(const char *arg, int *created, char **err_msg)
}
if (!rend_valid_client_name(client->client_name)) {
- *err_msg = tor_strdup("512 Invalid name in ClientAuth\r\n");
+ control_write_endreply(conn, 512, "Invalid name in ClientAuth");
goto err;
}
diff --git a/src/feature/control/control_cmd.h b/src/feature/control/control_cmd.h
index 5c3d1a1cec..4b6d54abe7 100644
--- a/src/feature/control/control_cmd.h
+++ b/src/feature/control/control_cmd.h
@@ -91,10 +91,11 @@ STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out,
char **key_new_blob_out,
add_onion_secret_key_t *decoded_key,
- int *hs_version, char **err_msg_out);
+ int *hs_version,
+ control_connection_t *conn);
STATIC rend_authorized_client_t *add_onion_helper_clientauth(const char *arg,
- int *created, char **err_msg_out);
+ int *created, control_connection_t *conn);
STATIC control_cmd_args_t *control_cmd_parse_args(
const char *command,
diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c
index e596a8aee2..9e0966ca54 100644
--- a/src/feature/control/control_events.c
+++ b/src/feature/control/control_events.c
@@ -1287,7 +1287,7 @@ enable_control_logging(void)
/** We got a log message: tell any interested control connections. */
void
-control_event_logmsg(int severity, uint32_t domain, const char *msg)
+control_event_logmsg(int severity, log_domain_mask_t domain, const char *msg)
{
int event;
diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h
index 0bdbb9cfd2..34986fdb89 100644
--- a/src/feature/control/control_events.h
+++ b/src/feature/control/control_events.h
@@ -128,7 +128,8 @@ int control_event_circ_bandwidth_used_for_circ(origin_circuit_t *ocirc);
int control_event_conn_bandwidth(connection_t *conn);
int control_event_conn_bandwidth_used(void);
int control_event_circuit_cell_stats(void);
-void control_event_logmsg(int severity, uint32_t domain, const char *msg);
+void control_event_logmsg(int severity, log_domain_mask_t domain,
+ const char *msg);
void control_event_logmsg_pending(void);
int control_event_descriptors_changed(smartlist_t *routers);
int control_event_address_mapped(const char *from, const char *to,
diff --git a/src/feature/control/control_proto.c b/src/feature/control/control_proto.c
index 1dd62da2be..d2541e7308 100644
--- a/src/feature/control/control_proto.c
+++ b/src/feature/control/control_proto.c
@@ -176,8 +176,9 @@ send_control_done(control_connection_t *conn)
* @param c separator character, usually ' ', '-', or '+'
* @param s string
*/
-void
-control_write_reply(control_connection_t *conn, int code, int c, const char *s)
+MOCK_IMPL(void,
+control_write_reply, (control_connection_t *conn, int code, int c,
+ const char *s))
{
connection_printf_to_buf(conn, "%03d%c%s\r\n", code, c, s);
}
diff --git a/src/feature/control/control_proto.h b/src/feature/control/control_proto.h
index 101b808d88..3182f3d415 100644
--- a/src/feature/control/control_proto.h
+++ b/src/feature/control/control_proto.h
@@ -21,8 +21,8 @@ size_t write_escaped_data(const char *data, size_t len, char **out);
size_t read_escaped_data(const char *data, size_t len, char **out);
void send_control_done(control_connection_t *conn);
-void control_write_reply(control_connection_t *conn, int code, int c,
- const char *s);
+MOCK_DECL(void, control_write_reply, (control_connection_t *conn, int code,
+ int c, const char *s));
void control_vprintf_reply(control_connection_t *conn, int code, int c,
const char *fmt, va_list ap)
CHECK_PRINTF(4, 0);
diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c
index 667feb2c03..3ca2c3ef91 100644
--- a/src/feature/dirauth/keypin.c
+++ b/src/feature/dirauth/keypin.c
@@ -438,7 +438,7 @@ keypin_load_journal_impl(const char *data, size_t size)
tor_log(severity, LD_DIRSERV,
"Loaded %d entries from keypin journal. "
"Found %d corrupt lines (ignored), %d duplicates (harmless), "
- "and %d conflicts (resolved in favor or more recent entry).",
+ "and %d conflicts (resolved in favor of more recent entry).",
n_entries, n_corrupt_lines, n_duplicates, n_conflicts);
return 0;
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index 1b36f716f4..7c6af3582b 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -1390,8 +1390,9 @@ handle_get_hs_descriptor_v3(dir_connection_t *conn,
const char *pubkey_str = NULL;
const char *url = args->url;
- /* Reject unencrypted dir connections */
- if (!connection_dir_is_encrypted(conn)) {
+ /* Reject non anonymous dir connections (which also tests if encrypted). We
+ * do not allow single hop clients to query an HSDir. */
+ if (!connection_dir_is_anonymous(conn)) {
write_short_http_response(conn, 404, "Not found");
goto done;
}
@@ -1632,10 +1633,10 @@ directory_handle_command_post,(dir_connection_t *conn, const char *headers,
goto done;
}
- /* Handle HS descriptor publish request. */
- /* XXX: This should be disabled with a consensus param until we want to
- * the prop224 be deployed and thus use. */
- if (connection_dir_is_encrypted(conn) && !strcmpstart(url, "/tor/hs/")) {
+ /* Handle HS descriptor publish request. We force an anonymous connection
+ * (which also tests for encrypted). We do not allow single-hop client to
+ * post a descriptor onto an HSDir. */
+ if (connection_dir_is_anonymous(conn) && !strcmpstart(url, "/tor/hs/")) {
const char *msg = "HS descriptor stored successfully.";
/* We most probably have a publish request for an HS descriptor. */
diff --git a/src/feature/dircommon/directory.c b/src/feature/dircommon/directory.c
index 9e6f72e9ac..b3db0aa108 100644
--- a/src/feature/dircommon/directory.c
+++ b/src/feature/dircommon/directory.c
@@ -7,6 +7,10 @@
#include "app/config/config.h"
#include "core/mainloop/connection.h"
+#include "core/or/circuitlist.h"
+#include "core/or/connection_edge.h"
+#include "core/or/connection_or.h"
+#include "core/or/channeltls.h"
#include "feature/dircache/dircache.h"
#include "feature/dircache/dirserv.h"
#include "feature/dirclient/dirclient.h"
@@ -15,6 +19,10 @@
#include "feature/stats/geoip_stats.h"
#include "lib/compress/compress.h"
+#include "core/or/circuit_st.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/edge_connection_st.h"
+#include "core/or/or_connection_st.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/nodelist/routerinfo_st.h"
@@ -167,6 +175,67 @@ connection_dir_is_encrypted(const dir_connection_t *conn)
return TO_CONN(conn)->linked;
}
+/** Return true iff the given directory connection <b>dir_conn</b> is
+ * anonymous, that is, it is on a circuit via a public relay and not directly
+ * from a client or bridge.
+ *
+ * For client circuits via relays: true for 2-hop+ paths.
+ * For client circuits via bridges: true for 3-hop+ paths.
+ *
+ * This first test if the connection is encrypted since it is a strong
+ * requirement for anonymity. */
+bool
+connection_dir_is_anonymous(const dir_connection_t *dir_conn)
+{
+ const connection_t *conn, *linked_conn;
+ const edge_connection_t *edge_conn;
+ const circuit_t *circ;
+
+ tor_assert(dir_conn);
+
+ if (!connection_dir_is_encrypted(dir_conn)) {
+ return false;
+ }
+
+ /*
+ * Buckle up, we'll do a deep dive into the connection in order to get the
+ * final connection channel of that connection in order to figure out if
+ * this is a client or relay link.
+ *
+ * We go: dir_conn -> linked_conn -> edge_conn -> on_circuit -> p_chan.
+ */
+
+ conn = TO_CONN(dir_conn);
+ linked_conn = conn->linked_conn;
+
+ /* The dir connection should be connected to an edge connection. It can not
+ * be closed or marked for close. */
+ if (linked_conn == NULL || linked_conn->magic != EDGE_CONNECTION_MAGIC ||
+ conn->linked_conn_is_closed || conn->linked_conn->marked_for_close) {
+ log_info(LD_DIR, "Rejected HSDir request: not linked to edge");
+ return false;
+ }
+
+ edge_conn = TO_EDGE_CONN((connection_t *) linked_conn);
+ circ = edge_conn->on_circuit;
+
+ /* Can't be a circuit we initiated and without a circuit, no channel. */
+ if (circ == NULL || CIRCUIT_IS_ORIGIN(circ)) {
+ log_info(LD_DIR, "Rejected HSDir request: not on OR circuit");
+ return false;
+ }
+
+ /* Get the previous channel to learn if it is a client or relay link. */
+ if (BUG(CONST_TO_OR_CIRCUIT(circ)->p_chan == NULL)) {
+ log_info(LD_DIR, "Rejected HSDir request: no p_chan");
+ return false;
+ }
+
+ /* Will be true if the channel is an unauthenticated peer which is only true
+ * for clients and bridges. */
+ return !channel_is_client(CONST_TO_OR_CIRCUIT(circ)->p_chan);
+}
+
/** Parse an HTTP request line at the start of a headers string. On failure,
* return -1. On success, set *<b>command_out</b> to a copy of the HTTP
* command ("get", "post", etc), set *<b>url_out</b> to a copy of the URL, and
diff --git a/src/feature/dircommon/directory.h b/src/feature/dircommon/directory.h
index ba3f8c1b0e..4fc743ad3d 100644
--- a/src/feature/dircommon/directory.h
+++ b/src/feature/dircommon/directory.h
@@ -94,6 +94,7 @@ int parse_http_command(const char *headers,
char *http_get_header(const char *headers, const char *which);
int connection_dir_is_encrypted(const dir_connection_t *conn);
+bool connection_dir_is_anonymous(const dir_connection_t *conn);
int connection_dir_reached_eof(dir_connection_t *conn);
int connection_dir_process_inbuf(dir_connection_t *conn);
int connection_dir_finished_flushing(dir_connection_t *conn);
diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c
index 05f9940ae6..9817113b23 100644
--- a/src/feature/hs/hs_cache.c
+++ b/src/feature/hs/hs_cache.c
@@ -710,6 +710,11 @@ cache_clean_v3_as_client(time_t now)
MAP_DEL_CURRENT(key);
entry_size = cache_get_client_entry_size(entry);
bytes_removed += entry_size;
+ /* We just removed an old descriptor. We need to close all intro circuits
+ * so we don't have leftovers that can be selected while lacking a
+ * descriptor. We leave the rendezvous circuits opened because they could
+ * be in use. */
+ hs_client_close_intro_circuits_from_desc(entry->desc);
/* Entry is not in the cache anymore, destroy it. */
cache_client_desc_free(entry);
/* Update our OOM. We didn't use the remove() function because we are in
diff --git a/src/feature/hs/hs_circuitmap.c b/src/feature/hs/hs_circuitmap.c
index 5480d5eb84..e34f564fb4 100644
--- a/src/feature/hs/hs_circuitmap.c
+++ b/src/feature/hs/hs_circuitmap.c
@@ -272,6 +272,33 @@ hs_circuitmap_get_or_circuit(hs_token_type_t type,
/**** Public relay-side getters: */
+/* Public function: Return v2 and v3 introduction circuit to this relay.
+ * Always return a newly allocated list for which it is the caller's
+ * responsability to free it. */
+smartlist_t *
+hs_circuitmap_get_all_intro_circ_relay_side(void)
+{
+ circuit_t **iter;
+ smartlist_t *circuit_list = smartlist_new();
+
+ HT_FOREACH(iter, hs_circuitmap_ht, the_hs_circuitmap) {
+ circuit_t *circ = *iter;
+
+ /* An origin circuit or purpose is wrong or the hs token is not set to be
+ * a v2 or v3 intro relay side type, we ignore the circuit. Else, we have
+ * a match so add it to our list. */
+ if (CIRCUIT_IS_ORIGIN(circ) ||
+ circ->purpose != CIRCUIT_PURPOSE_INTRO_POINT ||
+ (circ->hs_token->type != HS_TOKEN_INTRO_V3_RELAY_SIDE &&
+ circ->hs_token->type != HS_TOKEN_INTRO_V2_RELAY_SIDE)) {
+ continue;
+ }
+ smartlist_add(circuit_list, circ);
+ }
+
+ return circuit_list;
+}
+
/* Public function: Return a v3 introduction circuit to this relay with
* <b>auth_key</b>. Return NULL if no such circuit is found in the
* circuitmap. */
diff --git a/src/feature/hs/hs_circuitmap.h b/src/feature/hs/hs_circuitmap.h
index c1bbb1ff1c..eac8230bbf 100644
--- a/src/feature/hs/hs_circuitmap.h
+++ b/src/feature/hs/hs_circuitmap.h
@@ -34,6 +34,8 @@ void hs_circuitmap_register_intro_circ_v2_relay_side(struct or_circuit_t *circ,
void hs_circuitmap_register_intro_circ_v3_relay_side(struct or_circuit_t *circ,
const ed25519_public_key_t *auth_key);
+smartlist_t *hs_circuitmap_get_all_intro_circ_relay_side(void);
+
/** Public service-side API: */
struct origin_circuit_t *
diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index a5747fe170..8661ce046a 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -21,6 +21,7 @@
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_dos.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_service.h"
#include "feature/hs_common/shared_random_client.h"
@@ -30,6 +31,7 @@
#include "feature/nodelist/routerset.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendservice.h"
+#include "feature/relay/routermode.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c
new file mode 100644
index 0000000000..a4586dd700
--- /dev/null
+++ b/src/feature/hs/hs_dos.c
@@ -0,0 +1,188 @@
+/* Copyright (c) 2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_dos.c
+ * \brief Implement denial of service mitigation for the onion service
+ * subsystem.
+ *
+ * This module defenses:
+ *
+ * - Introduction Rate Limiting: If enabled by the consensus, an introduction
+ * point will rate limit client introduction towards the service (INTRODUCE2
+ * cells). It uses a token bucket model with a rate and burst per second.
+ *
+ * Proposal 305 will expand this module by allowing an operator to define
+ * these values into the ESTABLISH_INTRO cell. Not yet implemented.
+ **/
+
+#define HS_DOS_PRIVATE
+
+#include "core/or/or.h"
+#include "app/config/config.h"
+
+#include "core/or/circuitlist.h"
+
+#include "feature/hs/hs_circuitmap.h"
+#include "feature/nodelist/networkstatus.h"
+#include "feature/relay/routermode.h"
+
+#include "lib/evloop/token_bucket.h"
+
+#include "hs_dos.h"
+
+/* Default value of the allowed INTRODUCE2 cell rate per second. Above that
+ * value per second, the introduction is denied. */
+#define HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC 25
+
+/* Default value of the allowed INTRODUCE2 cell burst per second. This is the
+ * maximum value a token bucket has per second. We thus allow up to this value
+ * of INTRODUCE2 cell per second but the bucket is refilled by the rate value
+ * but never goes above that burst value. */
+#define HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC 200
+
+/* Default value of the consensus parameter enabling or disabling the
+ * introduction DoS defense. Disabled by default. */
+#define HS_DOS_INTRODUCE_ENABLED_DEFAULT 0
+
+/* Consensus parameters. */
+static uint32_t hs_dos_introduce_rate_per_sec =
+ HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC;
+static uint32_t hs_dos_introduce_burst_per_sec =
+ HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC;
+static uint32_t hs_dos_introduce_enabled =
+ HS_DOS_INTRODUCE_ENABLED_DEFAULT;
+
+static uint32_t
+get_param_intro_dos_enabled(const networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSDefense",
+ HS_DOS_INTRODUCE_ENABLED_DEFAULT, 0, 1);
+}
+
+/* Return the parameter for the introduction rate per sec. */
+static uint32_t
+get_param_rate_per_sec(const networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSRatePerSec",
+ HS_DOS_INTRODUCE_DEFAULT_CELL_RATE_PER_SEC,
+ 0, INT32_MAX);
+}
+
+/* Return the parameter for the introduction burst per sec. */
+static uint32_t
+get_param_burst_per_sec(const networkstatus_t *ns)
+{
+ return networkstatus_get_param(ns, "HiddenServiceEnableIntroDoSBurstPerSec",
+ HS_DOS_INTRODUCE_DEFAULT_CELL_BURST_PER_SEC,
+ 0, INT32_MAX);
+}
+
+/* Go over all introduction circuit relay side and adjust their rate/burst
+ * values using the global parameters. This is called right after the
+ * consensus parameters might have changed. */
+static void
+update_intro_circuits(void)
+{
+ /* Returns all HS version intro circuits. */
+ smartlist_t *intro_circs = hs_circuitmap_get_all_intro_circ_relay_side();
+
+ SMARTLIST_FOREACH_BEGIN(intro_circs, circuit_t *, circ) {
+ /* Adjust the rate/burst value that might have changed. */
+ token_bucket_ctr_adjust(&TO_OR_CIRCUIT(circ)->introduce2_bucket,
+ hs_dos_get_intro2_rate(),
+ hs_dos_get_intro2_burst());
+ } SMARTLIST_FOREACH_END(circ);
+
+ smartlist_free(intro_circs);
+}
+
+/* Set consensus parameters. */
+static void
+set_consensus_parameters(const networkstatus_t *ns)
+{
+ hs_dos_introduce_rate_per_sec = get_param_rate_per_sec(ns);
+ hs_dos_introduce_burst_per_sec = get_param_burst_per_sec(ns);
+ hs_dos_introduce_enabled = get_param_intro_dos_enabled(ns);
+
+ /* The above might have changed which means we need to go through all
+ * introduction circuits (relay side) and update the token buckets. */
+ update_intro_circuits();
+}
+
+/*
+ * Public API.
+ */
+
+/* Return the INTRODUCE2 cell rate per second. */
+uint32_t
+hs_dos_get_intro2_rate(void)
+{
+ return hs_dos_introduce_rate_per_sec;
+}
+
+/* Return the INTRODUCE2 cell burst per second. */
+uint32_t
+hs_dos_get_intro2_burst(void)
+{
+ return hs_dos_introduce_burst_per_sec;
+}
+
+/* Called when the consensus has changed. We might have new consensus
+ * parameters to look at. */
+void
+hs_dos_consensus_has_changed(const networkstatus_t *ns)
+{
+ /* No point on updating these values if we are not a public relay that can
+ * be picked to be an introduction point. */
+ if (!public_server_mode(get_options())) {
+ return;
+ }
+
+ set_consensus_parameters(ns);
+}
+
+/* Return true iff an INTRODUCE2 cell can be sent on the given service
+ * introduction circuit. */
+bool
+hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
+{
+ tor_assert(s_intro_circ);
+
+ /* Always allowed if the defense is disabled. */
+ if (!hs_dos_introduce_enabled) {
+ return true;
+ }
+
+ /* Should not happen but if so, scream loudly. */
+ if (BUG(TO_CIRCUIT(s_intro_circ)->purpose != CIRCUIT_PURPOSE_INTRO_POINT)) {
+ return false;
+ }
+
+ /* This is called just after we got a valid and parsed INTRODUCE1 cell. The
+ * service has been found and we have its introduction circuit.
+ *
+ * First, the INTRODUCE2 bucket will be refilled (if any). Then, decremented
+ * because we are about to send or not the cell we just got. Finally,
+ * evaluate if we can send it based on our token bucket state. */
+
+ /* Refill INTRODUCE2 bucket. */
+ token_bucket_ctr_refill(&s_intro_circ->introduce2_bucket,
+ (uint32_t) approx_time());
+
+ /* Decrement the bucket for this valid INTRODUCE1 cell we just got. Don't
+ * underflow else we end up with a too big of a bucket. */
+ if (token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0) {
+ token_bucket_ctr_dec(&s_intro_circ->introduce2_bucket, 1);
+ }
+
+ /* Finally, we can send a new INTRODUCE2 if there are still tokens. */
+ return token_bucket_ctr_get(&s_intro_circ->introduce2_bucket) > 0;
+}
+
+/* Initialize the onion service Denial of Service subsystem. */
+void
+hs_dos_init(void)
+{
+ set_consensus_parameters(NULL);
+}
diff --git a/src/feature/hs/hs_dos.h b/src/feature/hs/hs_dos.h
new file mode 100644
index 0000000000..9fba00b52b
--- /dev/null
+++ b/src/feature/hs/hs_dos.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_dos.h
+ * \brief Header file containing denial of service defenses for the HS
+ * subsystem for all versions.
+ **/
+
+#ifndef TOR_HS_DOS_H
+#define TOR_HS_DOS_H
+
+#include "core/or/or_circuit_st.h"
+
+#include "feature/nodelist/networkstatus_st.h"
+
+/* Init */
+void hs_dos_init(void);
+
+/* Consensus. */
+void hs_dos_consensus_has_changed(const networkstatus_t *ns);
+
+bool hs_dos_can_send_intro2(or_circuit_t *s_intro_circ);
+
+/* Getters. */
+uint32_t hs_dos_get_intro2_rate(void);
+uint32_t hs_dos_get_intro2_burst(void);
+
+#ifdef HS_DOS_PRIVATE
+
+#ifdef TOR_UNIT_TESTS
+
+#endif /* define(TOR_UNIT_TESTS) */
+
+#endif /* defined(HS_DOS_PRIVATE) */
+
+#endif /* !defined(TOR_HS_DOS_H) */
diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c
index 9333060e7e..2c105f0b60 100644
--- a/src/feature/hs/hs_intropoint.c
+++ b/src/feature/hs/hs_intropoint.c
@@ -10,6 +10,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "core/or/channel.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/relay.h"
@@ -24,9 +25,10 @@
#include "trunnel/hs/cell_introduce1.h"
#include "feature/hs/hs_circuitmap.h"
+#include "feature/hs/hs_common.h"
#include "feature/hs/hs_descriptor.h"
+#include "feature/hs/hs_dos.h"
#include "feature/hs/hs_intropoint.h"
-#include "feature/hs/hs_common.h"
#include "core/or/or_circuit_st.h"
@@ -202,6 +204,9 @@ handle_verified_establish_intro_cell(or_circuit_t *circ,
hs_circuitmap_register_intro_circ_v3_relay_side(circ, &auth_key);
/* Repurpose this circuit into an intro circuit. */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
+ /* Initialize the INTRODUCE2 token bucket for the rate limiting. */
+ token_bucket_ctr_init(&circ->introduce2_bucket, hs_dos_get_intro2_rate(),
+ hs_dos_get_intro2_burst(), (uint32_t) approx_time());
return 0;
}
@@ -480,6 +485,20 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
}
}
+ /* Before sending, lets make sure this cell can be sent on the service
+ * circuit asking the DoS defenses. */
+ if (!hs_dos_can_send_intro2(service_circ)) {
+ char *msg;
+ static ratelim_t rlimit = RATELIM_INIT(5 * 60);
+ if ((msg = rate_limit_log(&rlimit, approx_time()))) {
+ log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v3 cell due to DoS "
+ "limitations. Sending NACK to client.");
+ tor_free(msg);
+ }
+ status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
+ goto send_ack;
+ }
+
/* Relay the cell to the service on its intro circuit with an INTRODUCE2
* cell which is the same exact payload. */
if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(service_circ),
@@ -546,6 +565,14 @@ circuit_is_suitable_for_introduce1(const or_circuit_t *circ)
return 0;
}
+ /* Disallow single hop client circuit. */
+ if (circ->p_chan && channel_is_client(circ->p_chan)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Single hop client was rejected while trying to introduce. "
+ "Closing circuit.");
+ return 0;
+ }
+
return 1;
}
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index 2db293a8af..496bafb865 100644
--- a/src/feature/nodelist/networkstatus.c
+++ b/src/feature/nodelist/networkstatus.c
@@ -68,6 +68,7 @@
#include "feature/dircommon/voting_schedule.h"
#include "feature/dirparse/ns_parse.h"
#include "feature/hibernate/hibernate.h"
+#include "feature/hs/hs_dos.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
#include "feature/nodelist/fmt_routerstatus.h"
@@ -1674,6 +1675,7 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
notify_control_networkstatus_changed(old_c, new_c);
dos_consensus_has_changed(new_c);
relay_consensus_has_changed(new_c);
+ hs_dos_consensus_has_changed(new_c);
}
/* Called after a new consensus has been put in the global state. It is safe
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index 5948445c96..0cd7a76a9a 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -954,20 +954,18 @@ routerlist_free_(routerlist_t *rl)
smartlist_free(rl->routers);
smartlist_free(rl->old_routers);
if (rl->desc_store.mmap) {
- int res = tor_munmap_file(routerlist->desc_store.mmap);
+ int res = tor_munmap_file(rl->desc_store.mmap);
if (res != 0) {
log_warn(LD_FS, "Failed to munmap routerlist->desc_store.mmap");
}
}
if (rl->extrainfo_store.mmap) {
- int res = tor_munmap_file(routerlist->extrainfo_store.mmap);
+ int res = tor_munmap_file(rl->extrainfo_store.mmap);
if (res != 0) {
log_warn(LD_FS, "Failed to munmap routerlist->extrainfo_store.mmap");
}
}
tor_free(rl);
-
- router_dir_info_changed();
}
/** Log information about how much memory is being used for routerlist,
@@ -1426,8 +1424,10 @@ routerlist_reparse_old(routerlist_t *rl, signed_descriptor_t *sd)
void
routerlist_free_all(void)
{
- routerlist_free(routerlist);
- routerlist = NULL;
+ routerlist_t *rl = routerlist;
+ routerlist = NULL; // Prevent internals of routerlist_free() from using
+ // routerlist.
+ routerlist_free(rl);
dirlist_free_all();
if (warned_nicknames) {
SMARTLIST_FOREACH(warned_nicknames, char *, cp, tor_free(cp));
@@ -2861,7 +2861,7 @@ int
router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
{
time_t r1pub, r2pub;
- long time_difference;
+ time_t time_difference;
tor_assert(r1 && r2);
/* r1 should be the one that was published first. */
@@ -2925,7 +2925,9 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
* give or take some slop? */
r1pub = r1->cache_info.published_on;
r2pub = r2->cache_info.published_on;
- time_difference = labs(r2->uptime - (r1->uptime + (r2pub - r1pub)));
+ time_difference = r2->uptime - (r1->uptime + (r2pub - r1pub));
+ if (time_difference < 0)
+ time_difference = - time_difference;
if (time_difference > ROUTER_ALLOW_UPTIME_DRIFT &&
time_difference > r1->uptime * .05 &&
time_difference > r2->uptime * .05)
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 6b33265294..51ced6289d 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -3158,6 +3158,8 @@ extrainfo_dump_to_string_header_helper(
ed_cert_line = tor_strdup("");
}
+ /* This is the first chunk in the file. If the file is too big, other chunks
+ * are removed. So we must only add one chunk here. */
tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n",
extrainfo->nickname, identity,
ed_cert_line,
@@ -3187,6 +3189,10 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
char *contents = NULL;
time_t now = time(NULL);
+ /* If the file is too big, these chunks are removed, starting with the last
+ * chunk. So each chunk must be a complete line, and the file must be valid
+ * after each chunk. */
+
/* Add information about the pluggable transports we support, even if we
* are not publishing statistics. This information is needed by BridgeDB
* to distribute bridges. */
@@ -3269,6 +3275,8 @@ extrainfo_dump_to_string_ed_sig_helper(
char buf[ED25519_SIG_BASE64_LEN+1];
int rv = -1;
+ /* These are two of the three final chunks in the file. If the file is too
+ * big, other chunks are removed. So we must only add two chunks here. */
smartlist_add_strdup(chunks, "router-sig-ed25519 ");
crypto_digest_smartlist_prefix(sha256_digest, DIGEST256_LEN,
ED_DESC_SIGNATURE_PREFIX,
@@ -3362,17 +3370,21 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
goto err;
}
+ /* This is one of the three final chunks in the file. If the file is too big,
+ * other chunks are removed. So we must only add one chunk here. */
smartlist_add_strdup(chunks, "router-signature\n");
s = smartlist_join_strings(chunks, "", 0, NULL);
while (strlen(s) > MAX_EXTRAINFO_UPLOAD_SIZE - DIROBJ_MAX_SIG_LEN) {
/* So long as there are at least two chunks (one for the initial
* extra-info line and one for the router-signature), we can keep removing
- * things. */
- if (smartlist_len(chunks) > 2) {
- /* We remove the next-to-last element (remember, len-1 is the last
- element), since we need to keep the router-signature element. */
- int idx = smartlist_len(chunks) - 2;
+ * things. If emit_ed_sigs is true, we also keep 2 additional chunks at the
+ * end for the ed25519 signature. */
+ const int required_chunks = emit_ed_sigs ? 4 : 2;
+ if (smartlist_len(chunks) > required_chunks) {
+ /* We remove the next-to-last or 4th-last element (remember, len-1 is the
+ * last element), since we need to keep the router-signature elements. */
+ int idx = smartlist_len(chunks) - required_chunks;
char *e = smartlist_get(chunks, idx);
smartlist_del_keeporder(chunks, idx);
log_warn(LD_GENERAL, "We just generated an extra-info descriptor "
diff --git a/src/feature/rend/rendmid.c b/src/feature/rend/rendmid.c
index 849f355990..ef2a44c40d 100644
--- a/src/feature/rend/rendmid.c
+++ b/src/feature/rend/rendmid.c
@@ -18,6 +18,7 @@
#include "feature/rend/rendmid.h"
#include "feature/stats/rephist.h"
#include "feature/hs/hs_circuitmap.h"
+#include "feature/hs/hs_dos.h"
#include "feature/hs/hs_intropoint.h"
#include "core/or/or_circuit_st.h"
@@ -116,6 +117,8 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request,
/* Now, set up this circuit. */
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
hs_circuitmap_register_intro_circ_v2_relay_side(circ, (uint8_t *)pk_digest);
+ token_bucket_ctr_init(&circ->introduce2_bucket, hs_dos_get_intro2_rate(),
+ hs_dos_get_intro2_burst(), (uint32_t) approx_time());
log_info(LD_REND,
"Established introduction point on circuit %u for service %s",
@@ -180,6 +183,14 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request,
goto err;
}
+ /* Before sending, lets make sure this cell can be sent on the service
+ * circuit asking the DoS defenses. */
+ if (!hs_dos_can_send_intro2(intro_circ)) {
+ log_info(LD_PROTOCOL, "Can't relay INTRODUCE1 v2 cell due to DoS "
+ "limitations. Sending NACK to client.");
+ goto err;
+ }
+
log_info(LD_REND,
"Sending introduction request for service %s "
"from circ %u to circ %u",
diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h
index c63ff66eff..d142ee1104 100644
--- a/src/lib/confmgt/var_type_def_st.h
+++ b/src/lib/confmgt/var_type_def_st.h
@@ -5,7 +5,7 @@
/* See LICENSE for licensing information */
/**
- * @file typedvar.h
+ * @file var_type_def_st.h
* @brief Structure declarations for typedvar type definitions.
*
* This structure is used for defining new variable types. If you are not
diff --git a/src/lib/defs/include.am b/src/lib/defs/include.am
index dfddc92e55..84ee403771 100644
--- a/src/lib/defs/include.am
+++ b/src/lib/defs/include.am
@@ -3,5 +3,6 @@
noinst_HEADERS += \
src/lib/defs/dh_sizes.h \
src/lib/defs/digest_sizes.h \
+ src/lib/defs/logging_types.h \
src/lib/defs/time.h \
src/lib/defs/x25519_sizes.h
diff --git a/src/lib/defs/logging_types.h b/src/lib/defs/logging_types.h
new file mode 100644
index 0000000000..57db818007
--- /dev/null
+++ b/src/lib/defs/logging_types.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file logging_types.h
+ *
+ * \brief Global definition for types used by logging systems.
+ **/
+
+#ifndef TOR_LOGGING_TYPES_H
+#define TOR_LOGGING_TYPES_H
+
+/* We define this here so that it can be used both by backtrace.h and
+ * log.h.
+ */
+
+/** Mask of zero or more log domains, OR'd together. */
+typedef uint64_t log_domain_mask_t;
+
+#endif
diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c
index b36e83dcc6..0d8384db13 100644
--- a/src/lib/encoding/confline.c
+++ b/src/lib/encoding/confline.c
@@ -33,23 +33,14 @@ config_line_append(config_line_t **lst,
const char *key,
const char *val)
{
+ tor_assert(lst);
+
config_line_t *newline;
newline = tor_malloc_zero(sizeof(config_line_t));
newline->key = tor_strdup(key);
newline->value = tor_strdup(val);
newline->next = NULL;
-
- config_line_append_line(lst, newline);
-}
-
-/** Helper: append <b>newline</b> to the end of <b>lst</b>. */
-void
-config_line_append_line(config_line_t **lst,
- config_line_t *newline)
-{
- tor_assert(lst);
-
while (*lst)
lst = &((*lst)->next);
diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h
index 7d0b9ce5fc..12c554c6e7 100644
--- a/src/lib/encoding/confline.h
+++ b/src/lib/encoding/confline.h
@@ -41,7 +41,6 @@ typedef struct config_line_t {
void config_line_append(config_line_t **lst,
const char *key, const char *val);
-void config_line_append_line(config_line_t **lst, config_line_t *newline);
void config_line_prepend(config_line_t **lst,
const char *key, const char *val);
config_line_t *config_lines_dup(const config_line_t *inp);
diff --git a/src/lib/err/.may_include b/src/lib/err/.may_include
index daa1b6e4ca..314424545e 100644
--- a/src/lib/err/.may_include
+++ b/src/lib/err/.may_include
@@ -1,5 +1,6 @@
orconfig.h
lib/cc/*.h
+lib/defs/*.h
lib/err/*.h
lib/subsys/*.h
-lib/version/*.h \ No newline at end of file
+lib/version/*.h
diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c
index 1d1b3bcfa3..e6cbe3d326 100644
--- a/src/lib/err/backtrace.c
+++ b/src/lib/err/backtrace.c
@@ -115,7 +115,7 @@ clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx)
* that with a backtrace log. Send messages via the tor_log function at
* logger". */
void
-log_backtrace_impl(int severity, int domain, const char *msg,
+log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg,
tor_log_fn logger)
{
size_t depth;
@@ -240,7 +240,7 @@ remove_bt_handler(void)
#ifdef NO_BACKTRACE_IMPL
void
-log_backtrace_impl(int severity, int domain, const char *msg,
+log_backtrace_impl(int severity, log_domain_mask_t domain, const char *msg,
tor_log_fn logger)
{
logger(severity, domain, "%s. (Stack trace not available)", msg);
diff --git a/src/lib/err/backtrace.h b/src/lib/err/backtrace.h
index 9b313261e6..dcd22cfef2 100644
--- a/src/lib/err/backtrace.h
+++ b/src/lib/err/backtrace.h
@@ -12,11 +12,14 @@
#include "orconfig.h"
#include "lib/cc/compat_compiler.h"
+#include "lib/cc/torint.h"
+#include "lib/defs/logging_types.h"
-typedef void (*tor_log_fn)(int, unsigned, const char *fmt, ...)
+typedef void (*tor_log_fn)(int, log_domain_mask_t, const char *fmt, ...)
CHECK_PRINTF(3,4);
-void log_backtrace_impl(int severity, int domain, const char *msg,
+void log_backtrace_impl(int severity, log_domain_mask_t domain,
+ const char *msg,
tor_log_fn logger);
int configure_backtrace_handler(const char *tor_version);
void clean_up_backtrace_handler(void);
diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include
index 11c87f0a0d..54d96324db 100644
--- a/src/lib/log/.may_include
+++ b/src/lib/log/.may_include
@@ -1,6 +1,7 @@
orconfig.h
lib/cc/*.h
+lib/defs/*.h
lib/smartlist_core/*.h
lib/err/*.h
lib/fdio/*.h
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index c68f335da6..d95bf1ff6e 100644
--- a/src/lib/log/log.c
+++ b/src/lib/log/log.c
@@ -1022,7 +1022,7 @@ flush_pending_log_callbacks(void)
do {
SMARTLIST_FOREACH_BEGIN(messages, pending_log_message_t *, msg) {
const int severity = msg->severity;
- const int domain = msg->domain;
+ const log_domain_mask_t domain = msg->domain;
for (lf = logfiles; lf; lf = lf->next) {
if (! lf->callback || lf->seems_dead ||
! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
@@ -1275,6 +1275,8 @@ static const char *domain_list[] = {
CTASSERT(ARRAY_LENGTH(domain_list) == N_LOGGING_DOMAINS + 1);
+CTASSERT((UINT64_C(1)<<(N_LOGGING_DOMAINS-1)) < LOWEST_RESERVED_LD_FLAG_);
+
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
* or 0 if there is no such name. */
static log_domain_mask_t
@@ -1375,7 +1377,7 @@ parse_log_severity_config(const char **cfg_ptr,
if (!strcmp(domain, "*")) {
domains = ~0u;
} else {
- int d;
+ log_domain_mask_t d;
int negate=0;
if (*domain == '~') {
negate = 1;
diff --git a/src/lib/log/log.h b/src/lib/log/log.h
index 3db2169584..c4a27782c3 100644
--- a/src/lib/log/log.h
+++ b/src/lib/log/log.h
@@ -16,6 +16,7 @@
#include <stdarg.h>
#include "lib/cc/torint.h"
#include "lib/cc/compat_compiler.h"
+#include "lib/defs/logging_types.h"
#include "lib/testsupport/testsupport.h"
#ifdef HAVE_SYSLOG_H
@@ -56,82 +57,81 @@
/* Logging domains */
/** Catch-all for miscellaneous events and fatal errors. */
-#define LD_GENERAL (1u<<0)
+#define LD_GENERAL (UINT64_C(1)<<0)
/** The cryptography subsystem. */
-#define LD_CRYPTO (1u<<1)
+#define LD_CRYPTO (UINT64_C(1)<<1)
/** Networking. */
-#define LD_NET (1u<<2)
+#define LD_NET (UINT64_C(1)<<2)
/** Parsing and acting on our configuration. */
-#define LD_CONFIG (1u<<3)
+#define LD_CONFIG (UINT64_C(1)<<3)
/** Reading and writing from the filesystem. */
-#define LD_FS (1u<<4)
+#define LD_FS (UINT64_C(1)<<4)
/** Other servers' (non)compliance with the Tor protocol. */
-#define LD_PROTOCOL (1u<<5)
+#define LD_PROTOCOL (UINT64_C(1)<<5)
/** Memory management. */
-#define LD_MM (1u<<6)
+#define LD_MM (UINT64_C(1)<<6)
/** HTTP implementation. */
-#define LD_HTTP (1u<<7)
+#define LD_HTTP (UINT64_C(1)<<7)
/** Application (socks) requests. */
-#define LD_APP (1u<<8)
+#define LD_APP (UINT64_C(1)<<8)
/** Communication via the controller protocol. */
-#define LD_CONTROL (1u<<9)
+#define LD_CONTROL (UINT64_C(1)<<9)
/** Building, using, and managing circuits. */
-#define LD_CIRC (1u<<10)
+#define LD_CIRC (UINT64_C(1)<<10)
/** Hidden services. */
-#define LD_REND (1u<<11)
+#define LD_REND (UINT64_C(1)<<11)
/** Internal errors in this Tor process. */
-#define LD_BUG (1u<<12)
+#define LD_BUG (UINT64_C(1)<<12)
/** Learning and using information about Tor servers. */
-#define LD_DIR (1u<<13)
+#define LD_DIR (UINT64_C(1)<<13)
/** Learning and using information about Tor servers. */
-#define LD_DIRSERV (1u<<14)
+#define LD_DIRSERV (UINT64_C(1)<<14)
/** Onion routing protocol. */
-#define LD_OR (1u<<15)
+#define LD_OR (UINT64_C(1)<<15)
/** Generic edge-connection functionality. */
-#define LD_EDGE (1u<<16)
+#define LD_EDGE (UINT64_C(1)<<16)
#define LD_EXIT LD_EDGE
/** Bandwidth accounting. */
-#define LD_ACCT (1u<<17)
+#define LD_ACCT (UINT64_C(1)<<17)
/** Router history */
-#define LD_HIST (1u<<18)
+#define LD_HIST (UINT64_C(1)<<18)
/** OR handshaking */
-#define LD_HANDSHAKE (1u<<19)
+#define LD_HANDSHAKE (UINT64_C(1)<<19)
/** Heartbeat messages */
-#define LD_HEARTBEAT (1u<<20)
+#define LD_HEARTBEAT (UINT64_C(1)<<20)
/** Abstract channel_t code */
-#define LD_CHANNEL (1u<<21)
+#define LD_CHANNEL (UINT64_C(1)<<21)
/** Scheduler */
-#define LD_SCHED (1u<<22)
+#define LD_SCHED (UINT64_C(1)<<22)
/** Guard nodes */
-#define LD_GUARD (1u<<23)
+#define LD_GUARD (UINT64_C(1)<<23)
/** Generation and application of consensus diffs. */
-#define LD_CONSDIFF (1u<<24)
+#define LD_CONSDIFF (UINT64_C(1)<<24)
/** Denial of Service mitigation. */
-#define LD_DOS (1u<<25)
+#define LD_DOS (UINT64_C(1)<<25)
/** Processes */
-#define LD_PROCESS (1u<<26)
+#define LD_PROCESS (UINT64_C(1)<<26)
/** Pluggable Transports. */
-#define LD_PT (1u<<27)
+#define LD_PT (UINT64_C(1)<<27)
/** Bootstrap tracker. */
-#define LD_BTRACK (1u<<28)
+#define LD_BTRACK (UINT64_C(1)<<28)
/** Message-passing backend. */
-#define LD_MESG (1u<<29)
+#define LD_MESG (UINT64_C(1)<<29)
#define N_LOGGING_DOMAINS 30
-/** This log message is not safe to send to a callback-based logger
- * immediately. Used as a flag, not a log domain. */
-#define LD_NOCB (1u<<31)
-/** This log message should not include a function name, even if it otherwise
- * would. Used as a flag, not a log domain. */
-#define LD_NOFUNCNAME (1u<<30)
-
+/** First bit that is reserved in log_domain_mask_t for non-domain flags. */
+#define LOWEST_RESERVED_LD_FLAG_ (UINT64_C(1)<<61)
#ifdef TOR_UNIT_TESTS
/** This log message should not be intercepted by mock_saving_logv */
-#define LD_NO_MOCK (1u<<29)
+#define LD_NO_MOCK (UINT64_C(1)<<61)
#endif
-/** Mask of zero or more log domains, OR'd together. */
-typedef uint32_t log_domain_mask_t;
+/** This log message is not safe to send to a callback-based logger
+ * immediately. Used as a flag, not a log domain. */
+#define LD_NOCB (UINT64_C(1)<<62)
+/** This log message should not include a function name, even if it otherwise
+ * would. Used as a flag, not a log domain. */
+#define LD_NOFUNCNAME (UINT64_C(1)<<63)
/** Configures which severities are logged for each logging domain for a given
* log target. */
@@ -142,7 +142,8 @@ typedef struct log_severity_list_t {
} log_severity_list_t;
/** Callback type used for add_callback_log. */
-typedef void (*log_callback)(int severity, uint32_t domain, const char *msg);
+typedef void (*log_callback)(int severity, log_domain_mask_t domain,
+ const char *msg);
void init_logging(int disable_startup_queue);
int parse_log_level(const char *level);
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 546af800a9..0a2c84caf2 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -373,7 +373,8 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate)
*
* If <b>accept_regular</b> is set and the address is in neither recognized
* reverse lookup hostname format, try parsing the address as a regular
- * IPv4 or IPv6 address too.
+ * IPv4 or IPv6 address too. This mode will accept IPv6 addresses with or
+ * without square brackets.
*/
int
tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
@@ -1187,17 +1188,22 @@ fmt_addr32(uint32_t addr)
}
/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string
- * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by
- * square brackets.
+ * may be an IPv4 address, or an IPv6 address surrounded by square brackets.
*
- * Return an address family on success, or -1 if an invalid address string is
- * provided. */
-int
-tor_addr_parse(tor_addr_t *addr, const char *src)
+ * If <b>allow_ipv6_without_brackets</b> is true, also allow IPv6 addresses
+ * without brackets.
+ *
+ * Always rejects IPv4 addresses with brackets.
+ *
+ * Returns an address family on success, or -1 if an invalid address string is
+ * provided. */
+static int
+tor_addr_parse_impl(tor_addr_t *addr, const char *src,
+ bool allow_ipv6_without_brackets)
{
/* Holds substring of IPv6 address after removing square brackets */
char *tmp = NULL;
- int result;
+ int result = -1;
struct in_addr in_tmp;
struct in6_addr in6_tmp;
int brackets_detected = 0;
@@ -1211,21 +1217,46 @@ tor_addr_parse(tor_addr_t *addr, const char *src)
src = tmp = tor_strndup(src+1, strlen(src)-2);
}
- if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) {
- result = AF_INET6;
- tor_addr_from_in6(addr, &in6_tmp);
- } else if (!brackets_detected &&
- tor_inet_pton(AF_INET, src, &in_tmp) > 0) {
- result = AF_INET;
- tor_addr_from_in(addr, &in_tmp);
- } else {
- result = -1;
+ /* Try to parse an IPv6 address if it has brackets, or if IPv6 addresses
+ * without brackets are allowed */
+ if (brackets_detected || allow_ipv6_without_brackets) {
+ if (tor_inet_pton(AF_INET6, src, &in6_tmp) > 0) {
+ result = AF_INET6;
+ tor_addr_from_in6(addr, &in6_tmp);
+ }
+ }
+
+ /* Try to parse an IPv4 address without brackets */
+ if (!brackets_detected) {
+ if (tor_inet_pton(AF_INET, src, &in_tmp) > 0) {
+ result = AF_INET;
+ tor_addr_from_in(addr, &in_tmp);
+ }
+ }
+
+ /* Clear the address on error, to avoid returning uninitialised or partly
+ * parsed data.
+ */
+ if (result == -1) {
+ memset(addr, 0, sizeof(tor_addr_t));
}
tor_free(tmp);
return result;
}
+/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string
+ * may be an IPv4 address, an IPv6 address, or an IPv6 address surrounded by
+ * square brackets.
+ *
+ * Returns an address family on success, or -1 if an invalid address string is
+ * provided. */
+int
+tor_addr_parse(tor_addr_t *addr, const char *src)
+{
+ return tor_addr_parse_impl(addr, src, 1);
+}
+
#ifdef HAVE_IFADDRS_TO_SMARTLIST
/*
* Convert a linked list consisting of <b>ifaddrs</b> structures
@@ -1718,6 +1749,11 @@ get_interface_address6_list,(int severity,
* form "ip" or "ip:0". Otherwise, accept those forms, and set
* *<b>port_out</b> to <b>default_port</b>.
*
+ * This function accepts:
+ * - IPv6 address and port, when the IPv6 address is in square brackets,
+ * - IPv6 address with square brackets,
+ * - IPv6 address without square brackets.
+ *
* Return 0 on success, -1 on failure. */
int
tor_addr_port_parse(int severity, const char *addrport,
@@ -1727,6 +1763,7 @@ tor_addr_port_parse(int severity, const char *addrport,
int retval = -1;
int r;
char *addr_tmp = NULL;
+ bool has_port;
tor_assert(addrport);
tor_assert(address_out);
@@ -1736,28 +1773,47 @@ tor_addr_port_parse(int severity, const char *addrport,
if (r < 0)
goto done;
- if (!*port_out) {
+ has_port = !! *port_out;
+ /* If there's no port, use the default port, or fail if there is no default
+ */
+ if (!has_port) {
if (default_port >= 0)
*port_out = default_port;
else
goto done;
}
- /* make sure that address_out is an IP address */
- if (tor_addr_parse(address_out, addr_tmp) < 0)
+ /* Make sure that address_out is an IP address.
+ * If there is no port in addrport, allow IPv6 addresses without brackets. */
+ if (tor_addr_parse_impl(address_out, addr_tmp, !has_port) < 0)
goto done;
retval = 0;
done:
+ /* Clear the address and port on error, to avoid returning uninitialised or
+ * partly parsed data.
+ */
+ if (retval == -1) {
+ memset(address_out, 0, sizeof(tor_addr_t));
+ *port_out = 0;
+ }
tor_free(addr_tmp);
return retval;
}
/** Given an address of the form "host[:port]", try to divide it into its host
- * and port portions, setting *<b>address_out</b> to a newly allocated string
- * holding the address portion and *<b>port_out</b> to the port (or 0 if no
- * port is given). Return 0 on success, -1 on failure. */
+ * and port portions.
+ *
+ * Like tor_addr_port_parse(), this function accepts:
+ * - IPv6 address and port, when the IPv6 address is in square brackets,
+ * - IPv6 address with square brackets,
+ * - IPv6 address without square brackets.
+ *
+ * Sets *<b>address_out</b> to a newly allocated string holding the address
+ * portion, and *<b>port_out</b> to the port (or 0 if no port is given).
+ *
+ * Return 0 on success, -1 on failure. */
int
tor_addr_port_split(int severity, const char *addrport,
char **address_out, uint16_t *port_out)
@@ -1766,8 +1822,11 @@ tor_addr_port_split(int severity, const char *addrport,
tor_assert(addrport);
tor_assert(address_out);
tor_assert(port_out);
+
/* We need to check for IPv6 manually because the logic below doesn't
- * do a good job on IPv6 addresses that lack a port. */
+ * do a good job on IPv6 addresses that lack a port.
+ * If an IPv6 address without square brackets is ambiguous, it gets parsed
+ * here as an address, rather than address:port. */
if (tor_addr_parse(&a_tmp, addrport) == AF_INET6) {
*port_out = 0;
*address_out = tor_strdup(addrport);
@@ -1807,8 +1866,7 @@ tor_addr_port_split(int severity, const char *addrport,
tor_free(address_);
}
- if (port_out)
- *port_out = ok ? ((uint16_t) port_) : 0;
+ *port_out = ok ? ((uint16_t) port_) : 0;
return ok ? 0 : -1;
}
diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c
index 2dda491d14..e8d7d0d94d 100644
--- a/src/lib/net/resolve.c
+++ b/src/lib/net/resolve.c
@@ -35,6 +35,8 @@
* *<b>addr</b> to the proper IP address, in host byte order. Returns 0
* on success, -1 on failure; 1 on transient failure.
*
+ * This function only accepts IPv4 addresses.
+ *
* (This function exists because standard windows gethostbyname
* doesn't treat raw IP addresses properly.)
*/
@@ -45,6 +47,11 @@ tor_lookup_hostname,(const char *name, uint32_t *addr))
tor_addr_t myaddr;
int ret;
+ if (BUG(!addr))
+ return -1;
+
+ *addr = 0;
+
if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
return ret;
@@ -56,12 +63,125 @@ tor_lookup_hostname,(const char *name, uint32_t *addr))
return -1;
}
+#ifdef HAVE_GETADDRINFO
+
+/* Host lookup helper for tor_addr_lookup(), when getaddrinfo() is
+ * available on this system.
+ *
+ * See tor_addr_lookup() for details.
+ */
+static int
+tor_addr_lookup_host_getaddrinfo(const char *name,
+ uint16_t family,
+ tor_addr_t *addr)
+{
+ int err;
+ struct addrinfo *res=NULL, *res_p;
+ struct addrinfo *best=NULL;
+ struct addrinfo hints;
+ int result = -1;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ err = tor_getaddrinfo(name, NULL, &hints, &res);
+ /* The check for 'res' here shouldn't be necessary, but it makes static
+ * analysis tools happy. */
+ if (!err && res) {
+ best = NULL;
+ for (res_p = res; res_p; res_p = res_p->ai_next) {
+ if (family == AF_UNSPEC) {
+ if (res_p->ai_family == AF_INET) {
+ best = res_p;
+ break;
+ } else if (res_p->ai_family == AF_INET6 && !best) {
+ best = res_p;
+ }
+ } else if (family == res_p->ai_family) {
+ best = res_p;
+ break;
+ }
+ }
+ if (!best)
+ best = res;
+ if (best->ai_family == AF_INET) {
+ tor_addr_from_in(addr,
+ &((struct sockaddr_in*)best->ai_addr)->sin_addr);
+ result = 0;
+ } else if (best->ai_family == AF_INET6) {
+ tor_addr_from_in6(addr,
+ &((struct sockaddr_in6*)best->ai_addr)->sin6_addr);
+ result = 0;
+ }
+ tor_freeaddrinfo(res);
+ return result;
+ }
+ return (err == EAI_AGAIN) ? 1 : -1;
+}
+
+#else /* !(defined(HAVE_GETADDRINFO)) */
+
+/* Host lookup helper for tor_addr_lookup(), which calls getaddrinfo().
+ * Used when gethostbyname() is not available on this system.
+ *
+ * See tor_addr_lookup() for details.
+ */
+static int
+tor_addr_lookup_host_gethostbyname(const char *name,
+ tor_addr_t *addr)
+{
+ struct hostent *ent;
+ int err;
+#ifdef HAVE_GETHOSTBYNAME_R_6_ARG
+ char buf[2048];
+ struct hostent hostent;
+ int r;
+ r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err);
+#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
+ char buf[2048];
+ struct hostent hostent;
+ ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err);
+#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG)
+ struct hostent_data data;
+ struct hostent hent;
+ memset(&data, 0, sizeof(data));
+ err = gethostbyname_r(name, &hent, &data);
+ ent = err ? NULL : &hent;
+#else
+ ent = gethostbyname(name);
+#ifdef _WIN32
+ err = WSAGetLastError();
+#else
+ err = h_errno;
+#endif /* defined(_WIN32) */
+#endif /* defined(HAVE_GETHOSTBYNAME_R_6_ARG) || ... */
+ if (ent) {
+ if (ent->h_addrtype == AF_INET) {
+ tor_addr_from_in(addr, (struct in_addr*) ent->h_addr);
+ } else if (ent->h_addrtype == AF_INET6) {
+ tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr);
+ } else {
+ tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type
+ }
+ return 0;
+ }
+#ifdef _WIN32
+ return (err == WSATRY_AGAIN) ? 1 : -1;
+#else
+ return (err == TRY_AGAIN) ? 1 : -1;
+#endif
+}
+
+#endif /* defined(HAVE_GETADDRINFO) */
+
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* *<b>addr</b> to the proper IP address and family. The <b>family</b>
* argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a
* <i>preferred</i> family, though another one may be returned if only one
* family is implemented for this address.
*
+ * Like tor_addr_parse(), this function accepts IPv6 addresses with or without
+ * square brackets.
+ *
* Return 0 on success, -1 on failure; 1 on transient failure.
*/
MOCK_IMPL(int,
@@ -70,169 +190,134 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr))
/* Perhaps eventually this should be replaced by a tor_getaddrinfo or
* something.
*/
- struct in_addr iaddr;
- struct in6_addr iaddr6;
+ int parsed_family = 0;
+ int result = -1;
+
tor_assert(name);
tor_assert(addr);
tor_assert(family == AF_INET || family == AF_INET6 || family == AF_UNSPEC);
+
if (!*name) {
/* Empty address is an error. */
- return -1;
- } else if (tor_inet_pton(AF_INET, name, &iaddr)) {
- /* It's an IPv4 IP. */
- if (family == AF_INET6)
- return -1;
- tor_addr_from_in(addr, &iaddr);
- return 0;
- } else if (tor_inet_pton(AF_INET6, name, &iaddr6)) {
- if (family == AF_INET)
- return -1;
- tor_addr_from_in6(addr, &iaddr6);
- return 0;
+ goto permfail;
+ }
+
+ /* Is it an IP address? */
+ parsed_family = tor_addr_parse(addr, name);
+
+ if (parsed_family >= 0) {
+ /* If the IP address family matches, or was unspecified */
+ if (parsed_family == family || family == AF_UNSPEC) {
+ goto success;
+ } else {
+ goto permfail;
+ }
} else {
+ /* Clear the address after a failed tor_addr_parse(). */
+ memset(addr, 0, sizeof(tor_addr_t));
#ifdef HAVE_GETADDRINFO
- int err;
- struct addrinfo *res=NULL, *res_p;
- struct addrinfo *best=NULL;
- struct addrinfo hints;
- int result = -1;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = family;
- hints.ai_socktype = SOCK_STREAM;
- err = tor_getaddrinfo(name, NULL, &hints, &res);
- /* The check for 'res' here shouldn't be necessary, but it makes static
- * analysis tools happy. */
- if (!err && res) {
- best = NULL;
- for (res_p = res; res_p; res_p = res_p->ai_next) {
- if (family == AF_UNSPEC) {
- if (res_p->ai_family == AF_INET) {
- best = res_p;
- break;
- } else if (res_p->ai_family == AF_INET6 && !best) {
- best = res_p;
- }
- } else if (family == res_p->ai_family) {
- best = res_p;
- break;
- }
- }
- if (!best)
- best = res;
- if (best->ai_family == AF_INET) {
- tor_addr_from_in(addr,
- &((struct sockaddr_in*)best->ai_addr)->sin_addr);
- result = 0;
- } else if (best->ai_family == AF_INET6) {
- tor_addr_from_in6(addr,
- &((struct sockaddr_in6*)best->ai_addr)->sin6_addr);
- result = 0;
- }
- tor_freeaddrinfo(res);
- return result;
- }
- return (err == EAI_AGAIN) ? 1 : -1;
+ result = tor_addr_lookup_host_getaddrinfo(name, family, addr);
+ goto done;
#else /* !(defined(HAVE_GETADDRINFO)) */
- struct hostent *ent;
- int err;
-#ifdef HAVE_GETHOSTBYNAME_R_6_ARG
- char buf[2048];
- struct hostent hostent;
- int r;
- r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err);
-#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
- char buf[2048];
- struct hostent hostent;
- ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err);
-#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG)
- struct hostent_data data;
- struct hostent hent;
- memset(&data, 0, sizeof(data));
- err = gethostbyname_r(name, &hent, &data);
- ent = err ? NULL : &hent;
-#else
- ent = gethostbyname(name);
-#ifdef _WIN32
- err = WSAGetLastError();
-#else
- err = h_errno;
-#endif
-#endif /* defined(HAVE_GETHOSTBYNAME_R_6_ARG) || ... */
- if (ent) {
- if (ent->h_addrtype == AF_INET) {
- tor_addr_from_in(addr, (struct in_addr*) ent->h_addr);
- } else if (ent->h_addrtype == AF_INET6) {
- tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr);
- } else {
- tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type
- }
- return 0;
- }
-#ifdef _WIN32
- return (err == WSATRY_AGAIN) ? 1 : -1;
-#else
- return (err == TRY_AGAIN) ? 1 : -1;
-#endif
+ result = tor_addr_lookup_host_gethostbyname(name, addr);
+ goto done;
#endif /* defined(HAVE_GETADDRINFO) */
}
+
+ /* If we weren't successful, and haven't already set the result,
+ * assume it's a permanent failure */
+ permfail:
+ result = -1;
+ goto done;
+ success:
+ result = 0;
+
+ /* We have set the result, now it's time to clean up */
+ done:
+ if (result) {
+ /* Clear the address on error */
+ memset(addr, 0, sizeof(tor_addr_t));
+ }
+ return result;
}
/** Parse an address or address-port combination from <b>s</b>, resolve the
* address as needed, and put the result in <b>addr_out</b> and (optionally)
- * <b>port_out</b>. Return 0 on success, negative on failure. */
+ * <b>port_out</b>.
+ *
+ * Like tor_addr_port_parse(), this function accepts:
+ * - IPv6 address and port, when the IPv6 address is in square brackets,
+ * - IPv6 address with square brackets,
+ * - IPv6 address without square brackets.
+ *
+ * Return 0 on success, negative on failure. */
int
tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
{
- const char *port;
tor_addr_t addr;
- uint16_t portval;
+ uint16_t portval = 0;
char *tmp = NULL;
+ int rv = 0;
+ int result;
tor_assert(s);
tor_assert(addr_out);
s = eat_whitespace(s);
- if (*s == '[') {
- port = strstr(s, "]");
- if (!port)
- goto err;
- tmp = tor_strndup(s+1, port-(s+1));
- port = port+1;
- if (*port == ':')
- port++;
- else
- port = NULL;
- } else {
- port = strchr(s, ':');
- if (port)
- tmp = tor_strndup(s, port-s);
- else
- tmp = tor_strdup(s);
- if (port)
- ++port;
+ /* Try parsing s as an address:port first, so we don't have to duplicate
+ * the logic that rejects IPv6:Port with no square brackets. */
+ rv = tor_addr_port_parse(LOG_WARN, s, &addr, &portval, 0);
+ /* That was easy, no DNS required. */
+ if (rv == 0)
+ goto success;
+
+ /* Now let's check for malformed IPv6 addresses and ports:
+ * tor_addr_port_parse() requires squared brackes if there is a port,
+ * and we want tor_addr_port_lookup() to have the same requirement.
+ * But we strip the port using tor_addr_port_split(), so tor_addr_lookup()
+ * only sees the address, and will accept it without square brackets. */
+ int family = tor_addr_parse(&addr, s);
+ /* If tor_addr_parse() succeeds where tor_addr_port_parse() failed, we need
+ * to reject this address as malformed. */
+ if (family >= 0) {
+ /* Double-check it's an IPv6 address. If not, we have a parsing bug.
+ */
+ tor_assertf_nonfatal(family == AF_INET6,
+ "Wrong family: %d (should be IPv6: %d) which "
+ "failed IP:port parsing, but passed IP parsing. "
+ "input string: '%s'; parsed address: '%s'.",
+ family, AF_INET6, s, fmt_addr(&addr));
+ goto err;
}
- if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0)
+ /* Now we have a hostname. Let's split off the port, if any. */
+ rv = tor_addr_port_split(LOG_WARN, s, &tmp, &portval);
+ if (rv < 0)
goto err;
- tor_free(tmp);
- if (port) {
- portval = (int) tor_parse_long(port, 10, 1, 65535, NULL, NULL);
- if (!portval)
- goto err;
- } else {
- portval = 0;
- }
+ /* And feed the hostname to the lookup function. */
+ if (tor_addr_lookup(tmp, AF_UNSPEC, &addr) != 0)
+ goto err;
+ success:
if (port_out)
*port_out = portval;
tor_addr_copy(addr_out, &addr);
+ result = 0;
+ goto done;
- return 0;
err:
+ /* Clear the address and port on error */
+ memset(addr_out, 0, sizeof(tor_addr_t));
+ if (port_out)
+ *port_out = 0;
+ result = -1;
+
+ /* We have set the result, now it's time to clean up */
+ done:
tor_free(tmp);
- return -1;
+ return result;
}
#ifdef USE_SANDBOX_GETADDRINFO
diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c
index a5cb71ce09..26203932e4 100644
--- a/src/lib/string/printf.c
+++ b/src/lib/string/printf.c
@@ -117,8 +117,8 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
*strp = NULL;
return -1;
}
- strp_tmp = tor_malloc(len + 1);
- r = _vsnprintf(strp_tmp, len+1, fmt, args);
+ strp_tmp = tor_malloc((size_t)len + 1);
+ r = _vsnprintf(strp_tmp, (size_t)len+1, fmt, args);
if (r != len) {
tor_free(strp_tmp);
*strp = NULL;
@@ -153,9 +153,9 @@ tor_vasprintf(char **strp, const char *fmt, va_list args)
*strp = tor_strdup(buf);
return len;
}
- strp_tmp = tor_malloc(len+1);
+ strp_tmp = tor_malloc((size_t)len+1);
/* use of tor_vsnprintf() will ensure string is null terminated */
- r = tor_vsnprintf(strp_tmp, len+1, fmt, args);
+ r = tor_vsnprintf(strp_tmp, (size_t)len+1, fmt, args);
if (r != len) {
tor_free(strp_tmp);
*strp = NULL;
diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c
index 7136eaba67..3f41500f3a 100644
--- a/src/lib/time/compat_time.c
+++ b/src/lib/time/compat_time.c
@@ -527,7 +527,7 @@ monotime_init_internal(void)
HANDLE h = load_windows_system_library(TEXT("kernel32.dll"));
if (h) {
- GetTickCount64_fn = (GetTickCount64_fn_t)
+ GetTickCount64_fn = (GetTickCount64_fn_t) (void(*)(void))
GetProcAddress(h, "GetTickCount64");
}
// We can't call FreeLibrary(h) here, because freeing the handle may
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index f7d9d6d15f..7a76fcdd94 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -168,7 +168,7 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
LinkAuth=3 \
Microdesc=1-2 \
Relay=1-2 \
- Padding=1 \
+ Padding=2 \
FlowCtrl=1"
)
} else {
@@ -183,7 +183,7 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
LinkAuth=1,3 \
Microdesc=1-2 \
Relay=1-2 \
- Padding=1 \
+ Padding=2 \
FlowCtrl=1"
)
}
diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs
index 98fccba5a9..bbaf97129c 100644
--- a/src/rust/tor_log/tor_log.rs
+++ b/src/rust/tor_log/tor_log.rs
@@ -99,14 +99,14 @@ pub mod log {
/// Domain log types. These mirror definitions in src/lib/log/log.h
/// C_RUST_COUPLED: src/lib/log/log.c, log severity types
extern "C" {
- static LD_NET_: u32;
- static LD_GENERAL_: u32;
+ static LD_NET_: u64;
+ static LD_GENERAL_: u64;
}
/// Translate Rust defintions of log domain levels to C. This exposes a 1:1
/// mapping between types.
#[inline]
- pub unsafe fn translate_domain(domain: LogDomain) -> u32 {
+ pub unsafe fn translate_domain(domain: LogDomain) -> u64 {
match domain {
LogDomain::Net => LD_NET_,
LogDomain::General => LD_GENERAL_,
@@ -128,7 +128,7 @@ pub mod log {
extern "C" {
pub fn tor_log_string(
severity: c_int,
- domain: u32,
+ domain: u64,
function: *const c_char,
string: *const c_char,
);
diff --git a/src/test/include.am b/src/test/include.am
index 0ec4d96ad4..1e20f3f53f 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -31,7 +31,11 @@ TESTSCRIPTS += \
endif
if USEPYTHON
-TESTSCRIPTS += src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh
+TESTSCRIPTS += \
+ src/test/test_ntor.sh \
+ src/test/test_hs_ntor.sh \
+ src/test/test_bt.sh \
+ scripts/maint/practracker/test_practracker.sh
if COVERAGE_ENABLED
# ...
@@ -154,6 +158,7 @@ src_test_test_SOURCES += \
src/test/test_handles.c \
src/test/test_hs_cache.c \
src/test/test_hs_descriptor.c \
+ src/test/test_hs_dos.c \
src/test/test_introduce.c \
src/test/test_keypin.c \
src/test/test_link_handshake.c \
diff --git a/src/test/test.c b/src/test/test.c
index 266b7454a3..b9a1da06f0 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -877,6 +877,7 @@ struct testgroup_t testgroups[] = {
{ "hs_config/", hs_config_tests },
{ "hs_control/", hs_control_tests },
{ "hs_descriptor/", hs_descriptor },
+ { "hs_dos/", hs_dos_tests },
{ "hs_intropoint/", hs_intropoint_tests },
{ "hs_ntor/", hs_ntor_tests },
{ "hs_service/", hs_service_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 322716a9ab..f5c21bfe88 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -227,6 +227,7 @@ extern struct testcase_t hs_common_tests[];
extern struct testcase_t hs_config_tests[];
extern struct testcase_t hs_control_tests[];
extern struct testcase_t hs_descriptor[];
+extern struct testcase_t hs_dos_tests[];
extern struct testcase_t hs_intropoint_tests[];
extern struct testcase_t hs_ntor_tests[];
extern struct testcase_t hs_service_tests[];
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 05d8bf6c7b..0f50a43615 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -724,155 +724,570 @@ test_addr_ip6_helpers(void *arg)
;
}
+/* Test that addr_str successfully parses, and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str.
+ */
+#define TEST_ADDR_PARSE_FMT(addr_str, expect_family, fmt_decorated, \
+ expect_str) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ char buf[TOR_ADDR_BUF_LEN]; \
+ const char *sv; \
+ r = tor_addr_parse(&addr, addr_str); \
+ tt_int_op(r, OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ STMT_END
+
+/* Test that addr_str fails to parse, and:
+ * - the returned address is null.
+ */
+#define TEST_ADDR_PARSE_XFAIL(addr_str) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ r = tor_addr_parse(&addr, addr_str); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ STMT_END
+
+/* Test that addr_port_str and default_port successfully parse, and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str,
+ * - the port is expect_port.
+ */
+#define TEST_ADDR_PORT_PARSE_FMT(addr_port_str, default_port, expect_family, \
+ fmt_decorated, expect_str, expect_port) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ uint16_t port; \
+ char buf[TOR_ADDR_BUF_LEN]; \
+ const char *sv; \
+ r = tor_addr_port_parse(LOG_DEBUG, addr_port_str, &addr, &port, \
+ default_port); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ tt_int_op(port, OP_EQ, expect_port); \
+ STMT_END
+
+/* Test that addr_port_str and default_port fail to parse, and:
+ * - the returned address is null,
+ * - the returned port is 0.
+ */
+#define TEST_ADDR_PORT_PARSE_XFAIL(addr_port_str, default_port) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ uint16_t port; \
+ r = tor_addr_port_parse(LOG_DEBUG, addr_port_str, &addr, &port, \
+ default_port); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ tt_int_op(port, OP_EQ, 0); \
+ STMT_END
+
+/* Test that addr_str successfully parses as an IPv4 address using
+ * tor_lookup_hostname(), and:
+ * - the fmt_addr32() of the result is expect_str.
+ */
+#define TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, expect_str) \
+ STMT_BEGIN \
+ int r; \
+ uint32_t addr32h; \
+ r = tor_lookup_hostname(addr_str, &addr32h); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_str_op(fmt_addr32(addr32h), OP_EQ, expect_str); \
+ STMT_END
+
+/* Test that bad_str fails to parse using tor_lookup_hostname(), with a
+ * permanent failure, and:
+ * - the returned address is 0.
+ */
+#define TEST_ADDR_V4_LOOKUP_XFAIL(bad_str) \
+ STMT_BEGIN \
+ int r; \
+ uint32_t addr32h; \
+ r = tor_lookup_hostname(bad_str, &addr32h); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_int_op(addr32h, OP_EQ, 0); \
+ STMT_END
+
+/* Test that looking up host_str as an IPv4 address using tor_lookup_hostname()
+ * does something sensible:
+ * - the result is -1, 0, or 1.
+ * - if the result is a failure, the returned address is 0.
+ * We can't rely on the result of this function, because it depends on the
+ * network.
+ */
+#define TEST_HOST_V4_LOOKUP(host_str) \
+ STMT_BEGIN \
+ int r; \
+ uint32_t addr32h; \
+ r = tor_lookup_hostname(host_str, &addr32h); \
+ tt_int_op(r, OP_GE, -1); \
+ tt_int_op(r, OP_LE, 1); \
+ if (r != 0) \
+ tt_int_op(addr32h, OP_EQ, 0); \
+ STMT_END
+
+/* Test that addr_str successfully parses as a require_family IP address using
+ * tor_addr_lookup(), and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str.
+ */
+#define TEST_ADDR_LOOKUP_FMT(addr_str, require_family, expect_family, \
+ fmt_decorated, expect_str) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ char buf[TOR_ADDR_BUF_LEN]; \
+ const char *sv; \
+ r = tor_addr_lookup(addr_str, require_family, &addr); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ STMT_END
+
+/* Test that bad_str fails to parse as a require_family IP address using
+ * tor_addr_lookup(), with a permanent failure, and:
+ * - the returned address is null.
+ */
+#define TEST_ADDR_LOOKUP_XFAIL(bad_str, require_family) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ r = tor_addr_lookup(bad_str, require_family, &addr); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ STMT_END
+
+/* Test that looking up host_string as a require_family IP address using
+ * tor_addr_lookup(), does something sensible:
+ * - the result is -1, 0, or 1.
+ * - if the result is a failure, the returned address is null.
+ * We can't rely on the result of this function, because it depends on the
+ * network.
+ */
+#define TEST_HOST_LOOKUP(host_str, require_family) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ r = tor_addr_lookup(host_str, require_family, &addr); \
+ tt_int_op(r, OP_GE, -1); \
+ tt_int_op(r, OP_LE, 1); \
+ if (r != 0) \
+ tt_assert(tor_addr_is_null(&addr)); \
+ STMT_END
+
+/* Test that addr_port_str successfully parses as an IP address and port
+ * using tor_addr_port_lookup(), and:
+ * - the address has family expect_family,
+ * - the fmt_decorated result of tor_addr_to_str() is expect_str,
+ * - the port is expect_port.
+ */
+#define TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, expect_family, \
+ fmt_decorated, expect_str, expect_port) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ uint16_t port; \
+ char buf[TOR_ADDR_BUF_LEN]; \
+ const char *sv; \
+ r = tor_addr_port_lookup(addr_port_str, &addr, &port); \
+ tt_int_op(r, OP_EQ, 0); \
+ tt_int_op(tor_addr_family(&addr), OP_EQ, expect_family); \
+ sv = tor_addr_to_str(buf, &addr, sizeof(buf), fmt_decorated); \
+ tt_str_op(sv, OP_EQ, buf); \
+ tt_str_op(buf, OP_EQ, expect_str); \
+ tt_int_op(port, OP_EQ, expect_port); \
+ STMT_END
+
+/* Test that bad_str fails to parse as an IP address and port
+ * using tor_addr_port_lookup(), and:
+ * - the returned address is null,
+ * - the returned port is 0.
+ */
+#define TEST_ADDR_PORT_LOOKUP_XFAIL(bad_str) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ uint16_t port; \
+ r = tor_addr_port_lookup(bad_str, &addr, &port); \
+ tt_int_op(r, OP_EQ, -1); \
+ tt_assert(tor_addr_is_null(&addr)); \
+ tt_int_op(port, OP_EQ, 0); \
+ STMT_END
+
+/* Test that looking up host_port_str as an IP address using
+ * tor_addr_port_lookup(), does something sensible:
+ * - the result is -1 or 0.
+ * - if the result is a failure, the returned address is null, and the
+ * returned port is zero,
+ * - if the result is a success, the returned port is expect_success_port,
+ * and the returned family is AF_INET or AF_INET6.
+ * We can't rely on the result of this function, because it depends on the
+ * network.
+ */
+#define TEST_HOST_PORT_LOOKUP(host_port_str, expect_success_port) \
+ STMT_BEGIN \
+ int r; \
+ tor_addr_t addr; \
+ uint16_t port; \
+ r = tor_addr_port_lookup(host_port_str, &addr, &port); \
+ tt_int_op(r, OP_GE, -1); \
+ tt_int_op(r, OP_LE, 0); \
+ if (r == -1) { \
+ tt_assert(tor_addr_is_null(&addr)); \
+ tt_int_op(port, OP_EQ, 0); \
+ } else { \
+ tt_assert(tor_addr_family(&addr) == AF_INET || \
+ tor_addr_family(&addr) == AF_INET6); \
+ tt_int_op(port, OP_EQ, expect_success_port); \
+ } \
+ STMT_END
+
+/* Test that addr_str successfully parses as a canonical IPv4 address.
+ * Check for successful parsing using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() with a default port,
+ * - tor_lookup_hostname(),
+ * - tor_addr_lookup() with AF_INET,
+ * - tor_addr_lookup() with AF_UNSPEC,
+ * - tor_addr_port_lookup(), with a zero port.
+ * Check for failures using:
+ * - tor_addr_port_parse() without a default port, because there is no port,
+ * - tor_addr_lookup() with AF_INET6,
+ * - tor_addr_port_lookup(), because there is no port.
+ */
+#define TEST_ADDR_V4_PARSE_CANONICAL(addr_str) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_FMT(addr_str, AF_INET, 0, addr_str); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_str, 111, AF_INET, 0, \
+ addr_str, 111); \
+ TEST_ADDR_V4_LOOKUP_HOSTNAME(addr_str, addr_str); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET, 0, addr_str, 0); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET, AF_INET, 0, addr_str); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET, 0, addr_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET6); \
+ STMT_END
+
+/* Test that addr_str successfully parses as a canonical fmt_decorated
+ * IPv6 address.
+ * Check for successful parsing using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_lookup() with AF_INET6,
+ * - tor_addr_lookup() with AF_UNSPEC,
+ * - tor_addr_port_lookup(), with a zero port.
+ * Check for failures using:
+ * - tor_addr_port_parse() without a default port, because there is no port,
+ * - tor_lookup_hostname(), because it only supports IPv4,
+ * - tor_addr_lookup() with AF_INET.
+ */
+#define TEST_ADDR_V6_PARSE_CANONICAL(addr_str, fmt_decorated) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, addr_str); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_str, 222, AF_INET6, fmt_decorated, \
+ addr_str, 222); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET6, AF_INET6, fmt_decorated, \
+ addr_str); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \
+ addr_str); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET6, fmt_decorated, addr_str, \
+ 0); \
+ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \
+ STMT_END
+
+/* Test that addr_str successfully parses, and the fmt_decorated canonical
+ * IPv6 string is expect_str.
+ * Check for successful parsing using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_lookup() with AF_INET6,
+ * - tor_addr_lookup() with AF_UNSPEC,
+ * - tor_addr_port_lookup(), with a zero port.
+ * Check for failures using:
+ * - tor_addr_port_parse() without a default port, because there is no port.
+ * - tor_lookup_hostname(), because it only supports IPv4,
+ * - tor_addr_lookup() with AF_INET.
+ */
+#define TEST_ADDR_V6_PARSE(addr_str, fmt_decorated, expect_str) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_FMT(addr_str, AF_INET6, fmt_decorated, expect_str); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_str, 333, AF_INET6, fmt_decorated, \
+ expect_str, 333); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_INET6, AF_INET6, fmt_decorated, \
+ expect_str); \
+ TEST_ADDR_LOOKUP_FMT(addr_str, AF_UNSPEC, AF_INET6, fmt_decorated, \
+ expect_str); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_str, AF_INET6, fmt_decorated, expect_str, \
+ 0); \
+ TEST_ADDR_PORT_PARSE_XFAIL(addr_str, -1); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_str, AF_INET); \
+ STMT_END
+
+/* Test that addr_port_str successfully parses to the canonical IPv4 address
+ * string expect_str, and port expect_port.
+ * Check for successful parsing using:
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_port_lookup().
+ * Check for failures using:
+ * - tor_addr_parse(), because there is a port,
+ * - tor_lookup_hostname(), because there is a port.
+ * - tor_addr_lookup(), regardless of the address family, because there is a
+ * port.
+ */
+#define TEST_ADDR_V4_PORT_PARSE(addr_port_str, expect_str, expect_port) \
+ STMT_BEGIN \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 444, AF_INET, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, AF_INET, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PARSE_XFAIL(addr_port_str); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET6); \
+ STMT_END
+
+/* Test that addr_port_str successfully parses to the canonical undecorated
+ * IPv6 address string expect_str, and port expect_port.
+ * Check for successful parsing using:
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_addr_port_lookup().
+ * Check for failures using:
+ * - tor_addr_parse(), because there is a port,
+ * - tor_lookup_hostname(), because there is a port, and because it only
+ * supports IPv4,
+ * - tor_addr_lookup(), regardless of the address family, because there is a
+ * port.
+ */
+#define TEST_ADDR_V6_PORT_PARSE(addr_port_str, expect_str, expect_port) \
+ STMT_BEGIN \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, -1, AF_INET6, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_PARSE_FMT(addr_port_str, 555, AF_INET6, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PORT_LOOKUP_FMT(addr_port_str, AF_INET6, 0, expect_str, \
+ expect_port); \
+ TEST_ADDR_PARSE_XFAIL(addr_port_str); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(addr_port_str); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET6); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(addr_port_str, AF_INET); \
+ STMT_END
+
+/* Test that bad_str fails to parse due to a bad address or port.
+ * Check for failures using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_lookup_hostname(),
+ * - tor_addr_lookup(), regardless of the address family,
+ * - tor_addr_port_lookup().
+ */
+#define TEST_ADDR_PARSE_XFAIL_MALFORMED(bad_str) \
+ STMT_BEGIN \
+ TEST_ADDR_PARSE_XFAIL(bad_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(bad_str, -1); \
+ TEST_ADDR_PORT_PARSE_XFAIL(bad_str, 666); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(bad_str); \
+ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET); \
+ TEST_ADDR_LOOKUP_XFAIL(bad_str, AF_INET6); \
+ TEST_ADDR_PORT_LOOKUP_XFAIL(bad_str); \
+ STMT_END
+
+/* Test that host_str is treated as a hostname, and not an address.
+ * Check for success or failure using the network-dependent functions:
+ * - tor_lookup_hostname(),
+ * - tor_addr_lookup(), regardless of the address family,
+ * - tor_addr_port_lookup(), expecting a zero port.
+ * Check for failures using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port.
+ */
+#define TEST_HOSTNAME(host_str) \
+ STMT_BEGIN \
+ TEST_HOST_V4_LOOKUP(host_str); \
+ TEST_HOST_LOOKUP(host_str, AF_UNSPEC); \
+ TEST_HOST_LOOKUP(host_str, AF_INET); \
+ TEST_HOST_LOOKUP(host_str, AF_INET6); \
+ TEST_HOST_PORT_LOOKUP(host_str, 0); \
+ TEST_ADDR_PARSE_XFAIL(host_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_str, -1); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_str, 777); \
+ STMT_END
+
+/* Test that host_port_str is treated as a hostname and port, and not a
+ * hostname or an address.
+ * Check for success or failure using the network-dependent function:
+ * - tor_addr_port_lookup(), expecting expect_success_port if the lookup is
+ * successful.
+ * Check for failures using:
+ * - tor_addr_parse(),
+ * - tor_addr_port_parse() without a default port,
+ * - tor_addr_port_parse() with a default port,
+ * - tor_lookup_hostname(), because it doesn't support ports,
+ * - tor_addr_lookup(), regardless of the address family, because it doesn't
+ * support ports.
+ */
+#define TEST_HOSTNAME_PORT(host_port_str, expect_success_port) \
+ STMT_BEGIN \
+ TEST_HOST_PORT_LOOKUP(host_port_str, expect_success_port); \
+ TEST_ADDR_PARSE_XFAIL(host_port_str); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, -1); \
+ TEST_ADDR_PORT_PARSE_XFAIL(host_port_str, 888); \
+ TEST_ADDR_V4_LOOKUP_XFAIL(host_port_str); \
+ TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_UNSPEC); \
+ TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_INET); \
+ TEST_ADDR_LOOKUP_XFAIL(host_port_str, AF_INET6); \
+ STMT_END
+
/** Test tor_addr_parse() and tor_addr_port_parse(). */
static void
test_addr_parse(void *arg)
{
- int r;
- tor_addr_t addr;
- char buf[TOR_ADDR_BUF_LEN];
- uint16_t port = 0;
-
- /* Correct call. */
(void)arg;
- r= tor_addr_parse(&addr, "192.0.2.1");
- tt_int_op(r,OP_EQ, AF_INET);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "192.0.2.1");
-
- r= tor_addr_parse(&addr, "11:22::33:44");
- tt_int_op(r,OP_EQ, AF_INET6);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "11:22::33:44");
-
- r= tor_addr_parse(&addr, "[11:22::33:44]");
- tt_int_op(r,OP_EQ, AF_INET6);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "11:22::33:44");
-
- r= tor_addr_parse(&addr, "11:22:33:44:55:66:1.2.3.4");
- tt_int_op(r,OP_EQ, AF_INET6);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "11:22:33:44:55:66:102:304");
-
- r= tor_addr_parse(&addr, "11:22::33:44:1.2.3.4");
- tt_int_op(r,OP_EQ, AF_INET6);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "11:22::33:44:102:304");
- /* Empty string. */
- r= tor_addr_parse(&addr, "");
- tt_int_op(r,OP_EQ, -1);
+ /* Correct calls. */
+ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.1");
+ TEST_ADDR_V4_PARSE_CANONICAL("192.0.2.2");
- /* Square brackets around IPv4 address. */
- r= tor_addr_parse(&addr, "[192.0.2.1]");
- tt_int_op(r,OP_EQ, -1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[11:22::33:44]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[::1]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[::]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[2::]", 1);
+ TEST_ADDR_V6_PARSE_CANONICAL("[11:22:33:44:55:66:77:88]", 1);
- /* Only left square bracket. */
- r= tor_addr_parse(&addr, "[11:22::33:44");
- tt_int_op(r,OP_EQ, -1);
+ /* Allow IPv6 without square brackets, when there is no port, but only if
+ * there is a default port */
+ TEST_ADDR_V6_PARSE_CANONICAL("11:22::33:44", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("::1", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("::", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("2::", 0);
+ TEST_ADDR_V6_PARSE_CANONICAL("11:22:33:44:55:66:77:88", 0);
- /* Only right square bracket. */
- r= tor_addr_parse(&addr, "11:22::33:44]");
- tt_int_op(r,OP_EQ, -1);
+ /* IPv6-mapped IPv4 addresses. Tor doesn't really use these. */
+ TEST_ADDR_V6_PARSE("11:22:33:44:55:66:1.2.3.4", 0,
+ "11:22:33:44:55:66:102:304");
- /* Leading colon. */
- r= tor_addr_parse(&addr, ":11:22::33:44");
- tt_int_op(r,OP_EQ, -1);
+ TEST_ADDR_V6_PARSE("11:22::33:44:1.2.3.4", 0,
+ "11:22::33:44:102:304");
- /* Trailing colon. */
- r= tor_addr_parse(&addr, "11:22::33:44:");
- tt_int_op(r,OP_EQ, -1);
-
- /* Too many hex words in IPv4-mapped IPv6 address. */
- r= tor_addr_parse(&addr, "11:22:33:44:55:66:77:88:1.2.3.4");
- tt_int_op(r,OP_EQ, -1);
-
- /* Correct call. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.1:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, 0);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "192.0.2.1");
- tt_int_op(port,OP_EQ, 1234);
-
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, 0);
- tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- tt_str_op(buf,OP_EQ, "::1");
- tt_int_op(port,OP_EQ, 1234);
-
- /* Domain name. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "torproject.org:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ /* Ports. */
+ TEST_ADDR_V4_PORT_PARSE("192.0.2.1:1234", "192.0.2.1", 1234);
+ TEST_ADDR_V6_PORT_PARSE("[::1]:1234", "::1", 1234);
- /* Only IP. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ /* Host names. */
+ TEST_HOSTNAME("localhost");
+ TEST_HOSTNAME_PORT("localhost:1234", 1234);
+ TEST_HOSTNAME_PORT("localhost:0", 0);
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,200);
+ TEST_HOSTNAME("torproject.org");
+ TEST_HOSTNAME_PORT("torproject.org:56", 56);
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ TEST_HOSTNAME("probably-not-a-valid-dns.name-tld");
+ TEST_HOSTNAME_PORT("probably-not-a-valid-dns.name-tld:789", 789);
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]",
- &addr, &port, 400);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,400);
+ /* Malformed addresses. */
+ /* Empty string. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("");
- /* Bad port. */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2:66666",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2:66666",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, -1);
+ /* Square brackets around IPv4 address. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.1]");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[192.0.2.3]:12345");
- /* Only domain name */
- r= tor_addr_port_parse(LOG_DEBUG,
- "torproject.org",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
- r= tor_addr_port_parse(LOG_DEBUG,
- "torproject.org",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, -1);
+ /* Only left square bracket. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[11:22::33:44");
- /* Bad IP address */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2:1234",
- &addr, &port, -1);
- tt_int_op(r, OP_EQ, -1);
+ /* Only right square bracket. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44]");
+
+ /* Leading colon. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED(":11:22::33:44");
+
+ /* Trailing colon. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("11:22::33:44:");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:");
- /* Make sure that the default port has lower priority than the real
- one */
- r= tor_addr_port_parse(LOG_DEBUG,
- "192.0.2.2:1337",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,1337);
-
- r= tor_addr_port_parse(LOG_DEBUG,
- "[::1]:1369",
- &addr, &port, 200);
- tt_int_op(r, OP_EQ, 0);
- tt_int_op(port,OP_EQ,1369);
+ /* Bad port. */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:66666");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:77777");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:88888");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:99999");
+
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:-1");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:-2");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:-3");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:-4");
+
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:1 bad");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("192.0.2.2:bad-port");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("[::1]:bad-port-1");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("::1:1-bad-port");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:1-bad-port");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("localhost:1-bad-port-1");
+
+ /* Bad hostname */
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid");
+ TEST_ADDR_PARSE_XFAIL_MALFORMED("definitely invalid:22222");
+
+ /* Ambiguous cases */
+ /* Too many hex words in IPv4-mapped IPv6 address.
+ * But some OS host lookup routines accept it as a hostname, or
+ * as an IP address?? (I assume they discard unused characters). */
+ TEST_HOSTNAME("11:22:33:44:55:66:77:88:1.2.3.4");
+
+ /* IPv6 address with port and no brackets
+ * We reject it, but some OS host lookup routines accept it as an
+ * IPv6 address:port ? */
+ TEST_HOSTNAME_PORT("11:22::33:44:12345", 12345);
+ /* Is it a port, or are there too many hex words?
+ * We reject it either way, but some OS host lookup routines accept it as an
+ * IPv6 address:port */
+ TEST_HOSTNAME_PORT("11:22:33:44:55:66:77:88:99", 99);
+ /* But we accept it if it has square brackets. */
+ TEST_ADDR_V6_PORT_PARSE("[11:22:33:44:55:66:77:88]:99",
+ "11:22:33:44:55:66:77:88",99);
+
+ /* Bad IPv4 address
+ * We reject it, but some OS host lookup routines accept it as an
+ * IPv4 address[:port], with a zero last octet */
+ TEST_HOSTNAME("192.0.1");
+ TEST_HOSTNAME_PORT("192.0.2:1234", 1234);
+
+ /* More bad IPv6 addresses and ports: no brackets
+ * We reject it, but some OS host lookup routines accept it as an
+ * IPv6 address[:port] */
+ TEST_HOSTNAME_PORT("::1:12345", 12345);
+ TEST_HOSTNAME_PORT("11:22::33:44:12345", 12345);
+
+ /* And this is an ambiguous case, which is interpreted as an IPv6 address. */
+ TEST_ADDR_V6_PARSE_CANONICAL("11:22::88:99", 0);
+ /* Use square brackets to resolve the ambiguity */
+ TEST_ADDR_V6_PARSE_CANONICAL("[11:22::88:99]", 1);
+ TEST_ADDR_V6_PORT_PARSE("[11:22::88]:99",
+ "11:22::88",99);
done:
;
diff --git a/src/test/test_btrack.c b/src/test/test_btrack.c
index 9e5d0d0723..21e88a57b6 100644
--- a/src/test/test_btrack.c
+++ b/src/test/test_btrack.c
@@ -44,6 +44,8 @@ test_btrack_launch(void *arg)
{
orconn_state_msg_t conn;
ocirc_chan_msg_t circ;
+ memset(&conn, 0, sizeof(conn));
+ memset(&circ, 0, sizeof(circ));
(void)arg;
conn.gid = 1;
@@ -93,6 +95,8 @@ test_btrack_delete(void *arg)
{
orconn_state_msg_t state;
orconn_status_msg_t status;
+ memset(&state, 0, sizeof(state));
+ memset(&status, 0, sizeof(status));
(void)arg;
state.gid = 1;
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 47218a559a..196d8cd355 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -4,6 +4,8 @@
/* See LICENSE for licensing information */
#define CIRCUITBUILD_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define ENTRYNODES_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
@@ -13,7 +15,11 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/cpath_build_state_st.h"
#include "core/or/extend_info_st.h"
+#include "core/or/origin_circuit_st.h"
+
+#include "feature/client/entrynodes.h"
/* Dummy nodes smartlist for testing */
static smartlist_t dummy_nodes;
@@ -126,10 +132,51 @@ test_new_route_len_unhandled_exit(void *arg)
UNMOCK(count_acceptable_nodes);
}
+static void
+test_upgrade_from_guard_wait(void *arg)
+{
+ circuit_t *circ = NULL;
+ origin_circuit_t *orig_circ = NULL;
+ entry_guard_t *guard = NULL;
+ smartlist_t *list = NULL;
+
+ (void) arg;
+
+ circ = dummy_origin_circuit_new(0);
+ orig_circ = TO_ORIGIN_CIRCUIT(circ);
+ tt_assert(orig_circ);
+
+ orig_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+
+ circuit_set_state(circ, CIRCUIT_STATE_GUARD_WAIT);
+
+ /* Put it in guard wait state. */
+ guard = tor_malloc_zero(sizeof(*guard));
+ guard->in_selection = get_guard_selection_info();
+
+ orig_circ->guard_state =
+ circuit_guard_state_new(guard, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD,
+ NULL);
+
+ /* Mark the circuit for close. */
+ circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
+ tt_int_op(circ->marked_for_close, OP_NE, 0);
+
+ /* We shouldn't pick the mark for close circuit. */
+ list = circuit_find_circuits_to_upgrade_from_guard_wait();
+ tt_assert(!list);
+
+ done:
+ circuit_free(circ);
+ entry_guard_free_(guard);
+}
+
struct testcase_t circuitbuild_tests[] = {
{ "noexit", test_new_route_len_noexit, 0, NULL, NULL },
{ "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL },
{ "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL },
{ "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL },
+ { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK,
+ &helper_pubsub_setup, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c
index 236f4a192d..934ddb0208 100644
--- a/src/test/test_circuitpadding.c
+++ b/src/test/test_circuitpadding.c
@@ -4,9 +4,11 @@
#define CIRCUITPADDING_MACHINES_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define CRYPT_PATH_PRIVATE
+#define RELAY_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
+#include "test/log_test_helpers.h"
#include "lib/testsupport/testsupport.h"
#include "core/or/connection_or.h"
#include "core/or/channel.h"
@@ -90,10 +92,10 @@ static void
nodes_init(void)
{
padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
- padding_node.rs->pv.supports_padding = 1;
+ padding_node.rs->pv.supports_hs_setup_padding = 1;
non_padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
- non_padding_node.rs->pv.supports_padding = 0;
+ non_padding_node.rs->pv.supports_hs_setup_padding = 0;
}
static void
@@ -3152,6 +3154,29 @@ test_circuitpadding_hs_machines(void *arg)
UNMOCK(circpad_machine_schedule_padding);
}
+/** Test that we effectively ignore non-padding cells in padding circuits. */
+static void
+test_circuitpadding_ignore_non_padding_cells(void *arg)
+{
+ int retval;
+ relay_header_t rh;
+
+ (void) arg;
+
+ client_side = (circuit_t *)origin_circuit_new();
+ client_side->purpose = CIRCUIT_PURPOSE_C_CIRCUIT_PADDING;
+
+ rh.command = RELAY_COMMAND_BEGIN;
+
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = handle_relay_cell_command(NULL, client_side, NULL, NULL, &rh, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ expect_log_msg_containing("Ignored cell");
+
+ done:
+ ;
+}
+
#define TEST_CIRCUITPADDING(name, flags) \
{ #name, test_##name, (flags), NULL, NULL }
@@ -3175,5 +3200,6 @@ struct testcase_t circuitpadding_tests[] = {
TEST_CIRCUITPADDING(circuitpadding_token_removal_exact, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_manage_circuit_lifetime, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_hs_machines, TT_FORK),
+ TEST_CIRCUITPADDING(circuitpadding_ignore_non_padding_cells, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index ee48d656bd..b9cbe0a14d 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -9,6 +9,7 @@
#include "feature/control/control.h"
#include "feature/control/control_cmd.h"
#include "feature/control/control_getinfo.h"
+#include "feature/control/control_proto.h"
#include "feature/client/entrynodes.h"
#include "feature/hs/hs_common.h"
#include "feature/nodelist/networkstatus.h"
@@ -201,42 +202,58 @@ static const control_cmd_syntax_t one_arg_kwargs_syntax = {
static const parse_test_params_t parse_one_arg_kwargs_params =
TESTPARAMS( one_arg_kwargs_syntax, one_arg_kwargs_tests );
+static char *reply_str = NULL;
+/* Mock for control_write_reply that copies the string for inspection
+ * by tests */
+static void
+mock_control_write_reply(control_connection_t *conn, int code, int c,
+ const char *s)
+{
+ (void)conn;
+ (void)code;
+ (void)c;
+ tor_free(reply_str);
+ reply_str = tor_strdup(s);
+}
+
static void
test_add_onion_helper_keyarg_v3(void *arg)
{
int ret, hs_version;
add_onion_secret_key_t pk;
char *key_new_blob = NULL;
- char *err_msg = NULL;
const char *key_new_alg = NULL;
(void) arg;
+ MOCK(control_write_reply, mock_control_write_reply);
memset(&pk, 0, sizeof(pk));
/* Test explicit ED25519-V3 key generation. */
+ tor_free(reply_str);
ret = add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg,
&key_new_blob, &pk, &hs_version,
- &err_msg);
+ NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
tt_assert(pk.v3);
tt_str_op(key_new_alg, OP_EQ, "ED25519-V3");
tt_assert(key_new_blob);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tor_free(pk.v3); pk.v3 = NULL;
tor_free(key_new_blob);
/* Test discarding the private key. */
+ tor_free(reply_str);
ret = add_onion_helper_keyarg("NEW:ED25519-V3", 1, &key_new_alg,
&key_new_blob, &pk, &hs_version,
- &err_msg);
+ NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
tt_assert(pk.v3);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tor_free(pk.v3); pk.v3 = NULL;
tor_free(key_new_blob);
@@ -256,9 +273,10 @@ test_add_onion_helper_keyarg_v3(void *arg)
tor_asprintf(&key_blob, "ED25519-V3:%s", base64_sk);
tt_assert(key_blob);
+ tor_free(reply_str);
ret = add_onion_helper_keyarg(key_blob, 1, &key_new_alg,
&key_new_blob, &pk, &hs_version,
- &err_msg);
+ NULL);
tor_free(key_blob);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
@@ -266,7 +284,7 @@ test_add_onion_helper_keyarg_v3(void *arg)
tt_mem_op(pk.v3, OP_EQ, hex_sk, 64);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tor_free(pk.v3); pk.v3 = NULL;
tor_free(key_new_blob);
}
@@ -274,7 +292,8 @@ test_add_onion_helper_keyarg_v3(void *arg)
done:
tor_free(pk.v3);
tor_free(key_new_blob);
- tor_free(err_msg);
+ tor_free(reply_str);
+ UNMOCK(control_write_reply);
}
static void
@@ -285,72 +304,73 @@ test_add_onion_helper_keyarg_v2(void *arg)
crypto_pk_t *pk1 = NULL;
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
- char *err_msg = NULL;
char *encoded = NULL;
char *arg_str = NULL;
(void) arg;
+ MOCK(control_write_reply, mock_control_write_reply);
memset(&pk, 0, sizeof(pk));
/* Test explicit RSA1024 key generation. */
+ tor_free(reply_str);
ret = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(pk.v2);
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
tt_assert(key_new_blob);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
/* Test "BEST" key generation (Assumes BEST = RSA1024). */
crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_free(key_new_blob);
ret = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(pk.v2);
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
tt_assert(key_new_blob);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
/* Test discarding the private key. */
crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_free(key_new_blob);
ret = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
/* Test generating a invalid key type. */
crypto_pk_free(pk.v2); pk.v2 = NULL;
ret = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, -1);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(err_msg);
+ tt_assert(reply_str);
/* Test loading a RSA1024 key. */
- tor_free(err_msg);
+ tor_free(reply_str);
pk1 = pk_generate(0);
tt_int_op(0, OP_EQ, crypto_pk_base64_encode_private(pk1, &encoded));
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
tt_int_op(crypto_pk_cmp_keys(pk1, pk.v2), OP_EQ, 0);
/* Test loading a invalid key type. */
@@ -359,36 +379,37 @@ test_add_onion_helper_keyarg_v2(void *arg)
crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_asprintf(&arg_str, "RSA512:%s", encoded);
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, -1);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(err_msg);
+ tt_assert(reply_str);
/* Test loading a invalid key. */
tor_free(arg_str);
crypto_pk_free(pk.v2); pk.v2 = NULL;
- tor_free(err_msg);
+ tor_free(reply_str);
encoded[strlen(encoded)/2] = '\0';
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &pk, &hs_version, &err_msg);
+ &pk, &hs_version, NULL);
tt_int_op(ret, OP_EQ, -1);
tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
- tt_assert(err_msg);
+ tt_assert(reply_str);
done:
crypto_pk_free(pk1);
crypto_pk_free(pk.v2);
tor_free(key_new_blob);
- tor_free(err_msg);
+ tor_free(reply_str);
tor_free(encoded);
tor_free(arg_str);
+ UNMOCK(control_write_reply);
}
static void
@@ -542,49 +563,52 @@ static void
test_add_onion_helper_clientauth(void *arg)
{
rend_authorized_client_t *client = NULL;
- char *err_msg = NULL;
int created = 0;
(void)arg;
+ MOCK(control_write_reply, mock_control_write_reply);
/* Test "ClientName" only. */
- client = add_onion_helper_clientauth("alice", &created, &err_msg);
+ tor_free(reply_str);
+ client = add_onion_helper_clientauth("alice", &created, NULL);
tt_assert(client);
tt_assert(created);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
rend_authorized_client_free(client);
/* Test "ClientName:Blob" */
+ tor_free(reply_str);
client = add_onion_helper_clientauth("alice:475hGBHPlq7Mc0cRZitK/B",
- &created, &err_msg);
+ &created, NULL);
tt_assert(client);
tt_assert(!created);
- tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_ptr_op(reply_str, OP_EQ, NULL);
rend_authorized_client_free(client);
/* Test invalid client names */
+ tor_free(reply_str);
client = add_onion_helper_clientauth("no*asterisks*allowed", &created,
- &err_msg);
+ NULL);
tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(err_msg);
- tor_free(err_msg);
+ tt_assert(reply_str);
/* Test invalid auth cookie */
- client = add_onion_helper_clientauth("alice:12345", &created, &err_msg);
+ tor_free(reply_str);
+ client = add_onion_helper_clientauth("alice:12345", &created, NULL);
tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(err_msg);
- tor_free(err_msg);
+ tt_assert(reply_str);
/* Test invalid syntax */
+ tor_free(reply_str);
client = add_onion_helper_clientauth(":475hGBHPlq7Mc0cRZitK/B", &created,
- &err_msg);
+ NULL);
tt_ptr_op(client, OP_EQ, NULL);
- tt_assert(err_msg);
- tor_free(err_msg);
+ tt_assert(reply_str);
done:
rend_authorized_client_free(client);
- tor_free(err_msg);
+ tor_free(reply_str);
+ UNMOCK(control_write_reply);
}
/* Mocks and data/variables used for GETINFO download status tests */
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
index a8967bba50..9fb2bc7256 100644
--- a/src/test/test_controller_events.c
+++ b/src/test/test_controller_events.c
@@ -429,6 +429,7 @@ static void
test_cntev_orconn_state(void *arg)
{
orconn_state_msg_t conn;
+ memset(&conn, 0, sizeof(conn));
(void)arg;
MOCK(queue_control_event_string, mock_queue_control_event_string);
@@ -468,6 +469,7 @@ static void
test_cntev_orconn_state_pt(void *arg)
{
orconn_state_msg_t conn;
+ memset(&conn, 0, sizeof(conn));
(void)arg;
MOCK(queue_control_event_string, mock_queue_control_event_string);
@@ -503,6 +505,7 @@ static void
test_cntev_orconn_state_proxy(void *arg)
{
orconn_state_msg_t conn;
+ memset(&conn, 0, sizeof(conn));
(void)arg;
MOCK(queue_control_event_string, mock_queue_control_event_string);
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
index d71f8b6b18..86ac7e7fb1 100644
--- a/src/test/test_hs_cache.c
+++ b/src/test/test_hs_cache.c
@@ -10,6 +10,7 @@
#define DIRCACHE_PRIVATE
#define DIRCLIENT_PRIVATE
#define HS_CACHE_PRIVATE
+#define TOR_CHANNEL_INTERNAL_
#include "trunnel/ed25519_cert.h"
#include "feature/hs/hs_cache.h"
@@ -20,7 +21,12 @@
#include "core/mainloop/connection.h"
#include "core/proto/proto_http.h"
#include "lib/crypt_ops/crypto_format.h"
+#include "core/or/circuitlist.h"
+#include "core/or/channel.h"
+#include "core/or/edge_connection_st.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/or_connection_st.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -232,6 +238,8 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
/* The dir conn we are going to simulate */
dir_connection_t *conn = NULL;
+ edge_connection_t *edge_conn = NULL;
+ or_circuit_t *or_circ = NULL;
/* First extract the blinded public key that we are going to use in our
query, and then build the actual query string. */
@@ -245,8 +253,16 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
/* Simulate an HTTP GET request to the HSDir */
conn = dir_connection_new(AF_INET);
tt_assert(conn);
+ TO_CONN(conn)->linked = 1; /* Signal that it is encrypted. */
tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001);
- TO_CONN(conn)->linked = 1;/* Pretend the conn is encrypted :) */
+
+ /* Pretend this conn is anonymous. */
+ edge_conn = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
+ TO_CONN(conn)->linked_conn = TO_CONN(edge_conn);
+ or_circ = or_circuit_new(0, NULL);
+ or_circ->p_chan = tor_malloc_zero(sizeof(channel_t));
+ edge_conn->on_circuit = TO_CIRCUIT(or_circ);
+
retval = directory_handle_command_get(conn, hsdir_query_str,
NULL, 0);
tt_int_op(retval, OP_EQ, 0);
@@ -263,8 +279,11 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
done:
tor_free(hsdir_query_str);
- if (conn)
+ if (conn) {
+ tor_free(or_circ->p_chan);
+ connection_free_minimal(TO_CONN(conn)->linked_conn);
connection_free_minimal(TO_CONN(conn));
+ }
return received_desc;
}
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 0d25a98bb3..fb497d52a1 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -37,6 +37,7 @@
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_cache.h"
+#include "feature/rend/rendcache.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
#include "core/mainloop/connection.h"
@@ -1007,6 +1008,92 @@ test_close_intro_circuits_new_desc(void *arg)
UNMOCK(networkstatus_get_live_consensus);
}
+static void
+test_close_intro_circuits_cache_clean(void *arg)
+{
+ int ret;
+ ed25519_keypair_t service_kp;
+ circuit_t *circ = NULL;
+ origin_circuit_t *ocirc = NULL;
+ hs_descriptor_t *desc1 = NULL;
+
+ (void) arg;
+
+ hs_init();
+ rend_cache_init();
+
+ /* This is needed because of the client cache expiration timestamp is based
+ * on having a consensus. See cached_client_descriptor_has_expired(). */
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Set consensus time */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+
+ /* Create and add to the global list a dummy client introduction circuits.
+ * We'll then make sure the hs_ident is attached to a dummy descriptor. */
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+
+ /* Build the first descriptor and cache it. */
+ {
+ char *encoded;
+ desc1 = hs_helper_build_hs_desc_with_ip(&service_kp);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &service_kp, NULL, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+
+ /* Store it */
+ ret = hs_cache_store_as_client(encoded, &service_kp.pubkey);
+ tt_int_op(ret, OP_EQ, 0);
+ tor_free(encoded);
+ tt_assert(hs_cache_lookup_as_client(&service_kp.pubkey));
+ }
+
+ /* We'll pick one introduction point and associate it with the circuit. */
+ {
+ const hs_desc_intro_point_t *ip =
+ smartlist_get(desc1->encrypted_data.intro_points, 0);
+ tt_assert(ip);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey,
+ HS_IDENT_CIRCUIT_INTRO);
+ ed25519_pubkey_copy(&ocirc->hs_ident->intro_auth_pk,
+ &ip->auth_key_cert->signed_key);
+ }
+
+ /* Before we are about to clean up the intro circuits, make sure it is
+ * actually there. */
+ tt_assert(circuit_get_next_intro_circ(NULL, true));
+
+ /* Cleanup the client cache. The ns valid after time is what decides if the
+ * descriptor has expired so put it in the future enough (72h) so we are
+ * sure to always expire. */
+ mock_ns.valid_after = approx_time() + (72 * 24 * 60 * 60);
+ hs_cache_clean_as_client(0);
+
+ /* Once stored, our intro circuit should be closed because it is related to
+ * an old introduction point that doesn't exists anymore. */
+ tt_assert(!circuit_get_next_intro_circ(NULL, true));
+
+ done:
+ circuit_free(circ);
+ hs_descriptor_free(desc1);
+ hs_free_all();
+ rend_cache_free_all();
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
struct testcase_t hs_client_tests[] = {
{ "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
TT_FORK, NULL, NULL },
@@ -1026,6 +1113,8 @@ struct testcase_t hs_client_tests[] = {
TT_FORK, NULL, NULL },
{ "close_intro_circuits_new_desc", test_close_intro_circuits_new_desc,
TT_FORK, NULL, NULL },
+ { "close_intro_circuits_cache_clean", test_close_intro_circuits_cache_clean,
+ TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index abded6021e..de3f7e04f7 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -502,6 +502,7 @@ test_desc_reupload_logic(void *arg)
pubkey_hex, strlen(pubkey_hex));
hs_build_address(&pubkey, HS_VERSION_THREE, onion_addr);
service = tor_malloc_zero(sizeof(hs_service_t));
+ tt_assert(service);
memcpy(service->onion_address, onion_addr, sizeof(service->onion_address));
ed25519_secret_key_generate(&service->keys.identity_sk, 0);
ed25519_public_key_generate(&service->keys.identity_pk,
diff --git a/src/test/test_hs_dos.c b/src/test/test_hs_dos.c
new file mode 100644
index 0000000000..3dfa057a4a
--- /dev/null
+++ b/src/test/test_hs_dos.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2017-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_cell.c
+ * \brief Test hidden service cell functionality.
+ */
+
+#define CIRCUITLIST_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+
+#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+
+#include "app/config/config.h"
+
+#include "core/or/circuitlist.h"
+#include "core/or/circuituse.h"
+#include "core/or/or_circuit_st.h"
+
+#include "feature/hs/hs_dos.h"
+#include "feature/nodelist/networkstatus.h"
+
+static void
+setup_mock_consensus(void)
+{
+ current_ns_consensus = tor_malloc_zero(sizeof(networkstatus_t));
+ current_ns_consensus->net_params = smartlist_new();
+ smartlist_add(current_ns_consensus->net_params,
+ (void *) "HiddenServiceEnableIntroDoSDefense=1");
+ hs_dos_consensus_has_changed(current_ns_consensus);
+}
+
+static void
+free_mock_consensus(void)
+{
+ smartlist_free(current_ns_consensus->net_params);
+ tor_free(current_ns_consensus);
+}
+
+static void
+test_can_send_intro2(void *arg)
+{
+ uint32_t now = (uint32_t) approx_time();
+ or_circuit_t *or_circ = NULL;
+
+ (void) arg;
+
+ hs_init();
+ hs_dos_init();
+
+ get_options_mutable()->ORPort_set = 1;
+ setup_mock_consensus();
+
+ or_circ = or_circuit_new(1, NULL);
+
+ /* Make that circuit a service intro point. */
+ circuit_change_purpose(TO_CIRCUIT(or_circ), CIRCUIT_PURPOSE_INTRO_POINT);
+ /* Initialize the INTRODUCE2 token bucket for the rate limiting. */
+ token_bucket_ctr_init(&or_circ->introduce2_bucket, hs_dos_get_intro2_rate(),
+ hs_dos_get_intro2_burst(), now);
+
+ /* Brand new circuit, we should be able to send INTRODUCE2 cells. */
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+
+ /* Simulate that 10 cells have arrived in 1 second. There should be no
+ * refill since the bucket is already at maximum on the first cell. */
+ update_approx_time(++now);
+ for (int i = 0; i < 10; i++) {
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ }
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ hs_dos_get_intro2_burst() - 10);
+
+ /* Fully refill the bucket minus 1 cell. */
+ update_approx_time(++now);
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ hs_dos_get_intro2_burst() - 1);
+
+ /* Receive an INTRODUCE2 at each second. We should have the bucket full
+ * since at every second it gets refilled. */
+ for (int i = 0; i < 10; i++) {
+ update_approx_time(++now);
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ }
+ /* Last check if we can send the cell decrements the bucket so minus 1. */
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ hs_dos_get_intro2_burst() - 1);
+
+ /* Manually reset bucket for next test. */
+ token_bucket_ctr_reset(&or_circ->introduce2_bucket, now);
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ hs_dos_get_intro2_burst());
+
+ /* Do a full burst in the current second which should empty the bucket and
+ * we shouldn't be allowed to send one more cell after that. We go minus 1
+ * cell else the very last check if we can send the INTRO2 cell returns
+ * false because the bucket goes down to 0. */
+ for (uint32_t i = 0; i < hs_dos_get_intro2_burst() - 1; i++) {
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ }
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 1);
+ /* Get the last remaining cell, we shouldn't be allowed to send it. */
+ tt_int_op(false, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 0);
+
+ /* Make sure the next 100 cells aren't allowed and bucket stays at 0. */
+ for (int i = 0; i < 100; i++) {
+ tt_int_op(false, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 0);
+ }
+
+ /* One second has passed, we should have the rate minus 1 cell added. */
+ update_approx_time(++now);
+ tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
+ tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
+ hs_dos_get_intro2_rate() - 1);
+
+ done:
+ circuit_free_(TO_CIRCUIT(or_circ));
+
+ hs_free_all();
+ free_mock_consensus();
+}
+
+struct testcase_t hs_dos_tests[] = {
+ { "can_send_intro2", test_can_send_intro2, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index 732836fb5b..7b01809f96 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -16,6 +16,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "core/or/or.h"
+#include "core/or/channel.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "ht.h"
@@ -25,6 +26,7 @@
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_common.h"
+#include "feature/hs/hs_dos.h"
#include "feature/hs/hs_intropoint.h"
#include "feature/hs/hs_service.h"
@@ -118,6 +120,8 @@ helper_create_intro_circuit(void)
or_circuit_t *circ = or_circuit_new(0, NULL);
tt_assert(circ);
circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
+ token_bucket_ctr_init(&circ->introduce2_bucket, 100, 100,
+ (uint32_t) approx_time());
done:
return circ;
}
@@ -693,6 +697,17 @@ test_introduce1_suitable_circuit(void *arg)
tt_int_op(ret, OP_EQ, 0);
}
+ /* Single hop circuit should not be allowed. */
+ {
+ circ = or_circuit_new(0, NULL);
+ circ->p_chan = tor_malloc_zero(sizeof(channel_t));
+ circ->p_chan->is_client = 1;
+ ret = circuit_is_suitable_for_introduce1(circ);
+ tor_free(circ->p_chan);
+ circuit_free_(TO_CIRCUIT(circ));
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
done:
;
}
@@ -888,43 +903,63 @@ test_received_introduce1_handling(void *arg)
UNMOCK(relay_send_command_from_edge_);
}
+static void *
+hs_subsystem_setup_fn(const struct testcase_t *tc)
+{
+ (void) tc;
+
+ return NULL;
+}
+
+static int
+hs_subsystem_cleanup_fn(const struct testcase_t *tc, void *arg)
+{
+ (void) tc;
+ (void) arg;
+
+ return 1;
+}
+
+static struct testcase_setup_t test_setup = {
+ hs_subsystem_setup_fn, hs_subsystem_cleanup_fn
+};
+
struct testcase_t hs_intropoint_tests[] = {
{ "intro_point_registration",
- test_intro_point_registration, TT_FORK, NULL, NULL },
+ test_intro_point_registration, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_keytype",
- test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_keytype, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_keytype2",
- test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_keytype2, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_purpose",
- test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_purpose, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_sig",
- test_establish_intro_wrong_sig, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_sig, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_sig_len",
- test_establish_intro_wrong_sig_len, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_sig_len, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_auth_key_len",
- test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, &test_setup},
{ "receive_establish_intro_wrong_mac",
- test_establish_intro_wrong_mac, TT_FORK, NULL, NULL },
+ test_establish_intro_wrong_mac, TT_FORK, NULL, &test_setup},
{ "introduce1_suitable_circuit",
- test_introduce1_suitable_circuit, TT_FORK, NULL, NULL },
+ test_introduce1_suitable_circuit, TT_FORK, NULL, &test_setup},
{ "introduce1_is_legacy",
- test_introduce1_is_legacy, TT_FORK, NULL, NULL },
+ test_introduce1_is_legacy, TT_FORK, NULL, &test_setup},
{ "introduce1_validation",
- test_introduce1_validation, TT_FORK, NULL, NULL },
+ test_introduce1_validation, TT_FORK, NULL, &test_setup},
{ "received_introduce1_handling",
- test_received_introduce1_handling, TT_FORK, NULL, NULL },
+ test_received_introduce1_handling, TT_FORK, NULL, &test_setup},
END_OF_TESTCASES
};
-
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index a303f10411..2e4be4e295 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1265,6 +1265,7 @@ test_service_event(void *arg)
/* Set a service for this circuit. */
service = helper_create_service();
+ tt_assert(service);
ed25519_pubkey_copy(&circ->hs_ident->identity_pk,
&service->keys.identity_pk);
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
index 4a6d90d97e..104e973b1f 100644
--- a/src/test/test_introduce.c
+++ b/src/test/test_introduce.c
@@ -383,8 +383,10 @@ make_intro_from_plaintext(
/* Output the cell */
*cell_out = cell;
+ cell = NULL;
done:
+ tor_free(cell);
return cell_len;
}
@@ -535,4 +537,3 @@ struct testcase_t introduce_tests[] = {
INTRODUCE_LEGACY(late_parse_v3),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 6416e98a4e..bb7018fe1c 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -15,7 +15,7 @@
#endif
static void
-dummy_cb_fn(int severity, uint32_t domain, const char *msg)
+dummy_cb_fn(int severity, log_domain_mask_t domain, const char *msg)
{
(void)severity; (void)domain; (void)msg;
}
diff --git a/src/test/test_options.c b/src/test/test_options.c
index b39cd4f1e4..64fcd011e7 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -31,14 +31,14 @@
typedef struct {
int severity;
- uint32_t domain;
+ log_domain_mask_t domain;
char *msg;
} logmsg_t;
static smartlist_t *messages = NULL;
static void
-log_cback(int severity, uint32_t domain, const char *msg)
+log_cback(int severity, log_domain_mask_t domain, const char *msg)
{
logmsg_t *x = tor_malloc(sizeof(*x));
x->severity = severity;
diff --git a/src/test/test_rebind.sh b/src/test/test_rebind.sh
index e0d8394d38..d6d9d86668 100755
--- a/src/test/test_rebind.sh
+++ b/src/test/test_rebind.sh
@@ -12,8 +12,6 @@ if test "$UNAME_OS" = 'CYGWIN' || \
fi
fi
-exitcode=0
-
tmpdir=
clean () {
if [ -n "$tmpdir" ] && [ -d "$tmpdir" ]; then
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index 84ec8cc462..6d596e87ea 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -631,7 +631,7 @@ mock_clock_skew_warning(const connection_t *conn, long apparent_skew,
(void)conn;
mock_apparent_skew = apparent_skew;
tt_int_op(trusted, OP_EQ, 1);
- tt_int_op(domain, OP_EQ, LD_GENERAL);
+ tt_i64_op(domain, OP_EQ, LD_GENERAL);
tt_str_op(received, OP_EQ, "microdesc flavor consensus");
tt_str_op(source, OP_EQ, "CONSENSUS");
done:
diff --git a/src/test/test_status.c b/src/test/test_status.c
index 9c47469975..2fb2a7b24f 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -404,7 +404,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -412,7 +412,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
break;
case 1:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -429,7 +429,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
break;
case 3:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "rep_hist_log_circuit_handshake_stats"),
OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
@@ -442,13 +442,13 @@ NS(logv)(int severity, log_domain_mask_t domain,
break;
case 4:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"),
OP_NE, NULL);
break;
case 5:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_str_op(format, OP_EQ, "DoS mitigation since startup:%s%s%s%s");
tt_str_op(va_arg(ap, char *), OP_EQ,
" 0 circuits killed with too many cells.");
@@ -574,7 +574,7 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
++NS(n_msgs);
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -709,7 +709,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -723,7 +723,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
break;
case 1:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -889,7 +889,7 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -903,7 +903,7 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
break;
case 1:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -1038,7 +1038,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
{
case 0:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
@@ -1052,7 +1052,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
break;
case 1:
tt_int_op(severity, OP_EQ, LOG_NOTICE);
- tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_u64_op(domain, OP_EQ, LD_HEARTBEAT);
tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
tt_ptr_op(suffix, OP_EQ, NULL);
tt_str_op(format, OP_EQ,
diff --git a/src/test/test_token_bucket.c b/src/test/test_token_bucket.c
index d3ce591388..31670718d9 100644
--- a/src/test/test_token_bucket.c
+++ b/src/test/test_token_bucket.c
@@ -93,7 +93,7 @@ test_token_bucket_ctr_dec(void *arg)
/* Keep underflowing shouldn't flag the bucket as empty. */
tt_uint_op(false, OP_EQ, token_bucket_ctr_dec(&tb, BURST));
- tt_int_op(tb.counter.bucket, OP_EQ, (int32_t) ((BURST + 1) * -1));
+ tt_int_op(tb.counter.bucket, OP_EQ, - (int32_t) (BURST + 1));
done:
;
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 41ecbfd388..c56d3488ba 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -5399,11 +5399,13 @@ test_util_socketpair(void *arg)
tt_skip();
}
#endif /* defined(__FreeBSD__) */
+#ifdef ENETUNREACH
if (ersatz && socketpair_result == -ENETUNREACH) {
/* We can also fail with -ENETUNREACH if we have no network stack at
* all. */
tt_skip();
}
+#endif
tt_int_op(0, OP_EQ, socketpair_result);
tt_assert(SOCKET_OK(fds[0]));
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 1c2a2e8960..ad22898ce5 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -243,7 +243,7 @@ tinytest_postfork(void)
}
static void
-log_callback_failure(int severity, uint32_t domain, const char *msg)
+log_callback_failure(int severity, log_domain_mask_t domain, const char *msg)
{
(void)msg;
if (severity == LOG_ERR || (domain & LD_BUG)) {
diff --git a/src/tools/tor-print-ed-signing-cert.c b/src/tools/tor-print-ed-signing-cert.c
index 1f1a01ab5c..43a1d7bcbd 100644
--- a/src/tools/tor-print-ed-signing-cert.c
+++ b/src/tools/tor-print-ed-signing-cert.c
@@ -10,11 +10,13 @@
#include "lib/cc/torint.h" /* TOR_PRIdSZ */
#include "lib/crypt_ops/crypto_format.h"
#include "lib/malloc/malloc.h"
+#include "lib/encoding/time_fmt.h"
int
main(int argc, char **argv)
{
ed25519_cert_t *cert = NULL;
+ char rfc1123_buf[RFC1123_TIME_LEN+1] = "";
if (argc != 2) {
fprintf(stderr, "Usage:\n");
@@ -59,6 +61,11 @@ main(int argc, char **argv)
printf("Expires at: %s", ctime(&expires_at));
+ format_rfc1123_time(rfc1123_buf, expires_at);
+ printf("RFC 1123 timestamp: %s\n", rfc1123_buf);
+
+ printf("UNIX timestamp: %ld\n", (long int)expires_at);
+
ed25519_cert_free(cert);
return 0;